Files
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

231 lines
9.8 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-routine-budget.frml"></INCLUDE>
</INCLUDES>
<DATASETS>
<DATASET ID="DS-MASTER">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGETS</TABLENAME>
<KEYFIELDS>PROJ_ID,ACM_CODE</KEYFIELDS>
<SQL>
<SELECT>SELECT PBDG.PROJ_ID
, PROJ.PROJ_YEAR
, PBDG.PBDG_ID
, PBDG.ACM_CODE
, BUD.GET_ACTIVITY(PBDG.ACM_CODE) ACM_NAME
, PBDG.PBDG_TOTAL
, PBDG.PBDG_COUNT
</SELECT>
<FROM>FROM PROJECT_BUDGETS PBDG
INNER JOIN PROJECTS PROJ ON PROJ.PROJ_ID=PBDG.PROJ_ID
</FROM>
<ORDER>ORDER BY PBDG.PROJ_ID,PBDG.PBDG_ID</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32" ORIGIN="PBDG.PROJ_ID"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="20" ORIGIN="PBDG.ACM_CODE"/>
<FIELD NAME="PBDG_TOTAL" TYPE="NUMBER" LABEL="ยอดรวม" WIDTH="15"/>
<FIELD NAME="PBDG_COUNT" TYPE="NUMBER" LABEL="จำนวนกิจกรรม" WIDTH="15"/>
</FIELDS>
</DATASET>
<DATASET ID="DS-PROJECT-TARGETS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_TARGETS</TABLENAME>
<KEYFIELDS>PROJ_ID,ACM_CODE</KEYFIELDS>
<SQL>
<SELECT>SELECT PROJ_ID
, ACM_CODE
, PWMT_UNIT
, PTGT_QT_0101
, PTGT_QT_0102
, PTGT_QT_0201
, PTGT_QT_0202
, PTGT_QT_0301
, PTGT_QT_0302
, PTGT_QT_0401
, PTGT_QT_0402
</SELECT>
<FROM>FROM PROJECT_TARGETS</FROM>
<ORDER>ORDER BY PROJ_ID,ACM_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="33"/>
<FIELD NAME="PWMT_UNIT" TYPE="TEXT" LABEL="หน่วยนับ" WIDTH="32"/>
<FIELD NAME="PTGT_QT_0101" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 1 (แผน)" WIDTH="15"/>
<FIELD NAME="PTGT_QT_0102" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 1 (ผล)" WIDTH="15"/>
<FIELD NAME="PTGT_QT_0201" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 2 (แผน)" WIDTH="15"/>
<FIELD NAME="PTGT_QT_0202" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 2 (ผล)" WIDTH="15"/>
<FIELD NAME="PTGT_QT_0301" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 3 (แผน)" WIDTH="15"/>
<FIELD NAME="PTGT_QT_0302" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 3 (ผล)" WIDTH="15"/>
<FIELD NAME="PTGT_QT_0401" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 4 (แผน)" WIDTH="15"/>
<FIELD NAME="PTGT_QT_0402" TYPE="NUMBER" LABEL="เป้าหมายไตรมาส 4 (ผล)" 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>
<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" RETURN="Y">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="ACM_CODE" CAPTION="project.acm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="PROJ_YEAR" CAPTION="project.year" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="PROJ_PRINCIPLES" CAPTION="project.remak" INPUTTYPE="TEXT" ROWS="3"/>
<FIELD NAME="ACM_NAME" CAPTION="project.acm_name" INPUTTYPE="TEXT" EDIT-READONLY="Y"/>
<SECTION ID="SECT-PROJECT-TARGET">
<FIELD NAME="PBDG_TOTAL" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_COUNT" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PWMT_UNIT" CAPTION="project.target" INPUTTYPE="TEXT" READONLY="Y"></FIELD>
<FIELD NAME="QUOTER_1" INPUTTYPE="MULTI-FIELD" CAPTION="project.quoter 1" FIELD-SEPARATOR="/">
<FIELD-LIST>
<FIELD NAME="PTGT_QT_0101" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
<FIELD NAME="PTGT_QT_0102" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
</FIELD-LIST>
</FIELD>
<FIELD NAME="QUOTER_2" INPUTTYPE="MULTI-FIELD" CAPTION="project.quoter 2" FIELD-SEPARATOR="/">
<FIELD-LIST>
<FIELD NAME="PTGT_QT_0201" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
<FIELD NAME="PTGT_QT_0202" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
</FIELD-LIST>
</FIELD>
<FIELD NAME="QUOTER_3" INPUTTYPE="MULTI-FIELD" CAPTION="project.quoter 3" FIELD-SEPARATOR="/">
<FIELD-LIST>
<FIELD NAME="PTGT_QT_0301" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
<FIELD NAME="PTGT_QT_0302" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
</FIELD-LIST>
</FIELD>
<FIELD NAME="QUOTER_4" INPUTTYPE="MULTI-FIELD" CAPTION="project.quoter 4" FIELD-SEPARATOR="/">
<FIELD-LIST>
<FIELD NAME="PTGT_QT_0401" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
<FIELD NAME="PTGT_QT_0402" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
</FIELD-LIST>
</FIELD>
<FIELD NAME="TOTAL_QT" INPUTTYPE="MULTI-FIELD" CAPTION="project.total" FIELD-SEPARATOR="/" READONLY="Y">
<FIELD-LIST>
<FIELD NAME="QT_TOTAL_01" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
<FIELD NAME="QT_TOTAL_02" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"></FIELD>
</FIELD-LIST>
</FIELD>
</SECTION>
<FIELD NAME="GRID-BUDGET" INPUTTYPE="DATA-GRID" GRID-ID="GRID-WORK-BUDGET" ROWS="5" CAPTION="project.budget"/>
<SECTION ID="SEC-ATTATCH-FILE">
<FIELD NAME="FILE_BOX_01" CAPTION="file.upload 1" 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="file.upload 2" 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="file.upload 3" 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="6"/>
</ROW>
<ROW>
<FIELD NAME="ACM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="ACM_NAME" LAYOUT_WIDTH="18"/>
</ROW>
<ROW>
<FIELD NAME="PROJ_PRINCIPLES" LAYOUT_WIDTH="18" OFFSET="6"/>
</ROW>
</SECTION>
<SECTION ID="SECT-PROJECT-TARGET" TYPE="DATA-SECTION" DATASET="DS-PROJECT-TARGETS">
<ROW>
<FIELD NAME="PWMT_UNIT" LAYOUT_WIDTH="6"/>
<FIELD NAME="QUOTER_1" LAYOUT_WIDTH="3"/>
<FIELD NAME="QUOTER_2" LAYOUT_WIDTH="3"/>
<FIELD NAME="QUOTER_3" LAYOUT_WIDTH="3"/>
<FIELD NAME="QUOTER_4" LAYOUT_WIDTH="3"/>
<FIELD NAME="TOTAL_QT" LAYOUT_WIDTH="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-FILE-UPLOAD">
<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="16" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="FILE_BOX_02" LAYOUT_WIDTH="16" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="FILE_BOX_03" LAYOUT_WIDTH="16" OFFSET="4"/>
</ROW>
</SECTION>
</LAYOUT>
<SCRIPT>
<EVENTS>
<BEFORE-SAVE><![CDATA[
({form, data}) => {
console.log("before save data");
if ($PageCtx.$action === "add") {
let $data = $PageCtx.main.pageData;
let budgetId = $$("VACM_CODE").val();
$$("PBDG_ID").val(budgetId);
}
let acmCount = $$("^QT_TOTAL_0").sum();
$$("PBDG_COUNT").val(acmCount);
let gridCtx = ($PageCtx.widgets["GRID-BUDGET"]||{})["$GridCtx"];
if (gridCtx) {
let bdgTotal = gridCtx.sum_of["pbgi_total"];
$$("PBDG_TOTAL").val(bdgTotal);
}
Object.assign(data,form.mainForm.jsonData());
}
]]></BEFORE-SAVE>
</EVENTS>
<INITIALIZE>
<![CDATA[
const quoterSum = ()=>{
for (let sect=1; sect <=2; sect++) {
let summary = 0;
for (let qt = 1; qt <= 4; qt++) {
summary += $$(`PTGT_QT_0${qt}0${sect}`).number();
}
$$(`QT_TOTAL_0${sect}`).val(formatNumber(summary));
}
}
$$("^PTGT_QT_").on("change",quoterSum);
]]>
</INITIALIZE>
</SCRIPT>
</FORM_ENTRY>
</FORM>
</FORMS>