feat: comprehensive cross-file support and performance optimization (v3.3.0)

- Implemented cross-file completion, references, and validation for .frml files.
- Optimized resource discovery using IntelliJ indexing (ReferencesSearch) to fix IDE freeze.
- Refactored shared search logic into DynFormPathUtils.
- Excluded <ROW> tags from field definition requirements.
- Updated plugin version to 3.3.0.
This commit is contained in:
2026-05-14 18:27:57 +07:00
parent b6dc46d775
commit 431e51079c
35 changed files with 4693 additions and 565 deletions

6
.idea/DynamicFormToolsProject.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.sdk.dynform.tools.config.DynFormSettings">
<option name="xsdFolderPath" value="DevResources/xsd" />
</component>
</project>

6
.idea/misc.xml generated
View File

@@ -56,6 +56,12 @@
</profile-state> </profile-state>
</entry> </entry>
</component> </component>
<component name="ProjectResources">
<resource url="/dynf/ajax.xsd" location="$PROJECT_DIR$/DevResources/xsd/ajax.xsd" />
<resource url="/dynf/dynf-form-def.xsd" location="$PROJECT_DIR$/DevResources/xsd/dynf-form-def.xsd" />
<resource url="/dynf/lovdef.xsd" location="$PROJECT_DIR$/DevResources/xsd/lovdef.xsd" />
<resource url="/dynf/system-config.xsd" location="$PROJECT_DIR$/DevResources/xsd/system-config.xsd" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>

View File

@@ -1 +1 @@
2026-04-22 2026-05-14

View File

