Files
Dynamic-Form-Tools/DevResources/full-examples/bdgt04/view/frm/bdgt-0403020/construct.frml
skidus f705cd11b9 feat: implement advanced bidirectional field referencing and cross-module path resolution
- Core Logic Enhancements:
    - Implement bidirectional field referencing between <FIELDS>, <LAYOUT>, and <TITLES> tags in .frml files, enabling seamless navigation from definitions to usages and vice versa.
    - Add robust support for AJAX-OPTION field mapping:
        - SRC attribute: Links to field definitions within defs/ajax.xml datasets.
        - TARGET attribute: Links to local field definitions within the same form.
    - Implement global grid resolution: GRID-ID now searches across the current file and all recursively included files (<INCLUDE>).
    - Enhance deep recursive search for fields/sections within nested tags like <SECTION>, <ROW>, and <FIELD-LIST>.

- Path Resolution & Helpers (DynFormPathUtils):
    - Added support for module-relative paths starting with # (mapping to view/frm/).
    - Added support for cross-module paths starting with / (mapping to WEB-INF/app/module/{module}/view/frm/).
    - Implemented auto-correction for common keyboard typos (Thai 'ิ' instead of /).
    - Added specialized helpers for locating ajax.xml and included files within the framework's structure.

- Smart Completion Enhancements:
    - Added context-aware completion for TARGET and SRC fields in AJAX update-fields.
    - Enabled global GRID-ID completion by scanning all included resources.
    - Improved dataset completion to include both local and AJAX-defined datasets.

- Test Resources:
    - Added a comprehensive set of real-world examples (bdgt04, bdgt05, bdgt06) in DevResources/full-examples/ to validate complex cross-module and master-detail scenarios.
2026-04-10 12:56:04 +07:00

298 lines
14 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/#dynf_form_def.xsd">
<INCLUDES>
<INCLUDE FILE="#grids/grid-construct-budget.frml"></INCLUDE>
</INCLUDES>
<DATASETS>
<DATASET ID="DS-MASTER">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECTS</TABLENAME>
<KEYFIELDS>PROJ_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT PROJ_ID
, PROJ_TYPE
, PROJ_YEAR
, PJM_CODE
, STM_CODE
, BTM_CODE
, ACM_CODE
, BUD.GET_ACTIVITY(ACM_CODE) ACM_NAME
, PLAN_TYPE
, PROJ_DURATION
, PROJ_INST_COUNT
, PROJ_START_YEAR
, PROJ_END_YEAR
, PROJ_FOR_STAFF
, PROJ_FROM_YEAR
, CREATE_BY
, CREATE_TIME
, UPDATE_BY
, UPDATE_TIME
</SELECT>
<FROM>FROM PROJECTS</FROM>
<FILTER>WHERE STM_CODE = :STM_CODE AND PROJ_TYPE='CNST'</FILTER>
<ORDER>ORDER BY PROJ_ID</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PROJ_TYPE" TYPE="TEXT" LABEL="ประเภทโครงการ" WIDTH="25"/>
<FIELD NAME="PROJ_YEAR" TYPE="NUMBER" LABEL="ปีงบประมาณ" WIDTH="15"/>
<FIELD NAME="PJM_CODE" TYPE="TEXT" LABEL="รหัสโครงการ (BUD)" WIDTH="20"/>
<FIELD NAME="STM_CODE" TYPE="TEXT" LABEL="รหัสหน่วยงาน" WIDTH="10"/>
<FIELD NAME="BTM_CODE" TYPE="TEXT" LABEL="รหัสประเภทงบประมาณ" WIDTH="10"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="20"/>
<FIELD NAME="PLAN_TYPE" TYPE="TEXT" LABEL="ประเภทแผน" WIDTH="15"/>
<FIELD NAME="PROJ_DURATION" TYPE="NUMBER" LABEL="ระยะเวลาดำเนินการ (วัน)" WIDTH="15"/>
<FIELD NAME="PROJ_INST_COUNT" TYPE="NUMBER" LABEL="ระยะเวลาดำเนินการ (วัน)" WIDTH="15"/>
<FIELD NAME="PROJ_START_YEAR" TYPE="NUMBER" LABEL="ปีที่เริ่มโครงการ (ก่อสร้าง)" WIDTH="15"/>
<FIELD NAME="PROJ_END_YEAR" TYPE="NUMBER" LABEL="ปีที่สิ้นสุดโครงการ (ก่อสร้าง)" WIDTH="15"/>
<FIELD NAME="PROJ_FOR_STAFF" TYPE="NUMBER" LABEL="จำนวนบุคลากรที่รองรับ" WIDTH="15"/>
<FIELD NAME="PROJ_FROM_YEAR" TYPE="NUMBER" LABEL="ต่อเนื่องจากปี" WIDTH="15"/>
<FIELD NAME="CREATE_BY" TYPE="TEXT" LABEL="ผู้สร้างรายการ" WIDTH="50"/>
<FIELD NAME="CREATE_TIME" TYPE="DATE" LABEL="เวลาที่สร้างรายการ" WIDTH="0"/>
<FIELD NAME="UPDATE_BY" TYPE="TEXT" LABEL="ผู้แก้ไขรายการล่าสุด" WIDTH="50"/>
<FIELD NAME="UPDATE_TIME" TYPE="DATE" LABEL="เวลาที่แก้ไขรายการล่าสุด" WIDTH="0"/>
</FIELDS>
</DATASET>
<DATASET ID="DS-PROJECT-CONST">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_CONST_INFO</TABLENAME>
<KEYFIELDS>PROJ_ID,ACM_CODE</KEYFIELDS>
<SQL>
<SELECT>
SELECT PROJ_ID
, ACM_CODE
, PCTI_ADDRESS
, PCTI_TUMBON
, PCTI_AMPUR
, PCTI_PROVINCE
, PCTI_ADDR_NOTE
, PCTI_AREA
, PCTI_EMP_COUNT
, PCTI_CHK_LOCATION
, PCTI_CHK_DOCUMENT
, PCTI_REMARK
, CREATE_BY
, JDTOE(CREATE_TIME) CREATE_TIME, CREATE_TIME DT_CREATE_TIME
, UPDATE_BY
, JDTOE(UPDATE_TIME) UPDATE_TIME, UPDATE_TIME DT_UPDATE_TIME
</SELECT>
<FROM>FROM PROJECT_CONST_INFO</FROM>
<ORDER>ORDER BY PROJ_ID, ACM_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="project.id" WIDTH="50"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="project.acm_code" WIDTH="20"/>
<FIELD NAME="PCTI_ADDRESS" TYPE="TEXT" LABEL="pcti.address" WIDTH="200"/>
<FIELD NAME="PCTI_TUMBON" TYPE="TEXT" LABEL="pcti.tumbon" WIDTH="200"/>
<FIELD NAME="PCTI_AMPUR" TYPE="TEXT" LABEL="pcti.ampur" WIDTH="200"/>
<FIELD NAME="PCTI_PROVINCE" TYPE="TEXT" LABEL="pcti.province" WIDTH="200"/>
<FIELD NAME="PCTI_ADDR_NOTE" TYPE="TEXT" LABEL="pcti.addr_note" WIDTH="1000"/>
<FIELD NAME="PCTI_AREA" TYPE="NUMBER" LABEL="pcti.area" WIDTH="15"/>
<FIELD NAME="PCTI_EMP_COUNT" TYPE="NUMBER" LABEL="pcti.emp_count" WIDTH="15"/>
<FIELD NAME="PCTI_CHK_LOCATION" TYPE="TEXT" LABEL="pcti.chk_location" WIDTH="500"/>
<FIELD NAME="PCTI_CHK_DOCUMENT" TYPE="TEXT" LABEL="pcti.chk_document" WIDTH="500"/>
<FIELD NAME="PCTI_REMARK" TYPE="TEXT" LABEL="pcti.remark" WIDTH="2000"/>
<FIELD NAME="CREATE_BY" TYPE="TEXT" LABEL="sys.create_by" WIDTH="50"/>
<FIELD NAME="CREATE_TIME" TYPE="DATE" LABEL="sys.create_time" WIDTH="0"/>
<FIELD NAME="UPDATE_BY" TYPE="TEXT" LABEL="sys.update_by" WIDTH="50"/>
<FIELD NAME="UPDATE_TIME" TYPE="DATE" LABEL="sys.update_time" WIDTH="0"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,ACM_CODE" DETAIL-FIELDS="PROJ_ID,ACM_CODE"/>
</DATASET>
</DATASETS>
<FORM>
<FORM_ENTRY DATAID="DS-MASTER" SAVE="Y" RESET="Y" RETURN="Y">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PROJ_TYPE" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PJM_CODE" INPUTTYPE="HIDDEN"/>
<FIELD NAME="STM_CODE" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BTM_CODE" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PLAN_TYPE" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PROJ_DURATION" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PROJ_YEAR" CAPTION="project.year" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="ACM_CODE" CAPTION="project.const_code" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="ACM_NAME" CAPTION="project.const_name" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="PROJ_START_YEAR" CAPTION="project.start_year" INPUTTYPE="TEXT" DATATYPE="NUMTEXT" ALIGN="center"/>
<FIELD NAME="PROJ_END_YEAR" CAPTION="project.end_year" INPUTTYPE="TEXT" DATATYPE="NUMTEXT" ALIGN="center"/>
<FIELD NAME="PROJ_DURATION" CAPTION="project.duration" INPUTTYPE="TEXT" DATATYPE="NUMBER" ALIGN="center" DECIMAL="0" SUFFIX="day"/>
<FIELD NAME="PROJ_INST_COUNT" CAPTION="project.inst_count" INPUTTYPE="TEXT" DATATYPE="NUMTEXT" ALIGN="center" REQUIRE="Y"/>
<FIELD NAME="BUDGET_YEAR_01" CAPTION="2567" INPUTTYPE="TEXT" DATATYPE="NUMBER"/>
<FIELD NAME="BUDGET_YEAR_02" CAPTION="2568" INPUTTYPE="TEXT" DATATYPE="NUMBER"/>
<FIELD NAME="BUDGET_YEAR_03" CAPTION="2569" INPUTTYPE="TEXT" DATATYPE="NUMBER"/>
<FIELD NAME="BUDGET_YEAR_04" CAPTION="2570" INPUTTYPE="TEXT" DATATYPE="NUMBER"/>
<FIELD NAME="BUDGET_YEAR_05" CAPTION="2571" INPUTTYPE="TEXT" DATATYPE="NUMBER"/>
<SECTION ID="SECT-PROJECT-CONST">
<FIELD NAME="PCTI_ADDRESS" CAPTION="pcti.address" INPUTTYPE="TEXT"/>
<FIELD NAME="PCTI_TUMBON" CAPTION="pcti.tumbon" INPUTTYPE="TEXT"/>
<FIELD NAME="PCTI_AMPUR" CAPTION="pcti.ampur" INPUTTYPE="TEXT"/>
<FIELD NAME="PCTI_PROVINCE" CAPTION="pcti.province" INPUTTYPE="TEXT"/>
<FIELD NAME="PCTI_ADDR_NOTE" CAPTION="pcti.addr_note" INPUTTYPE="TEXT"/>
<FIELD NAME="PCTI_AREA" CAPTION="pcti.area" INPUTTYPE="TEXT" DATATYPE="NUMBER" SUFFIX="segtor"/>
<FIELD NAME="PCTI_EMP_COUNT" CAPTION="pcti.emp_count" INPUTTYPE="TEXT" DATATYPE="NUMBER"/>
<FIELD NAME="PCTI_CHK_LOCATION" CAPTION="pcti.chk_location" INPUTTYPE="CHECKBOXGROUP">
<LIST-OPTION TABLE="REFER_CODE" VALUE="RFC_CODE" TEXT="RFC_DESC" FILTER="RFG_GRP='CNT-PAREA'" COLUMN="4" ORDER="RFC_ORDER"/>
</FIELD>
<FIELD NAME="PCTI_CHK_DOCUMENT" CAPTION="pcti.chk_document" INPUTTYPE="CHECKBOXGROUP">
<LIST-OPTION TABLE="REFER_CODE" VALUE="RFC_CODE" TEXT="RFC_DESC" FILTER="RFG_GRP='CNT-PDOC'" COLUMN="4" ORDER="RFC_ORDER"/>
</FIELD>
<FIELD NAME="PCTI_REMARK" CAPTION="pcti.remark" INPUTTYPE="TEXTAREA" ROWS="3"/>
</SECTION>
<FIELD NAME="GRID-BUDGET" INPUTTYPE="DATA-GRID" GRID-ID="GRID-CONST-BUDGET" ROWS="5" CAPTION="project.budget"/>
<SECTION ID="SEC-ATTATCH-FILE">
<FIELD NAME="FILE_BOX_01" CAPTION="แบบ/ประมาณการราคาอาคารสำนักงาน" INPUTTYPE="FILE-BOX" DATATYPE="TEXT">
<FILE-BOX FILE-TYPE="budget" FILE-ACCEPTS="pdf,docx,xlsx,jpeg,jpg,png"
UPLOAD-URL="/file-upload.jbx" FILE-URL="/get-file.jbx"
DEFAULT-NAME="@{filepath}/@{acm_code}/file-01"/>
</FIELD>
<FIELD NAME="FILE_BOX_02" CAPTION="หนังสืออนุญาตให้ใช้ที่ดิน ได้มาซึ่งกรรมสิทธิ์ในที่ดิน" INPUTTYPE="FILE-BOX" DATATYPE="TEXT">
<FILE-BOX FILE-TYPE="budget" FILE-ACCEPTS="pdf,docx,xlsx,jpeg,jpg,png"
UPLOAD-URL="/file-upload.jbx" FILE-URL="/get-file.jbx"
DEFAULT-NAME="@{filepath}/@{acm_code}/file-01"/>
</FIELD>
<FIELD NAME="FILE_BOX_03" CAPTION="ผังบริเวณ ประมาณราคาผังบริเวณ สิ่งก่อสร้างประกอบ" INPUTTYPE="FILE-BOX" DATATYPE="TEXT">
<FILE-BOX FILE-TYPE="budget" FILE-ACCEPTS="pdf,docx,xlsx,jpeg,jpg,png"
UPLOAD-URL="/file-upload.jbx" FILE-URL="/get-file.jbx"
DEFAULT-NAME="@{filepath}/@{acm_code}/file-01"/>
</FIELD>
<FIELD NAME="FILE_BOX_04" CAPTION="ประมาณการถมดิน/รื้อถอนอาคาร/กำแพงกันดิน ฯลฯ (ถ้ามี)" INPUTTYPE="FILE-BOX" DATATYPE="TEXT">
<FILE-BOX FILE-TYPE="budget" FILE-ACCEPTS="pdf,docx,xlsx,jpeg,jpg,png"
UPLOAD-URL="/file-upload.jbx" FILE-URL="/get-file.jbx"
DEFAULT-NAME="@{filepath}/@{acm_code}/file-01"/>
</FIELD>
<FIELD NAME="FILE_BOX_05" CAPTION="ประมาณการขยายเขตไฟฟ้า ขยายเขตประปา" INPUTTYPE="FILE-BOX" DATATYPE="TEXT">
<FILE-BOX FILE-TYPE="budget" FILE-ACCEPTS="pdf,docx,xlsx,jpeg,jpg,png"
UPLOAD-URL="/file-upload.jbx" FILE-URL="/get-file.jbx"
DEFAULT-NAME="@{filepath}/@{acm_code}/file-01"/>
</FIELD>
</SECTION>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<SECTION ID="SECT-MAIN">
<ROW>
<FIELD NAME="PROJ_YEAR" LAYOUT_WIDTH="6" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="ACM_CODE" LAYOUT_WIDTH="4"/>
<FIELD NAME="ACM_NAME" LAYOUT_WIDTH="18"/>
</ROW>
<ROW>
<FIELD NAME="PCTI_EMP_COUNT" LAYOUT_WIDTH="4" OFFSET="4"/>
<FIELD NAME="PROJ_DURATION" LAYOUT_WIDTH="4"/>
<FIELD NAME="PROJ_INST_COUNT" LAYOUT_WIDTH="4"/>
<FIELD NAME="PROJ_START_YEAR" LAYOUT_WIDTH="4"/>
<FIELD NAME="PROJ_END_YEAR" LAYOUT_WIDTH="4"/>
</ROW>
</SECTION>
<SECTION ID="SECT-PROJECT-CONST" DATASET="DS-PROJECT-CONST" AUTO-INSERT="Y" TYPE="DATA-SECTION">
<HEADER CLASS="col-24 mg-b-n30 mg-t-16 border-top-1">
<![CDATA[<h4 class="ml-3 col-24">@M{project.year_budgets}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="BUDGET_YEAR_01" LAYOUT_WIDTH="4" OFFSET="4"/>
<FIELD NAME="BUDGET_YEAR_02" LAYOUT_WIDTH="4"/>
<FIELD NAME="BUDGET_YEAR_03" LAYOUT_WIDTH="4"/>
<FIELD NAME="BUDGET_YEAR_04" LAYOUT_WIDTH="4"/>
<FIELD NAME="BUDGET_YEAR_05" LAYOUT_WIDTH="4"/>
</ROW>
</SECTION>
<SECTION ID="SECT-PROJECT-CONST" DATASET="DS-PROJECT-CONST" AUTO-INSERT="Y" TYPE="DATA-SECTION">
<HEADER CLASS="col-24 mg-b-n30 mg-t-16 border-top-1">
<![CDATA[
<h4 class="ml-3 col-24">@M{pcti.location_info}</h4>
]]>
</HEADER>
<ROW>
<FIELD NAME="PCTI_ADDRESS" LAYOUT_WIDTH="18" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="PCTI_TUMBON" LAYOUT_WIDTH="4" OFFSET="4"/>
<FIELD NAME="PCTI_AMPUR" LAYOUT_WIDTH="4"/>
<FIELD NAME="PCTI_PROVINCE" LAYOUT_WIDTH="4"/>
<FIELD NAME="PCTI_AREA" LAYOUT_WIDTH="4"/>
</ROW>
<ROW>
<FIELD NAME="PCTI_ADDR_NOTE" LAYOUT_WIDTH="18" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="PCTI_CHK_LOCATION" LAYOUT_WIDTH="18" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="PCTI_CHK_DOCUMENT" LAYOUT_WIDTH="18" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="PCTI_REMARK" LAYOUT_WIDTH="18" OFFSET="4"/>
</ROW>
</SECTION>
<SECTION ID="SECT-PROJECT-BUTGET">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">@M{project.budget}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="GRID-BUDGET" LAYOUT_WIDTH="24" OFFSET=""/>
</ROW>
</SECTION>
<SECTION ID="SECT-PROJECT-BUTGET">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">@M{project.constructor_attatchment}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="FILE_BOX_01" LAYOUT_WIDTH="10" OFFSET="4"/>
<FIELD NAME="FILE_BOX_02" LAYOUT_WIDTH="10"/>
</ROW>
<ROW>
<FIELD NAME="FILE_BOX_03" LAYOUT_WIDTH="10" OFFSET="4"/>
<FIELD NAME="FILE_BOX_04" LAYOUT_WIDTH="10"/>
</ROW>
<ROW>
<FIELD NAME="FILE_BOX_05" LAYOUT_WIDTH="10" OFFSET="4"/>
</ROW>
</SECTION>
</LAYOUT>
<SCRIPT>
<EVENTS>
<BEFORE-SAVE>
<![CDATA[
({form, data}) => {
console.log("before save data ...");
if ($PageCtx.$action === "add") {
let projYear = $$("PROJ_YEAR").val();
let projType = "CNST";
let stmCode = $user.deptCode;
let pjmCode = "B.2.01";
let btmCode = "01";
let acmCode = $$("ACM_CODE").val();
let projId = `${projYear}x${projType}x${stmCode}x${pjmCode}x${btmCode}x${acmCode}`;
$$("PROJ_ID").val(projId);
$$("PROJ_TYPE").val("CONST");
$$("STM_CODE").val(stmCode);
$$("PJM_CODE").val(pjmCode);
$$("BTM_CODE").val(btmCode);
$$("AC_CODE").val(acmCode);
}
//update data to save
Object.assign(data, $PageCtx.$form.jsonData());
}
]]>
</BEFORE-SAVE>
</EVENTS>
</SCRIPT>
</FORM_ENTRY>
</FORM>
</FORMS>