@@ -11,7 +11,7 @@
SDKLogger logger = new SDKLogger("Operate-actions"); SDKLogger logger = new SDKLogger("Operate-actions");
public boolean bgt0102010_add(SystemFactory factory, JSONObject jsData) { public boolean flowAdd(SystemFactory factory, JSONObject jsData) {
if (!jsData.getString("-- some important field --").isBlank()) { if (!jsData.getString("-- some important field --").isBlank()) {
DBConnector dbConn = factory.appDatabase.getXConnector(); DBConnector dbConn = factory.appDatabase.getXConnector();
try { try {
@@ -45,6 +45,14 @@
return true; return true;
} }
public boolean flowUpdate(SystemFactory factory, JSONObject jsData) {
return true;
}
public boolean flowDelete(SystemFactory factory, JSONObject jsData) {
return true;
}
public boolean _action_skeleton(SystemFactory factory, JSONObject jsData) { public boolean _action_skeleton(SystemFactory factory, JSONObject jsData) {
if (!jsData.getString("-- some important field --").isBlank()) { if (!jsData.getString("-- some important field --").isBlank()) {
DBConnector dbConn = factory.appDatabase.getXConnector(); DBConnector dbConn = factory.appDatabase.getXConnector();
@@ -62,7 +70,7 @@
return true; return true;
} }
public boolean execute(String action, SystemFactory factory) { private boolean execute(String action, SystemFactory factory) {
try { try {
Class<?> thisClass = getClass(); Class<?> thisClass = getClass();
Method mtAction = thisClass.getMethod(action, SystemFactory.class, JSONObject.class); Method mtAction = thisClass.getMethod(action, SystemFactory.class, JSONObject.class);

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/#dynf_form_def.xsd"> <FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../xsd/dynf-form-def.xsd">
<INCLUDES> <INCLUDES>
<INCLUDE FILE="#grids/grid-construct-budget.frml"></INCLUDE> <INCLUDE FILE="#grids/grid-construct-budget.frml"></INCLUDE>
</INCLUDES> </INCLUDES>
@@ -94,6 +94,7 @@
</DATASETS> </DATASETS>
<FORM> <FORM>
<EXECUTOR NAME="bdgt04-actions" ADD-ACTION="flowAdd" UPDATE-ACTION="flowUpdate" DELETE-ACTION="flowDelete"/>
<FORM_BROWSE DATAID="DS-MASTER"> <FORM_BROWSE DATAID="DS-MASTER">
<HEADER NAVI="N" EDIT="N" ADD="N" DELETE="N" VIEW="N"/> <HEADER NAVI="N" EDIT="N" ADD="N" DELETE="N" VIEW="N"/>
<PAGESIZE>0</PAGESIZE> <PAGESIZE>0</PAGESIZE>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/#dynf_form_def.xsd"> <FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="/xsd/#dynf_form_def.xsd">
<DATASETS> <DATASETS>
<DATASET ID="DS-PROJECT-STTGYS"> <DATASET ID="DS-PROJECT-STTGYS">
<SCHEMA>APP</SCHEMA> <SCHEMA>APP</SCHEMA>

View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="UTF-8"?>
<DATASETS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/ajax.xsd">
<DATASET ID="DS-PROJECT-02">
<SCHEMA>BUD</SCHEMA>
<TABLEDESC>Main Activity</TABLEDESC>
<MAXROWS>100</MAXROWS>
<SQL>
<SELECT>SELECT PJM.PJM_CODE
, PJM.PJM_NAME
, PJM.PJM_JOB_TYPE
, PJM.PJM_WORK_PLAN
, PJM.PJM_PRODUCT
, PJM.PJM_GROUP_PLAN
, PJM.PJM_JOB_PROJECT
, PJM.PJM_STRATEGY
, PJM.PJM_ACTIVE
</SELECT>
<FROM>FROM PROJECT_M PJM</FROM>
<WHERE>
WHERE (PJM.PJM_CODE LIKE '%'||:SEARCH||'%' OR PJM.PJM_NAME LIKE '%'||:SEARCH||'%')
</WHERE>
<GROUP/>
<ORDER/>
</SQL>
</DATASET>
<DATASET ID="DS-ACTIVITY-02">
<SCHEMA>BUD</SCHEMA>
<TABLEDESC>Main Activity</TABLEDESC>
<MAXROWS>100</MAXROWS>
<SQL>
<SELECT>
SELECT ACM_CODE
, ACM_NAME
, NODE_LEVEL
, MAIN_NODE
, ACM_UNIT
, ACM_START_YEAR
, ACM_END_YEAR
, STM_CODE
, JBT_CODE
, JBP_CODE
, EXP_CODE
, PJM_CODE
, STG_CODE
, NODE_TYPE
, DECODE(NODE_TYPE,'C','true','') disabled
</SELECT>
<FROM>FROM BGT.V_ACTIVITY_TREE ACM</FROM>
<WHERE>
WHERE 0=0
AND (:DV_YEAR BETWEEN ACM_START_YEAR AND ACM_END_YEAR)
-- AND (ACM.STM_CODE = '%' OR ACM.STM_CODE = :STM_CODE)
AND (ACM.ACM_CODE LIKE '%'||:SEARCH||'%' OR ACM.ACM_NAME LIKE '%'||:SEARCH||'%')
</WHERE>
<GROUP/>
<ORDER/>
</SQL>
</DATASET>
<DATASET ID="DS-BUDGET-02">
<SCHEMA>BUD</SCHEMA>
<TABLEDESC>Main Activity</TABLEDESC>
<MAXROWS>100</MAXROWS>
<SQL>
<SELECT>
SELECT BGD.BGM_CODE
, BGD.BGM_NAME
, BGD.BGM_EXPENSE_TYPE
, BGD.BGM_UNIT
, BGD.BGM_UNIT_RATE
, BGD.BGM_ACTIVE
, BGD.BGM_PREPARE
</SELECT>
<FROM>FROM BUDGET_M BGD</FROM>
<WHERE>
WHERE (BGD.BGM_CODE LIKE '%'||:SEARCH||'%' OR BGD.BGM_NAME LIKE '%'||:SEARCH||'%')
</WHERE>
<ORDER>ORDER BY BGM_CODE</ORDER>
</SQL>
</DATASET>
<DATASET ID="DS-STTGY-GROUP-02">
<SCHEMA>APP</SCHEMA>
<SQL>
<SELECT>SELECT RFG_GRP
, RFC_CODE
, RFC_DESC
, RFC_FLAG
, RFC_ORDER
</SELECT>
<FROM>FROM REFER_CODE</FROM>
<WHERE>WHERE (RFG_GRP = 'STG-ITEMS')
AND (RFC_CODE LIKE '%'||:SEARCH||'%' OR RFC_DESC LIKE '%'||:SEARCH||'%')</WHERE>
<ORDER>ORDER BY RFC_CODE</ORDER>
</SQL>
</DATASET>
<DATASET ID="DS-STTGY-ITEMS-02">
<SCHEMA>APP</SCHEMA>
<SQL>
<SELECT>SELECT RFG_GRP
, RFC_CODE
, RFC_DESC
, RFC_FLAG
, RFC_ORDER
</SELECT>
<FROM>FROM REFER_CODE</FROM>
<WHERE>WHERE (RFG_GRP = :RFG_GRP)
AND (RFC_CODE LIKE '%'||:SEARCH||'%' OR RFC_DESC LIKE '%'||:SEARCH||'%')</WHERE>
<ORDER>ORDER BY RFC_CODE</ORDER>
</SQL>
</DATASET>
<DATASET ID="DS-ACTIVITY-02-BDGT">
<SCHEMA>BUD</SCHEMA>
<TABLEDESC>Main Activity</TABLEDESC>
<MAXROWS>100</MAXROWS>
<SQL>
<SELECT>
SELECT ACM_CODE
, ACM_NAME
, NODE_LEVEL
, MAIN_NODE
, ACM_UNIT
, ACM_START_YEAR
, ACM_END_YEAR
, STM_CODE
, JBT_CODE
, JBP_CODE
, EXP_CODE
, PJM_CODE
, STG_CODE
, NODE_TYPE
, DECODE(NODE_TYPE,'C','true','') disabled
</SELECT>
<FROM>FROM BGT.V_ACTIVITY_TREE ACM</FROM>
<WHERE>
WHERE 0=0
AND (:DV_YEAR BETWEEN ACM_START_YEAR AND ACM_END_YEAR)
-- AND (ACM.STM_CODE = '%' OR ACM.STM_CODE = :STM_CODE)
AND (ACM.ACM_CODE LIKE '%'||:SEARCH||'%' OR ACM.ACM_NAME LIKE '%'||:SEARCH||'%')
</WHERE>
<GROUP/>
<ORDER/>
</SQL>
</DATASET>
<DATASET ID="DS-BUDGET-02-BDGT">
<SCHEMA>APP</SCHEMA>
<TABLEDESC>Main Activity</TABLEDESC>
<MAXROWS>100</MAXROWS>
<SQL>
<SELECT>
SELECT BGM.BGM_CODE
, BGM.BGM_NAME
, BGM.EXP_TYPE
, BGM.BGM_UNIT
, BGM.BGM_UNIT_RATE
, BGM.BGM_SEQ
, BGM.NODE_LEVEL
, BGM.MAIN_NODE
, DECODE(NODE_TYPE,'C','true','') disabled
</SELECT>
<FROM>FROM V_BUDGET_TREE BGM</FROM>
<WHERE>
WHERE (BGM.BGM_CODE LIKE '%'||:SEARCH||'%' OR BGM.BGM_NAME LIKE '%'||:SEARCH||'%')
</WHERE>
<ORDER>ORDER BY BGM_SEQ</ORDER>
</SQL>
</DATASET>
<DATASET ID="DS-EQUIPT-BUDGET">
<SCHEMA>APP</SCHEMA>
<TABLEDESC>Main Activity</TABLEDESC>
<MAXROWS>100</MAXROWS>
<SQL>
<SELECT>
SELECT BGM.BGM_CODE
, BGM.BGM_NAME
, BGM.EXP_TYPE
, BGM.BGM_UNIT
, BGM.BGM_UNIT_RATE
, BGM.BGM_SEQ
, BGM.NODE_LEVEL
, BGM.MAIN_NODE
, DECODE(NODE_TYPE,'C','true','') disabled
</SELECT>
<FROM>FROM V_BUDGET_TREE BGM</FROM>
<WHERE>
WHERE (BGM_CODE LIKE '3.1%')
AND (BGM.BGM_CODE LIKE '%'||:SEARCH||'%' OR BGM.BGM_NAME LIKE '%'||:SEARCH||'%')
</WHERE>
<ORDER>ORDER BY BGM_SEQ</ORDER>
</SQL>
</DATASET>
</DATASETS>

View File

@@ -0,0 +1,50 @@
<%@ page import="org.apache.commons.codec.*" %>
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%@ include file="/WEB-INF/app/system/dynf/dynfSysInfo.jsp" %>
<!-- =========================================================================================== -->
<h1 class="page-header"><%=pageItemInfo.getProgTitle()%></h1>
<%
String _formId = "bdgt-0501010/general";
try {
String data = factory.rqsCtx.getParameter("data","");
boolean detailMode = false;
if (!data.isBlank()) {
data = JUtils.decBase64(data);
data = URLDecoder.decode(data, CharEncoding.UTF_8);
JSONObject jsData = new JSONObject(data);
String type = jsData.getString("type").toLowerCase();
String acmCode = jsData.getString("acm_code");
String projId = jsData.getString("proj_id");
if (type.equals("rutn")) {
_formId = "bdgt-0501010/routine";
} else if (type.equals("mngt")) {
_formId = "bdgt-0501010/manage";
} else if (type.equals("eqpt")) {
_formId = "bdgt-0501010/equipt";
} else if (type.equals("cnst")) {
_formId = "bdgt-0501010/construct";
}
detailMode = true;
dynForm = new DynForm(application, request, response, "bdgt05", _formId);
dynForm.setFormOwner(request.getRequestURL().toString());
dynForm.setFormvar("ACM_CODE",acmCode);
dynForm.setFormvar("PROJ_ID",projId);
} else {
dynForm = new DynForm(application, request, response, "bdgt05", _formId);
}
if (detailMode) {
factory.pageCtx.addWidget(DynConstants.PageWidget.FileBox);
%><%@ include file="/WEB-INF/app/system/dynf/dynfDataEdit.jsp" %><%
} else {
%><%@ include file="/WEB-INF/app/system/dynf/dynfDataList.jsp" %><%
}
} catch (Exception ex) {
factory.setRestCode("ERROR");
factory.setRestMsg(ex.getMessage() + "\n" + JUtils.stackToString(ex,16));
logger.error(ex.getMessage(),ex);
}
%>

View File

@@ -0,0 +1,20 @@
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%@ include file="/WEB-INF/app/system/dynf/dynfSysInfo.jsp" %>
<!-- =========================================================================================== -->
<h1 class="page-header"><%=pageItemInfo.getProgTitle()%></h1>
<%
try {
dynForm = new DynForm(application, request, response, "bdgt05", "bdgt-0501010");
dynForm.setFormOwner(request.getRequestURL().toString());
dynForm.setFormvar("USER_CODE",factory.user.getUSER_CODE());
if (dynForm.workIn(WorkMode.Editing)) {
%><%@ include file="/WEB-INF/app/system/dynf/dynfDataEdit.jsp" %><%
} else {
%><%@ include file="/WEB-INF/app/system/dynf/dynfDataList.jsp" %><%
}
} catch (Exception ex) {
factory.setRestCode("ERROR");
factory.setRestMsg(ex.getMessage() + "\n" + JUtils.stackToString(ex,16));
logger.error(ex.getMessage(),ex);
}
%>

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-MASTER">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECTS</TABLENAME>
<KEYFIELDS>PROJ_ID</KEYFIELDS>
<SQL>
<SELECT>
SELECT DISTINCT PRPS.PROP_ID
, PRPS.PROP_YEAR
, PRPS.PROP_YEAR FLOW_YEAR
, PRPS.STM_CODE STM_CODE
, BUD.GET_SECTION(PRPS.STM_CODE) STM_NAME
, PRPS.BTM_CODE BTM_CODE
, PRPS.FLOW_TYPE FLOW_TYPE
, PRPS.FLOW_STATE FLOW_STATE
, NVL(BUD.GET_PROJECT(PROJ.PJM_CODE), VPSTT.FLOW_TYPE_DESC) PROJ_NAME
, BUD.GET_ACTIVITY(PROJ.ACM_CODE) ACM_NAME
, VPSTT.FLOW_TYPE_DESC
, VPSTT.FLOW_LEVEL
, VPSTT.FLOW_STATE
, VPSTT.FLOW_STEP_DESC
, VPSTT.FLOW_STATE_DESC
, VPSTT.NEXT_STEP
, VPSTT.NEXT_STEP_DESC
, VPSTT.NEXT_STATE_DESC
, PRPS.PROP_VERSION VERSION
, PRPS.PROP_DOCNO DOCNO
, PRPS.PROP_PROVED_DATE PROVED_DATE
, JDTOT(PRPS.FLOW_DATE) STATE_DATE
</SELECT>
<FROM>
FROM PROPOSALS PRPS
INNER JOIN V_PROJECT_STATE VPSTT on PRPS.PROP_ID = VPSTT.PROP_ID
LEFT OUTER JOIN PROPS_PROJECTS PROJ ON PRPS.PROP_ID = PROJ.PROJ_ID
INNER JOIN V_PROPS_APPROVERS PAPVS ON PAPVS.PROP_ID=PRPS.PROP_ID
</FROM>
<FILTER>WHERE PRPS.FLOW_TYPE = 'PROP-GNL-01' AND PAPVS.FAPV_APPROVER = :USER_CODE</FILTER>
<ORDER>ORDER BY PRPS.PROP_ID</ORDER>
</SQL>
</DATASET>
</DATASETS>
<FORM>
<FORM_BROWSE DATAID="DS-MASTER">
<HEADER NAVI="N" EDIT="N" ADD="N" DELETE="N" VIEW="N"/>
<PAGESIZE>0</PAGESIZE>
<FIELDS>
<FIELD NAME="$itemno" LABEL="no" ALIGN="right" WIDTH="5em"/>
<FIELD NAME="STM_NAME" LABEL="props.stm_name" ALIGN="left" WIDTH="20em">
<DATA-FORMATTER>
<![CDATA[(value,row,idx)=>{return $(`<div class="col-24 text-nowrap"><div class="col offset-${+(row.node_level)-1}">${value}</div></div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="FLOW_TYPE_DESC" LABEL="props.type" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[(value,row,idx)=>{return $(`<div class="col-24 row"><div class="col offset-${+(row.node_level)-1}">${value}</div></div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="FLOW_STATE_DESC" LABEL="props.state" ALIGN="center" WIDTH="10em">
<DATA-FORMATTER>
<![CDATA[(value,row,idx)=>{return $(`<span class="grid-badge flow-state-${row.flow_level}">${value}</span>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="STATE_DATE" LABEL="props.state_date" ALIGN="center" WIDTH="10em"/>
<COMMAND-BUTTONS>
<BUTTON NAME="btnApprove" CLASS="btn btn-primary btn-tracking" ICON-CLASS="bi bi-distribute-vertical white">
<EVENT ON="click"><![CDATA[
({ev,row})=>{
console.log(row);
$PageCtx.saveSessionData("general", row);
$PageCtx.saveStorageData("general#search", {prop_id: row.prop_id});
$WebNavi.goto("/bdgt05/bgt0501010-general");
}
]]></EVENT>
</BUTTON>
</COMMAND-BUTTONS>
</FIELDS>
<FILTERS AUTO-APPLY="Y" ALLOW-NO-FILTER="Y">
<FIELDS>
<FIELD NAME="PROP_YEAR" CAPTION="project.year" INPUTTYPE="COMBOBOX" SEARCH-ORIGIN="PRPS.PROP_YEAR=${VALUE}">
<LIST-OPTION TABLE="VL_YEAR" TEXT="#DV_YEAR" VALUE="DV_YEAR" ORDER="DV_YEAR" FIRSTLIST="@{NONE}"/>
</FIELD>
<FIELD NAME="STM_CODE" CAPTION="props.stm_name" INPUTTYPE="COMBOBOX" SEARCH-ORIGIN="STM_CODE=${VALUE}">
<LIST-OPTION TABLE="BUD.SECTION_M" TEXT="#STM_NAME" VALUE="STM_CODE" ORDER="STM_NAME" FIRSTLIST=""/>
</FIELD>
</FIELDS>
<LAYOUT>
<ROW>
<FIELD NAME="PROP_YEAR" VAL_WIDTH="6" CAPT_WIDTH="12" LAYOUT_WIDTH="12"/>
</ROW>
<ROW>
<FIELD NAME="STM_CODE" VAL_WIDTH="12" CAPT_WIDTH="6" LAYOUT_WIDTH="24"/>
</ROW>
</LAYOUT>
</FILTERS>
</FORM_BROWSE>
</FORM>
</FORMS>

View File

@@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/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
</SELECT>
<FROM>FROM PROJECTS</FROM>
<FILTER>WHERE PROJ_ID = :PROJ_ID</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"/>
</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
</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"/>
</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"/>
<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-ATTATCH-FILE">
<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>
<SECTION ID="SECT-REVISE-COMMENT">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">การส่งกลับแก้ไข</h4>]]></HEADER>
<ROW TYPE="CONTENT">
<![CDATA[
<div class="mg-b-16">
<div id="FIELD-REVISE_COMMENT" class="form-group col-24 offset-0">
<label id="lbREVISE_COMMENT" for="REVISE_COMMENT" class="col-form-label form-label col-sm-10">รายการแก้ไข</label>
<div class="form-col col-24 col-sm-14" data-field="REVISE_COMMENT">
<input type="text" name="REVISE_COMMENT" id="REVISE_COMMENT" value="" input-type="TEXT" charcase="NORMAL" class="form-control dyn-form-control text">
</div>
</div>
</div>
<div>
<div>ประวัติการแก้ไข</div>
<ul>
<li>แก้ครั้งที่ 1 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 2 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 3 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 4 วันที่ xx/xx/xxxx : ...................................</li>
</ul>
</div>
]]>
</ROW>
</SECTION>
<SECTION ID="SECT-FILE-UPLOAD">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">เอกสารประกอบการพิจารณา</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 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>

View File

@@ -0,0 +1,348 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-MASTER">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGETS</TABLENAME>
<KEYFIELDS>PROJ_ID,ACM_CODE</KEYFIELDS>
<SQL>
<SELECT>SELECT PBDG.PROJ_ID
, PBDG.PBDG_ID
, PBDG.ACM_CODE
, BUD.GET_ACTIVITY(PBDG.ACM_CODE) ACM_NAME
, PBDG.PBDG_TOTAL
, PBDG.PBDG_COUNT
, PBDG.PBDG_ASSET_TYPE
, PBDG.PBDG_REASON
, PMAS.PROJ_YEAR
, PMAS.STM_CODE
, PMAS.PROJ_YEAR||'/'||PMAS.STM_CODE||'/'||PBDG.PROJ_ID FILEPATH
</SELECT>
<FROM>FROM PROJECT_BUDGETS PBDG
INNER JOIN PROJECTS PMAS ON PMAS.PROJ_ID = PBDG.PROJ_ID
</FROM>
<ORDER>ORDER BY PROJ_ID,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" ORIGIN="PBDG.PROJ_ID"/>
<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"/>
<FIELD NAME="PBDG_ASSET_TYPE" TYPE="TEXT" LABEL="ประเภทครุภัณฑ์" WIDTH="25"/>
<FIELD NAME="PBDG_REASON" TYPE="TEXT" LABEL="เหตุผลในการจัดหา" WIDTH="2000"/>
</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"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,ACM_CODE" DETAIL-FIELDS="PROJ_ID,ACM_CODE"/>
</DATASET>
<DATASET ID="DS-BUDGET-ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT PROJ_ID
, PBDG_ID
, BGM_CODE
, PBGI_QT_01
, PBGI_QT_02
, PBGI_QT_03
, PBGI_QT_04
, PBGI_QTY
, PBGI_COST
, PBGI_FREQ
, PBGI_ASSET_TYPE
, PBGI_REPLACE
, PBGI_ADDITION
, PBGI_ACQUIRE
, PBGI_TOTAL
, PBGI_REASON
</SELECT>
<FROM>FROM PROJECT_BUDGET_ITEMS</FROM>
<ORDER>ORDER BY PROJ_ID,BGM_CODE,PBDG_ID</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="pbgi.id" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="pbgi.pbdg_id" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="pbgi.bgm_code" WIDTH="20"/>
<FIELD NAME="PBGI_QT_01" TYPE="NUMBER" LABEL="pwbg.quotr_01" WIDTH="15"/>
<FIELD NAME="PBGI_QT_02" TYPE="NUMBER" LABEL="pwbg.quotr_02" WIDTH="15"/>
<FIELD NAME="PBGI_QT_03" TYPE="NUMBER" LABEL="pwbg.quotr_03" WIDTH="15"/>
<FIELD NAME="PBGI_QT_04" TYPE="NUMBER" LABEL="pwbg.quotr_04" WIDTH="15"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="pbgi.qty" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="pbgi.cost" WIDTH="15"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="pbgi.freq" WIDTH="10"/>
<FIELD NAME="PBGI_ASSET_TYPE" TYPE="TEXT" LABEL="pbgi.asset_type" WIDTH="10"/>
<FIELD NAME="PBGI_REPLACE" TYPE="NUMBER" LABEL="pbgi.replace" WIDTH="10"/>
<FIELD NAME="PBGI_ADDITION" TYPE="NUMBER" LABEL="pbgi.addition" WIDTH="10"/>
<FIELD NAME="PBGI_ACQUIRE" TYPE="NUMBER" LABEL="pbgi.acquire" WIDTH="10"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="pbgi.total" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="pbgi.reason" WIDTH="4000"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,PBDG_ID" DETAIL-FIELDS="PROJ_ID,PBDG_ID"/>
</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.equipt_code" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="ACM_NAME" CAPTION="project.equipt_name" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="PROJ_YEAR" CAPTION="project.year" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="PBDG_ASSET_TYPE" CAPTION="pbge.asset_type" INPUTTYPE="COMBOBOX" REQUIRE="Y">
<LIST-OPTION TABLE="REFER_CODE" TEXT="RFC_DESC" VALUE="RFC_CODE" ORDER="RFC_ORDER" FILTER="RFG_GRP='ASSET-TYPE'" FIRSTLIST="@{CAPTION}"/>
</FIELD>
<FIELD NAME="PBDG_REASON" CAPTION="pbge.reason" INPUTTYPE="TEXT" />
<FIELD NAME="FILE_BOX_01" CAPTION="pbge.quotaion_file 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="pbge.quotaion_file 2" INPUTTYPE="FILE-BOX">
<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-02"/>
</FIELD>
<FIELD NAME="FILE_BOX_03" CAPTION="pbge.quotaion_file 3" INPUTTYPE="FILE-BOX">
<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-03"/>
</FIELD>
<SECTION ID="SECT-PROJECT-TARGET">
<FIELD NAME="PBDG_TOTAL" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_COUNT" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PWMT_UNIT" CAPTION="project.unit" INPUTTYPE="TEXT" READONLY="Y"></FIELD>
<FIELD NAME="PTGT_QT_0101" INPUTTYPE="TEXT" DATATYPE="NUMBER" CAPTION="project.quoter 1"/>
<FIELD NAME="PTGT_QT_0201" INPUTTYPE="TEXT" DATATYPE="NUMBER" CAPTION="project.quoter 2"/>
<FIELD NAME="PTGT_QT_0301" INPUTTYPE="TEXT" DATATYPE="NUMBER" CAPTION="project.quoter 3"/>
<FIELD NAME="PTGT_QT_0401" INPUTTYPE="TEXT" DATATYPE="NUMBER" CAPTION="project.quoter 4"/>
<FIELD NAME="QT_TOTAL_01" INPUTTYPE="TEXT" DATATYPE="NUMBER" CAPTION="project.total" READONLY="Y"/>
</SECTION>
<SECTION ID="SECT-BUDGET-ITEMS">
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-EQUIPT-BUDGET" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div><label class="offset-${data.node_level}">[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_QT_01" CAPTION="pbge.origin" INPUTTYPE="TEXT" DATATYPE="NUMBER"/>
<FIELD NAME="PBGI_REPLACE" CAPTION="pbge.replace" INPUTTYPE="TEXT" DATATYPE="NUMBER" CLASS-NAME="equipt-qty equipt-item"/>
<FIELD NAME="PBGI_ADDITION" CAPTION="pbge.addition" INPUTTYPE="TEXT" DATATYPE="NUMBER" CLASS-NAME="equipt-qty equipt-item"/>
<FIELD NAME="PBGI_ACQUIRE" CAPTION="pbge.acquire" INPUTTYPE="TEXT" DATATYPE="NUMBER" CLASS-NAME="equipt-qty equipt-item"/>
<FIELD NAME="PBGI_QTY" CAPTION="pbge.qty" INPUTTYPE="TEXT" DATATYPE="NUMBER" READONLY="Y" CLASS-NAME="equipt-item"/>
<FIELD NAME="PBGI_COST" CAPTION="pbge.cost" INPUTTYPE="TEXT" DATATYPE="NUMBER" CLASS-NAME=" equipt-item"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="pbge.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" READONLY="Y"/>
</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="PBDG_ASSET_TYPE" LAYOUT_WIDTH="4"/>
<FIELD NAME="PBDG_REASON" LAYOUT_WIDTH="18"/>
</ROW>
</SECTION>
<SECTION ID="SECT-PROJECT-BUTGET" TYPE="DATA-SECTION" DATASET="DS-BUDGET-ITEMS">
<ROW ID="ROW-BUDGET-DATA">
<FIELD NAME="PBGI_QT_01" LAYOUT_WIDTH="4"/>
<FIELD NAME="PBGI_REPLACE" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_ADDITION" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_ACQUIRE" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_QTY" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_COST" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="4" OFFSET="4"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="14"/>
</ROW>
</SECTION>
<SECTION ID="SECT-PROJECT-TARGET" TYPE="DATA-SECTION" DATASET="DS-PROJECT-TARGETS">
<HEADER CLASS="col-24 mg-b-n30 mg-t-16 border-top-1">
<![CDATA[<h4 class="ml-3 col-24">@M{project.target}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="PTGT_QT_0101" LAYOUT_WIDTH="3" OFFSET="4"/>
<FIELD NAME="PTGT_QT_0201" LAYOUT_WIDTH="3"/>
<FIELD NAME="PTGT_QT_0301" LAYOUT_WIDTH="3"/>
<FIELD NAME="PTGT_QT_0401" LAYOUT_WIDTH="3"/>
<FIELD NAME="QT_TOTAL_01" LAYOUT_WIDTH="3"/>
<FIELD NAME="PWMT_UNIT" LAYOUT_WIDTH="3"/>
</ROW>
</SECTION>
<SECTION ID="SECT-QUOTATION-FILE">
<HEADER CLASS="col-24 mg-b-n30 mg-t-16 border-top-1">
<![CDATA[<h4 class="ml-3 col-24">@M{pbge.quotaion_file}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="FILE_BOX_01" LAYOUT_WIDTH="12" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="FILE_BOX_02" LAYOUT_WIDTH="12" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="FILE_BOX_03" LAYOUT_WIDTH="12" OFFSET="4"/>
</ROW>
</SECTION>
<SECTION ID="SECT-REVISE-COMMENT">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">การส่งกลับแก้ไข</h4>]]></HEADER>
<ROW TYPE="CONTENT">
<![CDATA[
<div class="mg-b-16">
<div id="FIELD-REVISE_COMMENT" class="form-group col-24 offset-0">
<label id="lbREVISE_COMMENT" for="REVISE_COMMENT" class="col-form-label form-label col-sm-10">รายการแก้ไข</label>
<div class="form-col col-24 col-sm-14" data-field="REVISE_COMMENT">
<input type="text" name="REVISE_COMMENT" id="REVISE_COMMENT" value="" input-type="TEXT" charcase="NORMAL" class="form-control dyn-form-control text">
</div>
</div>
</div>
<div>
<div>ประวัติการแก้ไข</div>
<ul>
<li>แก้ครั้งที่ 1 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 2 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 3 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 4 วันที่ xx/xx/xxxx : ...................................</li>
</ul>
</div>
]]>
</ROW>
</SECTION>
<SECTION ID="SECT-FILE-UPLOAD">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">เอกสารประกอบการพิจารณา</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>
<DECLARATION>
const equiptQty = $$(".equipt-qty");
const equiptItem = $$(".equipt-item");
const txtEquiptQty = $$("PBGI_QTY");
const txtEquiptCost = $$("PBGI_COST");
const txtEquiptTotal = $$("PBGI_TOTAL");
</DECLARATION>
<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);
}
$$("PBDG_COUNT").val(txtEquiptQty.number());
$$("PBDG_TOTAL").val(txtEquiptTotal.number());
Object.assign(data, form.mainForm.jsonData());
}
]]></BEFORE-SAVE>
</EVENTS>
<INITIALIZE>
<![CDATA[
const quoterSum = () => {
let summary = 0;
for (let qt = 1; qt <= 4; qt++) {
summary += $$(`PTGT_QT_0${qt}01`).number();
}
$$(`QT_TOTAL_01`).val(formatNumber(summary));
}
$$("^PTGT_QT_").on("change", quoterSum);
const equiptSum = ()=>{
let sumEquipt = equiptQty.sum();
txtEquiptQty.val(formatNumber(sumEquipt));
let equiptCost = txtEquiptCost.number();
txtEquiptTotal.val(formatNumber(sumEquipt*equiptCost));
}
equiptItem.on("change",equiptSum);
]]>
</INITIALIZE>
</SCRIPT>
</FORM_ENTRY>
</FORM>
</FORMS>

View File

@@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-MASTER">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROPS_PROJECTS</TABLENAME>
<KEYFIELDS>PROP_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT PPROJ.PROP_ID
, PROJ.PROJ_ID
, PROJ.PROJ_TYPE
, PROJ.PROJ_YEAR
, PROJ.PJM_CODE
, PROJ.STM_CODE
, PROJ.BTM_CODE
, PROJ.ACM_CODE
, BUD.GET_ACTIVITY(PROJ.ACM_CODE) ACM_NAME
, PROJ.PLAN_TYPE
, PROJ.PROJ_DURATION
, PROJ.PROJ_START_YEAR
, PROJ.PROJ_END_YEAR
, PROJ.PROJ_FOR_STAFF
, PROJ.PROJ_FROM_YEAR
, VPSTT.PROJ_ORDER
, VPSTT.FLOW_LEVEL
, 0 BDGT_TOTAL
</SELECT>
<FROM>FROM PROPS_PROJECTS PROJ
INNER JOIN PROPOSALS_PROJECTS PPROJ ON PROJ.PROJ_ID=PPROJ.PROJ_ID
INNER JOIN V_PROJECT_STATE VPSTT ON VPSTT.PROJ_ID=PPROJ.PROJ_ID
</FROM>
<FILTER>WHERE PPROJ.PROP_ID = :PROP_ID</FILTER>
<ORDER>ORDER BY VPSTT.PROJ_ORDER</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_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"/>
</FIELDS>
<SUBDATASETS>
<SUBDATASET NAME="ACTIVITIES" DATASET-ID="DS-ACTIVITY-TREE" LINK-FIELDS="PROJ_ID"/>
</SUBDATASETS>
</DATASET>
<DATASET ID="DS-ACTIVITY-TREE">
<SCHEMA>APP</SCHEMA>
<TABLENAME>V_ACTIVITY_TREE</TABLENAME>
<SQL>
<SELECT>
SELECT PACT.PROJ_ID
, PACT.PROJ_YEAR
, PACT.PROJ_TYPE
, PACT.PROJ_GROUP
, ACTT.ACM_CODE
, ACTT.ACM_NAME
, ACTT.ACM_SEQ
, ACTT.NODE_LEVEL+1 NODE_LEVEL
, ACTT.MAIN_NODE
, ACTT.ACM_UNIT
, ACTT.ACM_START_YEAR
, ACTT.ACM_END_YEAR
, ACTT.NODE_TYPE
, PACT.BDGT_COUNT
, PACT.BDGT_TOTAL
</SELECT>
<FROM>
FROM BGT.V_ACTIVITY_TREE ACTT
INNER JOIN (SELECT DISTINCT ACM.ACM_CODE
FROM BUD.ACTIVITY_M ACM
INNER JOIN BUD.ACTIVITY_CTRL_H ACH ON ACM.ACM_CODE = ACH.ACH_CODE
START WITH ACM.ACM_CODE IN (SELECT ACM_CODE FROM V_PROJECT_ACTIVITY PACT WHERE PACT.PROJ_ID = :PROJ_ID)
CONNECT BY PRIOR ACH.ACH_CTRL_CODE = ACH.ACH_CODE) FLTR ON FLTR.ACM_CODE = ACTT.ACM_CODE
LEFT OUTER JOIN V_PROJECT_ACTIVITY PACT ON PACT.ACM_CODE = ACTT.ACM_CODE AND PACT.PROJ_ID = :PROJ_ID
</FROM>
<ORDER>
ORDER BY ACTT.ACM_SEQ
</ORDER>
</SQL>
</DATASET>
</DATASETS>
<FORM>
<FORM_BROWSE DATAID="DS-MASTER">
<HEADER NAVI="N" EDIT="N" ADD="N" DELETE="N" VIEW="N"/>
<PAGESIZE>0</PAGESIZE>
<FIELDS>
<FIELD NAME="$itemno" LABEL="no" ALIGN="right" WIDTH="5em"/>
<FIELD NAME="ACM_CODE" LABEL="project.const_code" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[(value,row,idx)=>{return $(`<div class="col-24 row text-nowrap"><div class="col offset-${+(row.node_level)-1}">${value}</div></div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="ACM_NAME" LABEL="project.const_name" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[(value,row,idx)=>{return $(`<div class="col-24 row text-nowrap"><div class="col offset-${+(row.node_level)-1}">${value}</div></div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="BDGT_COUNT" LABEL="pbdg.acm_count" ALIGN="right" WIDTH="10em">
<DATA-FORMATTER>
<![CDATA[(value, row, idx) => {
if (row["node_type"] === "D") {
return `<div class="col-24 text-nowrap">${formatNumber(value,"#,##0")} ${row["acm_unit"]}</div>`;
} else {
return ""
}
}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="BDGT_TOTAL" LABEL="project.bgt_amount" ALIGN="right" WIDTH="10em"/>
<COMMAND-BUTTONS>
<BUTTON NAME="btnTracking" CLASS="btn btn-primary btn-tracking" ICON-CLASS="bi bi-distribute-vertical white">
<FILTER><![CDATA[({$ctx,row})=>{return ["D"].includes(row["node_type"]);}]]></FILTER>
<EVENT ON="click"><![CDATA[
({ev, row}) => {
console.log(row);
$PageCtx.saveSessionData("general", row);
$PageCtx.saveStorageData("general#search", {PROP_ID: row.prop_id});
let $data = {proj_id : row.proj_id,type : row.proj_type,acm_code : row.acm_code,}
$WebNavi.goto("/bdgt05/bgt0501010-general?data="+SdkXUtils.jsonBase64($data));
}
]]></EVENT>
</BUTTON>
</COMMAND-BUTTONS>
</FIELDS>
<FILTERS AUTO-APPLY="N" ALLOW-NO-FILTER="Y">
<FIELDS>
<FIELD NAME="PROP_YEAR" CAPTION="project.year" INPUTTYPE="TEXT" READONLY="Y"/>
</FIELDS>
<LAYOUT>
<ROW>
<FIELD NAME="PROP_YEAR" LAYOUT_WIDTH="12" VAL_WIDTH="5" CAPT_WIDTH="14"/>
</ROW>
</LAYOUT>
</FILTERS>
<FOOTER SHOW="Y"/>
<BUTTONS>
<BUTTON NAME="btnRevise" CAPTION="send||send.revise" CLASS="btn btn-outline-warning" SECTION="RIGHT"/>
<BUTTON NAME="btnSend" CAPTION="" CLASS="btn btn-warning" SECTION="RIGHT"/>
</BUTTONS>
<SCRIPT>
<EVENTS>
<AFTER-LOAD>
<![CDATA[
({$ctx,data})=>{
let src = [...data]; // clone data to src
data.splice(0); // clear data element
let id = 1;
let lastItem = {};
let itemCount = 0;
let projType = "";
for (let item of src) {
item["node_type"] = "P";
item["node_level"] = "0";
if (item["node_type"] === "P") {
projType = ProjType.$(item["proj_type"]);
}
if (lastItem["node_type"] !== "P") {
id = 1;
item["$itemno"] = "";
item["acm_code"] = "";
item["acm_name"] = "";
item["projType"] = projType;
data.push(item);
}
lastItem = item;
if (isArray(item.activities)) {
for (let sitem of item.activities) {
sitem["$itemno"] = id++;
sitem["projType"] = projType;
data.push(sitem);
lastItem = sitem;
itemCount++;
}
}
}
}
]]>
</AFTER-LOAD>
</EVENTS>
<INITIALIZE>
<![CDATA[
{
// console.log("init activity grid");
const fieldFormat = (value,row) => {
let projType = row.projType;
if (row["node_type"] === "P" || projType.is(ProjType.RUTN)) {
return "";
}
return formatNumber(value, 0);
}
const summary = (field, data) => {
let total = 0;
for (let id=0; id < data.length; id++) {
let row = data[id];
if (row["node_type"] === "D") {
total += (+row[field]) || 0;
}
}
if ($PageCtx.$dataGrid.load && !$PageCtx.$dataGrid.reload) {
$PageCtx.$dataGrid.reload = true;
for (let id=data.length-1; id>=0; id--) {
let row = data[id];
if (row["node_type"] === "C") {
let grpTotal = 0;
let mainNode = row["acm_code"];
let nodes = [];
nodes.push($$("main_node="+mainNode,data));
for (let node of nodes.flat()) {
grpTotal += +node[field];
}
data[id][field] = grpTotal;
}
}
$PageCtx.$dataGrid.load(data);
$PageCtx.$dataGrid.reload = false;
}
return formatNumber(total, 0);
}
const $ctx = $PageCtx;
const gridFields = [$$("field=bdgt_total", $ctx.gridColumn.flat())].flat();
for (let field of gridFields) {
field.formatter = fieldFormat;
field.footerFormatter = function (data) {
return summary(this.field, data);
}
}
$ctx.rowStyle = function (row, index) {
if (row["node_type"] === "C") {
return {classes : `group-level-${row["node_level"]}`};
}
if (row["node_type"] === "P") {
return {classes : `group-level-0`};
}
return {}; // Default style for other rows
}
}
]]>
</INITIALIZE>
</SCRIPT>
</FORM_BROWSE>
</FORM>
</FORMS>

View File

@@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<INCLUDES>
<INCLUDE FILE="#grids/grid-manage-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"/>
</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>
<SECTION ID="SECT-REVISE-COMMENT">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">การส่งกลับแก้ไข</h4>]]></HEADER>
<ROW TYPE="CONTENT">
<![CDATA[
<div class="mg-b-16">
<div id="FIELD-REVISE_COMMENT" class="form-group col-24 offset-0">
<label id="lbREVISE_COMMENT" for="REVISE_COMMENT" class="col-form-label form-label col-sm-10">รายการแก้ไข</label>
<div class="form-col col-24 col-sm-14" data-field="REVISE_COMMENT">
<input type="text" name="REVISE_COMMENT" id="REVISE_COMMENT" value="" input-type="TEXT" charcase="NORMAL" class="form-control dyn-form-control text">
</div>
</div>
</div>
<div>
<div>ประวัติการแก้ไข</div>
<ul>
<li>แก้ครั้งที่ 1 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 2 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 3 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 4 วันที่ xx/xx/xxxx : ...................................</li>
</ul>
</div>
]]>
</ROW>
</SECTION>
<SECTION ID="SECT-FILE-UPLOAD">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">เอกสารประกอบการพิจารณา</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.sumOf["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>

View File

@@ -0,0 +1,267 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/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"/>
</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-ATTATCH-FILES">
<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>
<SECTION ID="SECT-REVISE-COMMENT">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">การส่งกลับแก้ไข</h4>]]></HEADER>
<ROW TYPE="CONTENT">
<![CDATA[
<div class="mg-b-16">
<div id="FIELD-REVISE_COMMENT" class="form-group col-24 offset-0">
<label id="lbREVISE_COMMENT" for="REVISE_COMMENT" class="col-form-label form-label col-sm-10">รายการแก้ไข</label>
<div class="form-col col-24 col-sm-14" data-field="REVISE_COMMENT">
<input type="text" name="REVISE_COMMENT" id="REVISE_COMMENT" value="" input-type="TEXT" charcase="NORMAL" class="form-control dyn-form-control text">
</div>
</div>
</div>
<div>
<div>ประวัติการแก้ไข</div>
<ul>
<li>แก้ครั้งที่ 1 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 2 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 3 วันที่ xx/xx/xxxx : ...................................</li>
<li>แก้ครั้งที่ 4 วันที่ xx/xx/xxxx : ...................................</li>
</ul>
</div>
]]>
</ROW>
</SECTION>
<SECTION ID="SECT-FILE-UPLOAD">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">เอกสารประกอบการพิจารณา</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.sumOf["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>

View File

@@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<INCLUDES>
<INCLUDE FILE="#datasets/attatch-files.frml"></INCLUDE>
<INCLUDE FILE="#sections/sect-approve.frml"></INCLUDE>
<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 PROPS.PROP_ID, PROPS.PROP_YEAR,PROPS.STM_CODE,PROPS.PROP_VERSION
, 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
, 'budget' FILE_TYPE
, 'budget-apvs' APPROVE_TYPE
</SELECT>
<FROM>FROM PROPS_BUDGETS PBDG
INNER JOIN PROPS_PROJECTS PROJ ON PROJ.PROJ_ID=PBDG.PROJ_ID
INNER JOIN PROPOSALS_PROJECTS PPROJ ON PPROJ.PROJ_ID=PROJ.PROJ_ID
INNER JOIN PROPOSALS PROPS ON PROPS.PROP_ID=PPROJ.PROP_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"/>
</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="PROP_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="STM_CODE" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PROP_VERSION" INPUTTYPE="HIDDEN"/>
<FIELD NAME="ACM_CODE" CAPTION="project.acm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="PROJ_YEAR" CAPTION="project.year" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="ACM_NAME" CAPTION="project.acm_name" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="PBDG_REASON" CAPTION="project.remark" INPUTTYPE="TEXTAREA" ROWS="2" MAX-LENGTH="2000"/>
<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="/" REQUIRE="Y">
<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="/" REQUIRE="Y">
<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="/" REQUIRE="Y">
<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="/" REQUIRE="Y">
<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>
<SECTION ID="SEC-ATTATCH-FILE">
<FIELD NAME="BUDGET_FILES" CAPTION="file.upload" INPUTTYPE="FILE-LIST-BOX">
<FILE-LIST-BOX DATASET="DS-ATTACH_FILES" FILE-TYPE="ATFI_TYPE" FILE-PATH="ATFI_FILE" FILE-DESC="ATFI_DESC" FILE-MIME="ATFI_MIME"/>
<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="@{stm_code}/@{proj_year}/@{-uuid-}"/>
</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="PBDG_REASON" 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="3" OFFSET="3"/>
<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-FILE-UPLOAD">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">@M{project.file_attatchment}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="BUDGET_FILES" LAYOUT_WIDTH="16" OFFSET="4"/>
</ROW>
</SECTION>
<SECTION ID="SECT-APPROVE-DATA" TYPE="DATA-SECTION" DATASET="DS-ACM-COMMENT">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">@M{revise.title}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="PPSC_COMMENT" LAYOUT_WIDTH="16" OFFSET="4"/>
</ROW>
<ROW>
<FIELD NAME="COMMENT-HISTORY" LAYOUT_WIDTH="16" OFFSET="4"/>
</ROW>
</SECTION>
<SECTION ID="SECT-APPROVE-FILE-UPLOAD">
<HEADER CLASS="col-24 pd-t-16">
<![CDATA[<h4 class="ml-3 border-bottom-1 col-24">@M{approve.file_attatchment}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="APPROVE_FILES" LAYOUT_WIDTH="16" OFFSET="4"/>
</ROW>
</SECTION>
</LAYOUT>
<SCRIPT>
<EVENTS>
<BEFORE-SAVE><![CDATA[
({$ctx, 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.sumOf["pbgi_total"];
$$("PBDG_TOTAL").val(bdgTotal);
}
Object.assign(data, $ctx.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>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-ATTACH_FILES">
<SCHEMA>APP</SCHEMA>
<TABLENAME>ATTACH_FILES</TABLENAME>
<KEYFIELDS>ATFI_SEQ</KEYFIELDS>
<SQL>
<SELECT>SELECT ATFI_SEQ
, PROJ_ID
, ACM_CODE
, ATFI_TYPE
, ATFI_FILE
, ATFI_MIME
, ATFI_DESC
</SELECT>
<FROM>FROM ATTACH_FILES</FROM>
<ORDER>ORDER BY PROJ_ID,ATFI_SEQ,ACM_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="ATFI_SEQ" TYPE="AUTO" LABEL="ลำดับไฟล์แนบ" WIDTH="15"/>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสโครงการ" WIDTH="50"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="25"/>
<FIELD NAME="ATFI_TYPE" TYPE="TEXT" LABEL="ประเภทไฟล์แนบ" WIDTH="25"/>
<FIELD NAME="ATFI_FILE" TYPE="TEXT" LABEL="ชื่อไฟล์แนบ" WIDTH="250"/>
<FIELD NAME="ATFI_MIME" TYPE="TEXT" LABEL="ชนิดของไฟล์แนบ (MIME Type)" WIDTH="100"/>
<FIELD NAME="ATFI_DESC" TYPE="TEXT" LABEL="คำอธิบาย/รายละเอียดไฟล์แนบ" WIDTH="250"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,ACM_CODE,FILE_TYPE" DETAIL-FIELDS="PROJ_ID,ACM_CODE,ATFI_TYPE"/>
</DATASET>
</DATASETS>
</FORMS>

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-ACM-COMMENT">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROPOSALS_COMMENTS</TABLENAME>
<KEYFIELDS>PPSC_SEQ</KEYFIELDS>
<SQL>
<SELECT>SELECT PROP_ID
, PROP_VERSION
, PROJ_ID
, ACM_CODE
, BGM_CODE
, PPSC_LEVEL
, PPSC_SEQ
, PPSC_COMMENT
, PPSC_COMMENT_BY
, PPSC_COMMENT_TIME
</SELECT>
<FROM>FROM PROPOSALS_COMMENTS</FROM>
</SQL>
<FIELDS>
<FIELD NAME="PROP_ID" TYPE="TEXT" LABEL="รหัสคำขอ" WIDTH="50"/>
<FIELD NAME="PROP_VERSION" TYPE="NUMBER" LABEL="เวอร์ชั่นคำขอ" WIDTH="10"/>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสโครงการ" WIDTH="50"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="50"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสรายการงบประมาณ" WIDTH="50"/>
<FIELD NAME="PPSC_LEVEL" TYPE="TEXT" LABEL="ระดับของความเห็น (PROJECT, GROUP, ITEM)" WIDTH="10" DEFAULT="GROUP"/>
<FIELD NAME="PPSC_SEQ" TYPE="NUMBER" LABEL="ลำดับความเห็น" WIDTH="10"/>
<FIELD NAME="PPSC_COMMENT" TYPE="TEXT" LABEL="เนื้อหาความเห็น" WIDTH="2000"/>
<FIELD NAME="PPSC_COMMENT_BY" TYPE="TEXT" LABEL="ผู้ให้ความเห็น" WIDTH="50" DEFAULT="${$UserCode}"/>
<FIELD NAME="PPSC_COMMENT_TIME" TYPE="DATE" LABEL="เวลาที่ให้ความเห็น" WIDTH="19"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROP_ID,PROJ_ID,ACM_CODE,PROP_VERSION" DETAIL-FIELDS="PROP_ID,PROJ_ID,ACM_CODE,PROP_VERSION"/>
</DATASET>
<DATASET ID="DS-ACM-HIST-COMMENT">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROPOSALS_COMMENTS</TABLENAME>
<KEYFIELDS>PROJ_ID,PROP_ID,PPSC_SEQ</KEYFIELDS>
<SQL>
<SELECT>SELECT PROP_ID
, PROP_VERSION
, PROJ_ID
, ACM_CODE
, BGM_CODE
, PPSC_LEVEL
, PPSC_SEQ
, PPSC_COMMENT
, PPSC_COMMENT_BY
, PPSC_COMMENT_TIME
</SELECT>
<FROM>FROM PROPOSALS_COMMENTS</FROM>
<FILTER><![CDATA[WHERE PROP_VERSION <= :PROP_VERSION]]></FILTER>
<ORDER>ORDER BY PROJ_ID,PROP_ID,PPSC_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROP_ID" TYPE="TEXT" LABEL="รหัสคำขอ" WIDTH="50"/>
<FIELD NAME="PROP_VERSION" TYPE="NUMBER" LABEL="เวอร์ชั่นคำขอ" WIDTH="10"/>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสโครงการ" WIDTH="50"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="50"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสรายการงบประมาณ" WIDTH="50"/>
<FIELD NAME="PPSC_LEVEL" TYPE="TEXT" LABEL="ระดับของความเห็น (PROJECT, GROUP, ITEM)" WIDTH="10"/>
<FIELD NAME="PPSC_SEQ" TYPE="NUMBER" LABEL="ลำดับความเห็น" WIDTH="10"/>
<FIELD NAME="PPSC_COMMENT" TYPE="TEXT" LABEL="เนื้อหาความเห็น" WIDTH="4000"/>
<FIELD NAME="PPSC_COMMENT_BY" TYPE="TEXT" LABEL="ผู้ให้ความเห็น" WIDTH="50"/>
<FIELD NAME="PPSC_COMMENT_TIME" TYPE="DATE" LABEL="เวลาที่ให้ความเห็น" WIDTH="19"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROP_ID,PROJ_ID,ACM_CODE" DETAIL-FIELDS="PROP_ID,PROJ_ID,ACM_CODE"/>
</DATASET>
</DATASETS>
</FORMS>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASET ID="DS-PROJECT_POLICY_INFO">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_POLICY_INFO</TABLENAME>
<KEYFIELDS>PROJ_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT PROJ_ID
, PROJ_PRINCIPLES
, PROJ_OBJECTIVE
, PROJ_BENEFIT
, PROJ_GOLD
, PROJ_TAGET_GROUP
, PROJ_LOCATION
, PROJ_ACTIVITY
, PROJ_RESPONDER
, PROJ_INVOLVERS
, PROJ_INVOLVISSE
, PROJ_PHASE
, PROJ_MONITORING
, CREATE_BY
, CREATE_AT
, UPDATE_BY
, UPDATE_AT
</SELECT>
<FROM>FROM PROJECT_POLICY_INFO</FROM>
<ORDER>ORDER BY PROJ_ID</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="proj_id" WIDTH="50"/>
<FIELD NAME="PROJ_PRINCIPLES" TYPE="TEXT" LABEL="proj_principles" WIDTH="2000"/>
<FIELD NAME="PROJ_OBJECTIVE" TYPE="TEXT" LABEL="proj_objective" WIDTH="2000"/>
<FIELD NAME="PROJ_BENEFIT" TYPE="TEXT" LABEL="proj_benefit" WIDTH="2000"/>
<FIELD NAME="PROJ_GOLD" TYPE="TEXT" LABEL="proj_gold" WIDTH="2000"/>
<FIELD NAME="PROJ_TAGET_GROUP" TYPE="TEXT" LABEL="proj_taget_group" WIDTH="2000"/>
<FIELD NAME="PROJ_LOCATION" TYPE="TEXT" LABEL="proj_location" WIDTH="100"/>
<FIELD NAME="PROJ_ACTIVITY" TYPE="TEXT" LABEL="proj_activity" WIDTH="2000"/>
<FIELD NAME="PROJ_RESPONDER" TYPE="TEXT" LABEL="proj_responder" WIDTH="1250"/>
<FIELD NAME="PROJ_INVOLVERS" TYPE="TEXT" LABEL="proj_involvers" WIDTH="2000"/>
<FIELD NAME="PROJ_INVOLVISSE" TYPE="TEXT" LABEL="proj_involvisse" WIDTH="2000"/>
<FIELD NAME="PROJ_PHASE" TYPE="TEXT" LABEL="proj_phase" WIDTH="50"/>
<FIELD NAME="PROJ_MONITORING" TYPE="TEXT" LABEL="proj_monitoring" WIDTH="2000"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID" DETAIL-FIELDS="PROJ_ID"/>
</DATASET>
<DATASET ID="DS-PROJECT_EXPENSES">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_EXPENSES</TABLENAME>
<KEYFIELDS>PROJ_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT PROJ_ID
, PEXP_SEQ
, PEXP_DETAIL
, PEXP_QT_01
, PEXP_QT_02
, PEXP_QT_03
, PEXP_QT_04
, PEXP_TOTAL
, CREATE_BY
, CREATE_AT
, UPDATE_BY
, UPDATE_AT
</SELECT>
<FROM>FROM PROJECT_EXPENSES</FROM>
<ORDER>ORDER BY PROJ_ID,PEXP_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="50"/>
<FIELD NAME="PEXP_SEQ" TYPE="NUMBER" LABEL="ลำดับ" WIDTH="10"/>
<FIELD NAME="PEXP_DETAIL" TYPE="TEXT" LABEL="รายละเอียด" WIDTH="250"/>
<FIELD NAME="PEXP_QT_01" TYPE="NUMBER" LABEL="ไตรมาส 1" WIDTH="15"/>
<FIELD NAME="PEXP_QT_02" TYPE="NUMBER" LABEL="ไตรมาส 2" WIDTH="15"/>
<FIELD NAME="PEXP_QT_03" TYPE="NUMBER" LABEL="ไตรมาส 3" WIDTH="15"/>
<FIELD NAME="PEXP_QT_04" TYPE="NUMBER" LABEL="ไตรมาส 4" WIDTH="15"/>
<FIELD NAME="PEXP_TOTAL" TYPE="NUMBER" LABEL="รวมยอดเงิน" WIDTH="2" FORM-NAME="PROJ_BDGT_TOTAL"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID" DETAIL-FIELDS="PROJ_ID"/>
</DATASET>
</FORMS>

View File

@@ -0,0 +1,260 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT_BUDGET_ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>
SELECT :PROJ_ID PROJ_ID
, ACTT.ACM_CODE
, ACTT.ACM_NAME
, ACTT.ACM_SEQ
, ACTT.NODE_LEVEL
, ACTT.MAIN_NODE
, ACTT.ACM_UNIT
, ACTT.ACM_START_YEAR
, ACTT.ACM_END_YEAR
, ACTT.NODE_TYPE
, PBGI.PBDG_ID
, PBGI.BGM_CODE
, PBGI.PBGI_QTY
, PBGI.PBGI_COST
, PBGI.PBGI_FREQ
, PBGI.PBGI_ASSET_TYPE
, PBGI.PBGI_REPLACE
, PBGI.PBGI_ADDITION
, PBGI.PBGI_ACQUIRE
, PBGI.PBGI_TOTAL
, PBGI.PBGI_REASON
</SELECT>
<FROM>
FROM BGT.V_ACTIVITY_TREE ACTT
INNER JOIN ( SELECT DISTINCT ACM.ACM_CODE
FROM BUD.ACTIVITY_M ACM
INNER JOIN BUD.ACTIVITY_CTRL_H ACH ON ACM.ACM_CODE = ACH.ACH_CODE
START WITH ACM.ACM_CODE IN (SELECT PBGI.PBDG_ID ACM_CODE FROM PROJECT_BUDGET_ITEMS PBGI WHERE PROJ_ID = :PROJ_ID)
CONNECT BY PRIOR ACH.ACH_CTRL_CODE = ACH.ACH_CODE) FLTR ON FLTR.ACM_CODE = ACTT.ACM_CODE
LEFT OUTER JOIN BGT.PROJECT_BUDGET_ITEMS PBGI ON PBGI.PBDG_ID = ACTT.ACM_CODE
</FROM>
<ORDER>ORDER BY ACTT.ACM_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสหมวดงบประมาณ" WIDTH="20"/>
<FIELD NAME="PBGI_QT_01" TYPE="NUMBER" LABEL="จำนวนไตรมาส 1" WIDTH="15"/>
<FIELD NAME="PBGI_QT_02" TYPE="NUMBER" LABEL="จำนวนไตรมาส 2" WIDTH="15"/>
<FIELD NAME="PBGI_QT_03" TYPE="NUMBER" LABEL="จำนวนไตรมาส 3" WIDTH="15"/>
<FIELD NAME="PBGI_QT_04" TYPE="NUMBER" LABEL="จำนวนไตรมาส 4" WIDTH="15"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="จำนวน" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="ราคาต่อหน่วย" WIDTH="15"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="ความถี่/จำนวนครั้ง" WIDTH="10"/>
<FIELD NAME="PBGI_ASSET_TYPE" TYPE="TEXT" LABEL="ประเภทสินทรัพย์" WIDTH="10"/>
<FIELD NAME="PBGI_REPLACE" TYPE="NUMBER" LABEL="ทดแทนของเดิม" WIDTH="10"/>
<FIELD NAME="PBGI_ADDITION" TYPE="NUMBER" LABEL="เพิ่มเติม" WIDTH="10"/>
<FIELD NAME="PBGI_ACQUIRE" TYPE="NUMBER" LABEL="จัดหาใหม่" WIDTH="10"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="รวมเป็นเงิน" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="เหตุผลความจำเป็น" WIDTH="4000"/>
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-CONST-BUDGET">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID" DETAIL-FIELDS="PROJ_ID"/>
<UNIQ-CHECK CHECK-FIELDS="ACM_CODE" MESSAGE="pctbi.const_code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT_BUDGET_ITEMS" EDIT="Y" DELETE="Y" CLASS="table-primary">
<KEYFIELDS>PROJ_ID,BGM_CODE</KEYFIELDS>
<TITLES>
<ROW>
<FIELD NAME="ACM_CODE" LABEL="pctbi.const_code" WIDTH="10em" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="ACM_NAME" LABEL="pctbi.const_name" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BUDGET_INFO" LABEL="pctbi.budget" ALIGN="center" COLS-SPAN="3"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_QTY" LABEL="pctbi.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pctbi.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pctbi.total" WIDTH="8em" ALIGN="right"/>
</ROW>
</TITLES>
<FIELDS>
<FIELD NAME="PBDG_ID" LABEL="pctbi.const_code" WIDTH="15em" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="ACM_NAME" LABEL="pctbi.const_name" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="PBGI_QTY" LABEL="pbgz.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pbgz.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pbgz.total" WIDTH="8em" ALIGN="right"/>
<COMMAND-BUTTONS>
<BUTTONS-FILTER>
<EDIT><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></EDIT>
<DELETE><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></DELETE>
<VIEW><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></VIEW>
</BUTTONS-FILTER>
</COMMAND-BUTTONS>
</FIELDS>
<FOOTER SHOW="Y"/>
<SCRIPT>
<INITIALIZE>
<![CDATA[
(ctx)=> {
ctx.sumOf = {};
console.log("init grid-budget");
const fieldFormat = (field,value,row) => {
if (row["node_type"] === "D" || field === "pbgi_total") {
return formatNumber(value, 0);
} else {
return "";
}
}
const summary = (field, data) => {
let total = 0;
for (const row of data) {
total += (+row[field])||0;
}
ctx.sumOf[field] = total;
if (ctx.$dataGrid && ctx.$dataGrid.load && !ctx.$dataGrid.reload) {
ctx.$dataGrid.reload = true;
for (let id=data.length-1; id>=0; id--) {
let row = data[id];
if (row["node_type"] === "C") {
let grpTotal = 0;
let mainNode = row["acm_code"];
let nodes = [];
let dataNode = $$("main_node="+mainNode,data);
if (dataNode) {
nodes.push(dataNode);
for (let node of nodes.flat()) {
grpTotal += +node[field];
}
data[id][field] = grpTotal;
}
}
}
ctx.$dataGrid.load(data);
ctx.$dataGrid.reload = false;
}
return formatNumber(total,0);
}
const fieldList = ["pbgi_qty","pbgi_cost","pbgi_total"];
for (let field of fieldList) {
let column = $$(`field=${field}`,ctx.gridColumn.flat());
column.formatter = (value,row) => {
return fieldFormat(field, value, row);
}
column.footerFormatter = (data)=>{
return summary(field,data);
}
}
ctx.option.rowStyle = function (row, index) {
if (row["node_type"] === "C") {
return {classes : `group-level-${row["node_level"]}`};
}
return {}; // Default style for other rows
}
}
]]>
</INITIALIZE>
</SCRIPT>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT_BUDGET_ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="ACM_CODE" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BGM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="ACM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="VACM_CODE" CAPTION="pctbi.const_code" INPUTTYPE="TEXT" REQUIRE="Y" READONLY="Y"/>
<FIELD NAME="ACM_CODE" CAPTION="pctbi.const_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-ACTIVITY-04" VALUE-FIELD="ACM_CODE" TEXT-FIELD="ACM_NAME" PARAMETERS="DV_YEAR=PROJ_YEAR,STM_CODE=STM_CODE">
<UPDATE-FIELDS>
<FIELD SRC="ACM_CODE" TARGET="VACM_CODE"/>
<FIELD SRC="ACM_CODE" TARGET="PBDG_ID"/>
<FIELD SRC="ACM_NAME" TARGET="ACM_NAME"/>
<FIELD SRC="ACM_UNIT" TARGET="PBGI_UNIT"/>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div class="d-flex flex-row gap-1"><label class="flex-column text-nowrap col-3">[${data.acm_code}]</label> : <label>${data.acm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-BUDGET-04" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div class="d-flex flex-row gap-1"><label class="flex-column text-nowrap col-3">[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_UNIT" CAPTION="pctbi.unit" INPUTTYPE="TEXT" DATATYPE="TEXT" READONLY="Y"/>
<FIELD NAME="PBGI_QTY" CAPTION="pctbi.qty" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_COST" CAPTION="pctbi.cost" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="pctbi.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" READONLY="Y"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="VACM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="ACM_CODE" LAYOUT_WIDTH="16"/>
</ROW>
<ROW ID="ROW-BUDGET-DATA">
<FIELD NAME="PBGI_QTY" LAYOUT_WIDTH="3" OFFSET="6"/>
<FIELD NAME="PBGI_UNIT" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_COST" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="4" OFFSET="6"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="12"/>
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 350px"></div>]]>
</ROW>
</LAYOUT>
<SCRIPT>
<INITIALIZE><![CDATA[
console.log("sum budget value");
let budgetField = $$("input.budget-data");
const sumBudget = ()=>{
$$("PBGI_TOTAL").setValue(budgetField.multiply());
}
budgetField.on("change",sumBudget);
]]></INITIALIZE>
</SCRIPT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT_BUDGET_ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT BGTT.BGM_CODE
, BGTT.BGM_NAME
, BGTT.BGM_UNIT
, BGTT.BGM_UNIT_RATE
, BGTT.NODE_LEVEL
, BGTT.BGM_SEQ
, BGTT.EXP_TYPE
, BGTT.MAIN_NODE
, BGTT.NODE_TYPE
, PBGI.PBGI_QTY
, PBGI.PBGI_COST
, PBGI.PBGI_FREQ
, PBGI.PBGI_ASSET_TYPE
, PBGI.PBGI_REPLACE
, PBGI.PBGI_ADDITION
, PBGI.PBGI_ACQUIRE
, PBGI.PBGI_TOTAL
, PBGI.PBGI_REASON
</SELECT>
<FROM>
FROM BGT.V_BUDGET_TREE BGTT
INNER JOIN (SELECT DISTINCT BGDM.BGM_CODE
FROM BUD.BUDGET_M BGDM
INNER JOIN BUD.BUDGET_M BGDH ON BGDM.BGM_CODE = BGDH.BGM_CODE
START WITH BGDM.BGM_CODE IN (SELECT PBGI.BGM_CODE FROM BGT.PROJECT_BUDGET_ITEMS PBGI WHERE PBGI.PROJ_ID = :PROJ_ID AND PBGI.PBDG_ID = :PBDG_ID)
CONNECT BY PRIOR BGDH.BGM_MAIN_NODE = BGDH.BGM_CODE) FLTR ON FLTR.BGM_CODE = BGTT.BGM_CODE
LEFT OUTER JOIN BGT.PROJECT_BUDGET_ITEMS PBGI ON PBGI.BGM_CODE = BGTT.BGM_CODE
</FROM>
<ORDER>ORDER BY BGTT.BGM_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสหมวดงบประมาณ" WIDTH="20"/>
<FIELD NAME="PBGI_QT_01" TYPE="NUMBER" LABEL="จำนวนไตรมาส 1" WIDTH="15"/>
<FIELD NAME="PBGI_QT_02" TYPE="NUMBER" LABEL="จำนวนไตรมาส 2" WIDTH="15"/>
<FIELD NAME="PBGI_QT_03" TYPE="NUMBER" LABEL="จำนวนไตรมาส 3" WIDTH="15"/>
<FIELD NAME="PBGI_QT_04" TYPE="NUMBER" LABEL="จำนวนไตรมาส 4" WIDTH="15"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="จำนวน" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="ราคาต่อหน่วย" WIDTH="15"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="ความถี่/จำนวนครั้ง" WIDTH="10"/>
<FIELD NAME="PBGI_ASSET_TYPE" TYPE="TEXT" LABEL="ประเภทสินทรัพย์" WIDTH="10"/>
<FIELD NAME="PBGI_REPLACE" TYPE="NUMBER" LABEL="ทดแทนของเดิม" WIDTH="10"/>
<FIELD NAME="PBGI_ADDITION" TYPE="NUMBER" LABEL="เพิ่มเติม" WIDTH="10"/>
<FIELD NAME="PBGI_ACQUIRE" TYPE="NUMBER" LABEL="จัดหาใหม่" WIDTH="10"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="รวมเป็นเงิน" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="เหตุผลความจำเป็น" WIDTH="4000"/>
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-EQUIPT-BUDGET">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,PBDG_ID" DETAIL-FIELDS="PROJ_ID,PBDG_ID"/>
<UNIQ-CHECK CHECK-FIELDS="BGM_CODE" MESSAGE="pwbg.bgm_code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT_BUDGET_ITEMS" EDIT="Y" DELETE="Y" CLASS="table-primary">
<KEYFIELDS>PROJ_ID,BGM_CODE</KEYFIELDS>
<TITLES>
<ROW>
<FIELD NAME="BGM_CODE" LABEL="pbgz.bgm_code" WIDTH="10em" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_NAME" LABEL="pbgz.bgm_name" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_BUTGETS" LABEL="pbgz.budget" ALIGN="center" COLS-SPAN="5"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_FREQ" LABEL="pbgz.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QTY" LABEL="pbgz.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_ACQUIRE" LABEL="pbgz.acquire" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pbgz.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pbgz.total" WIDTH="8em" ALIGN="right"/>
</ROW>
</TITLES>
<FIELDS>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="15em" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="PBGI_FREQ" LABEL="pbgz.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QTY" LABEL="pbgz.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_ACQUIRE" LABEL="pbgz.acquire" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pbgz.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pbgz.total" WIDTH="8em" ALIGN="right"/>
<COMMAND-BUTTONS>
<BUTTONS-FILTER>
<EDIT><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></EDIT>
<DELETE><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></DELETE>
<VIEW><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></VIEW>
</BUTTONS-FILTER>
</COMMAND-BUTTONS>
</FIELDS>
<FOOTER SHOW="Y"/>
<SCRIPT>
<INITIALIZE>
<![CDATA[
(ctx)=> {
ctx.sumOf = {};
console.log("init grid-budget");
const fieldFormat = (field,value,row) => {
if (row["node_type"] === "D" || field === "pbgi_total") {
return formatNumber(value, 0);
} else {
return "";
}
}
const summary = (field, data) => {
let total = 0;
for (const row of data) {
total += (+row[field])||0;
}
ctx.sumOf[field] = total;
if (ctx.$dataGrid && ctx.$dataGrid.load && !ctx.$dataGrid.reload) {
ctx.$dataGrid.reload = true;
for (let id=data.length-1; id>=0; id--) {
let row = data[id];
if (row["node_type"] === "C") {
let grpTotal = 0;
let mainNode = row["bgm_code"];
let nodes = [];
nodes.push($$("main_node="+mainNode,data));
for (let node of nodes.flat()) {
grpTotal += +node[field];
}
data[id][field] = grpTotal;
}
}
ctx.$dataGrid.load(data);
ctx.$dataGrid.reload = false;
}
return formatNumber(total,0);
}
const fieldList = ["pbgi_freq","pbgi_qty","pbgi_acquire","pbgi_cost","pbgi_total"];
for (let field of fieldList) {
let column = $$(`field=${field}`,ctx.gridColumn.flat());
column.formatter = (value,row) => {
return fieldFormat(field, value, row);
}
column.footerFormatter = (data)=>{
return summary(field,data);
}
}
ctx.option.rowStyle = function (row, index) {
if (row["node_type"] === "C") {
return {classes : `group-level-${row["node_level"]}`};
}
return {}; // Default style for other rows
}
}
]]>
</INITIALIZE>
</SCRIPT>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT_BUDGET_ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BGM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-BUDGET-03" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div><label class="offset-${data.node_level}">[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_FREQ" CAPTION="pbgz.freq" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_QTY" CAPTION="pbgz.qty" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_ACQUIRE" CAPTION="pbgz.acquire" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_COST" CAPTION="pbgz.cost" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="pbgz.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" READONLY="Y"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="16"/>
</ROW>
<ROW ID="ROW-BUDGET-DATA">
<FIELD NAME="PBGI_FREQ" LAYOUT_WIDTH="3" OFFSET="6"/>
<FIELD NAME="PBGI_QTY" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_ACQUIRE" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_COST" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 350px"></div>]]>
</ROW>
</LAYOUT>
<SCRIPT>
<INITIALIZE><![CDATA[
console.log("sum budget value");
let budgetField = $$("input.budget-data");
const sumBudget = ()=>{
$$("PBGI_TOTAL").setValue(budgetField.multiply());
}
budgetField.on("change",sumBudget);
]]></INITIALIZE>
</SCRIPT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT_BUDGET_ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT BGTT.BGM_CODE
, BGTT.BGM_NAME
, BGTT.BGM_UNIT
, BGTT.BGM_UNIT_RATE
, BGTT.NODE_LEVEL
, BGTT.BGM_SEQ
, BGTT.EXP_TYPE
, BGTT.MAIN_NODE
, BGTT.NODE_TYPE
, PBGI.PBGI_QTY
, PBGI.PBGI_FREQ
, PBGI.PBGI_COST
, PBGI.PBGI_ACQUIRE
, PBGI.PBGI_TOTAL
</SELECT>
<FROM>
FROM BGT.V_BUDGET_TREE BGTT
INNER JOIN (SELECT DISTINCT BGDM.BGM_CODE
FROM BUD.BUDGET_M BGDM
INNER JOIN BUD.BUDGET_M BGDH ON BGDM.BGM_CODE = BGDH.BGM_CODE
START WITH BGDM.BGM_CODE IN (SELECT PBGI.BGM_CODE FROM BGT.PROJECT_BUDGET_ITEMS PBGI WHERE PBGI.PROJ_ID = :PROJ_ID AND PBGI.PBDG_ID = :PBDG_ID)
CONNECT BY PRIOR BGDH.BGM_MAIN_NODE = BGDH.BGM_CODE) FLTR ON FLTR.BGM_CODE = BGTT.BGM_CODE
LEFT OUTER JOIN BGT.PROJECT_BUDGET_ITEMS PBGI ON PBGI.BGM_CODE = BGTT.BGM_CODE AND PBGI.PROJ_ID = :PROJ_ID AND PBGI.PBDG_ID = :PBDG_ID
</FROM>
<ORDER>ORDER BY BGTT.BGM_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสหมวดงบประมาณ" WIDTH="20"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="จำนวนครั้ง" WIDTH="10"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="จำนวนคน" WIDTH="10"/>
<FIELD NAME="PBGI_ACQUIRE" TYPE="NUMBER" LABEL="จำนวนชั่วโมง" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="อัตรา" WIDTH="15"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="รวมเป็นเงิน" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="เหตุผลความจำเป็น" WIDTH="4000"/>
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-WORK-BUDGET">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,PBDG_ID" DETAIL-FIELDS="PROJ_ID,PBDG_ID"/>
<UNIQ-CHECK CHECK-FIELDS="BGM_CODE" MESSAGE="pwbg.bgm_code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT_BUDGET_ITEMS" EDIT="Y" DELETE="Y" CLASS="table-primary">
<KEYFIELDS>PROJ_ID,BGM_CODE</KEYFIELDS>
<TITLES>
<ROW>
<FIELD NAME="BGM_CODE" LABEL="pbgz.bgm_code" WIDTH="10em" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_NAME" LABEL="pbgz.bgm_name" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_BUTGETS" LABEL="pbgz.budget" ALIGN="center" COLS-SPAN="5"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_FREQ" LABEL="pbgz.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QTY" LABEL="pbgz.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_ACQUIRE" LABEL="pbgz.acquire" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pbgz.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pbgz.total" WIDTH="8em" ALIGN="right"/>
</ROW>
</TITLES>
<FIELDS>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="15em" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="PBGI_FREQ" LABEL="pbgz.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QTY" LABEL="pbgz.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_ACQUIRE" LABEL="pbgz.acquire" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pbgz.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pbgz.total" WIDTH="8em" ALIGN="right"/>
<COMMAND-BUTTONS>
<BUTTONS-FILTER>
<EDIT><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></EDIT>
<DELETE><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></DELETE>
<VIEW><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></VIEW>
</BUTTONS-FILTER>
</COMMAND-BUTTONS>
</FIELDS>
<FOOTER SHOW="Y"/>
<SCRIPT>
<INITIALIZE>
<![CDATA[
(ctx)=> {
ctx.sumOf = {};
console.log("init grid-budget");
const fieldFormat = (field,value,row) => {
if (row["node_type"] === "D" || field === "pbgi_total") {
return formatNumber(value, 0);
} else {
return "";
}
}
const summary = (field, data) => {
let total = 0;
for (const row of data) {
total += (+row[field])||0;
}
ctx.sumOf[field] = total;
if (ctx.$dataGrid && ctx.$dataGrid.load && !ctx.$dataGrid.reload) {
ctx.$dataGrid.reload = true;
for (let id=data.length-1; id>=0; id--) {
let row = data[id];
if (row["node_type"] === "C") {
let grpTotal = 0;
let mainNode = row["bgm_code"];
let nodes = [];
nodes.push($$("main_node="+mainNode,data));
for (let node of nodes.flat()) {
grpTotal += +node[field];
}
data[id][field] = grpTotal;
}
}
ctx.$dataGrid.load(data);
ctx.$dataGrid.reload = false;
}
return formatNumber(total,0);
}
const fieldList = ["pbgi_freq","pbgi_qty","pbgi_acquire","pbgi_cost","pbgi_total"];
for (let field of fieldList) {
let column = $$(`field=${field}`,ctx.gridColumn.flat());
column.formatter = (value,row) => {
return fieldFormat(field, value, row);
}
column.footerFormatter = (data)=>{
return summary(field,data);
}
}
ctx.option.rowStyle = function (row, index) {
if (row["node_type"] === "C") {
return {classes : `group-level-${row["node_level"]}`};
}
return {}; // Default style for other rows
}
}
]]>
</INITIALIZE>
</SCRIPT>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT_BUDGET_ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BGM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-BUDGET-02" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div><label class="offset-${data.node_level}">[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_FREQ" CAPTION="pbgz.freq" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_QTY" CAPTION="pbgz.qty" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_ACQUIRE" CAPTION="pbgz.acquire" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_COST" CAPTION="pbgz.cost" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="pbgz.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" READONLY="Y"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="16"/>
</ROW>
<ROW ID="ROW-BUDGET-DATA">
<FIELD NAME="PBGI_FREQ" LAYOUT_WIDTH="3" OFFSET="6"/>
<FIELD NAME="PBGI_QTY" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_ACQUIRE" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_COST" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 350px"></div>]]>
</ROW>
</LAYOUT>
<SCRIPT>
<INITIALIZE><![CDATA[
console.log("sum budget value");
let budgetField = $$("input.budget-data");
const sumBudget = ()=>{
$$("PBGI_TOTAL").setValue(budgetField.multiply());
}
budgetField.on("change",sumBudget);
]]></INITIALIZE>
</SCRIPT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,213 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT_BUDGET_ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT BGTT.BGM_CODE
, BGTT.BGM_NAME
, BGTT.BGM_UNIT
, BGTT.BGM_UNIT_RATE
, BGTT.NODE_LEVEL
, BGTT.BGM_SEQ
, BGTT.EXP_TYPE
, BGTT.MAIN_NODE
, BGTT.NODE_TYPE
, PBGI.PBGI_QTY
, PBGI.PBGI_FREQ
, PBGI.PBGI_COST
, PBGI.PBGI_TOTAL
</SELECT>
<FROM>
FROM BGT.V_BUDGET_TREE BGTT
INNER JOIN (SELECT DISTINCT BGDM.BGM_CODE
FROM BUD.BUDGET_M BGDM
INNER JOIN BUD.BUDGET_M BGDH ON BGDM.BGM_CODE = BGDH.BGM_CODE
START WITH BGDM.BGM_CODE IN (SELECT PBGI.BGM_CODE FROM BGT.PROJECT_BUDGET_ITEMS PBGI WHERE PBGI.PROJ_ID = :PROJ_ID AND PBGI.PBDG_ID = :PBDG_ID)
CONNECT BY PRIOR BGDH.BGM_MAIN_NODE = BGDH.BGM_CODE) FLTR ON FLTR.BGM_CODE = BGTT.BGM_CODE
LEFT OUTER JOIN BGT.PROJECT_BUDGET_ITEMS PBGI ON PBGI.BGM_CODE = BGTT.BGM_CODE AND PBGI.PROJ_ID = :PROJ_ID AND PBGI.PBDG_ID = :PBDG_ID
</FROM>
<ORDER>ORDER BY BGTT.BGM_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสหมวดงบประมาณ" WIDTH="20"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="จำนวนครั้ง" WIDTH="10"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="จำนวนคน" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="อัตรา" WIDTH="15"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="รวมเป็นเงิน" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="เหตุผลความจำเป็น" WIDTH="4000"/>
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-WORK-BUDGET">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,PBDG_ID" DETAIL-FIELDS="PROJ_ID,PBDG_ID"/>
<UNIQ-CHECK CHECK-FIELDS="BGM_CODE" MESSAGE="pwbg.bgm_code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT_BUDGET_ITEMS" EDIT="Y" DELETE="Y" CLASS="table-primary">
<KEYFIELDS>PROJ_ID,BGM_CODE</KEYFIELDS>
<TITLES>
<ROW>
<FIELD NAME="BGM_CODE" LABEL="plcbg.bgm_code" WIDTH="10em" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_NAME" LABEL="plcbg.bgm_name" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_BUTGETS" LABEL="plcbg.budget" ALIGN="center" COLS-SPAN="4"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_QTY" LABEL="plcbg.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_FREQ" LABEL="plcbg.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="plcbg.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="plcbg.total" WIDTH="8em" ALIGN="right"/>
</ROW>
</TITLES>
<FIELDS>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="15em" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="PBGI_QTY" LABEL="plcbg.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_FREQ" LABEL="plcbg.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="plcbg.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="plcbg.total" WIDTH="8em" ALIGN="right"/>
<COMMAND-BUTTONS>
<BUTTONS-FILTER>
<EDIT><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></EDIT>
<DELETE><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></DELETE>
<VIEW><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></VIEW>
</BUTTONS-FILTER>
</COMMAND-BUTTONS>
</FIELDS>
<FOOTER SHOW="Y"/>
<SCRIPT>
<INITIALIZE>
<![CDATA[
(ctx)=> {
ctx.sumOf = {};
console.log("init grid-budget");
const fieldFormat = (field,value,row) => {
return (row["node_type"] === "D" || field === "pbgi_total") ? formatNumber(value, 0) : "";
}
const summary = (field, data) => {
let total = 0;
for (const row of data) {
if (row["node_type"] === "D") {
total += (strToFloat(row[field])) || 0;
}
}
ctx.sumOf[field] = total;
if (ctx.$dataGrid && ctx.$dataGrid.load && !ctx.$dataGrid.reload) {
ctx.$dataGrid.reload = true;
for (let id=data.length-1; id>=0; id--) {
let row = data[id];
if (row["node_type"] === "C") {
let grpTotal = 0;
let mainNode = row["bgm_code"];
let nodes = [];
nodes.push($$("main_node="+mainNode,data));
for (let node of nodes.flat()) {
grpTotal += +node[field];
}
data[id][field] = grpTotal;
}
}
ctx.$dataGrid.load(data);
ctx.$dataGrid.reload = false;
}
return formatNumber(total,0);
}
const fieldList = ["pbgi_freq","pbgi_qty","pbgi_cost","pbgi_total"];
for (let field of fieldList) {
let column = $$(`field=${field}`,ctx.gridColumn.flat());
column.formatter = (value,row) => {
return fieldFormat(field, value, row);
}
column.footerFormatter =function (data) {
return summary(field,data);
}
}
ctx.option.rowStyle = function (row, index) {
if (row["node_type"] === "C") {
return {classes : `group-level-${row["node_level"]}`};
}
return {}; // Default style for other rows
}
}
]]>
</INITIALIZE>
</SCRIPT>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT_BUDGET_ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BGM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="NODE_TYPE" INPUTTYPE="HIDDEN" VALUE="D"/>
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-BUDGET-02-BDGT" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
return $(`<div><label class="offset-${data.node_level}">[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_QTY" CAPTION="plcbg.qty" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_FREQ" CAPTION="plcbg.freq" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_COST" CAPTION="plcbg.cost" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="plcbg.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" READONLY="Y"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="16"/>
</ROW>
<ROW ID="ROW-BUDGET-DATA">
<FIELD NAME="PBGI_QTY" LAYOUT_WIDTH="3" OFFSET="6"/>
<FIELD NAME="PBGI_FREQ" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_COST" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 350px"></div>]]>
</ROW>
</LAYOUT>
<SCRIPT>
<INITIALIZE><![CDATA[
console.log("sum budget value");
let budgetField = $$("input.budget-data");
const sumBudget = ()=>{
$$("PBGI_TOTAL").setValue(budgetField.multiply());
}
budgetField.on("change",sumBudget);
]]></INITIALIZE>
</SCRIPT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT_BUDGET_ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT BGTT.BGM_CODE
, BGTT.BGM_NAME
, BGTT.BGM_UNIT
, BGTT.BGM_UNIT_RATE
, BGTT.NODE_LEVEL
, BGTT.BGM_SEQ
, BGTT.EXP_TYPE
, BGTT.MAIN_NODE
, BGTT.NODE_TYPE
, PBGI.PBGI_QTY
, PBGI.PBGI_FREQ
, PBGI.PBGI_COST
, PBGI.PBGI_ACQUIRE
, PBGI.PBGI_TOTAL
</SELECT>
<FROM>
FROM BGT.V_BUDGET_TREE BGTT
INNER JOIN (SELECT DISTINCT BGDM.BGM_CODE
FROM BUD.BUDGET_M BGDM
INNER JOIN BUD.BUDGET_M BGDH ON BGDM.BGM_CODE = BGDH.BGM_CODE
START WITH BGDM.BGM_CODE IN (SELECT PBGI.BGM_CODE FROM BGT.PROJECT_BUDGET_ITEMS PBGI WHERE PBGI.PROJ_ID = :PROJ_ID AND PBGI.PBDG_ID = :PBDG_ID)
CONNECT BY PRIOR BGDH.BGM_MAIN_NODE = BGDH.BGM_CODE) FLTR ON FLTR.BGM_CODE = BGTT.BGM_CODE
LEFT OUTER JOIN BGT.PROJECT_BUDGET_ITEMS PBGI ON PBGI.BGM_CODE = BGTT.BGM_CODE AND PBGI.PROJ_ID = :PROJ_ID AND PBGI.PBDG_ID = :PBDG_ID
</FROM>
<ORDER>ORDER BY BGTT.BGM_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสหมวดงบประมาณ" WIDTH="20"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="จำนวนครั้ง" WIDTH="10"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="จำนวนคน" WIDTH="10"/>
<FIELD NAME="PBGI_ACQUIRE" TYPE="NUMBER" LABEL="จำนวนชั่วโมง" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="อัตรา" WIDTH="15"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="รวมเป็นเงิน" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="เหตุผลความจำเป็น" WIDTH="4000"/>
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-WORK-BUDGET">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,PBDG_ID" DETAIL-FIELDS="PROJ_ID,PBDG_ID"/>
<UNIQ-CHECK CHECK-FIELDS="BGM_CODE" MESSAGE="pwbg.bgm_code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT_BUDGET_ITEMS" EDIT="Y" DELETE="Y" CLASS="table-primary">
<KEYFIELDS>PROJ_ID,BGM_CODE</KEYFIELDS>
<TITLES>
<ROW>
<FIELD NAME="BGM_CODE" LABEL="pbgz.bgm_code" WIDTH="10em" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_NAME" LABEL="pbgz.bgm_name" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_BUTGETS" LABEL="pbgz.budget" ALIGN="center" COLS-SPAN="5"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_FREQ" LABEL="pbgz.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QTY" LABEL="pbgz.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_ACQUIRE" LABEL="pbgz.acquire" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pbgz.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pbgz.total" WIDTH="8em" ALIGN="right"/>
</ROW>
</TITLES>
<FIELDS>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="15em" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left">
<DATA-FORMATTER>
<![CDATA[ (value,row,idx)=>{return $(`<div class="col offset-${row["node_level"]}">${value}</div>`);}]]>
</DATA-FORMATTER>
</FIELD>
<FIELD NAME="PBGI_FREQ" LABEL="pbgz.freq" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QTY" LABEL="pbgz.qty" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_ACQUIRE" LABEL="pbgz.acquire" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_COST" LABEL="pbgz.cost" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pbgz.total" WIDTH="8em" ALIGN="right"/>
<COMMAND-BUTTONS>
<BUTTONS-FILTER>
<EDIT><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></EDIT>
<DELETE><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></DELETE>
<VIEW><![CDATA[({$ctx,row})=>{return row["node_type"] !== "C"}]]></VIEW>
</BUTTONS-FILTER>
</COMMAND-BUTTONS>
</FIELDS>
<FOOTER SHOW="Y"/>
<SCRIPT>
<INITIALIZE>
<![CDATA[
(ctx)=> {
ctx.sumOf = {};
console.log("init grid-budget");
const fieldFormat = (field,value,row) => {
if (row["node_type"] === "D" || field === "pbgi_total") {
return formatNumber(value, 0);
} else {
return "";
}
}
const summary = (field, data) => {
let total = 0;
for (const row of data) {
total += (+row[field])||0;
}
ctx.sumOf[field] = total;
if (ctx.$dataGrid && ctx.$dataGrid.load && !ctx.$dataGrid.reload) {
ctx.$dataGrid.reload = true;
for (let id=data.length-1; id>=0; id--) {
let row = data[id];
if (row["node_type"] === "C") {
let grpTotal = 0;
let mainNode = row["bgm_code"];
let nodes = [];
nodes.push($$("main_node="+mainNode,data));
for (let node of nodes.flat()) {
grpTotal += +node[field];
}
data[id][field] = grpTotal;
}
}
ctx.$dataGrid.load(data);
ctx.$dataGrid.reload = false;
}
return formatNumber(total,0);
}
const fieldList = ["pbgi_freq","pbgi_qty","pbgi_acquire","pbgi_cost","pbgi_total"];
for (let field of fieldList) {
let column = $$(`field=${field}`,ctx.gridColumn.flat());
column.formatter = (value,row) => {
return fieldFormat(field, value, row);
}
column.footerFormatter = (data)=>{
return summary(field,data);
}
}
ctx.option.rowStyle = function (row, index) {
if (row["node_type"] === "C") {
return {classes : `group-level-${row["node_level"]}`};
}
return {}; // Default style for other rows
}
}
]]>
</INITIALIZE>
</SCRIPT>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT_BUDGET_ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BGM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-BUDGET-02" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div><label class="offset-${data.node_level}">[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_FREQ" CAPTION="pbgz.freq" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_QTY" CAPTION="pbgz.qty" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_ACQUIRE" CAPTION="pbgz.acquire" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_COST" CAPTION="pbgz.cost" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" CLASS-NAME="budget-data"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="pbgz.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" READONLY="Y"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="16"/>
</ROW>
<ROW ID="ROW-BUDGET-DATA">
<FIELD NAME="PBGI_FREQ" LAYOUT_WIDTH="3" OFFSET="6"/>
<FIELD NAME="PBGI_QTY" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_ACQUIRE" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_COST" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 350px"></div>]]>
</ROW>
</LAYOUT>
<SCRIPT>
<INITIALIZE><![CDATA[
console.log("sum budget value");
let budgetField = $$("input.budget-data");
const sumBudget = ()=>{
$$("PBGI_TOTAL").setValue(budgetField.multiply());
}
budgetField.on("change",sumBudget);
]]></INITIALIZE>
</SCRIPT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT-STTGYS-ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_STTGYS_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,PSTG_CODE,PSTI_GROUP</KEYFIELDS>
<SQL>
<SELECT>
SELECT PSTI.PROJ_ID
, PSTI.PSTG_CODE
, PSTI.PSTI_GROUP
, RFGP.RFC_DESC GROUP_DESC
, PSTI.PSTI_CODE
, RFCI.RFC_DESC ITEM_DESC
, PSTI_DETAIL
</SELECT>
<FROM>FROM PROJECT_STTGYS_ITEMS PSTI
INNER JOIN BGT.REFER_CODE RFGP ON RFGP.RFG_GRP='STG-ITEMS' AND RFC.RFC_CODE=STTG.PSTI_CODE
INNER JOIN BGT.REFER_CODE RFCI ON RFC.RFG_GRP=PSTI.PSTI_GROUP AND RFC.RFC_CODE=STTG.PSTI_CODE
</FROM>
<ORDER>ORDER BY PSTI_GROUP, PSTI_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="VARCHAR" WIDTH="50" LABEL="project.id" />
<FIELD NAME="PSTG_CODE" TYPE="VARCHAR" WIDTH="20" LABEL="pstg.code" />
<FIELD NAME="PSTI_GROUP" TYPE="VARCHAR" WIDTH="15" LABEL="psti.group" />
<FIELD NAME="PSTI_CODE" TYPE="VARCHAR" WIDTH="15" LABEL="psti.code" />
<FIELD NAME="PSTI_DETAIL" TYPE="VARCHAR" WIDTH="250" LABEL="psti.detail" />
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-PROJECT-STTGYS-ITEMS">
<MASTER-DATA DATASET-ID="DS-PROJECT-STTGYS" MASTER-FIELDS="PROJ_ID,PSTG_CODE" DETAIL-FIELDS="PROJ_ID,PSTG_CODE"/>
<UNIQ-CHECK CHECK-FIELDS="PSTI_GROUP" MESSAGE="psti.group duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT-STTGYS-ITEMS" EDIT="Y" DELETE="Y" ADD="Y">
<FIELDS>
<FIELD NAME="$itemno" LABEL="no" ALIGN="right" WIDTH="5em"/>
<FIELD NAME="GROUP_DESC" LABEL="psti.group" WIDTH="10em" ALIGN="left" />
<FIELD NAME="ITEM_DESC" LABEL="psti.code" ALIGN="left" />
</FIELDS>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT-STTGYS-ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN" />
<FIELD NAME="PSTG_CODE" INPUTTYPE="HIDDEN" />
<FIELD NAME="GROUP_DESC" INPUTTYPE="HIDDEN" />
<FIELD NAME="ITEM_DESC" INPUTTYPE="HIDDEN" />
<FIELD NAME="PSTI_GROUP" CAPTION="psti.group" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-STTGY-GROUP-02" VALUE-FIELD="RFC_CODE" TEXT-FIELD="RFC_DESC" PARAMETERS="RFG_GRP=PSTI_GROUP" CHILD-FIELD="PSTI_CODE" ON-EMPTY="LOAD-ALL">
<UPDATE-FIELDS>
<FIELD TARGET="GROUP_DESC" SRC="RFC_DESC"/>
</UPDATE-FIELDS>
</AJAX-OPTION>
</FIELD>
<FIELD NAME="PSTI_CODE" CAPTION="psti.code" INPUTTYPE="COMBOBOX" REQUIRE="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-STTGY-ITEMS-02" VALUE-FIELD="RFC_CODE" TEXT-FIELD="RFC_DESC" PARAMETERS="RFG_GRP=PSTI_GROUP">
<UPDATE-FIELDS>
<FIELD TARGET="ITEM_DESC" SRC="RFC_DESC"/>
</UPDATE-FIELDS>
</AJAX-OPTION>
</FIELD>
<FIELD NAME="PSTI_DETAIL" CAPTION="psti.detail" INPUTTYPE="TEXTAREA" ROWS="3" />
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="PSTI_GROUP" LAYOUT_WIDTH="6"/>
<FIELD NAME="PSTI_CODE" LAYOUT_WIDTH="18" />
</ROW>
<ROW>
<FIELD NAME="PSTI_DETAIL" LAYOUT_WIDTH="18" OFFSET="6" />
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 200px"></div>]]>
</ROW>
</LAYOUT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT-STTGYS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_STTGYS</TABLENAME>
<KEYFIELDS>PROJ_ID,PSTG_CODE</KEYFIELDS>
<SQL>
<SELECT>
SELECT STTG.PROJ_ID
, STTG.PSTG_CODE
, RFC.RFC_DESC PSTG_DESC
, STTG.PSTG_CONCEPT
</SELECT>
<FROM>FROM PROJECT_STTGYS STTG
INNER JOIN BGT.REFER_CODE RFC ON RFC.RFG_GRP='STG-MAIN' AND RFC.RFC_CODE=STTG.PSTG_CODE
</FROM>
<ORDER>ORDER BY PSTG_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="VARCHAR" WIDTH="50" LABEL="project.id" />
<FIELD NAME="PSTG_CODE" TYPE="VARCHAR" WIDTH="20" LABEL="pstg.code" />
<FIELD NAME="PSTG_CONCEPT" TYPE="VARCHAR" WIDTH="500" LABEL="pstg.concept" />
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-PROJECT-STTGYS">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID" DETAIL-FIELDS="PROJ_ID"/>
<UNIQ-CHECK CHECK-FIELDS="PSTG_CODE" MESSAGE="pstg.code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT-STTGYS" EDIT="Y" DELETE="Y" ADD="Y">
<FIELDS>
<FIELD NAME="$itemno" LABEL="no" ALIGN="right" WIDTH="5em"/>
<FIELD NAME="PSTG_CODE" LABEL="pstg.code" WIDTH="12em" ALIGN="center" />
<FIELD NAME="PSTG_DESC" LABEL="pstg.desc" ALIGN="left" />
</FIELDS>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT-STTGYS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN" />
<FIELD NAME="PSTG_CODE" CAPTION="pstg.desc" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<LIST-OPTION TABLE="BGT.REFER_CODE" TEXT="#RFC_DESC" VALUE="RFC_CODE" FILTER="RFG_GRP='STG-MAIN'" FIRSTLIST="@{CAPTION}"/>
</FIELD>
<FIELD NAME="PSTG_CONCEPT" CAPTION="pstg.concept" INPUTTYPE="TEXTAREA" ROWS="2" />
<FIELD NAME="GRID-STTGYS-ITEMS" INPUTTYPE="DATA-GRID" GRID-ID="GRID-PROJECT-STTGYS-ITEMS" CAPTION="psti.header"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="PSTG_CODE" LAYOUT_WIDTH="16" OFFSET="4" />
</ROW>
<SECTION>
<HEADER CLASS="form-section-header col-24 mg-b-n30 mg-t-16 border-top-1">
<![CDATA[<h4 class="ml-3 col-24">@M{pstg.header}</h4>]]>
</HEADER>
<ROW>
<FIELD NAME="GRID-STTGYS-ITEMS" LAYOUT_WIDTH="20" OFFSET="4"/>
</ROW>
</SECTION>
<ROW>
<FIELD NAME="PSTG_CONCEPT" LAYOUT_WIDTH="16" OFFSET="4" />
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 200px"></div>]]>
</ROW>
</LAYOUT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT_BUDGET_ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT PROJ_ID
, PBDG_ID
, BGM_CODE
, BUD.GET_BUDGET (BGM_CODE) BGM_NAME
, PBGI_QT_01
, PBGI_QT_02
, PBGI_QT_03
, PBGI_QT_04
, PBGI_QTY
, PBGI_COST
, PBGI_FREQ
, PBGI_ASSET_TYPE
, PBGI_REPLACE
, PBGI_ADDITION
, PBGI_ACQUIRE
, PBGI_TOTAL
, PBGI_REASON
</SELECT>
<FROM>FROM PROJECT_BUDGET_ITEMS</FROM>
<ORDER>ORDER BY PROJ_ID,BGM_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสหมวดงบประมาณ" WIDTH="20"/>
<FIELD NAME="PBGI_QT_01" TYPE="NUMBER" LABEL="จำนวนไตรมาส 1" WIDTH="15"/>
<FIELD NAME="PBGI_QT_02" TYPE="NUMBER" LABEL="จำนวนไตรมาส 2" WIDTH="15"/>
<FIELD NAME="PBGI_QT_03" TYPE="NUMBER" LABEL="จำนวนไตรมาส 3" WIDTH="15"/>
<FIELD NAME="PBGI_QT_04" TYPE="NUMBER" LABEL="จำนวนไตรมาส 4" WIDTH="15"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="จำนวน" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="ราคาต่อหน่วย" WIDTH="15"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="ความถี่/จำนวนครั้ง" WIDTH="10"/>
<FIELD NAME="PBGI_ASSET_TYPE" TYPE="TEXT" LABEL="ประเภทสินทรัพย์" WIDTH="10"/>
<FIELD NAME="PBGI_REPLACE" TYPE="NUMBER" LABEL="ทดแทนของเดิม" WIDTH="10"/>
<FIELD NAME="PBGI_ADDITION" TYPE="NUMBER" LABEL="เพิ่มเติม" WIDTH="10"/>
<FIELD NAME="PBGI_ACQUIRE" TYPE="NUMBER" LABEL="จัดหาใหม่" WIDTH="10"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="รวมเป็นเงิน" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="เหตุผลความจำเป็น" WIDTH="4000"/>
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-WORK-BUDGET">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,PBDG_ID" DETAIL-FIELDS="PROJ_ID,PBDG_ID"/>
<UNIQ-CHECK CHECK-FIELDS="BGM_CODE" MESSAGE="pwbg.bgm_code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT_BUDGET_ITEMS" EDIT="Y" DELETE="Y" CLASS="table-primary">
<KEYFIELDS>PROJ_ID,BGM_CODE</KEYFIELDS>
<TITLES>
<ROW>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="10em" ALIGN="center" ROWS-SPAN="2"/>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_QUOTERS" LABEL="pwbg.quoter" ALIGN="center" COLS-SPAN="4"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pwbg.total" WIDTH="6em" ALIGN="right" ROWS-SPAN="2"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_QT_01" LABEL="1" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_02" LABEL="2" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_03" LABEL="3" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_04" LABEL="4" WIDTH="6em" ALIGN="right"/>
</ROW>
</TITLES>
<FIELDS>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="15em" ALIGN="center"/>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left"/>
<FIELD NAME="PBGI_QT_01" LABEL="pwbg.quotr_01" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_02" LABEL="pwbg.quotr_02" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_03" LABEL="pwbg.quotr_03" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_04" LABEL="pwbg.quotr_04" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pwbg.total" WIDTH="10em" ALIGN="right"/>
</FIELDS>
<FOOTER SHOW="Y"/>
<SCRIPT>
<INITIALIZE>
<![CDATA[
(ctx)=> {
ctx.sumOf = {};
console.log("init grid-budget");
const fieldFormat = (value) => {
return formatNumber(value, 0);
}
const summary = (field, data) => {
let total = 0;
for (const row of data) {
total += (+row[field])||0;
}
ctx.sumOf[field] = total;
return formatNumber(total,0);
}
const quoterFields = $$("field^pbgi_qt_",ctx.gridColumn.flat());
for (let field of quoterFields) {
field.formatter = fieldFormat;
let fieldName = field.field;
field.footerFormatter = (data)=>{
return summary(fieldName,data);
}
}
let fieldName = "pbgi_total";
$$("field=pbgi_total",ctx.gridColumn.flat()).formatter = fieldFormat;
$$("field=pbgi_total",ctx.gridColumn.flat()).footerFormatter = (data)=>{
return summary(fieldName,data);
};
}
]]>
</INITIALIZE>
</SCRIPT>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT_BUDGET_ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BGM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-BUDGET-01" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div><label>[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_QT_01" CAPTION="pwbg.quotr_01" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_QT_02" CAPTION="pwbg.quotr_02" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_QT_03" CAPTION="pwbg.quotr_03" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_QT_04" CAPTION="pwbg.quotr_04" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="pwbg.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" READONLY="Y"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="16"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_QT_01" LAYOUT_WIDTH="3" OFFSET="6"/>
<FIELD NAME="PBGI_QT_02" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_QT_03" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_QT_04" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 350px"></div>]]>
</ROW>
</LAYOUT>
<SCRIPT>
<INITIALIZE><![CDATA[
const quoterTotal = ()=>{
$$("PBGI_TOTAL").setValue($$("^PBGI_QT_").sum());
}
$$("^PBGI_QT_").on("change",quoterTotal);
]]></INITIALIZE>
</SCRIPT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-PROJECT_BUDGET_ITEMS">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROJECT_BUDGET_ITEMS</TABLENAME>
<KEYFIELDS>PROJ_ID,BGM_CODE,PBDG_ID</KEYFIELDS>
<SQL>
<SELECT>SELECT PROJ_ID
, PBDG_ID
, BGM_CODE
, BUD.GET_BUDGET (BGM_CODE) BGM_NAME
, PBGI_QT_01
, PBGI_QT_02
, PBGI_QT_03
, PBGI_QT_04
, PBGI_QTY
, PBGI_COST
, PBGI_FREQ
, PBGI_ASSET_TYPE
, PBGI_REPLACE
, PBGI_ADDITION
, PBGI_ACQUIRE
, PBGI_TOTAL
, PBGI_REASON
</SELECT>
<FROM>FROM PROJECT_BUDGET_ITEMS</FROM>
<ORDER>ORDER BY PROJ_ID,BGM_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสอ้างอิงโครงการ" WIDTH="32"/>
<FIELD NAME="PBDG_ID" TYPE="TEXT" LABEL="รหัสงบประมาณโครงการ" WIDTH="32"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสหมวดงบประมาณ" WIDTH="20"/>
<FIELD NAME="PBGI_QT_01" TYPE="NUMBER" LABEL="จำนวนไตรมาส 1" WIDTH="15"/>
<FIELD NAME="PBGI_QT_02" TYPE="NUMBER" LABEL="จำนวนไตรมาส 2" WIDTH="15"/>
<FIELD NAME="PBGI_QT_03" TYPE="NUMBER" LABEL="จำนวนไตรมาส 3" WIDTH="15"/>
<FIELD NAME="PBGI_QT_04" TYPE="NUMBER" LABEL="จำนวนไตรมาส 4" WIDTH="15"/>
<FIELD NAME="PBGI_QTY" TYPE="NUMBER" LABEL="จำนวน" WIDTH="10"/>
<FIELD NAME="PBGI_COST" TYPE="NUMBER" LABEL="ราคาต่อหน่วย" WIDTH="15"/>
<FIELD NAME="PBGI_FREQ" TYPE="NUMBER" LABEL="ความถี่/จำนวนครั้ง" WIDTH="10"/>
<FIELD NAME="PBGI_ASSET_TYPE" TYPE="TEXT" LABEL="ประเภทสินทรัพย์" WIDTH="10"/>
<FIELD NAME="PBGI_REPLACE" TYPE="NUMBER" LABEL="ทดแทนของเดิม" WIDTH="10"/>
<FIELD NAME="PBGI_ADDITION" TYPE="NUMBER" LABEL="เพิ่มเติม" WIDTH="10"/>
<FIELD NAME="PBGI_ACQUIRE" TYPE="NUMBER" LABEL="จัดหาใหม่" WIDTH="10"/>
<FIELD NAME="PBGI_TOTAL" TYPE="NUMBER" LABEL="รวมเป็นเงิน" WIDTH="15"/>
<FIELD NAME="PBGI_REASON" TYPE="TEXT" LABEL="เหตุผลความจำเป็น" WIDTH="4000"/>
</FIELDS>
</DATASET>
</DATASETS>
<DATA-GRIDS>
<DATA-GRID ID="GRID-WORK-BUDGET">
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,PBDG_ID" DETAIL-FIELDS="PROJ_ID,PBDG_ID"/>
<UNIQ-CHECK CHECK-FIELDS="BGM_CODE" MESSAGE="pwbg.bgm_code duplicate !"></UNIQ-CHECK>
<GRID-LIST DATAID="DS-PROJECT_BUDGET_ITEMS" ADD="Y" EDIT="Y" DELETE="Y" CLASS="table-primary">
<KEYFIELDS>PROJ_ID,BGM_CODE</KEYFIELDS>
<TITLES>
<ROW>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="10em" ALIGN="center" ROWS-SPAN="2"/>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left" ROWS-SPAN="2"/>
<FIELD NAME="BGM_QUOTERS" LABEL="pwbg.quoter" ALIGN="center" COLS-SPAN="4"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pwbg.total" WIDTH="6em" ALIGN="right" ROWS-SPAN="2"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_QT_01" LABEL="1" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_02" LABEL="2" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_03" LABEL="3" WIDTH="6em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_04" LABEL="4" WIDTH="6em" ALIGN="right"/>
</ROW>
</TITLES>
<FIELDS>
<FIELD NAME="BGM_CODE" LABEL="pwbg.bgm_code" WIDTH="15em" ALIGN="center"/>
<FIELD NAME="BGM_NAME" LABEL="pwbg.bgm_name" ALIGN="left"/>
<FIELD NAME="PBGI_QT_01" LABEL="pwbg.quotr_01" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_02" LABEL="pwbg.quotr_02" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_03" LABEL="pwbg.quotr_03" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_QT_04" LABEL="pwbg.quotr_04" WIDTH="5em" ALIGN="right"/>
<FIELD NAME="PBGI_TOTAL" LABEL="pwbg.total" WIDTH="10em" ALIGN="right"/>
</FIELDS>
<FOOTER SHOW="Y"/>
<SCRIPT>
<INITIALIZE>
<![CDATA[
(ctx)=> {
ctx.sumOf = {};
console.log("init grid-budget");
const fieldFormat = (value) => {
return formatNumber(value, 0);
}
const summary = (field, data) => {
let total = 0;
for (const row of data) {
total += (+row[field])||0;
}
ctx.sumOf[field] = total;
return formatNumber(total,0);
}
const quoterFields = $$("field^pbgi_qt_",ctx.gridColumn.flat());
for (let field of quoterFields) {
field.formatter = fieldFormat;
let fieldName = field.field;
field.footerFormatter = (data)=>{
return summary(fieldName,data);
}
}
let fieldName = "pbgi_total";
$$("field=pbgi_total",ctx.gridColumn.flat()).formatter = fieldFormat;
$$("field=pbgi_total",ctx.gridColumn.flat()).footerFormatter = (data)=>{
return summary(fieldName,data);
};
}
]]>
</INITIALIZE>
</SCRIPT>
</GRID-LIST>
<GRID-EDITOR DATAID="DS-PROJECT_BUDGET_ITEMS">
<FIELDS>
<FIELD NAME="PROJ_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="PBDG_ID" INPUTTYPE="HIDDEN"/>
<FIELD NAME="BGM_NAME" INPUTTYPE="HIDDEN"/>
<FIELD NAME="VBGM_CODE" CAPTION="pwbg.bgm_code" INPUTTYPE="TEXT" READONLY="Y"/>
<FIELD NAME="BGM_CODE" CAPTION="pwbg.bgm_name" INPUTTYPE="COMBOBOX" REQUIRE="Y" EDIT-READONLY="Y">
<AJAX-OPTION URL="/api-data.jbx" DATASET="DS-BUDGET-01" VALUE-FIELD="BGM_CODE" TEXT-FIELD="BGM_NAME">
<UPDATE-FIELDS>
<FIELD SRC="BGM_CODE" TARGET="VBGM_CODE"></FIELD>
<FIELD SRC="BGM_NAME" TARGET="BGM_NAME"></FIELD>
</UPDATE-FIELDS>
</AJAX-OPTION>
<LIST-OPTION>
<FORMATTER><![CDATA[
(data) => {
console.log("call formater with ", data);
return $(`<div><label>[${data.bgm_code}]</label> : <label>${data.bgm_name}</label></div>`);
}
]]></FORMATTER>
</LIST-OPTION>
</FIELD>
<FIELD NAME="PBGI_QT_01" CAPTION="pwbg.quotr_01" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_QT_02" CAPTION="pwbg.quotr_02" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_QT_03" CAPTION="pwbg.quotr_03" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_QT_04" CAPTION="pwbg.quotr_04" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0"/>
<FIELD NAME="PBGI_TOTAL" CAPTION="pwbg.total" INPUTTYPE="TEXT" DATATYPE="NUMBER" DECIMAL="0" READONLY="Y"/>
</FIELDS>
<LAYOUT CLASS="block-layout-form">
<ROW>
<FIELD NAME="VBGM_CODE" LAYOUT_WIDTH="6"/>
<FIELD NAME="BGM_CODE" LAYOUT_WIDTH="16"/>
</ROW>
<ROW>
<FIELD NAME="PBGI_QT_01" LAYOUT_WIDTH="3" OFFSET="6"/>
<FIELD NAME="PBGI_QT_02" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_QT_03" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_QT_04" LAYOUT_WIDTH="3"/>
<FIELD NAME="PBGI_TOTAL" LAYOUT_WIDTH="3"/>
</ROW>
<ROW TYPE="CONTENT">
<![CDATA[<div style="height: 350px"></div>]]>
</ROW>
</LAYOUT>
<SCRIPT>
<INITIALIZE><![CDATA[
const quoterTotal = ()=>{
$$("PBGI_TOTAL").setValue($$("^PBGI_QT_").sum());
}
$$("^PBGI_QT_").on("change",quoterTotal);
]]></INITIALIZE>
</SCRIPT>
</GRID-EDITOR>
</DATA-GRID>
</DATA-GRIDS>
</FORMS>

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<FORMS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dynf/dynf-form-def.xsd">
<DATASETS>
<DATASET ID="DS-APPROVE-FILES">
<SCHEMA>APP</SCHEMA>
<TABLENAME>ATTACH_FILES</TABLENAME>
<KEYFIELDS>ATFI_SEQ</KEYFIELDS>
<SQL>
<SELECT>SELECT ATFI_SEQ
, PROJ_ID
, ACM_CODE
, ATFI_TYPE
, ATFI_FILE
, ATFI_MIME
, ATFI_DESC
</SELECT>
<FROM>FROM ATTACH_FILES</FROM>
<ORDER>ORDER BY PROJ_ID,ATFI_SEQ,ACM_CODE</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="ATFI_SEQ" TYPE="AUTO" LABEL="ลำดับไฟล์แนบ" WIDTH="15"/>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสโครงการ" WIDTH="50"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="25"/>
<FIELD NAME="ATFI_TYPE" TYPE="TEXT" LABEL="ประเภทไฟล์แนบ" WIDTH="25"/>
<FIELD NAME="ATFI_FILE" TYPE="TEXT" LABEL="ชื่อไฟล์แนบ" WIDTH="250"/>
<FIELD NAME="ATFI_MIME" TYPE="TEXT" LABEL="ชนิดของไฟล์แนบ (MIME Type)" WIDTH="100"/>
<FIELD NAME="ATFI_DESC" TYPE="TEXT" LABEL="คำอธิบาย/รายละเอียดไฟล์แนบ" WIDTH="250"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROJ_ID,ACM_CODE,APPROVE_TYPE" DETAIL-FIELDS="PROJ_ID,ACM_CODE,ATFI_TYPE"/>
</DATASET>
<DATASET ID="DS-ACM-COMMENT">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROPOSALS_COMMENTS</TABLENAME>
<KEYFIELDS>PPSC_SEQ</KEYFIELDS>
<SQL>
<SELECT>SELECT PROP_ID
, PROP_VERSION
, PROJ_ID
, ACM_CODE
, BGM_CODE
, PPSC_LEVEL
, PPSC_SEQ
, PPSC_COMMENT
, PPSC_COMMENT_BY
, PPSC_COMMENT_TIME
</SELECT>
<FROM>FROM PROPOSALS_COMMENTS</FROM>
</SQL>
<FIELDS>
<FIELD NAME="PROP_ID" TYPE="TEXT" LABEL="รหัสคำขอ" WIDTH="50"/>
<FIELD NAME="PROP_VERSION" TYPE="NUMBER" LABEL="เวอร์ชั่นคำขอ" WIDTH="10"/>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสโครงการ" WIDTH="50"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="50"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสรายการงบประมาณ" WIDTH="50"/>
<FIELD NAME="PPSC_LEVEL" TYPE="TEXT" LABEL="ระดับของความเห็น (PROJECT, GROUP, ITEM)" WIDTH="10" DEFAULT="GROUP"/>
<FIELD NAME="PPSC_SEQ" TYPE="NUMBER" LABEL="ลำดับความเห็น" WIDTH="10"/>
<FIELD NAME="PPSC_COMMENT" TYPE="TEXT" LABEL="เนื้อหาความเห็น" WIDTH="2000"/>
<FIELD NAME="PPSC_COMMENT_BY" TYPE="TEXT" LABEL="ผู้ให้ความเห็น" WIDTH="50" DEFAULT="${$UserCode}"/>
<FIELD NAME="PPSC_COMMENT_TIME" TYPE="DATE" LABEL="เวลาที่ให้ความเห็น" WIDTH="19"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROP_ID,PROJ_ID,ACM_CODE,PROP_VERSION" DETAIL-FIELDS="PROP_ID,PROJ_ID,ACM_CODE,PROP_VERSION"/>
</DATASET>
<DATASET ID="DS-ACM-HIST-COMMENT">
<SCHEMA>APP</SCHEMA>
<TABLENAME>PROPOSALS_COMMENTS</TABLENAME>
<KEYFIELDS>PROJ_ID,PROP_ID,PPSC_SEQ</KEYFIELDS>
<SQL>
<SELECT>SELECT PROP_ID
, PROP_VERSION
, PROJ_ID
, ACM_CODE
, BGM_CODE
, PPSC_LEVEL
, PPSC_SEQ
, PPSC_COMMENT
, PPSC_COMMENT_BY
, PPSC_COMMENT_TIME
</SELECT>
<FROM>FROM PROPOSALS_COMMENTS</FROM>
<FILTER><![CDATA[WHERE PROP_VERSION <= :PROP_VERSION]]></FILTER>
<ORDER>ORDER BY PROJ_ID,PROP_ID,PPSC_SEQ</ORDER>
</SQL>
<FIELDS>
<FIELD NAME="PROP_ID" TYPE="TEXT" LABEL="รหัสคำขอ" WIDTH="50"/>
<FIELD NAME="PROP_VERSION" TYPE="NUMBER" LABEL="เวอร์ชั่นคำขอ" WIDTH="10"/>
<FIELD NAME="PROJ_ID" TYPE="TEXT" LABEL="รหัสโครงการ" WIDTH="50"/>
<FIELD NAME="ACM_CODE" TYPE="TEXT" LABEL="รหัสกิจกรรม" WIDTH="50"/>
<FIELD NAME="BGM_CODE" TYPE="TEXT" LABEL="รหัสรายการงบประมาณ" WIDTH="50"/>
<FIELD NAME="PPSC_LEVEL" TYPE="TEXT" LABEL="ระดับของความเห็น (PROJECT, GROUP, ITEM)" WIDTH="10"/>
<FIELD NAME="PPSC_SEQ" TYPE="NUMBER" LABEL="ลำดับความเห็น" WIDTH="10"/>
<FIELD NAME="PPSC_COMMENT" TYPE="TEXT" LABEL="เนื้อหาความเห็น" WIDTH="4000"/>
<FIELD NAME="PPSC_COMMENT_BY" TYPE="TEXT" LABEL="ผู้ให้ความเห็น" WIDTH="50"/>
<FIELD NAME="PPSC_COMMENT_TIME" TYPE="DATE" LABEL="เวลาที่ให้ความเห็น" WIDTH="19"/>
</FIELDS>
<MASTER-DATA DATASET-ID="DS-MASTER" MASTER-FIELDS="PROP_ID,PROJ_ID,ACM_CODE" DETAIL-FIELDS="PROP_ID,PROJ_ID,ACM_CODE"/>
</DATASET>
</DATASETS>
<FORM>
<FORM_ENTRY>
<FIELDS>
<SECTION ID="SECT-APPROVE-DATA">
<FIELD NAME="APPROVE_FILES" CAPTION="file.upload" INPUTTYPE="FILE-LIST-BOX">
<FILE-LIST-BOX DATASET="DS-APPROVE-FILES" FILE-TYPE="ATFI_TYPE" FILE-PATH="ATFI_FILE" FILE-DESC="ATFI_DESC" FILE-MIME="ATFI_MIME"/>
<FILE-BOX FILE-TYPE="budget-apvs" FILE-ACCEPTS="pdf,docx,xlsx,jpeg,jpg,png"
UPLOAD-URL="/file-upload.jbx" FILE-URL="/get-file.jbx"
DEFAULT-NAME="@{stm_code}/@{proj_year}/@{-uuid-}"/>
</FIELD>
<FIELD NAME="PPSC_COMMENT" INPUTTYPE="TEXTAREA" CAPTION="revise.caption" ROWS="1"/>
<FIELD NAME="COMMENT-HISTORY" CAPTION="revise.history" INPUTTYPE="HISTORY-BOX">
<HISTORY-BOX DATASET="DS-ACM-HIST-COMMENT" DATE-FIELD="PPSC_COMMENT_TIME" USER-FIELD="PPSC_COMMENT_BY"
HIST-FIELD="PPSC_COMMENT"/>
</FIELD>
</SECTION>
</FIELDS>
</FORM_ENTRY>
</FORM>
</FORMS>

View File

@@ -4,7 +4,7 @@ plugins {
id("org.jetbrains.intellij.platform") version "2.7.0" id("org.jetbrains.intellij.platform") version "2.7.0"
} }
group = "com.sdk.dynform.tools" group = "com.sdk.dynform.tools"
version = "3.2.9" version = "3.3.0"
repositories { repositories {
mavenCentral() mavenCentral()
@@ -38,6 +38,12 @@ intellijPlatform {
} }
changeNotes = """ changeNotes = """
<h2>[3.3.0]</h2>
<ul>
<li><strong>Cross-file Support:</strong> Implemented comprehensive cross-file completion, reference (Go to Definition), and validation for fields and sections across included <code>.frml</code> files.</li>
<li><strong>Performance Optimization:</strong> Optimized resource discovery logic by leveraging IntelliJ's indexing (ReferencesSearch), resolving IDE freeze issues in large projects.</li>
<li><strong>Refined Validation:</strong> Excluded <code>&lt;ROW&gt;</code> tags from field definition requirements, as they are structural elements.</li>
</ul>
<h2>[3.2.9]</h2> <h2>[3.2.9]</h2>
<ul> <ul>
<li><strong>Extended I18n Support:</strong> Added Inlay Hints, Autocomplete, and Reference support for the <code>MESSAGE</code> attribute in <code>&lt;UNIQ-CHECK&gt;</code> and other tags.</li> <li><strong>Extended I18n Support:</strong> Added Inlay Hints, Autocomplete, and Reference support for the <code>MESSAGE</code> attribute in <code>&lt;UNIQ-CHECK&gt;</code> and other tags.</li>

View File

@@ -9,71 +9,47 @@ import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.intellij.psi.PsiFile;
import java.util.HashSet;
public class DynFormAnnotator implements Annotator { public class DynFormAnnotator implements Annotator {
@Override @Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if (!(element instanceof XmlAttributeValue attrValue)) return; if (!(element instanceof XmlAttributeValue attrValue)) return;
PsiElement parent = attrValue.getParent(); PsiElement parent = attrValue.getParent();
if (!(parent instanceof XmlAttribute attr)) return; if (!(parent instanceof XmlAttribute attr)) return;
if (!"NAME".equals(attr.getName())) return;
PsiElement tagElem = attr.getParent();
if (!(tagElem instanceof XmlTag tag) || !"FIELD".equals(tag.getName())) return;
// Check if this FIELD is inside a LAYOUT tag String attrName = attr.getName();
PsiElement tagElem = attr.getParent();
if (!(tagElem instanceof XmlTag tag)) return;
String tagName = tag.getName();
boolean isField = "FIELD".equals(tagName) && "NAME".equals(attrName);
boolean isContainer = ("SECTION".equals(tagName) || "SECTIONS".equals(tagName)) && "ID".equals(attrName);
if (!isField && !isContainer) return;
// Check if this tag is inside a LAYOUT tag
XmlTag layoutTag = tag.getParentTag(); XmlTag layoutTag = tag.getParentTag();
while (layoutTag != null && !"LAYOUT".equals(layoutTag.getName())) { while (layoutTag != null && !"LAYOUT".equals(layoutTag.getName())) {
layoutTag = layoutTag.getParentTag(); layoutTag = layoutTag.getParentTag();
} }
if (layoutTag == null) return; if (layoutTag == null) return;
// The "Owner" of the LAYOUT (e.g., FORM_ENTRY, FILTERS, GRID-EDITOR) // The "Owner" of the LAYOUT (e.g., FORM_ENTRY, FILTERS, GRID-EDITOR, FORM_BROWSE, GRID-LIST)
XmlTag ownerTag = layoutTag.getParentTag(); XmlTag ownerTag = layoutTag.getParentTag();
if (ownerTag == null) return; if (ownerTag == null) return;
String fieldName = attrValue.getValue(); String fieldName = attrValue.getValue();
if (fieldName == null || fieldName.isEmpty()) return; if (fieldName == null || fieldName.isEmpty()) return;
// Look for the FIELDS tag that is a sibling of the current LAYOUT PsiFile currentFile = tag.getContainingFile();
XmlTag fieldsTag = ownerTag.findFirstSubTag("FIELDS"); if (DynFormPathUtils.findFieldInFormContext(currentFile, ownerTag.getName(), fieldName, new HashSet<>()) == null) {
if (fieldsTag == null) { holder.newAnnotation(HighlightSeverity.ERROR, (isField ? "Field '" : "Section/Row '") + fieldName + "' is not defined in <FIELDS> of <" + ownerTag.getName() + ">")
holder.newAnnotation(HighlightSeverity.ERROR, "No <FIELDS> definition found in <" + ownerTag.getName() + ">")
.range(attrValue.getTextRange())
.create();
return;
}
if (!isFieldDefined(fieldsTag, fieldName)) {
holder.newAnnotation(HighlightSeverity.ERROR, "Field '" + fieldName + "' is not defined in <FIELDS> of <" + ownerTag.getName() + ">")
.range(attrValue.getTextRange()) .range(attrValue.getTextRange())
.create(); .create();
} }
} }
private boolean isFieldDefined(XmlTag fieldsTag, String name) {
for (XmlTag field : fieldsTag.findSubTags("FIELD")) {
if (name.equals(field.getAttributeValue("NAME"))) {
return true;
}
}
// Also check inside SECTIONS or ROWS if any
for (XmlTag sub : fieldsTag.getSubTags()) {
if ("SECTION".equals(sub.getName()) || "ROW".equals(sub.getName())) {
if (isFieldDefined(sub, name)) return true;
}
}
return false;
}
private static boolean hasAncestorWithName(XmlTag tag, String name) {
XmlTag current = tag.getParentTag();
while (current != null) {
if (name.equals(current.getName())) return true;
current = current.getParentTag();
}
return false;
}
} }

View File

@@ -85,10 +85,34 @@ public class DynFormCompletionContributor extends CompletionContributor {
} }
if (formContainer != null) { if (formContainer != null) {
addFieldsInTagRecursive(formContainer, resultSet); DynFormPathUtils.addFieldsInTagRecursive(formContainer, resultSet);
}
// เพิ่มเติม: เสนอฟิลด์จากไฟล์ที่ include ไฟล์นี้ (Includers)
List<PsiFile> includers = DynFormPathUtils.findIncluders(parameters.getOriginalFile());
for (PsiFile includer : includers) {
if (includer instanceof XmlFile xmlFile) {
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag != null) {
for (XmlTag formTag : rootTag.findSubTags("FORM")) {
for (XmlTag entryTag : formTag.findSubTags("FORM_ENTRY")) {
XmlTag fieldsTag = entryTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
}
}
for (XmlTag browseTag : formTag.findSubTags("FORM_BROWSE")) {
XmlTag fieldsTag = browseTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
}
}
}
}
}
} }
} else { } else {
// เสนอฟิลด์ภายใต้ LAYOUT container เดียวกัน // เสนอฟิลด์ภายใต้ LAYOUT container เดียวกัน (ข้ามไฟล์ได้)
XmlTag layoutTag = PsiTreeUtil.getParentOfType(position, XmlTag.class); XmlTag layoutTag = PsiTreeUtil.getParentOfType(position, XmlTag.class);
while (layoutTag != null && !"LAYOUT".equals(layoutTag.getName())) { while (layoutTag != null && !"LAYOUT".equals(layoutTag.getName())) {
layoutTag = layoutTag.getParentTag(); layoutTag = layoutTag.getParentTag();
@@ -96,10 +120,8 @@ public class DynFormCompletionContributor extends CompletionContributor {
if (layoutTag == null) return; if (layoutTag == null) return;
XmlTag containerTag = layoutTag.getParentTag(); XmlTag containerTag = layoutTag.getParentTag();
if (containerTag == null) return; if (containerTag == null) return;
XmlTag fieldsTag = containerTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { DynFormPathUtils.addFieldsInFormContext(parameters.getOriginalFile(), containerTag.getName(), resultSet, new HashSet<>());
addFieldsInTagRecursive(fieldsTag, resultSet);
}
} }
} }
}); });
@@ -120,10 +142,10 @@ public class DynFormCompletionContributor extends CompletionContributor {
if (isAjaxOption) { if (isAjaxOption) {
PsiFile ajaxFile = DynFormPathUtils.findAjaxXml(parameters.getOriginalFile()); PsiFile ajaxFile = DynFormPathUtils.findAjaxXml(parameters.getOriginalFile());
if (ajaxFile != null) { if (ajaxFile != null) {
addDatasetsInFile(ajaxFile, resultSet); DynFormPathUtils.addDatasetsInFile(ajaxFile, resultSet);
} }
} else { } else {
addDatasetsInFileRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>(), false); DynFormPathUtils.addDatasetsInFileRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>(), false);
} }
} }
}); });
@@ -164,7 +186,7 @@ public class DynFormCompletionContributor extends CompletionContributor {
if (parentDataset != null && "DATASET".equals(parentDataset.getName())) { if (parentDataset != null && "DATASET".equals(parentDataset.getName())) {
XmlTag fieldsTag = parentDataset.findFirstSubTag("FIELDS"); XmlTag fieldsTag = parentDataset.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
addFieldsInTagRecursive(fieldsTag, resultSet); DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
} }
} }
} }
@@ -205,7 +227,7 @@ public class DynFormCompletionContributor extends CompletionContributor {
if (datasetId.equals(datasetTag.getAttributeValue("ID"))) { if (datasetId.equals(datasetTag.getAttributeValue("ID"))) {
XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
addFieldsInTagRecursive(fieldsTag, resultSet); DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
} }
} }
} }
@@ -223,7 +245,7 @@ public class DynFormCompletionContributor extends CompletionContributor {
protected void addCompletions(@NotNull CompletionParameters parameters, protected void addCompletions(@NotNull CompletionParameters parameters,
@NotNull ProcessingContext context, @NotNull ProcessingContext context,
@NotNull CompletionResultSet resultSet) { @NotNull CompletionResultSet resultSet) {
addGridsInFileRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>()); DynFormPathUtils.addGridsInFileRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>());
} }
}); });
@@ -239,7 +261,7 @@ public class DynFormCompletionContributor extends CompletionContributor {
protected void addCompletions(@NotNull CompletionParameters parameters, protected void addCompletions(@NotNull CompletionParameters parameters,
@NotNull ProcessingContext context, @NotNull ProcessingContext context,
@NotNull CompletionResultSet resultSet) { @NotNull CompletionResultSet resultSet) {
addFormFieldsForNameRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>()); DynFormPathUtils.addFormFieldsForNameRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>());
} }
}); });
@@ -284,171 +306,16 @@ public class DynFormCompletionContributor extends CompletionContributor {
}); });
} }
private void addFieldsInTagRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
for (XmlTag subTag : container.getSubTags()) {
if ("FIELD".equals(subTag.getName())) {
String name = subTag.getAttributeValue("NAME");
if (name != null && !name.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(name)
.withIcon(com.intellij.icons.AllIcons.Nodes.Field)
.withTypeText(subTag.getAttributeValue("TYPE")));
}
} else {
if (("SECTION".equals(subTag.getName()) || "FIELDS".equals(subTag.getName())) && subTag.getAttributeValue("ID") != null) {
String id = subTag.getAttributeValue("ID");
resultSet.addElement(LookupElementBuilder.create(id)
.withIcon(com.intellij.icons.AllIcons.Nodes.Package)
.withItemTextForeground(java.awt.Color.BLUE));
}
addFieldsInTagRecursive(subTag, resultSet);
}
}
}
private void addDatasetsInFileRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set<PsiFile> visited, boolean includeAjax) {
if (file == null || !visited.add(file)) return;
if (includeAjax) {
// สำหรับ AJAX-OPTION ให้หาใน ajax.xml เท่านั้น
PsiFile ajaxFile = DynFormPathUtils.findAjaxXml(file);
if (ajaxFile != null) {
addDatasetsInFile(ajaxFile, resultSet);
}
return;
}
// 1. Add datasets from current file
addDatasetsInFile(file, resultSet);
// 2. Add datasets from files that INCLUDE this file (Parent/Main Files)
if (visited.size() == 1) {
List<PsiFile> includers = DynFormPathUtils.findIncluders(file);
for (PsiFile includer : includers) {
if (visited.add(includer)) {
addDatasetsInFile(includer, resultSet);
}
}
}
// 3. Add datasets from included files (Downward)
if (file instanceof XmlFile xmlFile) {
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag != null) {
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = DynFormPathUtils.findIncludedFile(file, path);
if (includedFile != null && !visited.contains(includedFile)) {
addDatasetsInFileRecursive(includedFile, resultSet, visited, includeAjax);
}
}
}
}
}
}
// 4. Add datasets from all .frml files in module (fallback)
if (visited.size() <= 2) {
for (PsiFile frmlFile : DynFormPathUtils.getAllFrmlFiles(file)) {
if (visited.add(frmlFile)) {
addDatasetsInFile(frmlFile, resultSet);
}
}
}
}
private void addDatasetsInFile(PsiFile file, @NotNull CompletionResultSet resultSet) {
if (!(file instanceof XmlFile xmlFile)) return;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return;
XmlTag datasetsContainer = rootTag.findFirstSubTag("DATASETS");
if (datasetsContainer == null) datasetsContainer = rootTag;
for (XmlTag datasetTag : datasetsContainer.findSubTags("DATASET")) {
String id = datasetTag.getAttributeValue("ID");
if (id != null && !id.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(id)
.withIcon(com.intellij.icons.AllIcons.Nodes.DataTables)
.withTypeText(datasetTag.getAttributeValue("TABLENAME")));
}
}
}
private void addGridsInFileRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return;
// 1. Add grids from current file
addGridsInFile(file, resultSet);
// 2. Add grids from files that INCLUDE this file (Parent/Main Files)
if (visited.size() == 1) {
List<PsiFile> includers = DynFormPathUtils.findIncluders(file);
for (PsiFile includer : includers) {
if (visited.add(includer)) {
addGridsInFile(includer, resultSet);
}
}
}
// 3. Add grids from included files (Downward)
if (file instanceof XmlFile xmlFile) {
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag != null) {
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = DynFormPathUtils.findIncludedFile(file, path);
if (includedFile != null && !visited.contains(includedFile)) {
addGridsInFileRecursive(includedFile, resultSet, visited);
}
}
}
}
}
}
// 4. Add grids from all .frml files in module (fallback)
if (visited.size() <= 2) {
for (PsiFile frmlFile : DynFormPathUtils.getAllFrmlFiles(file)) {
if (visited.add(frmlFile)) {
addGridsInFile(frmlFile, resultSet);
}
}
}
}
private void addGridsInFile(PsiFile file, @NotNull CompletionResultSet resultSet) {
if (!(file instanceof XmlFile xmlFile)) return;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return;
XmlTag dataGridsTag = rootTag.findFirstSubTag("DATA-GRIDS");
if (dataGridsTag != null) {
for (XmlTag gridTag : dataGridsTag.findSubTags("DATA-GRID")) {
String id = gridTag.getAttributeValue("ID");
if (id != null && !id.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(id)
.withIcon(com.intellij.icons.AllIcons.Nodes.DataTables));
}
}
}
}
private void addFieldsFromDatasetId(XmlTag tag, @NotNull CompletionResultSet resultSet) { private void addFieldsFromDatasetId(XmlTag tag, @NotNull CompletionResultSet resultSet) {
String datasetId = tag.getAttributeValue("DATASET-ID"); String datasetId = tag.getAttributeValue("DATASET-ID");
if (datasetId == null || datasetId.isEmpty()) return; if (datasetId == null || datasetId.isEmpty()) return;
PsiFile file = tag.getContainingFile(); PsiFile file = tag.getContainingFile();
PsiElement datasetElement = findDatasetElement(file, datasetId); PsiElement datasetElement = DynFormPathUtils.findDatasetElement(file, datasetId);
if (datasetElement instanceof XmlTag datasetTag) { if (datasetElement instanceof XmlTag datasetTag) {
XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
addFieldsInTagRecursive(fieldsTag, resultSet); DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
} }
} }
} }
@@ -469,11 +336,11 @@ public class DynFormCompletionContributor extends CompletionContributor {
// 2. Add fields from that DATASET // 2. Add fields from that DATASET
if (dataId != null && !dataId.isEmpty()) { if (dataId != null && !dataId.isEmpty()) {
PsiElement datasetElement = findDatasetElement(gridTag.getContainingFile(), dataId); PsiElement datasetElement = DynFormPathUtils.findDatasetElement(gridTag.getContainingFile(), dataId);
if (datasetElement instanceof XmlTag datasetTag) { if (datasetElement instanceof XmlTag datasetTag) {
XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
addFieldsInTagRecursive(fieldsTag, resultSet); DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
} }
} }
} }
@@ -482,98 +349,18 @@ public class DynFormCompletionContributor extends CompletionContributor {
if (listTag != null) { if (listTag != null) {
XmlTag fieldsTag = listTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = listTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
addFieldsInTagRecursive(fieldsTag, resultSet); DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
} }
} }
XmlTag editorTag = gridTag.findFirstSubTag("GRID-EDITOR"); XmlTag editorTag = gridTag.findFirstSubTag("GRID-EDITOR");
if (editorTag != null) { if (editorTag != null) {
XmlTag fieldsTag = editorTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = editorTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
addFieldsInTagRecursive(fieldsTag, resultSet); DynFormPathUtils.addFieldsInTagRecursive(fieldsTag, resultSet);
} }
} }
} }
private PsiElement findDatasetElement(PsiFile file, String id) {
Set<PsiFile> visited = new HashSet<>();
// 1. Local
PsiElement found = findDatasetInFile(file, id);
if (found != null) return found;
visited.add(file);
// 2. Includers
List<PsiFile> includers = DynFormPathUtils.findIncluders(file);
for (PsiFile includer : includers) {
found = findDatasetInFile(includer, id);
if (found != null) return found;
visited.add(includer);
}
// 3. Ajax
PsiFile ajaxXml = DynFormPathUtils.findAjaxXml(file);
if (ajaxXml != null && visited.add(ajaxXml)) {
found = findDatasetInFile(ajaxXml, id);
if (found != null) return found;
}
// 4. Recursive search
return findDatasetInFileRecursiveForCompletion(file, id, visited);
}
private PsiElement findDatasetInFile(PsiFile file, String id) {
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
XmlTag datasetsContainer = rootTag.findFirstSubTag("DATASETS");
if (datasetsContainer == null) datasetsContainer = rootTag;
for (XmlTag datasetTag : datasetsContainer.findSubTags("DATASET")) {
if (id.equals(datasetTag.getAttributeValue("ID"))) {
return datasetTag;
}
}
return null;
}
private PsiElement findDatasetInFileRecursiveForCompletion(PsiFile file, String id, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return null;
if (!(file instanceof XmlFile xmlFile)) return null;
// Try local (should already be checked by findDatasetElement but for recursion consistency)
PsiElement found = findDatasetInFile(xmlFile, id);
if (found != null) return found;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
// Downward search
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = DynFormPathUtils.findIncludedFile(file, path);
found = findDatasetInFileRecursiveForCompletion(includedFile, id, visited);
if (found != null) return found;
}
}
}
// Final fallback: Module-wide
if (visited.size() <= 2) {
for (PsiFile frmlFile : DynFormPathUtils.getAllFrmlFiles(file)) {
if (!visited.contains(frmlFile)) {
found = findDatasetInFile(frmlFile, id);
if (found != null) return found;
}
}
}
return null;
}
private static boolean hasAncestorWithName(XmlTag tag, String name) { private static boolean hasAncestorWithName(XmlTag tag, String name) {
XmlTag current = tag.getParentTag(); XmlTag current = tag.getParentTag();
while (current != null) { while (current != null) {
@@ -676,60 +463,4 @@ public class DynFormCompletionContributor extends CompletionContributor {
} }
} }
} }
private void addFormFieldsForNameRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return;
if (!(file instanceof XmlFile xmlFile)) return;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return;
// 1. Search in current file FORM_ENTRY tags
for (XmlTag formTag : rootTag.findSubTags("FORM")) {
for (XmlTag entryTag : formTag.findSubTags("FORM_ENTRY")) {
// Collect hidden fields from FIELDS
XmlTag fieldsTag = entryTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
for (XmlTag fieldTag : fieldsTag.findSubTags("FIELD")) {
if ("HIDDEN".equals(fieldTag.getAttributeValue("INPUTTYPE"))) {
String name = fieldTag.getAttributeValue("NAME");
if (name != null && !name.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(name)
.withIcon(com.intellij.icons.AllIcons.Nodes.Field)
.withTypeText("Hidden Field"));
}
}
}
}
// Collect any field/tag with NAME from LAYOUT
XmlTag layoutTag = entryTag.findFirstSubTag("LAYOUT");
if (layoutTag != null) {
addFieldsInLayoutRecursive(layoutTag, resultSet);
}
}
}
// 2. Search in included files
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = DynFormPathUtils.findIncludedFile(file, path);
addFormFieldsForNameRecursive(includedFile, resultSet, visited);
}
}
}
}
private void addFieldsInLayoutRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
for (XmlTag subTag : container.getSubTags()) {
String name = subTag.getAttributeValue("NAME");
if (name != null && !name.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(name)
.withIcon(com.intellij.icons.AllIcons.Nodes.Field)
.withTypeText("Layout: " + subTag.getName()));
}
addFieldsInLayoutRecursive(subTag, resultSet);
}
}
} }

View File

@@ -5,18 +5,203 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager; import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.icons.AllIcons;
import java.awt.Color;
public class DynFormPathUtils { public class DynFormPathUtils {
public static final String MODULE_BASE_PATH = "src/main/webapp/WEB-INF/app/module"; public static final String MODULE_BASE_PATH = "src/main/webapp/WEB-INF/app/module";
public static void addFieldsInTagRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
for (XmlTag subTag : container.getSubTags()) {
if ("FIELD".equals(subTag.getName())) {
String name = subTag.getAttributeValue("NAME");
if (name != null && !name.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(name)
.withIcon(AllIcons.Nodes.Field)
.withTypeText(subTag.getAttributeValue("TYPE")));
}
} else {
if (("SECTION".equals(subTag.getName()) || "FIELDS".equals(subTag.getName())) && subTag.getAttributeValue("ID") != null) {
String id = subTag.getAttributeValue("ID");
resultSet.addElement(LookupElementBuilder.create(id)
.withIcon(AllIcons.Nodes.Package)
.withItemTextForeground(Color.BLUE));
}
addFieldsInTagRecursive(subTag, resultSet);
}
}
}
public static void addFieldsInFormContext(PsiFile file, String containerName, @NotNull CompletionResultSet resultSet, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return;
if (!(file instanceof XmlFile xmlFile)) return;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return;
// 1. Search for (containerName) > FIELDS in this file
List<XmlTag> containers = new ArrayList<>();
collectContainers(rootTag, containerName, containers);
for (XmlTag container : containers) {
XmlTag fieldsTag = container.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
addFieldsInTagRecursive(fieldsTag, resultSet);
}
}
// 2. Search in INCLUDES (Downward)
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
addFieldsInFormContext(includedFile, containerName, resultSet, visited);
}
}
}
// 3. Search in Includers (Upward)
if (visited.size() == 1) {
List<PsiFile> includers = findIncluders(file);
for (PsiFile includer : includers) {
addFieldsInFormContext(includer, containerName, resultSet, visited);
}
}
}
@Nullable
public static PsiElement findFieldInTag(XmlTag container, String name) {
for (XmlTag subTag : container.getSubTags()) {
if ("FIELD".equals(subTag.getName()) && name.equals(subTag.getAttributeValue("NAME"))) {
XmlAttribute nameAttr = subTag.getAttribute("NAME");
return nameAttr != null ? nameAttr.getValueElement() : subTag;
}
if (("SECTION".equals(subTag.getName()) || "SECTIONS".equals(subTag.getName())) && name.equals(subTag.getAttributeValue("ID"))) {
XmlAttribute idAttr = subTag.getAttribute("ID");
return idAttr != null ? idAttr.getValueElement() : subTag;
}
PsiElement found = findFieldInTag(subTag, name);
if (found != null) return found;
}
return null;
}
public static void collectContainers(XmlTag parent, String containerName, List<XmlTag> results) {
if (containerName.equals(parent.getName())) {
results.add(parent);
} else {
for (XmlTag subTag : parent.getSubTags()) {
collectContainers(subTag, containerName, results);
}
}
}
@Nullable
public static PsiElement findFieldInFormContext(PsiFile file, String containerName, String fieldName, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return null;
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
// 1. Search in all containers matching containerName anywhere in the file
List<XmlTag> containers = new ArrayList<>();
collectContainers(rootTag, containerName, containers);
for (XmlTag container : containers) {
XmlTag fieldsTag = container.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
PsiElement found = findFieldInTag(fieldsTag, fieldName);
if (found != null) return found;
}
}
// 2. Search in INCLUDES (Downward)
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
PsiElement found = findFieldInFormContext(includedFile, containerName, fieldName, visited);
if (found != null) return found;
}
}
}
// 3. Search in Includers (Upward)
if (visited.size() == 1) {
List<PsiFile> includers = findIncluders(file);
for (PsiFile includer : includers) {
PsiElement found = findFieldInFormContext(includer, containerName, fieldName, visited);
if (found != null) return found;
}
}
return null;
}
@Nullable
public static PsiElement findUsageInFormContext(PsiFile file, String containerName, String fieldName, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return null;
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
// 1. Search in all containers matching containerName
List<XmlTag> containers = new ArrayList<>();
collectContainers(rootTag, containerName, containers);
for (XmlTag container : containers) {
XmlTag layoutTag = container.findFirstSubTag("LAYOUT");
if (layoutTag != null) {
PsiElement found = findFieldInTag(layoutTag, fieldName);
if (found != null) return found;
}
XmlTag titlesTag = container.findFirstSubTag("TITLES");
if (titlesTag != null) {
PsiElement found = findFieldInTag(titlesTag, fieldName);
if (found != null) return found;
}
}
// 2. Search in INCLUDES (Downward)
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
PsiElement found = findUsageInFormContext(includedFile, containerName, fieldName, visited);
if (found != null) return found;
}
}
}
// 3. Search in Includers (Upward)
if (visited.size() == 1) {
List<PsiFile> includers = findIncluders(file);
for (PsiFile includer : includers) {
PsiElement found = findUsageInFormContext(includer, containerName, fieldName, visited);
if (found != null) return found;
}
}
return null;
}
@Nullable @Nullable
public static VirtualFile getModuleBaseDir(@NotNull Project project) { public static VirtualFile getModuleBaseDir(@NotNull Project project) {
VirtualFile baseDir = project.getBaseDir(); VirtualFile baseDir = project.getBaseDir();
@@ -155,19 +340,6 @@ public class DynFormPathUtils {
return null; return null;
} }
@NotNull
public static List<PsiFile> getAllFrmlFiles(@NotNull PsiFile contextFile) {
List<PsiFile> files = new ArrayList<>();
VirtualFile moduleDir = findModuleDir(contextFile);
if (moduleDir != null) {
VirtualFile frmDir = moduleDir.findFileByRelativePath("view/frm");
if (frmDir != null) {
collectFrmlFilesRecursive(frmDir, contextFile.getProject(), files);
}
}
return files;
}
@NotNull @NotNull
public static List<PsiFile> findIncluders(@NotNull PsiFile includedFile) { public static List<PsiFile> findIncluders(@NotNull PsiFile includedFile) {
List<PsiFile> includers = new ArrayList<>(); List<PsiFile> includers = new ArrayList<>();
@@ -175,41 +347,380 @@ public class DynFormPathUtils {
VirtualFile includedVFile = includedFile.getVirtualFile(); VirtualFile includedVFile = includedFile.getVirtualFile();
if (includedVFile == null) return includers; if (includedVFile == null) return includers;
VirtualFile moduleDir = findModuleDir(includedFile); // Optimization: Use ReferencesSearch to find files that point to this file via <INCLUDE FILE="...">
if (moduleDir == null) return includers; // This leverages IntelliJ's indices and is MUCH faster than scanning all files manually.
com.intellij.psi.search.searches.ReferencesSearch.search(includedFile).forEach(ref -> {
PsiElement element = ref.getElement();
if (element != null) {
PsiFile file = element.getContainingFile();
if (file != null && !includers.contains(file)) {
includers.add(file);
}
}
});
List<PsiFile> allFiles = getAllFrmlFiles(includedFile); // Fallback: If for some reason index-based search yields nothing,
for (PsiFile file : allFiles) { // we might do a limited scan, but let's stick to indices for performance to avoid freezing.
if (file.equals(includedFile)) continue; return includers;
if (!(file instanceof XmlFile xmlFile)) continue; }
public static void addDatasetsInFileRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set<PsiFile> visited, boolean includeAjax) {
if (file == null || !visited.add(file)) return;
if (includeAjax) {
// สำหรับ AJAX-OPTION ให้หาใน ajax.xml เท่านั้น
PsiFile ajaxFile = findAjaxXml(file);
if (ajaxFile != null) {
addDatasetsInFile(ajaxFile, resultSet);
}
return;
}
// 1. Add datasets from current file
addDatasetsInFile(file, resultSet);
// 2. Add datasets from files that INCLUDE this file (Parent/Main Files)
if (visited.size() == 1) {
List<PsiFile> includers = findIncluders(file);
for (PsiFile includer : includers) {
if (visited.add(includer)) {
addDatasetsInFile(includer, resultSet);
}
}
}
// 3. Add datasets from included files (Downward)
if (file instanceof XmlFile xmlFile) {
XmlTag rootTag = xmlFile.getRootTag(); XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return includers; if (rootTag != null) {
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES"); if (includesTag != null) {
if (includesTag != null) { for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) { String path = includeTag.getAttributeValue("FILE");
String path = includeTag.getAttributeValue("FILE"); if (path != null) {
if (path != null) { PsiFile includedFile = findIncludedFile(file, path);
PsiFile resolved = findIncludedFile(file, path); if (includedFile != null && !visited.contains(includedFile)) {
if (resolved != null && resolved.getVirtualFile().equals(includedVFile)) { addDatasetsInFileRecursive(includedFile, resultSet, visited, includeAjax);
includers.add(file); }
} }
} }
} }
} }
} }
return includers;
} }
private static void collectFrmlFilesRecursive(VirtualFile dir, Project project, List<PsiFile> files) { public static void addDatasetsInFile(PsiFile file, @NotNull CompletionResultSet resultSet) {
for (VirtualFile child : dir.getChildren()) { if (!(file instanceof XmlFile xmlFile)) return;
if (child.isDirectory()) { XmlTag rootTag = xmlFile.getRootTag();
collectFrmlFilesRecursive(child, project, files); if (rootTag == null) return;
} else if (child.getName().endsWith(".frml")) {
PsiFile psiFile = PsiManager.getInstance(project).findFile(child); XmlTag datasetsContainer = rootTag.findFirstSubTag("DATASETS");
if (psiFile != null) files.add(psiFile); if (datasetsContainer == null) datasetsContainer = rootTag;
for (XmlTag datasetTag : datasetsContainer.findSubTags("DATASET")) {
String id = datasetTag.getAttributeValue("ID");
if (id != null && !id.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(id)
.withIcon(AllIcons.Nodes.DataTables)
.withTypeText(datasetTag.getAttributeValue("TABLENAME")));
} }
} }
} }
public static void addGridsInFileRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return;
// 1. Add grids from current file
addGridsInFile(file, resultSet);
// 2. Add grids from files that INCLUDE this file (Parent/Main Files)
if (visited.size() == 1) {
List<PsiFile> includers = findIncluders(file);
for (PsiFile includer : includers) {
if (visited.add(includer)) {
addGridsInFile(includer, resultSet);
}
}
}
// 3. Add grids from included files (Downward)
if (file instanceof XmlFile xmlFile) {
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag != null) {
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
if (includedFile != null && !visited.contains(includedFile)) {
addGridsInFileRecursive(includedFile, resultSet, visited);
}
}
}
}
}
}
}
public static void addGridsInFile(PsiFile file, @NotNull CompletionResultSet resultSet) {
if (!(file instanceof XmlFile xmlFile)) return;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return;
XmlTag dataGridsTag = rootTag.findFirstSubTag("DATA-GRIDS");
if (dataGridsTag != null) {
for (XmlTag gridTag : dataGridsTag.findSubTags("DATA-GRID")) {
String id = gridTag.getAttributeValue("ID");
if (id != null && !id.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(id)
.withIcon(AllIcons.Nodes.DataTables));
}
}
}
}
@Nullable
public static PsiElement findDatasetElement(PsiFile file, String id) {
Set<PsiFile> visited = new HashSet<>();
// 1. Local
PsiElement found = findDatasetInFile(file, id);
if (found != null) return found;
visited.add(file);
// 2. Includers
List<PsiFile> includers = findIncluders(file);
for (PsiFile includer : includers) {
found = findDatasetInFile(includer, id);
if (found != null) return found;
visited.add(includer);
}
// 3. Ajax
PsiFile ajaxXml = findAjaxXml(file);
if (ajaxXml != null && visited.add(ajaxXml)) {
found = findDatasetInFile(ajaxXml, id);
if (found != null) return found;
}
// 4. Recursive search
return findDatasetInFileRecursiveForCompletion(file, id, visited);
}
@Nullable
public static PsiElement findDatasetInFile(PsiFile file, String id) {
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
XmlTag datasetsContainer = rootTag.findFirstSubTag("DATASETS");
if (datasetsContainer == null) datasetsContainer = rootTag;
for (XmlTag datasetTag : datasetsContainer.findSubTags("DATASET")) {
if (id.equals(datasetTag.getAttributeValue("ID"))) {
return datasetTag;
}
}
return null;
}
@Nullable
public static PsiElement findDatasetInFileRecursiveForCompletion(PsiFile file, String id, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return null;
if (!(file instanceof XmlFile xmlFile)) return null;
// Try local
PsiElement found = findDatasetInFile(xmlFile, id);
if (found != null) return found;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
// Downward search
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
found = findDatasetInFileRecursiveForCompletion(includedFile, id, visited);
if (found != null) return found;
}
}
}
return null;
}
public static void addFormFieldsForNameRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return;
if (!(file instanceof XmlFile xmlFile)) return;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return;
// 1. Search in current file FORM_ENTRY tags
for (XmlTag formTag : rootTag.findSubTags("FORM")) {
for (XmlTag entryTag : formTag.findSubTags("FORM_ENTRY")) {
// Collect hidden fields from FIELDS
XmlTag fieldsTag = entryTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
for (XmlTag fieldTag : fieldsTag.findSubTags("FIELD")) {
if ("HIDDEN".equals(fieldTag.getAttributeValue("INPUTTYPE"))) {
String name = fieldTag.getAttributeValue("NAME");
if (name != null && !name.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(name)
.withIcon(AllIcons.Nodes.Field)
.withTypeText("Hidden Field"));
}
}
}
}
// Collect any field/tag with NAME from LAYOUT
XmlTag layoutTag = entryTag.findFirstSubTag("LAYOUT");
if (layoutTag != null) {
addFieldsInLayoutRecursive(layoutTag, resultSet);
}
}
}
// 2. Search in included files
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
addFormFieldsForNameRecursive(includedFile, resultSet, visited);
}
}
}
}
public static void addFieldsInLayoutRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
for (XmlTag subTag : container.getSubTags()) {
String name = subTag.getAttributeValue("NAME");
if (name != null && !name.isEmpty()) {
resultSet.addElement(LookupElementBuilder.create(name)
.withIcon(AllIcons.Nodes.Field)
.withTypeText("Layout: " + subTag.getName()));
}
addFieldsInLayoutRecursive(subTag, resultSet);
}
}
@Nullable
public static PsiElement findFormFieldByNameRecursive(PsiFile file, String name, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return null;
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
// 1. Search in current file FORM_ENTRY tags
for (XmlTag formTag : rootTag.findSubTags("FORM")) {
for (XmlTag entryTag : formTag.findSubTags("FORM_ENTRY")) {
// Check hidden fields in FIELDS
XmlTag fieldsTag = entryTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
for (XmlTag fieldTag : fieldsTag.findSubTags("FIELD")) {
if ("HIDDEN".equals(fieldTag.getAttributeValue("INPUTTYPE")) && name.equals(fieldTag.getAttributeValue("NAME"))) {
XmlAttribute nameAttr = fieldTag.getAttribute("NAME");
return nameAttr != null ? nameAttr.getValueElement() : fieldTag;
}
}
}
// Check fields in LAYOUT
XmlTag layoutTag = entryTag.findFirstSubTag("LAYOUT");
if (layoutTag != null) {
PsiElement found = findFieldInTag(layoutTag, name);
if (found != null) return found;
}
}
}
// 2. Search in included files
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
PsiElement found = findFormFieldByNameRecursive(includedFile, name, visited);
if (found != null) return found;
}
}
}
return null;
}
@Nullable
public static PsiElement findGridInFile(PsiFile file, String id) {
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
XmlTag dataGridsTag = rootTag.findFirstSubTag("DATA-GRIDS");
if (dataGridsTag != null) {
for (XmlTag gridTag : dataGridsTag.findSubTags("DATA-GRID")) {
if (id.equals(gridTag.getAttributeValue("ID"))) {
return gridTag;
}
}
}
return null;
}
@Nullable
public static PsiElement findGridElement(PsiFile file, String id) {
Set<PsiFile> visited = new HashSet<>();
// 1. Local
PsiElement found = findGridInFile(file, id);
if (found != null) return found;
visited.add(file);
// 2. Includers
List<PsiFile> includers = findIncluders(file);
for (PsiFile includer : includers) {
found = findGridInFile(includer, id);
if (found != null) return found;
visited.add(includer);
}
// 3. Recursive
return findGridInIncludesRecursive(file, id, visited);
}
@Nullable
private static PsiElement findGridInIncludesRecursive(PsiFile file, String id, Set<PsiFile> visited) {
if (file == null || !visited.add(file) || !(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = findIncludedFile(file, path);
PsiElement found = findGridInFile(includedFile, id);
if (found != null) return found;
found = findGridInIncludesRecursive(includedFile, id, visited);
if (found != null) return found;
}
}
}
return null;
}
public static boolean hasAncestorWithName(XmlTag tag, String name) {
XmlTag current = tag.getParentTag();
while (current != null) {
if (name.equals(current.getName())) return true;
current = current.getParentTag();
}
return false;
}
} }

View File

@@ -56,7 +56,7 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
// XML Reference Provider for Field/Section NAME/ID // XML Reference Provider for Field/Section NAME/ID
registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue() registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue()
.withParent(XmlPatterns.xmlAttribute().withName("NAME", "ID", "TARGET") .withParent(XmlPatterns.xmlAttribute().withName("NAME", "ID", "TARGET")
.withParent(XmlPatterns.xmlTag().withName("FIELD", "SECTION"))), .withParent(XmlPatterns.xmlTag().withName("FIELD", "SECTION", "SECTIONS"))),
new PsiReferenceProvider() { new PsiReferenceProvider() {
@NotNull @NotNull
@Override @Override
@@ -74,12 +74,12 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
} }
// เคส 1: อยู่ใน LAYOUT หรือ TITLES -> ลิงก์ไปหา FIELDS (นิยาม) // เคส 1: อยู่ใน LAYOUT หรือ TITLES -> ลิงก์ไปหา FIELDS (นิยาม)
if (hasAncestorWithName(tag, "LAYOUT") || hasAncestorWithName(tag, "TITLES")) { if (DynFormPathUtils.hasAncestorWithName(tag, "LAYOUT") || DynFormPathUtils.hasAncestorWithName(tag, "TITLES")) {
return new PsiReference[]{new DynFormFieldDefinitionReference(attrValue, new TextRange(1, value.length() + 1), value)}; return new PsiReference[]{new DynFormFieldDefinitionReference(attrValue, new TextRange(1, value.length() + 1), value)};
} }
// เคส 2: อยู่ใน FIELDS (นิยาม) -> ลิงก์กลับไปหา LAYOUT หรือ TITLES (การใช้งาน) // เคส 2: อยู่ใน FIELDS (นิยาม) -> ลิงก์กลับไปหา LAYOUT หรือ TITLES (การใช้งาน)
if (hasAncestorWithName(tag, "FIELDS")) { if (DynFormPathUtils.hasAncestorWithName(tag, "FIELDS")) {
return new PsiReference[]{new DynFormFieldUsageReference(attrValue, new TextRange(1, value.length() + 1), value)}; return new PsiReference[]{new DynFormFieldUsageReference(attrValue, new TextRange(1, value.length() + 1), value)};
} }
@@ -123,7 +123,7 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
String tagName = tag.getName(); String tagName = tag.getName();
// Only process DATASET tag if it's inside FOREIGN-DATASETS // Only process DATASET tag if it's inside FOREIGN-DATASETS
if ("DATASET".equals(tagName) && !hasAncestorWithName(tag, "FOREIGN-DATASETS")) { if ("DATASET".equals(tagName) && !DynFormPathUtils.hasAncestorWithName(tag, "FOREIGN-DATASETS")) {
return PsiReference.EMPTY_ARRAY; return PsiReference.EMPTY_ARRAY;
} }
@@ -263,15 +263,6 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
}); });
} }
private static boolean hasAncestorWithName(XmlTag tag, String name) {
XmlTag current = tag.getParentTag();
while (current != null) {
if (name.equals(current.getName())) return true;
current = current.getParentTag();
}
return false;
}
@Nullable @Nullable
private PsiNewExpression getNewDynFormExpression(PsiLiteralExpression literal) { private PsiNewExpression getNewDynFormExpression(PsiLiteralExpression literal) {
PsiElement parent = literal.getParent(); PsiElement parent = literal.getParent();
@@ -328,15 +319,23 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
} }
@Nullable @Override public PsiElement resolve() { @Nullable @Override public PsiElement resolve() {
XmlTag container = PsiTreeUtil.getParentOfType(myElement, XmlTag.class); XmlTag container = PsiTreeUtil.getParentOfType(myElement, XmlTag.class);
while (container != null && !"FORM_ENTRY".equals(container.getName()) && !"FORM_BROWSE".equals(container.getName()) && !"GRID-LIST".equals(container.getName())) { while (container != null &&
!"FORM_ENTRY".equals(container.getName()) &&
!"FORM_BROWSE".equals(container.getName()) &&
!"GRID-LIST".equals(container.getName()) &&
!"GRID-EDITOR".equals(container.getName()) &&
!"FILTERS".equals(container.getName())) {
container = container.getParentTag(); container = container.getParentTag();
} }
if (container == null) { if (container == null) {
XmlFile file = (XmlFile) myElement.getContainingFile(); // If not in a specific container, search in all known containers across context
container = file.getRootTag(); PsiElement found = DynFormPathUtils.findFieldInFormContext(myElement.getContainingFile(), "FORM_ENTRY", fieldName, new HashSet<>());
if (found != null) return found;
return DynFormPathUtils.findFieldInFormContext(myElement.getContainingFile(), "FORM_BROWSE", fieldName, new HashSet<>());
} }
if (container == null) return null;
return findFieldInTag(container, fieldName); // Search in current container's FIELDS across context
return DynFormPathUtils.findFieldInFormContext(myElement.getContainingFile(), container.getName(), fieldName, new HashSet<>());
} }
} }
@@ -353,28 +352,19 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
XmlTag tag = PsiTreeUtil.getParentOfType(myElement, XmlTag.class); XmlTag tag = PsiTreeUtil.getParentOfType(myElement, XmlTag.class);
if (tag == null) return null; if (tag == null) return null;
// หา container (FORM_ENTRY, FORM_BROWSE, GRID-LIST หรือ FILTERS) // หา container (FORM_ENTRY, FORM_BROWSE, GRID-LIST, GRID-EDITOR หรือ FILTERS)
XmlTag container = tag; XmlTag container = tag;
while (container != null && while (container != null &&
!"LAYOUT".equals(container.getName()) &&
!"TITLES".equals(container.getName()) &&
!"FORM_ENTRY".equals(container.getName()) && !"FORM_ENTRY".equals(container.getName()) &&
!"FORM_BROWSE".equals(container.getName()) && !"FORM_BROWSE".equals(container.getName()) &&
!"GRID-LIST".equals(container.getName()) && !"GRID-LIST".equals(container.getName()) &&
!"GRID-EDITOR".equals(container.getName()) &&
!"FILTERS".equals(container.getName())) { !"FILTERS".equals(container.getName())) {
container = container.getParentTag(); container = container.getParentTag();
} }
if (container != null && ("LAYOUT".equals(container.getName()) || "TITLES".equals(container.getName()))) {
container = container.getParentTag();
}
if (container == null) return null; if (container == null) return null;
return DynFormPathUtils.findFieldInFormContext(myElement.getContainingFile(), container.getName(), fieldName, new HashSet<>());
XmlTag fieldsTag = container.findFirstSubTag("FIELDS");
if (fieldsTag == null) return null;
return findFieldInTag(fieldsTag, fieldName);
} }
} }
@@ -401,41 +391,10 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
XmlTag containerTag = fieldsTag.getParentTag(); XmlTag containerTag = fieldsTag.getParentTag();
if (containerTag == null) return null; if (containerTag == null) return null;
// หาใน LAYOUT ก่อน return DynFormPathUtils.findUsageInFormContext(myElement.getContainingFile(), containerTag.getName(), fieldName, new HashSet<>());
XmlTag layoutTag = containerTag.findFirstSubTag("LAYOUT");
if (layoutTag != null) {
PsiElement found = findFieldInTag(layoutTag, fieldName);
if (found != null) return found;
}
// ถ้าไม่เจอใน LAYOUT ให้หาใน TITLES
XmlTag titlesTag = containerTag.findFirstSubTag("TITLES");
if (titlesTag != null) {
PsiElement found = findFieldInTag(titlesTag, fieldName);
if (found != null) return found;
}
return null;
} }
} }
@Nullable
private static PsiElement findFieldInTag(XmlTag container, String name) {
for (XmlTag subTag : container.getSubTags()) {
if ("FIELD".equals(subTag.getName()) && name.equals(subTag.getAttributeValue("NAME"))) {
XmlAttribute nameAttr = subTag.getAttribute("NAME");
return nameAttr != null ? nameAttr.getValueElement() : subTag;
}
if (("SECTION".equals(subTag.getName()) || "ROW".equals(subTag.getName())) && name.equals(subTag.getAttributeValue("ID"))) {
XmlAttribute idAttr = subTag.getAttribute("ID");
return idAttr != null ? idAttr.getValueElement() : subTag;
}
PsiElement found = findFieldInTag(subTag, name);
if (found != null) return found;
}
return null;
}
private static class DynFormDatasetReference extends PsiReferenceBase<XmlAttributeValue> implements PsiPolyVariantReference { private static class DynFormDatasetReference extends PsiReferenceBase<XmlAttributeValue> implements PsiPolyVariantReference {
private final String datasetId; private final String datasetId;
private final boolean isAjaxOption; private final boolean isAjaxOption;
@@ -473,31 +432,15 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
// 3. ค้นหาในไฟล์ที่ถูก INCLUDE (Downward) // 3. ค้นหาในไฟล์ที่ถูก INCLUDE (Downward)
findDatasetInIncludesRecursive(currentFile, datasetId, results, new HashSet<>()); findDatasetInIncludesRecursive(currentFile, datasetId, results, new HashSet<>());
if (!results.isEmpty()) return filterOpenFiles(results, myElement.getProject());
// 4. ค้นหาแบบ Module-wide (fallback สุดท้าย)
List<PsiFile> allFiles = DynFormPathUtils.getAllFrmlFiles(currentFile);
for (PsiFile file : allFiles) {
if (file.equals(currentFile) || includers.contains(file)) continue;
findDatasetInFile(file, datasetId, results);
}
return filterOpenFiles(results, myElement.getProject()); return filterOpenFiles(results, myElement.getProject());
} }
private void findDatasetInFile(PsiFile file, String id, List<ResolveResult> results) { private void findDatasetInFile(PsiFile file, String id, List<ResolveResult> results) {
if (!(file instanceof XmlFile xmlFile)) return; PsiElement found = DynFormPathUtils.findDatasetInFile(file, id);
XmlTag rootTag = xmlFile.getRootTag(); if (found instanceof XmlTag datasetTag) {
if (rootTag == null) return; XmlAttribute idAttr = datasetTag.getAttribute("ID");
results.add(new PsiElementResolveResult(idAttr != null ? idAttr.getValueElement() : datasetTag));
XmlTag datasetsContainer = rootTag.findFirstSubTag("DATASETS");
if (datasetsContainer == null) datasetsContainer = rootTag;
for (XmlTag datasetTag : datasetsContainer.findSubTags("DATASET")) {
if (id.equals(datasetTag.getAttributeValue("ID"))) {
XmlAttribute idAttr = datasetTag.getAttribute("ID");
results.add(new PsiElementResolveResult(idAttr != null ? idAttr.getValueElement() : datasetTag));
}
} }
} }
@@ -573,7 +516,7 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
if (parentDataset != null && "DATASET".equals(parentDataset.getName())) { if (parentDataset != null && "DATASET".equals(parentDataset.getName())) {
XmlTag fieldsTag = parentDataset.findFirstSubTag("FIELDS"); XmlTag fieldsTag = parentDataset.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
PsiElement found = findFieldInTag(fieldsTag, fieldName); PsiElement found = DynFormPathUtils.findFieldInTag(fieldsTag, fieldName);
if (found != null) results.add(new PsiElementResolveResult(found)); if (found != null) results.add(new PsiElementResolveResult(found));
} }
} }
@@ -605,7 +548,7 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
if (datasetTag != null) { if (datasetTag != null) {
XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
PsiElement found = findFieldInTag(fieldsTag, fieldName); PsiElement found = DynFormPathUtils.findFieldInTag(fieldsTag, fieldName);
if (found != null) results.add(new PsiElementResolveResult(found)); if (found != null) results.add(new PsiElementResolveResult(found));
} }
} }
@@ -642,18 +585,10 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
} }
private void findDatasetInFile(PsiFile file, String id, List<ResolveResult> results) { private void findDatasetInFile(PsiFile file, String id, List<ResolveResult> results) {
if (!(file instanceof XmlFile xmlFile)) return; PsiElement found = DynFormPathUtils.findDatasetInFile(file, id);
XmlTag rootTag = xmlFile.getRootTag(); if (found instanceof XmlTag datasetTag) {
if (rootTag == null) return; XmlAttribute idAttr = datasetTag.getAttribute("ID");
results.add(new PsiElementResolveResult(idAttr != null ? idAttr.getValueElement() : datasetTag));
XmlTag datasetsContainer = rootTag.findFirstSubTag("DATASETS");
if (datasetsContainer == null) datasetsContainer = rootTag;
for (XmlTag datasetTag : datasetsContainer.findSubTags("DATASET")) {
if (id.equals(datasetTag.getAttributeValue("ID"))) {
XmlAttribute idAttr = datasetTag.getAttribute("ID");
results.add(new PsiElementResolveResult(idAttr != null ? idAttr.getValueElement() : datasetTag));
}
} }
} }
@@ -707,14 +642,6 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
// 3. ค้นหาในไฟล์ที่ถูก INCLUDE (Downward) // 3. ค้นหาในไฟล์ที่ถูก INCLUDE (Downward)
findGridInIncludesRecursive(currentFile, gridId, results, new HashSet<>()); findGridInIncludesRecursive(currentFile, gridId, results, new HashSet<>());
if (!results.isEmpty()) return filterOpenFiles(results, myElement.getProject());
// 4. ค้นหาแบบ Module-wide (fallback)
List<PsiFile> allFiles = DynFormPathUtils.getAllFrmlFiles(currentFile);
for (PsiFile file : allFiles) {
if (file.equals(currentFile) || includers.contains(file)) continue;
findGridInFile(file, gridId, results);
}
return filterOpenFiles(results, myElement.getProject()); return filterOpenFiles(results, myElement.getProject());
} }
@@ -800,7 +727,7 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
if (datasetId.equals(datasetTag.getAttributeValue("ID"))) { if (datasetId.equals(datasetTag.getAttributeValue("ID"))) {
XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
return findFieldInTag(fieldsTag, fieldName); return DynFormPathUtils.findFieldInTag(fieldsTag, fieldName);
} }
return datasetTag; return datasetTag;
} }
@@ -831,51 +758,7 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
@Nullable @Nullable
@Override @Override
public PsiElement resolve() { public PsiElement resolve() {
return findFieldInFormEntriesRecursive(myElement.getContainingFile(), fieldName, new HashSet<>()); return DynFormPathUtils.findFormFieldByNameRecursive(myElement.getContainingFile(), fieldName, new HashSet<>());
}
@Nullable
private PsiElement findFieldInFormEntriesRecursive(PsiFile file, String name, Set<PsiFile> visited) {
if (file == null || !visited.add(file)) return null;
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
// 1. Search in current file FORM_ENTRY tags
for (XmlTag formTag : rootTag.findSubTags("FORM")) {
for (XmlTag entryTag : formTag.findSubTags("FORM_ENTRY")) {
// Check hidden fields in FIELDS
XmlTag fieldsTag = entryTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) {
for (XmlTag fieldTag : fieldsTag.findSubTags("FIELD")) {
if ("HIDDEN".equals(fieldTag.getAttributeValue("INPUTTYPE")) && name.equals(fieldTag.getAttributeValue("NAME"))) {
XmlAttribute nameAttr = fieldTag.getAttribute("NAME");
return nameAttr != null ? nameAttr.getValueElement() : fieldTag;
}
}
}
// Check fields in LAYOUT
XmlTag layoutTag = entryTag.findFirstSubTag("LAYOUT");
if (layoutTag != null) {
PsiElement found = findFieldInTag(layoutTag, name);
if (found != null) return found;
}
}
}
// 2. Search in included files
XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
if (includesTag != null) {
for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
String path = includeTag.getAttributeValue("FILE");
if (path != null) {
PsiFile includedFile = DynFormPathUtils.findIncludedFile(file, path);
PsiElement found = findFieldInFormEntriesRecursive(includedFile, name, visited);
if (found != null) return found;
}
}
}
return null;
} }
} }
@@ -951,33 +834,17 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
if (dataId != null && !dataId.isEmpty()) { if (dataId != null && !dataId.isEmpty()) {
PsiFile file = gridTag.getContainingFile(); PsiFile file = gridTag.getContainingFile();
PsiElement datasetElement = findDatasetElement(file, dataId); PsiElement datasetElement = DynFormPathUtils.findDatasetElement(file, dataId);
if (datasetElement instanceof XmlTag datasetTag) { if (datasetElement instanceof XmlTag datasetTag) {
XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS"); XmlTag fieldsTag = datasetTag.findFirstSubTag("FIELDS");
if (fieldsTag != null) { if (fieldsTag != null) {
return findFieldInTag(fieldsTag, fieldName); return DynFormPathUtils.findFieldInTag(fieldsTag, fieldName);
} }
} }
} }
return null; return null;
} }
private PsiElement findDatasetElement(PsiFile file, String id) {
if (!(file instanceof XmlFile xmlFile)) return null;
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
XmlTag datasetsContainer = rootTag.findFirstSubTag("DATASETS");
if (datasetsContainer == null) datasetsContainer = rootTag;
for (XmlTag datasetTag : datasetsContainer.findSubTags("DATASET")) {
if (id.equals(datasetTag.getAttributeValue("ID"))) {
return datasetTag;
}
}
return null;
}
@Override @Override
public Object @NotNull [] getVariants() { public Object @NotNull [] getVariants() {
return new Object[0]; return new Object[0];