Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes
This commit is contained in:
BIN
doc/MCS_SQLServer_表结构说明.docx
Normal file
BIN
doc/MCS_SQLServer_表结构说明.docx
Normal file
Binary file not shown.
3550
doc/MCS_SQLServer_表结构说明.md
Normal file
3550
doc/MCS_SQLServer_表结构说明.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
doc/MCS_SQLServer_表结构说明.xlsx
Normal file
BIN
doc/MCS_SQLServer_表结构说明.xlsx
Normal file
Binary file not shown.
@@ -230,6 +230,10 @@ public class ShiroConfig {
|
||||
filterChainDefinitionMap.put("/sys/category/anon/**", "anon");
|
||||
// 桌面端用户反同步批量上报(Outbox -> /sys/sync/batch)
|
||||
filterChainDefinitionMap.put("/sys/sync/batch", "anon");
|
||||
//update-begin---author:cursor ---date:2026-07-20 for:【设备库桥接】桌面代理免密接口-----------
|
||||
filterChainDefinitionMap.put("/sys/device/agent/**", "anon");
|
||||
filterChainDefinitionMap.put("/xslmes/deviceAgent/anon/**", "anon");
|
||||
//update-end---author:cursor ---date:2026-07-20 for:【设备库桥接】桌面代理免密接口-----------
|
||||
|
||||
// 添加自己的过滤器并且取名为jwt
|
||||
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
|
||||
|
||||
@@ -1258,7 +1258,111 @@ JeecgUniapp-master/src/pages/rawMaterialInspect/rawMaterialInspect.vue
|
||||
JeecgUniapp-master/src/pages/rawMaterialInspect/inspectResult.vue
|
||||
JeecgUniapp-master/src/common/work.ts
|
||||
|
||||
-- author:GHT---date:20260730--for: <20><>XSLMES-20260730-DING-PULL<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܼ<EFBFBD><EFBFBD><EFBFBD> ---
|
||||
-- author:jiangxh---date:20260728--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD>Ϊͬһ<CDAC>豸<EFBFBD><E8B1B8>Ψһ ---
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerConditionService.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerConditionServiceImpl.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerConditionController.java
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/MesXslMixerCondition.api.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/MesXslMixerCondition.data.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>%/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λС<CEBB><D0A1> ---
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5>3λ<33><CEBB>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3λ<33><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2λ ---
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD>λС<CEBB><D0A1> ---
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD>ϲ<EFBFBD>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD>ϼ<EFBFBD>ʾ<EFBFBD><CABE>ѡ<EFBFBD>ϸ<EFBFBD>Ϊģ<CEAA><C4A3><EFBFBD><EFBFBD>ѯ ---
|
||||
jeecgboot-vue3/src/views/mes/material/materialQuery.util.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMixerMaterialList.vue
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterialList.vue
|
||||
jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue
|
||||
jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD>ϡ<EFBFBD><CFA1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>༭У<E0BCAD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ψһ ---
|
||||
jeecgboot-vue3/src/views/mes/material/MesMixerMaterial.api.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMixerMaterial.data.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.data.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><CFA1><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD>ϱ<EFBFBD><CFB1><EFBFBD><EFBFBD><EFBFBD>365<36><35> ---
|
||||
jeecgboot-vue3/src/views/mes/material/MesMixerMaterial.data.ts
|
||||
yy-admin-master/YY.Admin/ViewModels/MixerMaterial/MixerMaterialEditDialogViewModel.cs
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD><EFBFBD>%/<2F><><EFBFBD>ͳһ<CDB3><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λС<CEBB><D0A1> ---
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_171__mes_xsl_formula_spec_line_decimal3.sql
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.data.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><>WebSocket<65><74>pongTimeout 1s<31><73>10s <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
jeecgboot-vue3/src/hooks/web/useWebSocket.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><>WebSocket<65><74><EFBFBD><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Redis<69>ذ<EFBFBD><D8B0><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/websocket/WebSocket.java
|
||||
jeecgboot-vue3/src/hooks/web/useWebSocket.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><>HTTP<54><50>Ĭ<EFBFBD>ϳ<EFBFBD>ʱ10s<30><73>60s<30><73><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>120s ---
|
||||
jeecgboot-vue3/src/utils/http/axios/index.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD>ɡ<EFBFBD>B/F<><46><EFBFBD>ϸ<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>ƥ<EFBFBD>䣬<EFBFBD><E4A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE>ά<EFBFBD><CEAC> ---
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD>ɡ<EFBFBD><C9A1>ս<EFBFBD><D5BD><EFBFBD>ϸĸ<CFB8><C4B8><EFBFBD>д<EFBFBD><D0B4>뽺<EFBFBD><EBBDBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><>ѡ<EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE>/<2F><><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD><EFBFBD>ϱ<EFBFBD><CFB1> ---
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||
jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue
|
||||
jeecgboot-vue3/src/views/mes/material/materialQuery.util.ts
|
||||
|
||||
-- author:jiangxh---date:20260730--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD>ɡ<EFBFBD><C9A1>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɻ<EFBFBD><C9BB><EFBFBD>ʾ<EFBFBD><CABE>Ԥ<EFBFBD><D4A4>ʱ<EFBFBD><CAB1>ƥ<EFBFBD>佺<EFBFBD><E4BDBA><EFBFBD>б<EFBFBD> ---
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaGenerateMixingModal.vue
|
||||
|
||||
-- author:jiangxh---date:20260730--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD>ɡ<EFBFBD>B/Fƥ<46><C6A5><EFBFBD>Ž<EFBFBD>ǰ+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƴSA01<30>Ȱ汾<C8B0><E6B1BE> ---
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
|
||||
-- author:jiangxh---date:20260730--for: <20><><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD><EFBFBD>ϱ<EFBFBD><CFB1>ҵ<EFBFBD><D2B5><EFBFBD>ֶΣ<D6B6>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/entity/MesMaterial.java
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/IMesMaterialService.java
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/impl/MesMaterialServiceImpl.java
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.data.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts
|
||||
jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||
|
||||
-- author:jiangxh---date:20260730--for: <20><><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><CFA1>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD>ŸĶ<C5B8> ---
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/entity/MesMaterial.java
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/IMesMaterialService.java
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/impl/MesMaterialServiceImpl.java
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.data.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts
|
||||
jeecgboot-vue3/src/views/mes/material/modules/MesMaterialSelectModal.vue
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||
|
||||
-- author:jiangxh---date:20260730--for: <20><><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><CFA1><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><D8A3><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>Զ<EFBFBD><D4B6>뽺<EFBFBD><EBBDBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> ---
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.data.ts
|
||||
|
||||
-- author:GHT---date:20260730--for: <20><>XSLMES-20260730-DING-PULL<4C><4C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD><CCA8><EFBFBD>ֶ<EFBFBD><D6B6><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><C7BF><EFBFBD><EFBFBD><EFBFBD>ܼ<EFBFBD><DCBC><EFBFBD> ---
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/IntegrationForceReplayHolder.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/integration/engine/IntegrationOrchestrator.java
|
||||
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/dingtalk/stream/DingApprovalManualPullService.java
|
||||
@@ -1267,4 +1371,4 @@ jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/app
|
||||
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_164__mes_xsl_approval_record_pull_ding_result.sql
|
||||
jeecgboot-vue3/src/views/xslmes/approval/mesXslApprovalRecord/MesXslApprovalRecordList.vue
|
||||
jeecgboot-vue3/src/views/xslmes/approval/mesXslApprovalRecord/MesXslApprovalRecord.api.ts
|
||||
-- author:GHT---date:20260730--for: <20><>XSLMES-20260730-DING-PULL<4C><4C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD><CCA8><EFBFBD>ֶ<EFBFBD><D6B6><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܼ<EFBFBD><EFBFBD><EFBFBD> ---
|
||||
-- author:GHT---date:20260730--for: <20><>XSLMES-20260730-DING-PULL<4C><4C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD><CCA8><EFBFBD>ֶ<EFBFBD><D6B6><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><C7BF><EFBFBD><EFBFBD><EFBFBD>ܼ<EFBFBD><DCBC><EFBFBD> ---
|
||||
|
||||
@@ -36,5 +36,11 @@
|
||||
<artifactId>jeecg-module-print</artifactId>
|
||||
<version>${jeecgboot.version}</version>
|
||||
</dependency>
|
||||
<!-- 设备同步/桌面代理命令总线 -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot3</groupId>
|
||||
<artifactId>jeecg-module-device-sync</artifactId>
|
||||
<version>${jeecgboot.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -130,6 +130,7 @@ public class MesXslAutoSmallMaterialDemandPlanController {
|
||||
}
|
||||
|
||||
sql.append("GROUP BY ");
|
||||
sql.append(statDateExpr).append(", ");
|
||||
if (groupedByMachine) {
|
||||
sql.append(machineExpr).append(", ");
|
||||
}
|
||||
@@ -160,14 +161,20 @@ public class MesXslAutoSmallMaterialDemandPlanController {
|
||||
|
||||
private String buildOrderBy(boolean groupedByMachine) {
|
||||
if (groupedByMachine) {
|
||||
return " ORDER BY machineName, rawMaterialName";
|
||||
return " ORDER BY statDate DESC, machineName, rawMaterialName";
|
||||
}
|
||||
return " ORDER BY rawMaterialName";
|
||||
return " ORDER BY statDate DESC, rawMaterialName";
|
||||
}
|
||||
|
||||
private String buildRowId(MesXslSmallMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
|
||||
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
|
||||
return machine + "_" + StringUtils.defaultString(row.getRawMaterialName()) + "_" + seq;
|
||||
return StringUtils.defaultString(row.getStatDate())
|
||||
+ "_"
|
||||
+ machine
|
||||
+ "_"
|
||||
+ StringUtils.defaultString(row.getRawMaterialName())
|
||||
+ "_"
|
||||
+ seq;
|
||||
}
|
||||
|
||||
private String trim(String value) {
|
||||
|
||||
@@ -130,6 +130,7 @@ public class MesXslManualSmallMaterialDemandPlanController {
|
||||
}
|
||||
|
||||
sql.append("GROUP BY ");
|
||||
sql.append(statDateExpr).append(", ");
|
||||
if (groupedByMachine) {
|
||||
sql.append(machineExpr).append(", ");
|
||||
}
|
||||
@@ -160,14 +161,20 @@ public class MesXslManualSmallMaterialDemandPlanController {
|
||||
|
||||
private String buildOrderBy(boolean groupedByMachine) {
|
||||
if (groupedByMachine) {
|
||||
return " ORDER BY machineName, rawMaterialName";
|
||||
return " ORDER BY statDate DESC, machineName, rawMaterialName";
|
||||
}
|
||||
return " ORDER BY rawMaterialName";
|
||||
return " ORDER BY statDate DESC, rawMaterialName";
|
||||
}
|
||||
|
||||
private String buildRowId(MesXslSmallMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
|
||||
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
|
||||
return machine + "_" + StringUtils.defaultString(row.getRawMaterialName()) + "_" + seq;
|
||||
return StringUtils.defaultString(row.getStatDate())
|
||||
+ "_"
|
||||
+ machine
|
||||
+ "_"
|
||||
+ StringUtils.defaultString(row.getRawMaterialName())
|
||||
+ "_"
|
||||
+ seq;
|
||||
}
|
||||
|
||||
private String trim(String value) {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.jeecg.modules.xslmes.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMillActionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* MES 开炼机动作接收表
|
||||
*/
|
||||
@Tag(name = "开炼机动作接收")
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/mesXslMillAction")
|
||||
public class MesXslMillActionController extends JeecgController<MesXslMillAction, IMesXslMillActionService> {
|
||||
|
||||
@Autowired private IMesXslMillActionService mesXslMillActionService;
|
||||
|
||||
@Operation(summary = "开炼机动作接收-分页列表查询")
|
||||
@GetMapping("/list")
|
||||
public Result<IPage<MesXslMillAction>> queryPageList(
|
||||
MesXslMillAction model,
|
||||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<MesXslMillAction> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
|
||||
queryWrapper.orderByDesc("update_time");
|
||||
IPage<MesXslMillAction> pageList = mesXslMillActionService.page(new Page<>(pageNo, pageSize), queryWrapper);
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
@Operation(summary = "开炼机动作接收-通过id查询")
|
||||
@GetMapping("/queryById")
|
||||
public Result<MesXslMillAction> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
MesXslMillAction entity = mesXslMillActionService.getById(id);
|
||||
if (entity == null) {
|
||||
return Result.error("未找到对应数据");
|
||||
}
|
||||
return Result.OK(entity);
|
||||
}
|
||||
|
||||
@RequiresPermissions("xslmes:mes_xsl_mill_action:exportXls")
|
||||
@RequestMapping(value = "/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, MesXslMillAction model) {
|
||||
return super.exportXls(request, model, MesXslMillAction.class, "开炼机动作接收");
|
||||
}
|
||||
}
|
||||
@@ -110,31 +110,43 @@ public class MesXslMixerConditionController
|
||||
return Result.OK(entity);
|
||||
}
|
||||
|
||||
@Operation(summary = "校验条件名称是否重复")
|
||||
@Operation(summary = "校验条件名称是否重复(同一设备下)")
|
||||
@GetMapping("/checkConditionName")
|
||||
public Result<String> checkConditionName(
|
||||
@RequestParam(name = "conditionName", required = true) String conditionName,
|
||||
@RequestParam(name = "equipmentId", required = false) String equipmentId,
|
||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||
if (oConvertUtils.isEmpty(conditionName) || conditionName.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (mesXslMixerConditionService.isConditionNameDuplicated(conditionName, dataId)) {
|
||||
return Result.error("条件名称不能重复");
|
||||
//update-begin---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称按设备唯一-----------
|
||||
if (oConvertUtils.isEmpty(equipmentId) || equipmentId.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (mesXslMixerConditionService.isConditionNameDuplicated(conditionName, equipmentId, dataId)) {
|
||||
return Result.error("同一设备下条件名称不能重复");
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称按设备唯一-----------
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
|
||||
@Operation(summary = "校验条件代码是否重复")
|
||||
@Operation(summary = "校验条件代码是否重复(同一设备下)")
|
||||
@GetMapping("/checkConditionCode")
|
||||
public Result<String> checkConditionCode(
|
||||
@RequestParam(name = "conditionCode", required = true) String conditionCode,
|
||||
@RequestParam(name = "equipmentId", required = false) String equipmentId,
|
||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||
if (oConvertUtils.isEmpty(conditionCode) || conditionCode.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (mesXslMixerConditionService.isConditionCodeDuplicated(conditionCode, dataId)) {
|
||||
return Result.error("条件代码不能重复");
|
||||
//update-begin---author:jiangxh ---date:20260728 for:【密炼机条件】条件代码按设备唯一-----------
|
||||
if (oConvertUtils.isEmpty(equipmentId) || equipmentId.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (mesXslMixerConditionService.isConditionCodeDuplicated(conditionCode, equipmentId, dataId)) {
|
||||
return Result.error("同一设备下条件代码不能重复");
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260728 for:【密炼机条件】条件代码按设备唯一-----------
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
|
||||
@@ -153,16 +165,20 @@ public class MesXslMixerConditionController
|
||||
return "条件名称不能为空";
|
||||
}
|
||||
model.setConditionName(model.getConditionName().trim());
|
||||
if (mesXslMixerConditionService.isConditionNameDuplicated(model.getConditionName(), excludeId)) {
|
||||
return "条件名称不能重复";
|
||||
//update-begin---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称/代码按设备唯一-----------
|
||||
if (mesXslMixerConditionService.isConditionNameDuplicated(
|
||||
model.getConditionName(), model.getEquipmentId(), excludeId)) {
|
||||
return "同一设备下条件名称不能重复";
|
||||
}
|
||||
if (oConvertUtils.isEmpty(model.getConditionCode()) || StringUtils.isBlank(model.getConditionCode())) {
|
||||
return "条件代码不能为空";
|
||||
}
|
||||
model.setConditionCode(model.getConditionCode().trim());
|
||||
if (mesXslMixerConditionService.isConditionCodeDuplicated(model.getConditionCode(), excludeId)) {
|
||||
return "条件代码不能重复";
|
||||
if (mesXslMixerConditionService.isConditionCodeDuplicated(
|
||||
model.getConditionCode(), model.getEquipmentId(), excludeId)) {
|
||||
return "同一设备下条件代码不能重复";
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称/代码按设备唯一-----------
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +95,12 @@ public class MesXslRawMaterialDemandPlanController {
|
||||
|
||||
private String buildGroupedSql(
|
||||
MesXslRawMaterialDemandPlanSummary query, boolean groupedByMachine, List<Object> params) {
|
||||
String planDateExpr = "DATE(t.plan_date)";
|
||||
boolean hasPlanDate = hasColumn("mes_xsl_raw_material_demand_plan", "plan_date");
|
||||
boolean hasMaterialId = hasColumn("mes_xsl_raw_material_demand_plan", "material_id");
|
||||
String planDateExpr = hasPlanDate ? "t.plan_date" : "DATE(t.create_time)";
|
||||
String machineExpr = "COALESCE(NULLIF(TRIM(t.machine_name),''), '')";
|
||||
String materialIdExpr = "COALESCE(NULLIF(TRIM(t.material_id),''), '')";
|
||||
String materialIdExpr =
|
||||
hasMaterialId ? "COALESCE(NULLIF(TRIM(t.material_id),''), '')" : "''";
|
||||
String erpCodeExpr = "COALESCE(NULLIF(TRIM(t.erp_code),''), '')";
|
||||
String rawMaterialExpr = "COALESCE(NULLIF(TRIM(t.raw_material_name),''), '')";
|
||||
|
||||
@@ -192,4 +195,12 @@ public class MesXslRawMaterialDemandPlanController {
|
||||
private String trim(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private boolean hasColumn(String tableName, String columnName) {
|
||||
String sql =
|
||||
"SELECT COUNT(1) FROM information_schema.COLUMNS "
|
||||
+ "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?";
|
||||
Long count = jdbcTemplate.queryForObject(sql, Long.class, tableName, columnName);
|
||||
return count != null && count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.jeecg.modules.xslmes.deviceagent;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentCommandService;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentResult;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSession;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSessionRegistry;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 桌面设备代理免密接口(注册/心跳/分块回传)。
|
||||
*/
|
||||
@Tag(name = "桌面设备代理")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/deviceAgent/anon")
|
||||
@RequiredArgsConstructor
|
||||
public class MesXslDeviceAgentAnonController {
|
||||
|
||||
private final DeviceAgentSessionRegistry sessionRegistry;
|
||||
private final DeviceAgentCommandService commandService;
|
||||
|
||||
@Operation(summary = "注册/心跳")
|
||||
@PostMapping("/register")
|
||||
public Result<Map<String, Object>> register(@RequestBody Map<String, Object> body) {
|
||||
String deviceId = str(body, "deviceId");
|
||||
if (StringUtils.isBlank(deviceId)) {
|
||||
return Result.error("deviceId不能为空");
|
||||
}
|
||||
String hostName = str(body, "hostName");
|
||||
Boolean dbConnected = bool(body.get("dbConnected"));
|
||||
String dbMessage = str(body, "dbMessage");
|
||||
sessionRegistry.registerOrHeartbeat(deviceId, hostName, dbConnected, dbMessage);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("deviceId", deviceId);
|
||||
data.put("accepted", true);
|
||||
return Result.OK(data);
|
||||
}
|
||||
|
||||
@Operation(summary = "心跳")
|
||||
@PostMapping("/heartbeat")
|
||||
public Result<String> heartbeat(@RequestBody Map<String, Object> body) {
|
||||
String deviceId = str(body, "deviceId");
|
||||
if (StringUtils.isBlank(deviceId)) {
|
||||
return Result.error("deviceId不能为空");
|
||||
}
|
||||
sessionRegistry.registerOrHeartbeat(deviceId, str(body, "hostName"), bool(body.get("dbConnected")), str(body, "dbMessage"));
|
||||
return Result.OK("ok");
|
||||
}
|
||||
|
||||
@Operation(summary = "命令结果分块回传(大数据量)")
|
||||
@PostMapping("/resultChunk")
|
||||
public Result<String> resultChunk(@RequestBody DeviceAgentResult result) {
|
||||
if (result == null || StringUtils.isBlank(result.getRequestId())) {
|
||||
return Result.error("requestId不能为空");
|
||||
}
|
||||
// 当前实现:整包完成;桌面可在单次 chunk 中带 lastChunk=true 直接完成
|
||||
if (Boolean.TRUE.equals(result.getLastChunk()) || result.getChunkTotal() == null || result.getChunkTotal() <= 1) {
|
||||
commandService.completeResult(result);
|
||||
} else {
|
||||
log.info("收到分块回传 requestId={} chunk={}/{}", result.getRequestId(), result.getChunkIndex(), result.getChunkTotal());
|
||||
// 简化:仅最后一块完成;中间块忽略合并(桌面端大结果优先走单次 STOMP 或一次 REST 全量)
|
||||
if (Boolean.TRUE.equals(result.getLastChunk())) {
|
||||
commandService.completeResult(result);
|
||||
}
|
||||
}
|
||||
return Result.OK("ok");
|
||||
}
|
||||
|
||||
@Operation(summary = "在线代理列表")
|
||||
@GetMapping("/online")
|
||||
public Result<List<DeviceAgentSession>> online() {
|
||||
return Result.OK(sessionRegistry.listOnline());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询代理状态")
|
||||
@GetMapping("/status")
|
||||
public Result<DeviceAgentSession> status(@RequestParam(name = "deviceId", required = false) String deviceId) {
|
||||
return Result.OK(sessionRegistry.pickOnlineAgent(deviceId));
|
||||
}
|
||||
|
||||
private static String str(Map<String, Object> body, String key) {
|
||||
if (body == null || body.get(key) == null) {
|
||||
return null;
|
||||
}
|
||||
String v = String.valueOf(body.get(key)).trim();
|
||||
return v.isEmpty() || "null".equalsIgnoreCase(v) ? null : v;
|
||||
}
|
||||
|
||||
private static Boolean bool(Object v) {
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
if (v instanceof Boolean) {
|
||||
return (Boolean) v;
|
||||
}
|
||||
return Boolean.parseBoolean(String.valueOf(v));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.jeecg.modules.xslmes.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
/**
|
||||
* MES 开炼机动作接收表(采集自 MCSToMES_Act_Mill)
|
||||
*/
|
||||
@Data
|
||||
@TableName("mes_xsl_mill_action")
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(description = "MES开炼机动作接收表")
|
||||
public class MesXslMillAction implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
@Excel(name = "GUID", width = 36)
|
||||
@Schema(description = "源表GUID")
|
||||
private String guid;
|
||||
|
||||
@Excel(name = "动作地址", width = 10)
|
||||
@Schema(description = "动作地址")
|
||||
private Integer actAddr;
|
||||
|
||||
@Excel(name = "动作名称", width = 20)
|
||||
@Schema(description = "动作名称")
|
||||
private String actName;
|
||||
|
||||
@Excel(name = "动作名称(英)", width = 20)
|
||||
@Schema(description = "动作名称(英)")
|
||||
private String actNameEn;
|
||||
|
||||
@Excel(name = "动作备注", width = 15)
|
||||
@Schema(description = "动作备注")
|
||||
private String actMemo;
|
||||
|
||||
@Excel(name = "动作关联地址", width = 12)
|
||||
@Schema(description = "动作关联地址")
|
||||
private Integer actRepaddr;
|
||||
|
||||
@Excel(name = "写入时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "写入时间")
|
||||
private Date writeTime;
|
||||
|
||||
@Excel(name = "读取时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "读取时间")
|
||||
private Date readTime;
|
||||
|
||||
@Excel(name = "读写标识", width = 10)
|
||||
@Schema(description = "读写标识")
|
||||
private Integer rwFlag;
|
||||
|
||||
private Integer tenantId;
|
||||
private String sysOrgCode;
|
||||
private String createBy;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
private Integer delFlag;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jeecg.modules.xslmes.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
|
||||
public interface MesXslMillActionMapper extends BaseMapper<MesXslMillAction> {}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentCommandService;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentResult;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSession;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSessionRegistry;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 经桌面端代理访问设备库。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DesktopAgentMcsDataAccess implements IMcsDataAccess {
|
||||
|
||||
private final DeviceAgentCommandService commandService;
|
||||
private final DeviceAgentSessionRegistry sessionRegistry;
|
||||
private final McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Override
|
||||
public boolean isAgentMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveAgentDeviceId() {
|
||||
MesXslMcsDbConfig cfg = mcsDataSourceManager.getCachedConfig();
|
||||
String preferred = cfg == null ? null : cfg.getAgentDeviceId();
|
||||
DeviceAgentSession session = sessionRegistry.pickOnlineAgent(preferred);
|
||||
if (session == null) {
|
||||
throw new IllegalStateException("无在线桌面设备代理,无法访问设备库");
|
||||
}
|
||||
return session.getDeviceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> query(String sql, List<Object> params) {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
DeviceAgentResult result = commandService.query(deviceId, sql, params, 60_000);
|
||||
return result.getRows() == null ? List.of() : result.getRows();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(String sql, List<Object> params) {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
DeviceAgentResult result = commandService.write(deviceId, sql, params, 60_000);
|
||||
return result.getAffected() == null ? 0 : result.getAffected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("mode", StringUtils.defaultIfBlank(mode, "insert"));
|
||||
if (keys != null) {
|
||||
payload.put("keys", keys);
|
||||
}
|
||||
payload.put("rows", rows == null ? new ArrayList<>() : rows);
|
||||
DeviceAgentResult result = commandService.syncPush(deviceId, table, payload, 60_000);
|
||||
return result.getAffected() == null ? 0 : result.getAffected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection() {
|
||||
try {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
DeviceAgentResult result = commandService.test(deviceId, 10_000);
|
||||
return result != null && result.isSuccess();
|
||||
} catch (Exception e) {
|
||||
log.warn("桌面代理中间库测试失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 服务端直连 SQL Server(调试/兼容保留)。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DirectJdbcMcsDataAccess implements IMcsDataAccess {
|
||||
|
||||
private final DataSource dataSource;
|
||||
private final McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Override
|
||||
public boolean isAgentMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveAgentDeviceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> query(String sql, List<Object> params) {
|
||||
JdbcTemplate jt = new JdbcTemplate(requireDs());
|
||||
if (params == null || params.isEmpty()) {
|
||||
return jt.queryForList(sql);
|
||||
}
|
||||
return jt.queryForList(sql, params.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(String sql, List<Object> params) {
|
||||
JdbcTemplate jt = new JdbcTemplate(requireDs());
|
||||
if (params == null || params.isEmpty()) {
|
||||
return jt.update(sql);
|
||||
}
|
||||
return jt.update(sql, params.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int affected = 0;
|
||||
for (Map<String, Object> row : rows) {
|
||||
if ("update".equalsIgnoreCase(mode) || "upsert".equalsIgnoreCase(mode)) {
|
||||
int u = updateByKeys(table, keys, row);
|
||||
if (u > 0) {
|
||||
affected += u;
|
||||
continue;
|
||||
}
|
||||
if ("update".equalsIgnoreCase(mode)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
affected += insertRow(table, row);
|
||||
}
|
||||
return affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection() {
|
||||
try {
|
||||
query("SELECT 1", null);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.warn("直连中间库测试失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int insertRow(String table, Map<String, Object> row) {
|
||||
List<String> cols = new ArrayList<>(row.keySet());
|
||||
StringBuilder sql = new StringBuilder("INSERT INTO [").append(table).append("] (");
|
||||
StringBuilder values = new StringBuilder(" VALUES (");
|
||||
List<Object> params = new ArrayList<>();
|
||||
for (int i = 0; i < cols.size(); i++) {
|
||||
if (i > 0) {
|
||||
sql.append(',');
|
||||
values.append(',');
|
||||
}
|
||||
sql.append('[').append(cols.get(i)).append(']');
|
||||
values.append('?');
|
||||
params.add(row.get(cols.get(i)));
|
||||
}
|
||||
sql.append(')').append(values).append(')');
|
||||
return execute(sql.toString(), params);
|
||||
}
|
||||
|
||||
private int updateByKeys(String table, List<String> keys, Map<String, Object> row) {
|
||||
if (keys == null || keys.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
List<String> setCols = new ArrayList<>();
|
||||
for (String c : row.keySet()) {
|
||||
boolean isKey = keys.stream().anyMatch(k -> k.equalsIgnoreCase(c));
|
||||
if (!isKey) {
|
||||
setCols.add(c);
|
||||
}
|
||||
}
|
||||
if (setCols.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
StringBuilder sql = new StringBuilder("UPDATE [").append(table).append("] SET ");
|
||||
List<Object> params = new ArrayList<>();
|
||||
for (int i = 0; i < setCols.size(); i++) {
|
||||
if (i > 0) {
|
||||
sql.append(',');
|
||||
}
|
||||
sql.append('[').append(setCols.get(i)).append("]=?");
|
||||
params.add(getIgnoreCase(row, setCols.get(i)));
|
||||
}
|
||||
sql.append(" WHERE ");
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
if (i > 0) {
|
||||
sql.append(" AND ");
|
||||
}
|
||||
sql.append('[').append(keys.get(i)).append("]=?");
|
||||
params.add(getIgnoreCase(row, keys.get(i)));
|
||||
}
|
||||
return execute(sql.toString(), params);
|
||||
}
|
||||
|
||||
private Object getIgnoreCase(Map<String, Object> row, String key) {
|
||||
if (row.containsKey(key)) {
|
||||
return row.get(key);
|
||||
}
|
||||
for (Map.Entry<String, Object> e : row.entrySet()) {
|
||||
if (e.getKey() != null && e.getKey().equalsIgnoreCase(key)) {
|
||||
return e.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataSource requireDs() {
|
||||
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
|
||||
DataSource src = routing.getDataSources().get(McsDataSourceManager.DS_KEY);
|
||||
if (src == null) {
|
||||
throw new IllegalStateException("中间库数据源 " + McsDataSourceManager.DS_KEY + " 未注册");
|
||||
}
|
||||
return src;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MCS 中间库访问抽象:直连 JDBC 或经桌面代理。
|
||||
*/
|
||||
public interface IMcsDataAccess {
|
||||
|
||||
boolean isAgentMode();
|
||||
|
||||
String resolveAgentDeviceId();
|
||||
|
||||
List<Map<String, Object>> query(String sql, List<Object> params);
|
||||
|
||||
int execute(String sql, List<Object> params);
|
||||
|
||||
/**
|
||||
* 批量写入中间表(EQ_SYNC_PUSH)。
|
||||
*
|
||||
* @param table 白名单表名
|
||||
* @param mode insert / update / upsert
|
||||
* @param keys 匹配键(update/upsert)
|
||||
* @param rows 行数据
|
||||
* @return 影响行数
|
||||
*/
|
||||
int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows);
|
||||
|
||||
boolean testConnection();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 按配置在「桌面代理 / 直连」之间切换。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class McsDataAccessFacade implements IMcsDataAccess {
|
||||
|
||||
public static final String MODE_DESKTOP_AGENT = "DESKTOP_AGENT";
|
||||
public static final String MODE_DIRECT = "DIRECT";
|
||||
|
||||
private final McsDataSourceManager mcsDataSourceManager;
|
||||
private final DesktopAgentMcsDataAccess desktopAgentMcsDataAccess;
|
||||
private final DirectJdbcMcsDataAccess directJdbcMcsDataAccess;
|
||||
|
||||
public IMcsDataAccess current() {
|
||||
return isAgentMode() ? desktopAgentMcsDataAccess : directJdbcMcsDataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAgentMode() {
|
||||
MesXslMcsDbConfig cfg = mcsDataSourceManager.getCachedConfig();
|
||||
if (cfg == null) {
|
||||
// 默认优先桌面代理
|
||||
return true;
|
||||
}
|
||||
String mode = StringUtils.defaultIfBlank(cfg.getAccessMode(), MODE_DESKTOP_AGENT).trim().toUpperCase();
|
||||
return MODE_DESKTOP_AGENT.equals(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveAgentDeviceId() {
|
||||
return current().resolveAgentDeviceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> query(String sql, List<Object> params) {
|
||||
return current().query(sql, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(String sql, List<Object> params) {
|
||||
return current().execute(sql, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
return current().pushRows(table, mode, keys, rows);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection() {
|
||||
return current().testConnection();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MES → MCS 经桌面代理下发(EQ_SYNC_PUSH)。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MesToMcsPushService {
|
||||
|
||||
private final McsDataAccessFacade mcsDataAccessFacade;
|
||||
|
||||
public int push(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
if (StringUtils.isBlank(table)) {
|
||||
throw new IllegalArgumentException("table 不能为空");
|
||||
}
|
||||
int affected = mcsDataAccessFacade.pushRows(table, mode, keys, rows);
|
||||
log.info("MES→MCS 下发完成 table={} mode={} rows={} affected={}",
|
||||
table, mode, rows == null ? 0 : rows.size(), affected);
|
||||
return affected;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLClientInfoException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Struct;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class AgentProxyConnection implements Connection {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
private boolean closed;
|
||||
|
||||
public AgentProxyConnection(IMcsDataAccess dataAccess) {
|
||||
this.dataAccess = dataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement() {
|
||||
return new AgentProxyStatement(dataAccess, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql) {
|
||||
return new AgentProxyPreparedStatement(dataAccess, sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String sql) throws SQLException {
|
||||
throw new SQLException("CallableStatement not supported by agent proxy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nativeSQL(String sql) {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoCommit(boolean autoCommit) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAutoCommit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatabaseMetaData getMetaData() throws SQLException {
|
||||
throw new SQLException("DatabaseMetaData not supported by agent proxy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCatalog(String catalog) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCatalog() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransactionIsolation(int level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransactionIsolation() {
|
||||
return Connection.TRANSACTION_READ_COMMITTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency) {
|
||||
return createStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
|
||||
throw new SQLException("CallableStatement not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Class<?>> getTypeMap() {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTypeMap(Map<String, Class<?>> map) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHoldability(int holdability) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHoldability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Savepoint setSavepoint() throws SQLException {
|
||||
throw new SQLException("Savepoint not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Savepoint setSavepoint(String name) throws SQLException {
|
||||
throw new SQLException("Savepoint not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(Savepoint savepoint) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSavepoint(Savepoint savepoint) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
|
||||
return createStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||
throw new SQLException("CallableStatement not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clob createClob() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob createBlob() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLXML createSQLXML() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int timeout) {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInfo(String name, String value) throws SQLClientInfoException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInfo(Properties properties) throws SQLClientInfoException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientInfo(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getClientInfo() {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSchema(String schema) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSchema() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort(Executor executor) {
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetworkTimeout(Executor executor, int milliseconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNetworkTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
if (iface.isInstance(this)) {
|
||||
return iface.cast(this);
|
||||
}
|
||||
throw new SQLException("Not a wrapper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return iface.isInstance(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 将 JDBC 调用转发到桌面设备代理的 DataSource,供 @DS("sqlserver_mcs") 复用。
|
||||
*/
|
||||
public class AgentProxyDataSource implements DataSource {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
|
||||
public AgentProxyDataSource(IMcsDataAccess dataAccess) {
|
||||
this.dataAccess = dataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return new AgentProxyConnection(dataAccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String username, String password) {
|
||||
return getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
if (iface.isInstance(this)) {
|
||||
return iface.cast(this);
|
||||
}
|
||||
throw new SQLException("Not a wrapper for " + iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return iface.isInstance(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,565 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.NClob;
|
||||
import java.sql.ParameterMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AgentProxyPreparedStatement implements PreparedStatement {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
private final String sql;
|
||||
private final List<Object> params = new ArrayList<>();
|
||||
private ResultSet currentRs;
|
||||
private int updateCount = -1;
|
||||
|
||||
public AgentProxyPreparedStatement(IMcsDataAccess dataAccess, String sql) {
|
||||
this.dataAccess = dataAccess;
|
||||
this.sql = sql;
|
||||
ensureCapacity(16);
|
||||
}
|
||||
|
||||
private void ensureCapacity(int index1Based) {
|
||||
while (params.size() < index1Based) {
|
||||
params.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void setParam(int parameterIndex, Object value) {
|
||||
ensureCapacity(parameterIndex);
|
||||
params.set(parameterIndex - 1, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery() throws SQLException {
|
||||
try {
|
||||
List<Map<String, Object>> rows = dataAccess.query(sql, new ArrayList<>(params));
|
||||
currentRs = new MapListResultSet(rows);
|
||||
updateCount = -1;
|
||||
return currentRs;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() throws SQLException {
|
||||
try {
|
||||
updateCount = dataAccess.execute(sql, new ArrayList<>(params));
|
||||
currentRs = null;
|
||||
return updateCount;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute() throws SQLException {
|
||||
String trimmed = sql == null ? "" : sql.trim();
|
||||
if (trimmed.regionMatches(true, 0, "SELECT", 0, 6)) {
|
||||
executeQuery();
|
||||
return true;
|
||||
}
|
||||
executeUpdate();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(int parameterIndex, int sqlType) {
|
||||
setParam(parameterIndex, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoolean(int parameterIndex, boolean x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setByte(int parameterIndex, byte x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShort(int parameterIndex, short x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInt(int parameterIndex, int x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLong(int parameterIndex, long x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloat(int parameterIndex, float x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDouble(int parameterIndex, double x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setString(int parameterIndex, String x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBytes(int parameterIndex, byte[] x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLException("setAsciiStream not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParameters() {
|
||||
params.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRef(int parameterIndex, Ref x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, Blob x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Clob x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArray(int parameterIndex, Array x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetMetaData getMetaData() {
|
||||
return currentRs == null ? null : safeMeta();
|
||||
}
|
||||
|
||||
private ResultSetMetaData safeMeta() {
|
||||
try {
|
||||
return currentRs.getMetaData();
|
||||
} catch (SQLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(int parameterIndex, int sqlType, String typeName) {
|
||||
setParam(parameterIndex, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setURL(int parameterIndex, URL x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterMetaData getParameterMetaData() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRowId(int parameterIndex, RowId x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNString(int parameterIndex, String value) {
|
||||
setParam(parameterIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, NClob value) {
|
||||
setParam(parameterIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSQLXML(int parameterIndex, SQLXML xmlObject) {
|
||||
setParam(parameterIndex, xmlObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
// Statement methods
|
||||
@Override
|
||||
public ResultSet executeQuery(String sql) throws SQLException {
|
||||
throw new SQLException("use executeQuery()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql) throws SQLException {
|
||||
throw new SQLException("use executeUpdate()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
currentRs = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxFieldSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFieldSize(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEscapeProcessing(boolean enable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorName(String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
throw new SQLException("use execute()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet() {
|
||||
return currentRs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchDirection(int direction) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchDirection() {
|
||||
return ResultSet.FETCH_FORWARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(int rows) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetConcurrency() {
|
||||
return ResultSet.CONCUR_READ_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetType() {
|
||||
return ResultSet.TYPE_FORWARD_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(String sql) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBatch() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults(int current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getGeneratedKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, String[] columnNames) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetHoldability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPoolable(boolean poolable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOnCompletion() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCloseOnCompletion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
throw new SQLException("not a wrapper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AgentProxyStatement implements Statement {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
private ResultSet currentRs;
|
||||
private int updateCount = -1;
|
||||
|
||||
public AgentProxyStatement(IMcsDataAccess dataAccess, String ignored) {
|
||||
this.dataAccess = dataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery(String sql) throws SQLException {
|
||||
try {
|
||||
List<Map<String, Object>> rows = dataAccess.query(sql, new ArrayList<>());
|
||||
currentRs = new MapListResultSet(rows);
|
||||
updateCount = -1;
|
||||
return currentRs;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql) throws SQLException {
|
||||
try {
|
||||
updateCount = dataAccess.execute(sql, new ArrayList<>());
|
||||
currentRs = null;
|
||||
return updateCount;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
currentRs = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxFieldSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFieldSize(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEscapeProcessing(boolean enable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorName(String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
String trimmed = sql == null ? "" : sql.trim();
|
||||
if (trimmed.regionMatches(true, 0, "SELECT", 0, 6)) {
|
||||
executeQuery(sql);
|
||||
return true;
|
||||
}
|
||||
executeUpdate(sql);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet() {
|
||||
return currentRs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchDirection(int direction) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchDirection() {
|
||||
return ResultSet.FETCH_FORWARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(int rows) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetConcurrency() {
|
||||
return ResultSet.CONCUR_READ_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetType() {
|
||||
return ResultSet.TYPE_FORWARD_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(String sql) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBatch() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults(int current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getGeneratedKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, String[] columnNames) throws SQLException {
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetHoldability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPoolable(boolean poolable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOnCompletion() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCloseOnCompletion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
throw new SQLException("not a wrapper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
package org.jeecg.modules.xslmes.mcs.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.xslmes.mcs.util.McsQueryHelper;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import org.jeecg.modules.xslmes.mcs.service.IMcsToMesActMillService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库 MCSToMES_Act_Mill)
|
||||
*/
|
||||
@Tag(name = "开炼机动作(中间库)")
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/mcs/mcsToMesActMill")
|
||||
@Slf4j
|
||||
public class McsToMesActMillController extends JeecgController<McsToMesActMill, IMcsToMesActMillService> {
|
||||
|
||||
@Autowired
|
||||
private IMcsToMesActMillService mcsToMesActMillService;
|
||||
|
||||
@Operation(summary = "开炼机动作(中间库)-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<IPage<McsToMesActMill>> queryPageList(McsToMesActMill mcsToMesActMill,
|
||||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<McsToMesActMill> queryWrapper = McsQueryHelper.buildWrapper(mcsToMesActMill, req.getParameterMap());
|
||||
Page<McsToMesActMill> page = new Page<>(pageNo, pageSize);
|
||||
IPage<McsToMesActMill> pageList = mcsToMesActMillService.page(page, queryWrapper);
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
@Operation(summary = "开炼机动作(中间库)-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<McsToMesActMill> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
McsToMesActMill entity = mcsToMesActMillService.getById(id);
|
||||
if (entity == null) {
|
||||
return Result.error("未找到对应数据");
|
||||
}
|
||||
return Result.OK(entity);
|
||||
}
|
||||
|
||||
@RequiresPermissions("xslmes:mcsToMesActMill:exportXls")
|
||||
@RequestMapping(value = "/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, McsToMesActMill mcsToMesActMill) {
|
||||
return super.exportXls(request, mcsToMesActMill, McsToMesActMill.class, "开炼机动作(中间库)");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.jeecg.modules.xslmes.mcs.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.xslmes.mcs.access.MesToMcsPushService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MES → MCS 经桌面代理下发。
|
||||
*/
|
||||
@Tag(name = "MES上辅机下发")
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/mcs/push")
|
||||
@RequiredArgsConstructor
|
||||
public class MesToMcsPushController {
|
||||
|
||||
private final MesToMcsPushService mesToMcsPushService;
|
||||
|
||||
@Operation(summary = "经桌面代理写入中间表")
|
||||
@PostMapping("/rows")
|
||||
@SuppressWarnings("unchecked")
|
||||
public Result<Map<String, Object>> pushRows(@RequestBody Map<String, Object> body) {
|
||||
String table = body == null ? null : String.valueOf(body.getOrDefault("table", ""));
|
||||
String mode = body == null ? "insert" : String.valueOf(body.getOrDefault("mode", "insert"));
|
||||
List<String> keys = body == null ? null : (List<String>) body.get("keys");
|
||||
List<Map<String, Object>> rows = body == null ? null : (List<Map<String, Object>>) body.get("rows");
|
||||
int affected = mesToMcsPushService.push(table, mode, keys, rows);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("affected", affected);
|
||||
return Result.OK(data);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,9 @@ public class MesXslMcsDbConfigController {
|
||||
@Autowired
|
||||
private McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Autowired
|
||||
private org.jeecg.modules.device.sync.agent.DeviceAgentSessionRegistry agentSessionRegistry;
|
||||
|
||||
private Integer resolveTenantId(Integer tenantId) {
|
||||
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||
if (tenantId == null) {
|
||||
@@ -75,11 +78,21 @@ public class MesXslMcsDbConfigController {
|
||||
data.put("dbConfigActive", mcsDataSourceManager.isDbConfigActive());
|
||||
data.put("readEnabled", mcsDataSourceManager.isReadEnabled());
|
||||
data.put("writeEnabled", mcsDataSourceManager.isWriteEnabled());
|
||||
boolean agentMode = mcsDataSourceManager.isDesktopAgentMode();
|
||||
data.put("accessMode", agentMode ? "DESKTOP_AGENT" : "DIRECT");
|
||||
data.put("agentMode", agentMode);
|
||||
if (cfg != null) {
|
||||
data.put("serverHost", cfg.getServerHost());
|
||||
data.put("serverPort", cfg.getServerPort());
|
||||
data.put("dbName", cfg.getDbName());
|
||||
data.put("agentDeviceId", cfg.getAgentDeviceId());
|
||||
}
|
||||
var agent = agentSessionRegistry.pickOnlineAgent(cfg == null ? null : cfg.getAgentDeviceId());
|
||||
data.put("agentOnline", agent != null && agent.isOnline());
|
||||
data.put("agentDbConnected", agent != null && agent.isDbConnected());
|
||||
data.put("agentHostName", agent == null ? null : agent.getHostName());
|
||||
data.put("agentDbMessage", agent == null ? null : agent.getDbMessage());
|
||||
data.put("agentLastSeenAt", agent == null ? null : agent.getLastSeenAt());
|
||||
return Result.OK(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jeecg.common.util.dynamic.db.DataSourceCachePool;
|
||||
import org.jeecg.modules.system.util.SecurityUtil;
|
||||
import org.jeecg.modules.xslmes.mcs.access.DesktopAgentMcsDataAccess;
|
||||
import org.jeecg.modules.xslmes.mcs.access.McsDataAccessFacade;
|
||||
import org.jeecg.modules.xslmes.mcs.access.proxy.AgentProxyDataSource;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -37,6 +41,9 @@ public class McsDataSourceManager {
|
||||
@Autowired
|
||||
private DruidDataSourceCreator dataSourceCreator;
|
||||
|
||||
@Autowired
|
||||
private ObjectProvider<DesktopAgentMcsDataAccess> desktopAgentMcsDataAccessProvider;
|
||||
|
||||
@Value("${spring.datasource.dynamic.datasource.sqlserver_mcs.url:}")
|
||||
private String ymlUrl;
|
||||
|
||||
@@ -98,6 +105,17 @@ public class McsDataSourceManager {
|
||||
}
|
||||
if (Integer.valueOf(1).equals(config.getStatus())) {
|
||||
try {
|
||||
if (isDesktopAgentMode(config)) {
|
||||
DesktopAgentMcsDataAccess agent = desktopAgentMcsDataAccessProvider.getIfAvailable();
|
||||
if (agent == null) {
|
||||
throw new IllegalStateException("桌面代理访问组件未就绪");
|
||||
}
|
||||
routing.addDataSource(DS_KEY, new AgentProxyDataSource(agent));
|
||||
cachedConfig.set(config);
|
||||
log.info("[MCS中间库] 已切换为桌面代理模式 sqlserver_mcs -> AgentProxy, deviceId={}",
|
||||
config.getAgentDeviceId());
|
||||
return;
|
||||
}
|
||||
String plainPassword = decryptPassword(config.getDbPassword());
|
||||
DataSourceProperty property = buildDataSourceProperty(config, plainPassword);
|
||||
DataSource mcsDs = dataSourceCreator.createDataSource(property);
|
||||
@@ -117,6 +135,21 @@ public class McsDataSourceManager {
|
||||
log.info("[MCS中间库] 连接未启用,读写开关仍按页面配置生效");
|
||||
}
|
||||
|
||||
public boolean isDesktopAgentMode(MesXslMcsDbConfig config) {
|
||||
MesXslMcsDbConfig cfg = config != null ? config : cachedConfig.get();
|
||||
if (cfg == null) {
|
||||
return true;
|
||||
}
|
||||
String mode = StringUtils.isBlank(cfg.getAccessMode())
|
||||
? McsDataAccessFacade.MODE_DESKTOP_AGENT
|
||||
: cfg.getAccessMode().trim().toUpperCase();
|
||||
return McsDataAccessFacade.MODE_DESKTOP_AGENT.equals(mode);
|
||||
}
|
||||
|
||||
public boolean isDesktopAgentMode() {
|
||||
return isDesktopAgentMode(null);
|
||||
}
|
||||
|
||||
private void closeAndRemoveDataSource(DynamicRoutingDataSource routing) {
|
||||
if (!routing.getDataSources().containsKey(DS_KEY)) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.jeecg.modules.xslmes.mcs.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库 MCSToMES_Act_Mill)
|
||||
*/
|
||||
@Data
|
||||
@TableName("MCSToMES_Act_Mill")
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(description = "开炼机动作(中间库)")
|
||||
public class McsToMesActMill implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "GUID", type = IdType.INPUT)
|
||||
@Schema(description = "GUID")
|
||||
@Excel(name = "GUID", width = 36)
|
||||
private String guid;
|
||||
|
||||
@Excel(name = "动作地址", width = 10)
|
||||
@Schema(description = "动作地址")
|
||||
@TableField("act_addr")
|
||||
private Integer actAddr;
|
||||
|
||||
@Excel(name = "动作名称", width = 20)
|
||||
@Schema(description = "动作名称")
|
||||
@TableField("act_name")
|
||||
private String actName;
|
||||
|
||||
@Excel(name = "动作名称(英)", width = 20)
|
||||
@Schema(description = "动作名称(英)")
|
||||
@TableField("act_name_en")
|
||||
private String actNameEn;
|
||||
|
||||
@Excel(name = "动作备注", width = 15)
|
||||
@Schema(description = "动作备注")
|
||||
@TableField("act_memo")
|
||||
private String actMemo;
|
||||
|
||||
@Excel(name = "动作关联地址", width = 12)
|
||||
@Schema(description = "动作关联地址")
|
||||
@TableField("act_Repaddr")
|
||||
private Integer actRepaddr;
|
||||
|
||||
@Excel(name = "写入时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "写入时间")
|
||||
@TableField("WriteTime")
|
||||
private Date writeTime;
|
||||
|
||||
@Excel(name = "读取时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "读取时间")
|
||||
@TableField("ReadTime")
|
||||
private Date readTime;
|
||||
|
||||
@Excel(name = "读写标识", width = 10)
|
||||
@Schema(description = "读写标识")
|
||||
@TableField("RW_Flag")
|
||||
private Integer rwFlag;
|
||||
}
|
||||
@@ -66,6 +66,14 @@ public class MesXslMcsDbConfig implements Serializable {
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
//update-begin---author:cursor ---date:2026-07-20 for:【设备库桥接】访问模式与绑定桌面代理-----------
|
||||
@Schema(description = "访问模式:DESKTOP_AGENT=桌面代理,DIRECT=服务端直连")
|
||||
private String accessMode;
|
||||
|
||||
@Schema(description = "绑定的桌面代理 deviceId")
|
||||
private String agentDeviceId;
|
||||
//update-end---author:cursor ---date:2026-07-20 for:【设备库桥接】访问模式与绑定桌面代理-----------
|
||||
|
||||
private String createBy;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jeecg.modules.xslmes.mcs.mapper;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库)
|
||||
*/
|
||||
public interface McsToMesActMillMapper extends BaseMapper<McsToMesActMill> {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jeecg.modules.xslmes.mcs.service;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库)
|
||||
*/
|
||||
public interface IMcsToMesActMillService extends IService<McsToMesActMill> {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jeecg.modules.xslmes.mcs.service.impl;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import org.jeecg.modules.xslmes.mcs.mapper.McsToMesActMillMapper;
|
||||
import org.jeecg.modules.xslmes.mcs.service.IMcsToMesActMillService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库)
|
||||
*/
|
||||
@Service
|
||||
@DS("sqlserver_mcs")
|
||||
public class McsToMesActMillServiceImpl extends ServiceImpl<McsToMesActMillMapper, McsToMesActMill> implements IMcsToMesActMillService {
|
||||
}
|
||||
@@ -30,6 +30,9 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
@Autowired
|
||||
private McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Autowired
|
||||
private org.jeecg.modules.xslmes.mcs.access.McsDataAccessFacade mcsDataAccessFacade;
|
||||
|
||||
@Override
|
||||
public MesXslMcsDbConfig getCurrentConfig(Integer tenantId) {
|
||||
int tid = tenantId != null ? tenantId : 0;
|
||||
@@ -61,10 +64,14 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
if (config == null) {
|
||||
return Result.error("配置不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(config.getServerHost())) {
|
||||
if (StringUtils.isBlank(config.getAccessMode())) {
|
||||
config.setAccessMode("DESKTOP_AGENT");
|
||||
}
|
||||
boolean agentMode = "DESKTOP_AGENT".equalsIgnoreCase(config.getAccessMode().trim());
|
||||
if (!agentMode && StringUtils.isBlank(config.getServerHost())) {
|
||||
return Result.error("服务器地址不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(config.getDbUsername())) {
|
||||
if (!agentMode && StringUtils.isBlank(config.getDbUsername())) {
|
||||
return Result.error("用户名不能为空");
|
||||
}
|
||||
if (config.getTenantId() == null) {
|
||||
@@ -93,14 +100,21 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
}
|
||||
|
||||
String plainPassword = resolvePlainPassword(config);
|
||||
if (StringUtils.isBlank(plainPassword)) {
|
||||
if (!agentMode && StringUtils.isBlank(plainPassword)) {
|
||||
return Result.error("密码不能为空");
|
||||
}
|
||||
|
||||
if (agentMode && StringUtils.isBlank(config.getServerHost())) {
|
||||
config.setServerHost("desktop-agent");
|
||||
}
|
||||
if (agentMode && StringUtils.isBlank(config.getDbUsername())) {
|
||||
config.setDbUsername("desktop-agent");
|
||||
}
|
||||
if (!agentMode) {
|
||||
String err = mcsDataSourceManager.testConnection(config, plainPassword);
|
||||
if (err != null && Integer.valueOf(1).equals(config.getStatus())) {
|
||||
return Result.error("连接测试失败:" + err);
|
||||
}
|
||||
}
|
||||
|
||||
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
String username = user != null ? user.getUsername() : "system";
|
||||
@@ -111,12 +125,16 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
if (old == null) {
|
||||
return Result.error("配置不存在");
|
||||
}
|
||||
if (StringUtils.isNotBlank(plainPassword)) {
|
||||
config.setDbPassword(mcsDataSourceManager.encryptPassword(plainPassword));
|
||||
} else {
|
||||
config.setDbPassword(old.getDbPassword());
|
||||
}
|
||||
config.setUpdateBy(username);
|
||||
config.setUpdateTime(now);
|
||||
updateById(config);
|
||||
} else {
|
||||
config.setDbPassword(mcsDataSourceManager.encryptPassword(plainPassword));
|
||||
config.setDbPassword(mcsDataSourceManager.encryptPassword(StringUtils.defaultString(plainPassword)));
|
||||
config.setCreateBy(username);
|
||||
config.setCreateTime(now);
|
||||
config.setUpdateBy(username);
|
||||
@@ -151,6 +169,14 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
if (config == null) {
|
||||
return Result.error("尚未配置中间库连接");
|
||||
}
|
||||
if (mcsDataSourceManager.isDesktopAgentMode(config)) {
|
||||
try {
|
||||
boolean ok = mcsDataAccessFacade.testConnection();
|
||||
return ok ? Result.OK("桌面代理设备库连接成功") : Result.error("桌面代理设备库连接失败(代理离线或库不可达)");
|
||||
} catch (Exception e) {
|
||||
return Result.error("桌面代理探测失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
String plainPassword = mcsDataSourceManager.decryptPassword(config.getDbPassword());
|
||||
String err = mcsDataSourceManager.testConnection(config, plainPassword);
|
||||
if (err == null) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.jeecg.modules.xslmes.mcs.sync;
|
||||
|
||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.xslmes.mcs.access.McsDataAccessFacade;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncField;
|
||||
@@ -69,6 +69,9 @@ public class GenericMcsSyncEngine {
|
||||
@Autowired
|
||||
private org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Autowired
|
||||
private McsDataAccessFacade mcsDataAccessFacade;
|
||||
|
||||
//update-begin---author:GHT ---date:20260617 for:【MES上辅机】采集模式 全量/时间/增量-----------
|
||||
public String sync(MesXslMcsSyncConfig cfg, List<MesXslMcsSyncField> fields) {
|
||||
String sourceTable = trim(cfg.getSourceTable());
|
||||
@@ -91,7 +94,6 @@ public class GenericMcsSyncEngine {
|
||||
}
|
||||
|
||||
String mode = StringUtils.isBlank(cfg.getSyncMode()) ? MODE_FULL : cfg.getSyncMode().trim().toUpperCase();
|
||||
JdbcTemplate sourceJt = new JdbcTemplate(getSourceDataSource());
|
||||
JdbcTemplate targetJt = new JdbcTemplate(dataSource);
|
||||
|
||||
// 目标表标准字段探测 + 自动填充列
|
||||
@@ -134,7 +136,7 @@ public class GenericMcsSyncEngine {
|
||||
String predicate = flagPredicate(flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue());
|
||||
String sql = "SELECT TOP " + limit + " " + colList(srcCols) + " FROM [" + sourceTable + "]"
|
||||
+ " WHERE (" + predicate + ")";
|
||||
rows = sourceJt.queryForList(sql);
|
||||
rows = mcsDataAccessFacade.query(sql, null);
|
||||
if (rows.isEmpty()) {
|
||||
return "增量采集:无待采集数据";
|
||||
}
|
||||
@@ -149,10 +151,10 @@ public class GenericMcsSyncEngine {
|
||||
sql.append(" AND [").append(incrCol).append("] < ?");
|
||||
args.add(window[1]);
|
||||
}
|
||||
rows = sourceJt.queryForList(sql.toString(), args.toArray());
|
||||
rows = mcsDataAccessFacade.query(sql.toString(), args);
|
||||
} else {
|
||||
// FULL
|
||||
rows = sourceJt.queryForList("SELECT " + colList(srcCols) + " FROM [" + sourceTable + "]");
|
||||
rows = mcsDataAccessFacade.query("SELECT " + colList(srcCols) + " FROM [" + sourceTable + "]", null);
|
||||
}
|
||||
|
||||
if (rows.isEmpty()) {
|
||||
@@ -209,7 +211,7 @@ public class GenericMcsSyncEngine {
|
||||
// INCR(标记回写):对本批所有源行回写标记值,下轮不再采集
|
||||
if (flagMode) {
|
||||
String writeValue = StringUtils.isBlank(cfg.getFlagWriteValue()) ? FLAG_SYNCED : cfg.getFlagWriteValue();
|
||||
int marked = writeBackFlag(sourceJt, sourceTable, flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue(), writeValue, keyMaps, rows);
|
||||
int marked = writeBackFlag(sourceTable, flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue(), writeValue, keyMaps, rows);
|
||||
return String.format("增量采集:新增%d,更新%d,未变%d,回写标记%d,源%d条",
|
||||
ins, upd, unchanged, marked, rows.size());
|
||||
}
|
||||
@@ -252,14 +254,14 @@ public class GenericMcsSyncEngine {
|
||||
* 避免误标在本轮 SELECT 之后才进入中间库、尚未采集的新数据;
|
||||
* 并以采集条件谓词做守卫,避开本轮已被其他进程改动的行。</p>
|
||||
*/
|
||||
private int writeBackFlag(JdbcTemplate sourceJt, String sourceTable, String flagCol, String condition,
|
||||
private int writeBackFlag(String sourceTable, String flagCol, String condition,
|
||||
String matchValue, String writeValue, List<MesXslMcsSyncField> keyMaps, List<Map<String, Object>> rows) {
|
||||
validateIdent(flagCol);
|
||||
StringBuilder sql = new StringBuilder("UPDATE [").append(sourceTable).append("] SET [")
|
||||
.append(flagCol).append("] = ? WHERE ");
|
||||
sql.append(keyMaps.stream().map(k -> "[" + k.getSourceField() + "] = ?").collect(Collectors.joining(" AND ")));
|
||||
sql.append(" AND (").append(flagPredicate(flagCol, condition, matchValue)).append(")");
|
||||
List<Object[]> argsList = new ArrayList<>();
|
||||
int total = 0;
|
||||
Set<String> handled = new HashSet<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
Map<String, Object> rci = ci(row);
|
||||
@@ -272,9 +274,9 @@ public class GenericMcsSyncEngine {
|
||||
for (MesXslMcsSyncField k : keyMaps) {
|
||||
args.add(rci.get(k.getSourceField()));
|
||||
}
|
||||
argsList.add(args.toArray());
|
||||
total += mcsDataAccessFacade.execute(sql.toString(), args);
|
||||
}
|
||||
return batch(sourceJt, sql.toString(), argsList);
|
||||
return total;
|
||||
}
|
||||
//update-end---author:GHT ---date:20260617 for:【MES上辅机】增量匹配改为标记位回写-----------
|
||||
|
||||
@@ -502,15 +504,6 @@ public class GenericMcsSyncEngine {
|
||||
return maps.stream().anyMatch(m -> m.getTargetField() != null && m.getTargetField().equalsIgnoreCase(targetCol));
|
||||
}
|
||||
|
||||
private DataSource getSourceDataSource() {
|
||||
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
|
||||
DataSource src = routing.getDataSources().get(McsDataSourceManager.DS_KEY);
|
||||
if (src == null) {
|
||||
throw new IllegalStateException("中间库数据源 " + McsDataSourceManager.DS_KEY + " 未注册");
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
private void validateIdent(String name) {
|
||||
if (name == null || !IDENT.matcher(name).matches()) {
|
||||
throw new IllegalArgumentException("非法的表名或字段名: " + name);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jeecg.modules.xslmes.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
|
||||
public interface IMesXslMillActionService extends IService<MesXslMillAction> {}
|
||||
@@ -7,7 +7,9 @@ public interface IMesXslMixerConditionService extends IService<MesXslMixerCondit
|
||||
|
||||
void fillEquipmentName(MesXslMixerCondition model);
|
||||
|
||||
boolean isConditionNameDuplicated(String conditionName, String excludeId);
|
||||
//update-begin---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称/代码按设备唯一-----------
|
||||
boolean isConditionNameDuplicated(String conditionName, String equipmentId, String excludeId);
|
||||
|
||||
boolean isConditionCodeDuplicated(String conditionCode, String excludeId);
|
||||
boolean isConditionCodeDuplicated(String conditionCode, String equipmentId, String excludeId);
|
||||
//update-end---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称/代码按设备唯一-----------
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -300,6 +301,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
//update-begin---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算-----------
|
||||
fillWeightPercent(line, weightBase);
|
||||
//update-end---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算-----------
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【配合示方】明细重量%/体积统一保留三位小数-----------
|
||||
normalizeLineDecimals(line);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【配合示方】明细重量%/体积统一保留三位小数-----------
|
||||
if (line.getCreateTime() == null) {
|
||||
line.setCreateTime(now);
|
||||
}
|
||||
@@ -339,7 +343,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
if (material == null || material.getSpecificGravity() == null || material.getSpecificGravity().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return;
|
||||
}
|
||||
line.setVolume(line.getPhr().divide(material.getSpecificGravity(), 6, RoundingMode.HALF_UP));
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【配合示方】明细体积保留三位小数-----------
|
||||
line.setVolume(line.getPhr().divide(material.getSpecificGravity(), 3, RoundingMode.HALF_UP));
|
||||
//update-end---author:jiangxh ---date:20260729 for:【配合示方】明细体积保留三位小数-----------
|
||||
}
|
||||
|
||||
private void fillWeightPercent(MesXslFormulaSpecLine line, BigDecimal totalPhr) {
|
||||
@@ -347,10 +353,27 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
if (line.getWeightPercent() != null || line.getPhr() == null || totalPhr == null || totalPhr.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return;
|
||||
}
|
||||
line.setWeightPercent(line.getPhr().multiply(BigDecimal.valueOf(100)).divide(totalPhr, 4, RoundingMode.HALF_UP));
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【配合示方】明细重量%/体积保留三位小数-----------
|
||||
line.setWeightPercent(line.getPhr().multiply(BigDecimal.valueOf(100)).divide(totalPhr, 3, RoundingMode.HALF_UP));
|
||||
//update-end---author:jiangxh ---date:20260729 for:【配合示方】明细重量%/体积保留三位小数-----------
|
||||
//update-end---author:cursor ---date:20260521 for:配合示方明细重量%按PHR/总PHR自动计算(可手工覆盖)-----------
|
||||
}
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【配合示方】明细重量%/体积统一保留三位小数-----------
|
||||
/** 明细重量%、体积统一四舍五入到三位小数(含手工录入值) */
|
||||
private void normalizeLineDecimals(MesXslFormulaSpecLine line) {
|
||||
if (line == null) {
|
||||
return;
|
||||
}
|
||||
if (line.getWeightPercent() != null) {
|
||||
line.setWeightPercent(line.getWeightPercent().setScale(3, RoundingMode.HALF_UP));
|
||||
}
|
||||
if (line.getVolume() != null) {
|
||||
line.setVolume(line.getVolume().setScale(3, RoundingMode.HALF_UP));
|
||||
}
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【配合示方】明细重量%/体积统一保留三位小数-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260521 for:【配合示方】保存后汇总A/Q胶比重写入数据库-----------
|
||||
/** 根据明细重新汇总主表 TOTAL PHR、A胶TOTAL PHR、比重与人工配料标记 */
|
||||
private void refreshMainSummary(String mainId) {
|
||||
@@ -457,7 +480,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
if (material == null || material.getSpecificGravity() == null || material.getSpecificGravity().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return null;
|
||||
}
|
||||
return line.getPhr().divide(material.getSpecificGravity(), 6, RoundingMode.HALF_UP);
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【配合示方】明细体积保留三位小数-----------
|
||||
return line.getPhr().divide(material.getSpecificGravity(), 3, RoundingMode.HALF_UP);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【配合示方】明细体积保留三位小数-----------
|
||||
}
|
||||
//update-end---author:cursor ---date:20260521 for:【配合示方】保存后汇总A/Q胶比重写入数据库-----------
|
||||
|
||||
@@ -540,7 +565,6 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
throw new IllegalArgumentException("请先维护混合段数");
|
||||
}
|
||||
String rubberName = resolveRubberName(main);
|
||||
String formulaCodeSuffix = resolveFormulaCodeSuffix(main);
|
||||
boolean hasQ = hasStepQ(main.getLineList());
|
||||
List<MesXslFormulaMixingGeneratePreviewItemVO> items = new ArrayList<>();
|
||||
int aIndex = 0;
|
||||
@@ -551,16 +575,24 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
item.setStageIndex(i);
|
||||
if (isQSegment) {
|
||||
item.setStepType("Q");
|
||||
item.setSpecCode(appendFormulaCodeSuffix("F" + rubberName, formulaCodeSuffix));
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】B/F匹配编号不拼版本后缀-----------
|
||||
item.setSpecCode(buildBfRubberSpecCode("F", rubberName));
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】B/F匹配编号不拼版本后缀-----------
|
||||
item.setASegmentIndex(null);
|
||||
} else {
|
||||
aIndex++;
|
||||
item.setStepType("A");
|
||||
item.setASegmentIndex(aIndex);
|
||||
item.setSpecCode(appendFormulaCodeSuffix("B" + aIndex + rubberName, formulaCodeSuffix));
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】B/F匹配编号不拼版本后缀-----------
|
||||
item.setSpecCode(buildBfRubberSpecCode("B" + aIndex, rubberName));
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】B/F匹配编号不拼版本后缀-----------
|
||||
}
|
||||
items.add(item);
|
||||
}
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】列表点生成混炼示方时即匹配胶料列表-----------
|
||||
// 点击「生成混炼示方」打开预览时即校验拼接示方编号是否已在胶料列表维护
|
||||
assertRequiredRubberMaterialsExist(toGenerateRowsFromPreviewItems(items), main, main.getLineList());
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】列表点生成混炼示方时即匹配胶料列表-----------
|
||||
MesXslFormulaMixingGeneratePreviewVO preview = new MesXslFormulaMixingGeneratePreviewVO();
|
||||
preview.setFormulaSpecId(formulaSpecId);
|
||||
preview.setRubberName(rubberName);
|
||||
@@ -598,10 +630,10 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
int created = 0;
|
||||
int totalStages = normalizeMixingStages(formula.getMixingStages());
|
||||
Date today = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||
Set<String> syncedRubberSpecCodes = new HashSet<>();
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【混炼示方生成】B/F胶料改为胶料列表匹配,不存在则提示先维护-----------
|
||||
Map<String, String> categoryIdCache = new HashMap<>();
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||
assertRequiredRubberMaterialsExist(request.getRows(), formula, lines);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【混炼示方生成】B/F胶料改为胶料列表匹配,不存在则提示先维护-----------
|
||||
for (MesXslFormulaMixingGenerateRowVO row : request.getRows()) {
|
||||
if (row == null || oConvertUtils.isEmpty(row.getSpecCode()) || row.getStageIndex() == null) {
|
||||
continue;
|
||||
@@ -609,11 +641,6 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
if (CollectionUtils.isEmpty(row.getMachines())) {
|
||||
throw new IllegalArgumentException("示方「" + row.getSpecCode() + "」请至少选择一个机台");
|
||||
}
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||
if (syncedRubberSpecCodes.add(row.getSpecCode().trim())) {
|
||||
syncGeneratedRubberMixerMaterial(row, formula, compoundSpecificGravity, categoryIdCache);
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||
String materialStep = resolveMixingMaterialStep(row);
|
||||
int mixingColumn = resolveMixingColumn(row, formula);
|
||||
List<MesXslMixingSpecMaterial> materials = buildMixingMaterials(
|
||||
@@ -647,11 +674,15 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积-----------
|
||||
mixing.setConvertFactor(BigDecimal.ONE);
|
||||
boolean isFinalStage = "Q".equalsIgnoreCase(row.getStepType());
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【混炼示方】母胶/终炼胶比重保留三位小数-----------
|
||||
if (isFinalStage) {
|
||||
mixing.setFinalRubberSg(compoundSpecificGravity);
|
||||
} else {
|
||||
mixing.setMotherRubberSg(formula.getARubberSg());
|
||||
if (compoundSpecificGravity != null) {
|
||||
mixing.setFinalRubberSg(compoundSpecificGravity.setScale(3, RoundingMode.HALF_UP));
|
||||
}
|
||||
} else if (formula.getARubberSg() != null) {
|
||||
mixing.setMotherRubberSg(formula.getARubberSg().setScale(3, RoundingMode.HALF_UP));
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【混炼示方】母胶/终炼胶比重保留三位小数-----------
|
||||
BigDecimal specificGravity = isFinalStage ? compoundSpecificGravity : formula.getARubberSg();
|
||||
String machineLabel = StringUtils.defaultIfBlank(machine.getMachineName(), machine.getMachineId());
|
||||
MesXslEquipmentLedger equipment = equipmentCache.computeIfAbsent(
|
||||
@@ -766,15 +797,88 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
.divide(effectiveVolume, 6, RoundingMode.HALF_UP)
|
||||
.multiply(BigDecimal.valueOf(100))
|
||||
.multiply(factor)
|
||||
.setScale(6, RoundingMode.HALF_UP);
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【混炼示方】填充体积保留两位小数-----------
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【混炼示方】填充体积保留两位小数-----------
|
||||
}
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260601 for:【XSLMES-20260601-A62】生成混炼示方改为同步B/F段胶至胶料信息-----------
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【混炼示方生成】B/F胶料改为胶料列表匹配,不存在则提示先维护-----------
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】预览项转生成行供胶料匹配校验-----------
|
||||
/** 预览行转为生成行结构,供胶料匹配校验复用 */
|
||||
private List<MesXslFormulaMixingGenerateRowVO> toGenerateRowsFromPreviewItems(
|
||||
List<MesXslFormulaMixingGeneratePreviewItemVO> items) {
|
||||
List<MesXslFormulaMixingGenerateRowVO> rows = new ArrayList<>();
|
||||
if (CollectionUtils.isEmpty(items)) {
|
||||
return rows;
|
||||
}
|
||||
for (MesXslFormulaMixingGeneratePreviewItemVO item : items) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
MesXslFormulaMixingGenerateRowVO row = new MesXslFormulaMixingGenerateRowVO();
|
||||
row.setSpecCode(item.getSpecCode());
|
||||
row.setStageIndex(item.getStageIndex());
|
||||
row.setASegmentIndex(item.getASegmentIndex());
|
||||
row.setStepType(item.getStepType());
|
||||
rows.add(row);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】预览项转生成行供胶料匹配校验-----------
|
||||
|
||||
/**
|
||||
* 生成混炼示方时,将 B 段/F 段胶料同步写入「胶料信息」(mes_material):
|
||||
* 除 ERP 编号留空、编码/名称为示方编号外,其余字段按配合示方所选原胶料信息赋值。
|
||||
* 生成前校验:按 B段序号/F + 胶料名 拼出的示方编号,必须已在胶料信息中存在;不再自动新建。
|
||||
* 在列表点击「生成混炼示方」预览时即调用,确认生成时再次校验。
|
||||
*/
|
||||
private void assertRequiredRubberMaterialsExist(
|
||||
List<MesXslFormulaMixingGenerateRowVO> rows,
|
||||
MesXslFormulaSpec formula,
|
||||
List<MesXslFormulaSpecLine> lines) {
|
||||
if (CollectionUtils.isEmpty(rows)) {
|
||||
return;
|
||||
}
|
||||
LinkedHashSet<String> requiredCodes = new LinkedHashSet<>();
|
||||
String rubberName = resolveRubberName(formula);
|
||||
for (MesXslFormulaMixingGenerateRowVO row : rows) {
|
||||
if (row == null || StringUtils.isBlank(row.getSpecCode())) {
|
||||
continue;
|
||||
}
|
||||
requiredCodes.add(row.getSpecCode().trim());
|
||||
String stepFilter = resolveMixingMaterialStep(row);
|
||||
int mixingColumn = resolveMixingColumn(row, formula);
|
||||
if ("Q".equalsIgnoreCase(stepFilter)) {
|
||||
int lastBSegment = resolveLastBSegmentIndex(formula, lines);
|
||||
if (lastBSegment > 0 && StringUtils.isNotBlank(rubberName)) {
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀-----------
|
||||
requiredCodes.add(buildBfRubberSpecCode("B" + lastBSegment, rubberName));
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀-----------
|
||||
}
|
||||
} else if (mixingColumn > 1 && StringUtils.isNotBlank(rubberName)) {
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀-----------
|
||||
requiredCodes.add(buildBfRubberSpecCode("B" + (mixingColumn - 1), rubberName));
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶匹配不拼版本后缀-----------
|
||||
}
|
||||
}
|
||||
List<String> missing = new ArrayList<>();
|
||||
for (String code : requiredCodes) {
|
||||
if (StringUtils.isBlank(code)) {
|
||||
continue;
|
||||
}
|
||||
if (findRubberMaterialByCodeOrName(code.trim()) == null) {
|
||||
missing.add(code.trim());
|
||||
}
|
||||
}
|
||||
if (!missing.isEmpty()) {
|
||||
throw new IllegalArgumentException("请先维护母胶和终胶信息:" + String.join("、", missing));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 已改为仅匹配胶料列表,保留方法避免历史调用编译缺口;生成流程不再自动写入胶料。
|
||||
*/
|
||||
@Deprecated
|
||||
private void syncGeneratedRubberMixerMaterial(
|
||||
MesXslFormulaMixingGenerateRowVO row,
|
||||
MesXslFormulaSpec formula,
|
||||
@@ -784,60 +888,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
return;
|
||||
}
|
||||
String specCode = row.getSpecCode().trim();
|
||||
boolean isFinalStage = "Q".equalsIgnoreCase(resolveMixingMaterialStep(row));
|
||||
String materialPhase = resolveGeneratedMaterialPhase(row);
|
||||
MesMaterial sourceRubber = resolveSourceRubberMaterial(formula);
|
||||
String categoryId = sourceRubber != null ? sourceRubber.getCategoryId() : null;
|
||||
String rubberName = resolveRubberName(formula);
|
||||
String generatedName = buildGeneratedRubberMaterialName(row, rubberName);
|
||||
MesMaterial existing = findGeneratedRubberMaterialByCodeOrName(specCode, materialPhase);
|
||||
Date now = new Date();
|
||||
if (existing != null) {
|
||||
copyGeneratedMaterialFieldsFromSource(existing, sourceRubber);
|
||||
if (StringUtils.isNotBlank(categoryId)) {
|
||||
existing.setCategoryId(categoryId);
|
||||
if (findRubberMaterialByCodeOrName(specCode) == null) {
|
||||
throw new IllegalArgumentException("请先维护母胶和终胶信息:" + specCode);
|
||||
}
|
||||
if (StringUtils.isBlank(existing.getMaterialCode())) {
|
||||
existing.setMaterialCode(specCode);
|
||||
}
|
||||
existing.setMaterialName(generatedName);
|
||||
if (StringUtils.isBlank(existing.getAliasName()) && StringUtils.isNotBlank(rubberName)) {
|
||||
existing.setAliasName(rubberName);
|
||||
}
|
||||
existing.setMaterialPhase(materialPhase);
|
||||
existing.setEnableFlag(existing.getEnableFlag() == null ? 1 : existing.getEnableFlag());
|
||||
existing.setUpdateTime(now);
|
||||
mesMaterialService.updateById(existing);
|
||||
log.info(
|
||||
"[混炼示方生成] 更新胶料信息 id={}, code={}, phase={}, categoryId={}, isFinal={}",
|
||||
existing.getId(),
|
||||
specCode,
|
||||
materialPhase,
|
||||
categoryId,
|
||||
isFinalStage);
|
||||
return;
|
||||
}
|
||||
|
||||
MesMaterial material = new MesMaterial();
|
||||
copyGeneratedMaterialFieldsFromSource(material, sourceRubber);
|
||||
material.setMaterialCode(specCode);
|
||||
material.setMaterialName(generatedName);
|
||||
material.setAliasName(StringUtils.isNotBlank(rubberName) ? rubberName : null);
|
||||
material.setCategoryId(categoryId);
|
||||
material.setMaterialPhase(materialPhase);
|
||||
material.setEnableFlag(1);
|
||||
material.setIsSpecialRubber(0);
|
||||
material.setDelFlag(CommonConstant.DEL_FLAG_0);
|
||||
material.setCreateTime(now);
|
||||
material.setUpdateTime(now);
|
||||
mesMaterialService.save(material);
|
||||
log.info(
|
||||
"[混炼示方生成] 新增胶料信息 id={}, code={}, phase={}, categoryId={}, isFinal={}",
|
||||
material.getId(),
|
||||
specCode,
|
||||
materialPhase,
|
||||
categoryId,
|
||||
isFinalStage);
|
||||
}
|
||||
|
||||
private void copyGeneratedMaterialFieldsFromSource(MesMaterial target, MesMaterial source) {
|
||||
@@ -867,6 +920,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
target.setLastErpSyncTime(source.getLastErpSyncTime());
|
||||
target.setRemark(source.getRemark());
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【混炼示方生成】B/F胶料改为胶料列表匹配,不存在则提示先维护-----------
|
||||
|
||||
private MesMaterial resolveSourceRubberMaterial(MesXslFormulaSpec formula) {
|
||||
if (formula == null || StringUtils.isBlank(formula.getRubberMaterialId())) {
|
||||
@@ -967,8 +1021,10 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
}
|
||||
|
||||
/**
|
||||
* 配合示方胶料代号/示方编号中,胶料名称之后的后缀原样截取(如 SA01、SB01 等,不做固定拼接)。
|
||||
* 配合示方胶料代号/示方编号中,胶料名称之后的后缀原样截取(如 SA01、SB01 等)。
|
||||
* @deprecated 生成混炼示方匹配胶料已改为仅 B/F+胶料名,不再拼接版本后缀
|
||||
*/
|
||||
@Deprecated
|
||||
private String resolveFormulaCodeSuffix(MesXslFormulaSpec main) {
|
||||
if (main == null) {
|
||||
return "";
|
||||
@@ -995,6 +1051,10 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 生成混炼示方匹配胶料已改为仅 B/F+胶料名,请使用 {@link #buildBfRubberSpecCode(String, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
private String appendFormulaCodeSuffix(String baseSpecCode, String formulaCodeSuffix) {
|
||||
if (StringUtils.isBlank(baseSpecCode)) {
|
||||
return baseSpecCode;
|
||||
@@ -1005,6 +1065,16 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
return baseSpecCode + formulaCodeSuffix;
|
||||
}
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】B/F匹配编号仅前缀+胶料名-----------
|
||||
/**
|
||||
* 生成/匹配用示方编号:仅「B{n}/F + 胶料名」,不拼接 SA01 等版本号。
|
||||
* 例:胶料 XC001 三段 → B1XC001、B2XC001、FXC001
|
||||
*/
|
||||
private String buildBfRubberSpecCode(String phasePrefix, String rubberName) {
|
||||
return StringUtils.defaultString(phasePrefix) + StringUtils.defaultString(rubberName).trim();
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】B/F匹配编号仅前缀+胶料名-----------
|
||||
|
||||
private boolean hasStepQ(List<MesXslFormulaSpecLine> lines) {
|
||||
if (CollectionUtils.isEmpty(lines)) {
|
||||
return false;
|
||||
@@ -1071,10 +1141,11 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
if ("Q".equals(stepFilter)) {
|
||||
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】F段加入最后一段B炼好胶料一条再加Q配合剂-----------
|
||||
String rubberName = resolveRubberName(formula);
|
||||
String codeSuffix = resolveFormulaCodeSuffix(formula);
|
||||
int lastBSegment = resolveLastBSegmentIndex(formula, lines);
|
||||
if (lastBSegment > 0) {
|
||||
String motherSpecCode = appendFormulaCodeSuffix("B" + lastBSegment + rubberName, codeSuffix);
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶编号不拼版本后缀-----------
|
||||
String motherSpecCode = buildBfRubberSpecCode("B" + lastBSegment, rubberName);
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶编号不拼版本后缀-----------
|
||||
BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, lastBSegment);
|
||||
materials.add(
|
||||
createMotherRubberMaterial(
|
||||
@@ -1095,7 +1166,6 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
}
|
||||
int bColumn = Math.max(stageIndex, 1);
|
||||
String rubberName = resolveRubberName(formula);
|
||||
String codeSuffix = resolveFormulaCodeSuffix(formula);
|
||||
if (bColumn <= 1) {
|
||||
appendBStageColumnAgents(lines, 1, materials, mixerCache, categoryNameCache, kindLookup);
|
||||
reindexMaterialSortNo(materials);
|
||||
@@ -1103,7 +1173,9 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
}
|
||||
// B2/B3…:上一段炼好胶料一条(如 B1+胶料名) + 本段列配合剂
|
||||
int prevB = bColumn - 1;
|
||||
String motherSpecCode = appendFormulaCodeSuffix("B" + prevB + rubberName, codeSuffix);
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶编号不拼版本后缀-----------
|
||||
String motherSpecCode = buildBfRubberSpecCode("B" + prevB, rubberName);
|
||||
//update-end---author:jiangxh ---date:20260730 for:【混炼示方生成】母胶编号不拼版本后缀-----------
|
||||
BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, prevB);
|
||||
materials.add(
|
||||
createMotherRubberMaterial(
|
||||
@@ -1205,7 +1277,7 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
//update-end---author:cursor ---date:20260601 for:【XSLMES-20260601-A62】上一段母胶明细行改绑胶料信息-----------
|
||||
}
|
||||
|
||||
/** 上一段 B 段胶尚未写入胶料信息时,按配合示方胶料类别补建一条胶料信息 */
|
||||
/** 上一段 B 段胶必须已在胶料信息中维护,不再自动补建 */
|
||||
private void ensureMotherRubberMaterialSynced(
|
||||
String motherSpecCode,
|
||||
MesXslFormulaSpec formula,
|
||||
@@ -1214,13 +1286,12 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
return;
|
||||
}
|
||||
String normalized = motherSpecCode.trim();
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【混炼示方生成】上一段母胶改为胶料列表匹配,不存在则提示-----------
|
||||
if (findRubberMaterialByCodeOrName(normalized) != null) {
|
||||
return;
|
||||
}
|
||||
MesXslFormulaMixingGenerateRowVO stub = new MesXslFormulaMixingGenerateRowVO();
|
||||
stub.setSpecCode(normalized);
|
||||
stub.setStepType("A");
|
||||
syncGeneratedRubberMixerMaterial(stub, formula, null, categoryIdCache);
|
||||
throw new IllegalArgumentException("请先维护母胶和终胶信息:" + normalized);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【混炼示方生成】上一段母胶改为胶料列表匹配,不存在则提示-----------
|
||||
}
|
||||
|
||||
/** 按密炼物料主数据回填混炼示方明细行(名称/大小类/种类) */
|
||||
@@ -1272,9 +1343,17 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
material.setMaterialMajor(null);
|
||||
material.setMaterialMinor(categoryName);
|
||||
material.setMixerMaterialId(rubber.getId());
|
||||
material.setMaterialKind(
|
||||
mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||
kindLookup, rubber.getCategoryId(), null, categoryName));
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【混炼示方生成】母胶行种类按配置解析,未命中则带入胶料兜底种类-----------
|
||||
String kind = mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||
kindLookup, rubber.getCategoryId(), null, categoryName);
|
||||
if (StringUtils.isBlank(kind) && kindLookup != null && StringUtils.isNotBlank(kindLookup.getRubberKindName())) {
|
||||
kind = kindLookup.getRubberKindName().trim();
|
||||
}
|
||||
if (StringUtils.isBlank(kind)) {
|
||||
kind = "胶料";
|
||||
}
|
||||
material.setMaterialKind(kind);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【混炼示方生成】母胶行种类按配置解析,未命中则带入胶料兜底种类-----------
|
||||
}
|
||||
|
||||
/** 未查到胶料信息时,按配合示方胶料类别从配置表解析种类 */
|
||||
@@ -1287,9 +1366,17 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
||||
String categoryName = resolveCategoryName(categoryId, categoryNameCache);
|
||||
material.setMaterialMajor(null);
|
||||
material.setMaterialMinor(categoryName);
|
||||
material.setMaterialKind(
|
||||
mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||
kindLookup, categoryId, null, categoryName));
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【混炼示方生成】母胶兜底种类带入胶料种类-----------
|
||||
String kind = mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||
kindLookup, categoryId, null, categoryName);
|
||||
if (StringUtils.isBlank(kind) && kindLookup != null && StringUtils.isNotBlank(kindLookup.getRubberKindName())) {
|
||||
kind = kindLookup.getRubberKindName().trim();
|
||||
}
|
||||
if (StringUtils.isBlank(kind)) {
|
||||
kind = "胶料";
|
||||
}
|
||||
material.setMaterialKind(kind);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【混炼示方生成】母胶兜底种类带入胶料种类-----------
|
||||
}
|
||||
//update-end---author:cursor ---date:20260601 for:【XSLMES-20260601-A62】母胶明细行按胶料信息回填-----------
|
||||
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A54】母炼胶明细行绑定已同步密炼物料主数据-----------
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jeecg.modules.xslmes.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
import org.jeecg.modules.xslmes.mapper.MesXslMillActionMapper;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMillActionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MesXslMillActionServiceImpl extends ServiceImpl<MesXslMillActionMapper, MesXslMillAction> implements IMesXslMillActionService {}
|
||||
@@ -18,13 +18,16 @@ public class MesXslMixerConditionServiceImpl
|
||||
|
||||
@Autowired private MesXslEquipmentLedgerMapper equipmentLedgerMapper;
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称/代码按设备唯一-----------
|
||||
@Override
|
||||
public boolean isConditionNameDuplicated(String conditionName, String excludeId) {
|
||||
if (StringUtils.isBlank(conditionName)) {
|
||||
public boolean isConditionNameDuplicated(String conditionName, String equipmentId, String excludeId) {
|
||||
if (StringUtils.isBlank(conditionName) || StringUtils.isBlank(equipmentId)) {
|
||||
return false;
|
||||
}
|
||||
LambdaQueryWrapper<MesXslMixerCondition> wrapper =
|
||||
new LambdaQueryWrapper<MesXslMixerCondition>().eq(MesXslMixerCondition::getConditionName, conditionName.trim());
|
||||
new LambdaQueryWrapper<MesXslMixerCondition>()
|
||||
.eq(MesXslMixerCondition::getEquipmentId, equipmentId.trim())
|
||||
.eq(MesXslMixerCondition::getConditionName, conditionName.trim());
|
||||
if (StringUtils.isNotBlank(excludeId)) {
|
||||
wrapper.ne(MesXslMixerCondition::getId, excludeId.trim());
|
||||
}
|
||||
@@ -32,17 +35,20 @@ public class MesXslMixerConditionServiceImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConditionCodeDuplicated(String conditionCode, String excludeId) {
|
||||
if (StringUtils.isBlank(conditionCode)) {
|
||||
public boolean isConditionCodeDuplicated(String conditionCode, String equipmentId, String excludeId) {
|
||||
if (StringUtils.isBlank(conditionCode) || StringUtils.isBlank(equipmentId)) {
|
||||
return false;
|
||||
}
|
||||
LambdaQueryWrapper<MesXslMixerCondition> wrapper =
|
||||
new LambdaQueryWrapper<MesXslMixerCondition>().eq(MesXslMixerCondition::getConditionCode, conditionCode.trim());
|
||||
new LambdaQueryWrapper<MesXslMixerCondition>()
|
||||
.eq(MesXslMixerCondition::getEquipmentId, equipmentId.trim())
|
||||
.eq(MesXslMixerCondition::getConditionCode, conditionCode.trim());
|
||||
if (StringUtils.isNotBlank(excludeId)) {
|
||||
wrapper.ne(MesXslMixerCondition::getId, excludeId.trim());
|
||||
}
|
||||
return this.count(wrapper) > 0;
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260728 for:【密炼机条件】条件名称/代码按设备唯一-----------
|
||||
|
||||
@Override
|
||||
public void fillEquipmentName(MesXslMixerCondition model) {
|
||||
|
||||
@@ -103,6 +103,8 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
|
||||
private void rebuildRawMaterialDemandPlan(List<MesXslMixingProductionPlan> savedPlans) {
|
||||
jdbcTemplate.update("DELETE FROM mes_xsl_raw_material_demand_plan");
|
||||
jdbcTemplate.update("DELETE FROM mes_xsl_auto_small_material_demand_plan");
|
||||
jdbcTemplate.update("DELETE FROM mes_xsl_manual_small_material_demand_plan");
|
||||
if (CollectionUtils.isEmpty(savedPlans)) {
|
||||
return;
|
||||
}
|
||||
@@ -184,6 +186,8 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
}
|
||||
|
||||
Map<String, RawDemandAggregate> aggregateMap = new HashMap<>();
|
||||
Map<String, SmallDemandAggregate> autoAggregateMap = new HashMap<>();
|
||||
Map<String, SmallDemandAggregate> manualAggregateMap = new HashMap<>();
|
||||
for (MesXslMixingProductionPlan plan : validPlans) {
|
||||
String specId = specIdByName.get(StringUtils.trimToEmpty(plan.getFormulaName()));
|
||||
if (StringUtils.isBlank(specId)) {
|
||||
@@ -241,19 +245,39 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
StringUtils.defaultString(erpCode),
|
||||
rawMaterialName));
|
||||
aggregate.demandWeight = aggregate.demandWeight.add(demandWeight);
|
||||
|
||||
String smallKey =
|
||||
String.join(
|
||||
"|",
|
||||
planDateKey,
|
||||
StringUtils.defaultString(plan.getMachineId()),
|
||||
StringUtils.defaultString(plan.getMachineName()),
|
||||
rawMaterialName);
|
||||
boolean isAutoKind = StringUtils.contains(StringUtils.trimToEmpty(detail.getMaterialKind()), "自动");
|
||||
Map<String, SmallDemandAggregate> targetSmallMap = isAutoKind ? autoAggregateMap : manualAggregateMap;
|
||||
SmallDemandAggregate smallAggregate =
|
||||
targetSmallMap.computeIfAbsent(
|
||||
smallKey,
|
||||
k ->
|
||||
new SmallDemandAggregate(
|
||||
plan.getPlanDate(),
|
||||
StringUtils.trimToNull(plan.getMachineId()),
|
||||
StringUtils.trimToNull(plan.getMachineName()),
|
||||
rawMaterialName));
|
||||
smallAggregate.demandWeight = smallAggregate.demandWeight.add(demandWeight);
|
||||
}
|
||||
}
|
||||
if (aggregateMap.isEmpty()) {
|
||||
if (aggregateMap.isEmpty() && autoAggregateMap.isEmpty() && manualAggregateMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Object[]> batchArgs = new ArrayList<>();
|
||||
List<Object[]> rawBatchArgs = new ArrayList<>();
|
||||
Date now = new Date();
|
||||
for (RawDemandAggregate aggregate : aggregateMap.values()) {
|
||||
if (aggregate.demandWeight.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
continue;
|
||||
}
|
||||
batchArgs.add(
|
||||
rawBatchArgs.add(
|
||||
new Object[] {
|
||||
IdWorker.getIdStr(),
|
||||
aggregate.machineId,
|
||||
@@ -270,14 +294,53 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
CommonConstant.DEL_FLAG_0
|
||||
});
|
||||
}
|
||||
if (batchArgs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!rawBatchArgs.isEmpty()) {
|
||||
jdbcTemplate.batchUpdate(
|
||||
"INSERT INTO mes_xsl_raw_material_demand_plan "
|
||||
+ "(id, machine_id, machine_name, material_id, erp_code, raw_material_name, demand_weight, standard_weight, actual_weight, plan_date, create_time, update_time, del_flag) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
batchArgs);
|
||||
rawBatchArgs);
|
||||
}
|
||||
|
||||
List<Object[]> autoBatchArgs = buildSmallDemandBatchArgs(autoAggregateMap, now);
|
||||
if (!autoBatchArgs.isEmpty()) {
|
||||
jdbcTemplate.batchUpdate(
|
||||
"INSERT INTO mes_xsl_auto_small_material_demand_plan "
|
||||
+ "(id, stat_date, machine_id, machine_name, raw_material_name, demand_weight, create_time, update_time, del_flag) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
autoBatchArgs);
|
||||
}
|
||||
List<Object[]> manualBatchArgs = buildSmallDemandBatchArgs(manualAggregateMap, now);
|
||||
if (!manualBatchArgs.isEmpty()) {
|
||||
jdbcTemplate.batchUpdate(
|
||||
"INSERT INTO mes_xsl_manual_small_material_demand_plan "
|
||||
+ "(id, stat_date, machine_id, machine_name, raw_material_name, demand_weight, create_time, update_time, del_flag) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
manualBatchArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Object[]> buildSmallDemandBatchArgs(
|
||||
Map<String, SmallDemandAggregate> aggregateMap, Date now) {
|
||||
List<Object[]> batchArgs = new ArrayList<>();
|
||||
for (SmallDemandAggregate aggregate : aggregateMap.values()) {
|
||||
if (aggregate.demandWeight.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
continue;
|
||||
}
|
||||
batchArgs.add(
|
||||
new Object[] {
|
||||
IdWorker.getIdStr(),
|
||||
aggregate.statDate,
|
||||
aggregate.machineId,
|
||||
aggregate.machineName,
|
||||
aggregate.rawMaterialName,
|
||||
aggregate.demandWeight,
|
||||
now,
|
||||
now,
|
||||
CommonConstant.DEL_FLAG_0
|
||||
});
|
||||
}
|
||||
return batchArgs;
|
||||
}
|
||||
|
||||
private static class RawDemandAggregate {
|
||||
@@ -305,6 +368,22 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
}
|
||||
}
|
||||
|
||||
private static class SmallDemandAggregate {
|
||||
private final Date statDate;
|
||||
private final String machineId;
|
||||
private final String machineName;
|
||||
private final String rawMaterialName;
|
||||
private BigDecimal demandWeight = BigDecimal.ZERO;
|
||||
|
||||
private SmallDemandAggregate(
|
||||
Date statDate, String machineId, String machineName, String rawMaterialName) {
|
||||
this.statDate = statDate;
|
||||
this.machineId = machineId;
|
||||
this.machineName = machineName;
|
||||
this.rawMaterialName = rawMaterialName;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasBusinessData(MesXslMixingProductionPlan row) {
|
||||
return StringUtils.isNotBlank(row.getMachineId())
|
||||
|| StringUtils.isNotBlank(row.getPlanId())
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.jeecg.modules.device.sync.agent;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MES → 桌面设备库命令。
|
||||
*/
|
||||
@Data
|
||||
public class DeviceAgentCommand implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String CMD_QUERY = "EQ_QUERY";
|
||||
public static final String CMD_WRITE = "EQ_WRITE";
|
||||
public static final String CMD_SYNC_PULL = "EQ_SYNC_PULL";
|
||||
public static final String CMD_SYNC_PUSH = "EQ_SYNC_PUSH";
|
||||
public static final String CMD_TEST = "EQ_TEST";
|
||||
|
||||
private String requestId;
|
||||
private String cmd;
|
||||
private String deviceId;
|
||||
/** 白名单表名(可选,与 sql 二选一或同时校验) */
|
||||
private String table;
|
||||
/** 已登记 sqlKey 或受限 SQL(桌面端白名单校验) */
|
||||
private String sql;
|
||||
private String sqlKey;
|
||||
private List<Object> params;
|
||||
private Map<String, Object> payload;
|
||||
private Integer timeoutMs;
|
||||
private Long sentAt;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package org.jeecg.modules.device.sync.agent;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* 设备代理命令总线:下发 EQ_* 并等待回执。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceAgentCommandService {
|
||||
|
||||
public static final int DEFAULT_TIMEOUT_MS = 30_000;
|
||||
|
||||
private final SimpMessagingTemplate messagingTemplate;
|
||||
private final DeviceAgentSessionRegistry sessionRegistry;
|
||||
|
||||
private final ConcurrentHashMap<String, CompletableFuture<DeviceAgentResult>> pending = new ConcurrentHashMap<>();
|
||||
|
||||
public DeviceAgentResult sendAndWait(DeviceAgentCommand command) {
|
||||
if (command == null) {
|
||||
throw new IllegalArgumentException("command 不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(command.getRequestId())) {
|
||||
command.setRequestId(UUID.randomUUID().toString().replace("-", ""));
|
||||
}
|
||||
if (StringUtils.isBlank(command.getDeviceId())) {
|
||||
DeviceAgentSession picked = sessionRegistry.pickOnlineAgent(null);
|
||||
if (picked == null) {
|
||||
throw new IllegalStateException("无在线桌面设备代理,无法访问设备库");
|
||||
}
|
||||
command.setDeviceId(picked.getDeviceId());
|
||||
}
|
||||
if (!sessionRegistry.isOnline(command.getDeviceId())) {
|
||||
throw new IllegalStateException("桌面设备代理不在线: " + command.getDeviceId());
|
||||
}
|
||||
int timeout = command.getTimeoutMs() != null && command.getTimeoutMs() > 0
|
||||
? command.getTimeoutMs() : DEFAULT_TIMEOUT_MS;
|
||||
command.setSentAt(System.currentTimeMillis());
|
||||
|
||||
CompletableFuture<DeviceAgentResult> future = new CompletableFuture<>();
|
||||
CompletableFuture<DeviceAgentResult> previous = pending.putIfAbsent(command.getRequestId(), future);
|
||||
if (previous != null) {
|
||||
throw new IllegalStateException("重复的 requestId: " + command.getRequestId());
|
||||
}
|
||||
|
||||
try {
|
||||
String destination = "/topic/device/" + command.getDeviceId() + "/cmd";
|
||||
messagingTemplate.convertAndSend(destination, JSON.toJSONString(command));
|
||||
log.info("已下发设备库命令 cmd={} requestId={} deviceId={}",
|
||||
command.getCmd(), command.getRequestId(), command.getDeviceId());
|
||||
return future.get(timeout, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
pending.remove(command.getRequestId(), future);
|
||||
throw new IllegalStateException("等待桌面设备库回执超时(" + timeout + "ms), requestId=" + command.getRequestId());
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
pending.remove(command.getRequestId(), future);
|
||||
throw new IllegalStateException("等待桌面设备库回执被中断", e);
|
||||
} catch (Exception e) {
|
||||
pending.remove(command.getRequestId(), future);
|
||||
if (e instanceof IllegalStateException) {
|
||||
throw (IllegalStateException) e;
|
||||
}
|
||||
throw new IllegalStateException("下发设备库命令失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void completeResult(DeviceAgentResult result) {
|
||||
if (result == null || StringUtils.isBlank(result.getRequestId())) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isNotBlank(result.getDeviceId())) {
|
||||
sessionRegistry.registerOrHeartbeat(
|
||||
result.getDeviceId(),
|
||||
null,
|
||||
result.getDbConnected(),
|
||||
result.getDbMessage());
|
||||
}
|
||||
CompletableFuture<DeviceAgentResult> future = pending.remove(result.getRequestId());
|
||||
if (future != null) {
|
||||
future.complete(result);
|
||||
} else {
|
||||
log.debug("收到无等待方的设备库回执 requestId={}", result.getRequestId());
|
||||
}
|
||||
}
|
||||
|
||||
public DeviceAgentResult query(String deviceId, String sql, List<Object> params, Integer timeoutMs) {
|
||||
DeviceAgentCommand cmd = new DeviceAgentCommand();
|
||||
cmd.setCmd(DeviceAgentCommand.CMD_QUERY);
|
||||
cmd.setDeviceId(deviceId);
|
||||
cmd.setSql(sql);
|
||||
cmd.setParams(params);
|
||||
cmd.setTimeoutMs(timeoutMs);
|
||||
DeviceAgentResult result = sendAndWait(cmd);
|
||||
ensureSuccess(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public DeviceAgentResult write(String deviceId, String sql, List<Object> params, Integer timeoutMs) {
|
||||
DeviceAgentCommand cmd = new DeviceAgentCommand();
|
||||
cmd.setCmd(DeviceAgentCommand.CMD_WRITE);
|
||||
cmd.setDeviceId(deviceId);
|
||||
cmd.setSql(sql);
|
||||
cmd.setParams(params);
|
||||
cmd.setTimeoutMs(timeoutMs);
|
||||
DeviceAgentResult result = sendAndWait(cmd);
|
||||
ensureSuccess(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public DeviceAgentResult test(String deviceId, Integer timeoutMs) {
|
||||
DeviceAgentCommand cmd = new DeviceAgentCommand();
|
||||
cmd.setCmd(DeviceAgentCommand.CMD_TEST);
|
||||
cmd.setDeviceId(deviceId);
|
||||
cmd.setTimeoutMs(timeoutMs != null ? timeoutMs : 10_000);
|
||||
return sendAndWait(cmd);
|
||||
}
|
||||
|
||||
public DeviceAgentResult syncPull(String deviceId, String table, String sql, List<Object> params, Integer timeoutMs) {
|
||||
DeviceAgentCommand cmd = new DeviceAgentCommand();
|
||||
cmd.setCmd(DeviceAgentCommand.CMD_SYNC_PULL);
|
||||
cmd.setDeviceId(deviceId);
|
||||
cmd.setTable(table);
|
||||
cmd.setSql(sql);
|
||||
cmd.setParams(params);
|
||||
cmd.setTimeoutMs(timeoutMs != null ? timeoutMs : 60_000);
|
||||
DeviceAgentResult result = sendAndWait(cmd);
|
||||
ensureSuccess(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public DeviceAgentResult syncPush(String deviceId, String table, Map<String, Object> payload, Integer timeoutMs) {
|
||||
DeviceAgentCommand cmd = new DeviceAgentCommand();
|
||||
cmd.setCmd(DeviceAgentCommand.CMD_SYNC_PUSH);
|
||||
cmd.setDeviceId(deviceId);
|
||||
cmd.setTable(table);
|
||||
cmd.setPayload(payload);
|
||||
cmd.setTimeoutMs(timeoutMs != null ? timeoutMs : 60_000);
|
||||
DeviceAgentResult result = sendAndWait(cmd);
|
||||
ensureSuccess(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ensureSuccess(DeviceAgentResult result) {
|
||||
if (result == null) {
|
||||
throw new IllegalStateException("桌面设备库无回执");
|
||||
}
|
||||
if (!result.isSuccess()) {
|
||||
throw new IllegalStateException(StringUtils.defaultIfBlank(result.getError(), "桌面设备库执行失败"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jeecg.modules.device.sync.agent;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 桌面 → MES 设备库命令回执。
|
||||
*/
|
||||
@Data
|
||||
public class DeviceAgentResult implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String requestId;
|
||||
private String deviceId;
|
||||
private String cmd;
|
||||
private boolean success;
|
||||
private String error;
|
||||
private Integer affected;
|
||||
private List<Map<String, Object>> rows;
|
||||
private Boolean dbConnected;
|
||||
private String dbMessage;
|
||||
private Long respondedAt;
|
||||
/** 分块回传时使用 */
|
||||
private Integer chunkIndex;
|
||||
private Integer chunkTotal;
|
||||
private Boolean lastChunk;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jeecg.modules.device.sync.agent;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 桌面设备代理在线会话(内存)。
|
||||
*/
|
||||
@Data
|
||||
public class DeviceAgentSession implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String deviceId;
|
||||
private String hostName;
|
||||
private boolean online;
|
||||
/** 设备库(SQL Server)是否连通 */
|
||||
private boolean dbConnected;
|
||||
private String dbMessage;
|
||||
private long lastSeenAt;
|
||||
private long registeredAt;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.jeecg.modules.device.sync.agent;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 桌面设备代理会话注册表。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DeviceAgentSessionRegistry {
|
||||
|
||||
private static final long ONLINE_TTL_MS = 60_000L;
|
||||
|
||||
private final ConcurrentHashMap<String, DeviceAgentSession> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
public void registerOrHeartbeat(String deviceId, String hostName, Boolean dbConnected, String dbMessage) {
|
||||
if (StringUtils.isBlank(deviceId)) {
|
||||
return;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
sessions.compute(deviceId, (id, old) -> {
|
||||
DeviceAgentSession s = old == null ? new DeviceAgentSession() : old;
|
||||
if (old == null) {
|
||||
s.setRegisteredAt(now);
|
||||
}
|
||||
s.setDeviceId(deviceId);
|
||||
if (StringUtils.isNotBlank(hostName)) {
|
||||
s.setHostName(hostName);
|
||||
}
|
||||
s.setOnline(true);
|
||||
if (dbConnected != null) {
|
||||
s.setDbConnected(dbConnected);
|
||||
}
|
||||
if (dbMessage != null) {
|
||||
s.setDbMessage(dbMessage);
|
||||
}
|
||||
s.setLastSeenAt(now);
|
||||
return s;
|
||||
});
|
||||
}
|
||||
|
||||
public void markOffline(String deviceId) {
|
||||
if (StringUtils.isBlank(deviceId)) {
|
||||
return;
|
||||
}
|
||||
DeviceAgentSession s = sessions.get(deviceId);
|
||||
if (s != null) {
|
||||
s.setOnline(false);
|
||||
s.setLastSeenAt(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
public DeviceAgentSession get(String deviceId) {
|
||||
if (StringUtils.isBlank(deviceId)) {
|
||||
return null;
|
||||
}
|
||||
DeviceAgentSession s = sessions.get(deviceId);
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
refreshOnlineFlag(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean isOnline(String deviceId) {
|
||||
DeviceAgentSession s = get(deviceId);
|
||||
return s != null && s.isOnline();
|
||||
}
|
||||
|
||||
/**
|
||||
* 选取一个在线代理:优先指定 deviceId,否则取最近心跳的在线设备。
|
||||
*/
|
||||
public DeviceAgentSession pickOnlineAgent(String preferredDeviceId) {
|
||||
if (StringUtils.isNotBlank(preferredDeviceId)) {
|
||||
DeviceAgentSession preferred = get(preferredDeviceId);
|
||||
if (preferred != null && preferred.isOnline()) {
|
||||
return preferred;
|
||||
}
|
||||
}
|
||||
return listOnline().stream()
|
||||
.max(Comparator.comparingLong(DeviceAgentSession::getLastSeenAt))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public List<DeviceAgentSession> listOnline() {
|
||||
List<DeviceAgentSession> list = new ArrayList<>();
|
||||
for (Map.Entry<String, DeviceAgentSession> e : sessions.entrySet()) {
|
||||
DeviceAgentSession s = e.getValue();
|
||||
refreshOnlineFlag(s);
|
||||
if (s.isOnline()) {
|
||||
list.add(s);
|
||||
}
|
||||
}
|
||||
list.sort(Comparator.comparingLong(DeviceAgentSession::getLastSeenAt).reversed());
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<DeviceAgentSession> listAll() {
|
||||
List<DeviceAgentSession> list = new ArrayList<>(sessions.values());
|
||||
list.forEach(this::refreshOnlineFlag);
|
||||
list.sort(Comparator.comparingLong(DeviceAgentSession::getLastSeenAt).reversed());
|
||||
return list;
|
||||
}
|
||||
|
||||
private void refreshOnlineFlag(DeviceAgentSession s) {
|
||||
if (s == null) {
|
||||
return;
|
||||
}
|
||||
if (System.currentTimeMillis() - s.getLastSeenAt() > ONLINE_TTL_MS) {
|
||||
s.setOnline(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,29 @@
|
||||
package org.jeecg.modules.device.sync.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentCommand;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentCommandService;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentResult;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSession;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSessionRegistry;
|
||||
import org.jeecg.modules.device.sync.entity.DeviceStatus;
|
||||
import org.jeecg.modules.device.sync.mapper.DeviceStatusMapper;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -29,6 +38,8 @@ public class DeviceWebSocketController {
|
||||
|
||||
private final DeviceStatusMapper deviceStatusMapper;
|
||||
private final SimpMessagingTemplate messagingTemplate;
|
||||
private final DeviceAgentSessionRegistry agentSessionRegistry;
|
||||
private final DeviceAgentCommandService agentCommandService;
|
||||
|
||||
@MessageMapping("/device/status")
|
||||
public void receiveDeviceStatus(DeviceStatus payload) {
|
||||
@@ -70,6 +81,8 @@ public class DeviceWebSocketController {
|
||||
if (deviceId.isBlank()) {
|
||||
return;
|
||||
}
|
||||
// 心跳同时刷新设备代理在线状态
|
||||
agentSessionRegistry.registerOrHeartbeat(deviceId, null, null, null);
|
||||
Map<String, Object> pong = new HashMap<>();
|
||||
pong.put("cmd", "PONG_DEVICE");
|
||||
pong.put("deviceId", deviceId);
|
||||
@@ -91,6 +104,8 @@ public class DeviceWebSocketController {
|
||||
commandPayload.put("sentAt", System.currentTimeMillis());
|
||||
|
||||
messagingTemplate.convertAndSendToUser(deviceId, "/queue/command", commandPayload);
|
||||
// 匿名桌面同样订阅 /topic/device/{id}/cmd
|
||||
messagingTemplate.convertAndSend("/topic/device/" + deviceId + "/cmd", commandJson);
|
||||
log.info("下发设备指令成功, deviceId={}", deviceId);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
@@ -98,4 +113,87 @@ public class DeviceWebSocketController {
|
||||
result.put("queued", true);
|
||||
return Result.OK(result);
|
||||
}
|
||||
|
||||
//update-begin---author:cursor ---date:2026-07-20 for:【设备库桥接】代理状态/回执/在线列表-----------
|
||||
/**
|
||||
* 桌面代理上报在线与设备库连通状态。
|
||||
* destination: /app/device/agent/status
|
||||
*/
|
||||
@MessageMapping("/device/agent/status")
|
||||
public void receiveAgentStatus(@org.springframework.messaging.handler.annotation.Payload(required = false) Map<String, Object> payload) {
|
||||
if (payload == null) {
|
||||
return;
|
||||
}
|
||||
String deviceId = String.valueOf(payload.getOrDefault("deviceId", "")).trim();
|
||||
if (deviceId.isBlank()) {
|
||||
return;
|
||||
}
|
||||
String hostName = payload.get("hostName") == null ? null : String.valueOf(payload.get("hostName"));
|
||||
Boolean dbConnected = null;
|
||||
if (payload.get("dbConnected") instanceof Boolean) {
|
||||
dbConnected = (Boolean) payload.get("dbConnected");
|
||||
} else if (payload.get("dbConnected") != null) {
|
||||
dbConnected = Boolean.parseBoolean(String.valueOf(payload.get("dbConnected")));
|
||||
}
|
||||
String dbMessage = payload.get("dbMessage") == null ? null : String.valueOf(payload.get("dbMessage"));
|
||||
agentSessionRegistry.registerOrHeartbeat(deviceId, hostName, dbConnected, dbMessage);
|
||||
messagingTemplate.convertAndSend("/topic/device/" + deviceId + "/status", payload);
|
||||
log.debug("设备代理状态已更新 deviceId={} dbConnected={}", deviceId, dbConnected);
|
||||
}
|
||||
|
||||
/**
|
||||
* 桌面代理回传设备库命令结果。
|
||||
* destination: /app/device/agent/result
|
||||
*/
|
||||
@MessageMapping("/device/agent/result")
|
||||
public void receiveAgentResult(@org.springframework.messaging.handler.annotation.Payload(required = false) Map<String, Object> payload) {
|
||||
if (payload == null) {
|
||||
return;
|
||||
}
|
||||
DeviceAgentResult result = JSON.parseObject(JSON.toJSONString(payload), DeviceAgentResult.class);
|
||||
agentCommandService.completeResult(result);
|
||||
}
|
||||
|
||||
@GetMapping("/agent/online")
|
||||
public Result<List<DeviceAgentSession>> listOnlineAgents() {
|
||||
return Result.OK(agentSessionRegistry.listOnline());
|
||||
}
|
||||
|
||||
@GetMapping("/agent/list")
|
||||
public Result<List<DeviceAgentSession>> listAgents() {
|
||||
return Result.OK(agentSessionRegistry.listAll());
|
||||
}
|
||||
|
||||
@PostMapping("/agent/test")
|
||||
public Result<DeviceAgentResult> testAgentDb(@RequestBody(required = false) Map<String, Object> body) {
|
||||
String deviceId = body == null ? null : String.valueOf(body.getOrDefault("deviceId", "")).trim();
|
||||
if (deviceId == null || deviceId.isBlank()) {
|
||||
DeviceAgentSession picked = agentSessionRegistry.pickOnlineAgent(null);
|
||||
if (picked == null) {
|
||||
return Result.error("无在线桌面代理");
|
||||
}
|
||||
deviceId = picked.getDeviceId();
|
||||
}
|
||||
try {
|
||||
return Result.OK(agentCommandService.test(deviceId, 10_000));
|
||||
} catch (Exception e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/agent/command")
|
||||
public Result<DeviceAgentResult> sendAgentCommand(@RequestBody DeviceAgentCommand command) {
|
||||
try {
|
||||
return Result.OK(agentCommandService.sendAndWait(command));
|
||||
} catch (Exception e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/agent/status")
|
||||
public Result<DeviceAgentSession> agentStatus(@RequestParam(name = "deviceId", required = false) String deviceId) {
|
||||
DeviceAgentSession session = agentSessionRegistry.pickOnlineAgent(deviceId);
|
||||
return Result.OK(session);
|
||||
}
|
||||
//update-end---author:cursor ---date:2026-07-20 for:【设备库桥接】代理状态/回执/在线列表-----------
|
||||
}
|
||||
|
||||
@@ -606,3 +606,26 @@ jeecgboot-vue3/src/views/xslmes/mesXslRubberQuickTestRecord/components/MesXslRub
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/service/impl/SysImChatServiceImpl.java
|
||||
jeecgboot-vue3/src/views/system/im/imCache.ts
|
||||
jeecgboot-vue3/src/views/system/im/ImChat.vue
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/<2F><><EFBFBD>ϡ<EFBFBD><CFA1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>༭У<E0BCAD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ψһ ---
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/IMesMixerMaterialService.java
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/impl/MesMixerMaterialServiceImpl.java
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMixerMaterialController.java
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/IMesMaterialService.java
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/service/impl/MesMaterialServiceImpl.java
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java
|
||||
jeecgboot-vue3/src/views/mes/material/MesMixerMaterial.api.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMixerMaterial.data.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.api.ts
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.data.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><CFA1><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD>ϱ<EFBFBD><CFB1><EFBFBD><EFBFBD><EFBFBD>365<36><35> ---
|
||||
jeecgboot-vue3/src/views/mes/material/MesMixerMaterial.data.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><>WebSocket<65><74><EFBFBD><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Redis<69>ذ<EFBFBD><D8B0><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/websocket/WebSocket.java
|
||||
jeecgboot-vue3/src/hooks/web/useWebSocket.ts
|
||||
|
||||
-- author:jiangxh---date:20260729--for: <20><><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><CFA1>б<EFBFBD>/<2F><><EFBFBD><EFBFBD>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD><EFBFBD>ϱ<EFBFBD><CFB1><EFBFBD><EFBFBD>ֶ<EFBFBD> ---
|
||||
jeecgboot-vue3/src/views/mes/material/MesMaterial.data.ts
|
||||
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mes/material/controller/MesMaterialController.java
|
||||
|
||||
@@ -10,11 +10,13 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.modules.mes.material.entity.MesMaterial;
|
||||
import org.jeecg.modules.mes.material.service.IMesMaterialService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -59,6 +61,12 @@ public class MesMaterialController extends JeecgController<MesMaterial, IMesMate
|
||||
@RequiresPermissions("mes:mes_material:add")
|
||||
@PostMapping("/add")
|
||||
public Result<String> add(@RequestBody MesMaterial model) {
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
String err = validateUnique(model, null);
|
||||
if (err != null) {
|
||||
return Result.error(err);
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
mesMaterialService.save(model);
|
||||
mesMaterialService.notifyMaterialChanged("material.created", model);
|
||||
return Result.OK("添加成功!");
|
||||
@@ -69,6 +77,12 @@ public class MesMaterialController extends JeecgController<MesMaterial, IMesMate
|
||||
@RequiresPermissions("mes:mes_material:edit")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||
public Result<String> edit(@RequestBody MesMaterial model) {
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
String err = validateUnique(model, model.getId());
|
||||
if (err != null) {
|
||||
return Result.error(err);
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
mesMaterialService.updateById(model);
|
||||
mesMaterialService.notifyMaterialChanged("material.updated", model);
|
||||
return Result.OK("编辑成功!");
|
||||
@@ -106,6 +120,57 @@ public class MesMaterialController extends JeecgController<MesMaterial, IMesMate
|
||||
return Result.OK(mesMaterialService.getById(id));
|
||||
}
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验接口-----------
|
||||
@Operation(summary = "校验胶料编码是否重复")
|
||||
@GetMapping("/checkMaterialCode")
|
||||
public Result<String> checkMaterialCode(
|
||||
@RequestParam(name = "materialCode", required = true) String materialCode,
|
||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||
if (oConvertUtils.isEmpty(materialCode) || materialCode.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (mesMaterialService.isMaterialCodeDuplicated(materialCode, dataId)) {
|
||||
return Result.error("胶料编码不能重复");
|
||||
}
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
|
||||
@Operation(summary = "校验胶料名称是否重复")
|
||||
@GetMapping("/checkMaterialName")
|
||||
public Result<String> checkMaterialName(
|
||||
@RequestParam(name = "materialName", required = true) String materialName,
|
||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||
if (oConvertUtils.isEmpty(materialName) || materialName.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (mesMaterialService.isMaterialNameDuplicated(materialName, dataId)) {
|
||||
return Result.error("胶料名称不能重复");
|
||||
}
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
|
||||
private String validateUnique(MesMaterial model, String excludeId) {
|
||||
if (model == null) {
|
||||
return "数据不能为空";
|
||||
}
|
||||
if (oConvertUtils.isEmpty(model.getMaterialName()) || StringUtils.isBlank(model.getMaterialName())) {
|
||||
return "胶料名称不能为空";
|
||||
}
|
||||
model.setMaterialName(model.getMaterialName().trim());
|
||||
//update-begin---author:jiangxh ---date:20260730 for:【胶料】保存时编号与名称保持一致(界面隐藏编号)-----------
|
||||
// 表单/列表不展示编号,保存时自动用胶料名称回填胶料编号
|
||||
model.setMaterialCode(model.getMaterialName());
|
||||
//update-end---author:jiangxh ---date:20260730 for:【胶料】保存时编号与名称保持一致(界面隐藏编号)-----------
|
||||
if (mesMaterialService.isMaterialNameDuplicated(model.getMaterialName(), excludeId)) {
|
||||
return "胶料名称不能重复";
|
||||
}
|
||||
if (mesMaterialService.isMaterialCodeDuplicated(model.getMaterialCode(), excludeId)) {
|
||||
return "胶料编码不能重复";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验接口-----------
|
||||
|
||||
@RequiresPermissions("mes:mes_material:exportXls")
|
||||
@RequestMapping("/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, MesMaterial model) {
|
||||
|
||||
@@ -11,11 +11,13 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
||||
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
@@ -52,6 +54,12 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
||||
@RequiresPermissions("mes:mes_mixer_material:add")
|
||||
@PostMapping("/add")
|
||||
public Result<String> add(@RequestBody MesMixerMaterial model) {
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
String err = validateUnique(model, null);
|
||||
if (err != null) {
|
||||
return Result.error(err);
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
service.save(model);
|
||||
publishChanged("add", model.getId());
|
||||
return Result.OK("添加成功!");
|
||||
@@ -62,6 +70,12 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
||||
@RequiresPermissions("mes:mes_mixer_material:edit")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||
public Result<String> edit(@RequestBody MesMixerMaterial model) {
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
String err = validateUnique(model, model.getId());
|
||||
if (err != null) {
|
||||
return Result.error(err);
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
service.updateById(model);
|
||||
publishChanged("edit", model.getId());
|
||||
return Result.OK("编辑成功!");
|
||||
@@ -110,6 +124,12 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
||||
@Operation(summary = "MES-密炼物料信息-免密添加")
|
||||
@PostMapping("/anon/add")
|
||||
public Result<String> anonAdd(@RequestBody MesMixerMaterial model) {
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
String err = validateUnique(model, null);
|
||||
if (err != null) {
|
||||
return Result.error(err);
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
service.save(model);
|
||||
publishChanged("add", model.getId());
|
||||
return Result.OK("添加成功!");
|
||||
@@ -118,6 +138,12 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
||||
@Operation(summary = "MES-密炼物料信息-免密编辑")
|
||||
@RequestMapping(value = "/anon/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||
public Result<String> anonEdit(@RequestBody MesMixerMaterial model) {
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
String err = validateUnique(model, model.getId());
|
||||
if (err != null) {
|
||||
return Result.error(err);
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
boolean ok = service.updateById(model);
|
||||
if (!ok) {
|
||||
return Result.error("数据已被他人修改,请刷新后重试");
|
||||
@@ -148,6 +174,57 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
||||
return Result.OK(service.getById(id));
|
||||
}
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验接口-----------
|
||||
@Operation(summary = "校验物料编码是否重复")
|
||||
@GetMapping("/checkMaterialCode")
|
||||
public Result<String> checkMaterialCode(
|
||||
@RequestParam(name = "materialCode", required = true) String materialCode,
|
||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||
if (oConvertUtils.isEmpty(materialCode) || materialCode.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (service.isMaterialCodeDuplicated(materialCode, dataId)) {
|
||||
return Result.error("物料编码不能重复");
|
||||
}
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
|
||||
@Operation(summary = "校验物料名称是否重复")
|
||||
@GetMapping("/checkMaterialName")
|
||||
public Result<String> checkMaterialName(
|
||||
@RequestParam(name = "materialName", required = true) String materialName,
|
||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||
if (oConvertUtils.isEmpty(materialName) || materialName.trim().isEmpty()) {
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
if (service.isMaterialNameDuplicated(materialName, dataId)) {
|
||||
return Result.error("物料名称不能重复");
|
||||
}
|
||||
return Result.OK("该值可用!");
|
||||
}
|
||||
|
||||
private String validateUnique(MesMixerMaterial model, String excludeId) {
|
||||
if (model == null) {
|
||||
return "数据不能为空";
|
||||
}
|
||||
if (oConvertUtils.isEmpty(model.getMaterialCode()) || StringUtils.isBlank(model.getMaterialCode())) {
|
||||
return "物料编码不能为空";
|
||||
}
|
||||
model.setMaterialCode(model.getMaterialCode().trim());
|
||||
if (service.isMaterialCodeDuplicated(model.getMaterialCode(), excludeId)) {
|
||||
return "物料编码不能重复";
|
||||
}
|
||||
if (oConvertUtils.isEmpty(model.getMaterialName()) || StringUtils.isBlank(model.getMaterialName())) {
|
||||
return "物料名称不能为空";
|
||||
}
|
||||
model.setMaterialName(model.getMaterialName().trim());
|
||||
if (service.isMaterialNameDuplicated(model.getMaterialName(), excludeId)) {
|
||||
return "物料名称不能重复";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验接口-----------
|
||||
|
||||
@RequiresPermissions("mes:mes_mixer_material:exportXls")
|
||||
@RequestMapping("/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, MesMixerMaterial model) {
|
||||
|
||||
@@ -5,4 +5,10 @@ import org.jeecg.modules.mes.material.entity.MesMaterial;
|
||||
|
||||
public interface IMesMaterialService extends IService<MesMaterial> {
|
||||
void notifyMaterialChanged(String eventType, MesMaterial material);
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
boolean isMaterialCodeDuplicated(String materialCode, String excludeId);
|
||||
|
||||
boolean isMaterialNameDuplicated(String materialName, String excludeId);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
}
|
||||
|
||||
@@ -3,4 +3,11 @@ package org.jeecg.modules.mes.material.service;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
||||
|
||||
public interface IMesMixerMaterialService extends IService<MesMixerMaterial> {}
|
||||
public interface IMesMixerMaterialService extends IService<MesMixerMaterial> {
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
boolean isMaterialCodeDuplicated(String materialCode, String excludeId);
|
||||
|
||||
boolean isMaterialNameDuplicated(String materialName, String excludeId);
|
||||
//update-end---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package org.jeecg.modules.mes.material.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.mes.material.entity.MesMaterial;
|
||||
import org.jeecg.modules.mes.material.mapper.MesMaterialMapper;
|
||||
import org.jeecg.modules.mes.material.service.IMesMaterialService;
|
||||
@@ -25,4 +27,32 @@ public class MesMaterialServiceImpl extends ServiceImpl<MesMaterialMapper, MesMa
|
||||
event.put("timestamp", System.currentTimeMillis());
|
||||
webSocket.sendMessage(JSON.toJSONString(event));
|
||||
}
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
@Override
|
||||
public boolean isMaterialCodeDuplicated(String materialCode, String excludeId) {
|
||||
if (StringUtils.isBlank(materialCode)) {
|
||||
return false;
|
||||
}
|
||||
LambdaQueryWrapper<MesMaterial> wrapper =
|
||||
new LambdaQueryWrapper<MesMaterial>().eq(MesMaterial::getMaterialCode, materialCode.trim());
|
||||
if (StringUtils.isNotBlank(excludeId)) {
|
||||
wrapper.ne(MesMaterial::getId, excludeId.trim());
|
||||
}
|
||||
return this.count(wrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMaterialNameDuplicated(String materialName, String excludeId) {
|
||||
if (StringUtils.isBlank(materialName)) {
|
||||
return false;
|
||||
}
|
||||
LambdaQueryWrapper<MesMaterial> wrapper =
|
||||
new LambdaQueryWrapper<MesMaterial>().eq(MesMaterial::getMaterialName, materialName.trim());
|
||||
if (StringUtils.isNotBlank(excludeId)) {
|
||||
wrapper.ne(MesMaterial::getId, excludeId.trim());
|
||||
}
|
||||
return this.count(wrapper) > 0;
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【胶料】名称/编码唯一校验-----------
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.jeecg.modules.mes.material.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
||||
import org.jeecg.modules.mes.material.mapper.MesMixerMaterialMapper;
|
||||
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
|
||||
@@ -8,4 +10,33 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MesMixerMaterialServiceImpl extends ServiceImpl<MesMixerMaterialMapper, MesMixerMaterial>
|
||||
implements IMesMixerMaterialService {}
|
||||
implements IMesMixerMaterialService {
|
||||
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
@Override
|
||||
public boolean isMaterialCodeDuplicated(String materialCode, String excludeId) {
|
||||
if (StringUtils.isBlank(materialCode)) {
|
||||
return false;
|
||||
}
|
||||
LambdaQueryWrapper<MesMixerMaterial> wrapper =
|
||||
new LambdaQueryWrapper<MesMixerMaterial>().eq(MesMixerMaterial::getMaterialCode, materialCode.trim());
|
||||
if (StringUtils.isNotBlank(excludeId)) {
|
||||
wrapper.ne(MesMixerMaterial::getId, excludeId.trim());
|
||||
}
|
||||
return this.count(wrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMaterialNameDuplicated(String materialName, String excludeId) {
|
||||
if (StringUtils.isBlank(materialName)) {
|
||||
return false;
|
||||
}
|
||||
LambdaQueryWrapper<MesMixerMaterial> wrapper =
|
||||
new LambdaQueryWrapper<MesMixerMaterial>().eq(MesMixerMaterial::getMaterialName, materialName.trim());
|
||||
if (StringUtils.isNotBlank(excludeId)) {
|
||||
wrapper.ne(MesMixerMaterial::getId, excludeId.trim());
|
||||
}
|
||||
return this.count(wrapper) > 0;
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【密炼物料】名称/编码唯一校验-----------
|
||||
}
|
||||
|
||||
@@ -61,16 +61,30 @@ public class WebSocket {
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam(value = "userId") String userId) {
|
||||
try {
|
||||
sessionPool.put(userId, session);
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【WebSocket】同 userId 新连接顶替旧连接,避免双连接互踢-----------
|
||||
Session previous = sessionPool.put(userId, session);
|
||||
if (previous != null && previous.isOpen() && !previous.getId().equals(session.getId())) {
|
||||
try {
|
||||
previous.close();
|
||||
} catch (Exception ignore) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【WebSocket】同 userId 新连接顶替旧连接,避免双连接互踢-----------
|
||||
log.info("【系统 WebSocket】连接建立 userId={}, sessionId={}, online={}", userId, session.getId(), sessionPool.size());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(@PathParam("userId") String userId) {
|
||||
public void onClose(Session session, @PathParam("userId") String userId) {
|
||||
try {
|
||||
sessionPool.remove(userId);
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【WebSocket】仅移除当前 session,避免旧连接 onClose 清掉新连接-----------
|
||||
Session current = sessionPool.get(userId);
|
||||
if (current != null && session != null && current.getId().equals(session.getId())) {
|
||||
sessionPool.remove(userId, current);
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【WebSocket】仅移除当前 session,避免旧连接 onClose 清掉新连接-----------
|
||||
log.info("【系统 WebSocket】连接断开 userId={}, online={}", userId, sessionPool.size());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -155,13 +169,24 @@ public class WebSocket {
|
||||
* ws接受客户端消息
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, @PathParam(value = "userId") String userId) {
|
||||
public void onMessage(String message, Session session, @PathParam(value = "userId") String userId) {
|
||||
String normalized = message == null ? "" : message.trim();
|
||||
if (isHeartbeatOrBlank(normalized)) {
|
||||
log.debug("【系统 WebSocket】收到客户端心跳/空消息:{}", normalized);
|
||||
if ("ping".equalsIgnoreCase(normalized) || WebsocketConst.CMD_CHECK.equalsIgnoreCase(normalized)) {
|
||||
//update-begin---author:jiangxh ---date:20260729 for:【WebSocket】心跳直接回包,避免走 Redis 导致 pong 超时断线-----------
|
||||
// 代码逻辑说明: 【issues/1161】前端websocket因心跳导致监听不起作用---
|
||||
this.sendMessage(userId, "ping");
|
||||
// 心跳必须同连接即时回包;走 Redis 发布订阅可能延迟/失败,触发前端 pongTimeout 断线重连
|
||||
try {
|
||||
if (session != null && session.isOpen()) {
|
||||
synchronized (session) {
|
||||
session.getBasicRemote().sendText("ping");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("【系统 WebSocket】心跳回包失败 userId={}, err={}", userId, e.getMessage());
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260729 for:【WebSocket】心跳直接回包,避免走 Redis 导致 pong 超时断线-----------
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<#if po.fieldDbType=='Blob'>
|
||||
private transient java.lang.String ${po.fieldName}String;
|
||||
|
||||
private byte[] ${po.fieldName};
|
||||
|
||||
public byte[] get${po.fieldName?cap_first}(){
|
||||
if(${po.fieldName}String==null){
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return ${po.fieldName}String.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String get${po.fieldName?cap_first}String(){
|
||||
if(${po.fieldName}==null || ${po.fieldName}.length==0){
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return new String(${po.fieldName},"UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
<#elseif po.classType=='switch'>
|
||||
<#assign switch_extend_arr=['Y','N']>
|
||||
<#if po.dictField?default("")?contains("[")>
|
||||
<#assign switch_extend_arr=po.dictField?eval>
|
||||
</#if>
|
||||
<#list switch_extend_arr as a>
|
||||
<#if a_index == 0>
|
||||
<#assign switch_extend_arr1=a>
|
||||
<#else>
|
||||
<#assign switch_extend_arr2=a>
|
||||
</#if>
|
||||
</#list>
|
||||
@Excel(name = "${po.filedComment}", width = 15,replace = {"是_${switch_extend_arr1}","否_${switch_extend_arr2}"} )
|
||||
@Schema(description = "${po.filedComment}")
|
||||
private ${po.fieldType} ${po.fieldName};
|
||||
<#elseif po.classType=='pca'>
|
||||
@Excel(name = "${po.filedComment}", width = 15,exportConvert=true,importConvert = true )
|
||||
@Schema(description = "${po.filedComment}")
|
||||
private ${po.fieldType} ${po.fieldName};
|
||||
|
||||
public String convertis${po.fieldName?cap_first}() {
|
||||
return SpringContextUtils.getBean(ProvinceCityArea.class).getText(${po.fieldName});
|
||||
}
|
||||
|
||||
public void convertset${po.fieldName?cap_first}(String text) {
|
||||
this.${po.fieldName} = SpringContextUtils.getBean(ProvinceCityArea.class).getCode(text);
|
||||
}
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#assign list_field_dictCode=', dictTable = "sys_category", dicText = "name", dicCode = "id"'>
|
||||
@Excel(name = "${po.filedComment}", width = 15${list_field_dictCode})
|
||||
@Schema(description = "${po.filedComment}")
|
||||
private ${po.fieldType} ${po.fieldName};
|
||||
<#else>
|
||||
@Schema(description = "${po.filedComment}")
|
||||
<#if po.fieldDbName == 'del_flag'>
|
||||
@TableLogic
|
||||
</#if>
|
||||
private ${po.fieldType} ${po.fieldName};
|
||||
</#if>
|
||||
@@ -0,0 +1,53 @@
|
||||
<#if need_select_tag>
|
||||
JDictSelectTag,
|
||||
</#if>
|
||||
<#if need_switch>
|
||||
JSwitch,
|
||||
</#if>
|
||||
<#if need_multi>
|
||||
JSelectMultiple,
|
||||
</#if>
|
||||
<#if need_search>
|
||||
JSearchSelect,
|
||||
</#if>
|
||||
<#if need_popup>
|
||||
JPopup,
|
||||
</#if>
|
||||
<#if need_popup_dict>
|
||||
JPopupDict,
|
||||
</#if>
|
||||
<#if need_category>
|
||||
JCategorySelect,
|
||||
</#if>
|
||||
<#if need_dept>
|
||||
JSelectDept,
|
||||
</#if>
|
||||
<#if need_dept_user>
|
||||
<#-- update-begin---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
JSelectUser,
|
||||
<#-- update-end---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
</#if>
|
||||
<#if need_select_tree>
|
||||
JTreeSelect,
|
||||
</#if>
|
||||
<#if need_time>
|
||||
TimePicker,
|
||||
</#if>
|
||||
<#if need_pca>
|
||||
JAreaLinkage,
|
||||
</#if>
|
||||
<#if need_upload>
|
||||
JUpload,
|
||||
</#if>
|
||||
<#if need_image_upload>
|
||||
JImageUpload,
|
||||
</#if>
|
||||
<#if need_markdown>
|
||||
JMarkdownEditor,
|
||||
</#if>
|
||||
<#if need_editor>
|
||||
JEditor,
|
||||
</#if>
|
||||
<#if need_checkbox>
|
||||
JCheckbox,
|
||||
</#if>
|
||||
@@ -0,0 +1,119 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#-- update-begin---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#if po.isShow =='Y' && po.fieldName != 'id' && po.fieldName !='delFlag' && isNotPidField(tableVo, po.fieldDbName)>
|
||||
<#-- update-end---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#assign form_field_dictCode="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictField}">
|
||||
</#if>
|
||||
<a-col :span="${form_span}">
|
||||
<a-form-item label="${po.filedComment}" v-bind="validateInfos.${autoStringSuffixForModel(po)}" id="${formEntityName}-${autoStringSuffixForModel(po)}" name="${autoStringSuffixForModel(po)}">
|
||||
<#if po.classType =='date'>
|
||||
<a-date-picker placeholder="请选择${po.filedComment}" <#if po.extendParams?exists && po.extendParams.picker?exists>picker="${po.extendParams.picker}"</#if> v-model:value="formData.${po.fieldName}" value-format="YYYY-MM-DD" style="width: 100%" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType =='datetime'>
|
||||
<a-date-picker placeholder="请选择${po.filedComment}" v-model:value="formData.${po.fieldName}" showTime value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType =='time'>
|
||||
<#assign need_time = true>
|
||||
<time-picker placeholder="请选择${po.filedComment}" value-format="HH:mm:ss" v-model:value="formData.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType =='popup'>
|
||||
<#assign need_popup = true>
|
||||
<#assign sourceFields = po.dictField?default("")?trim?split(",")/>
|
||||
<#assign targetFields = po.dictText?default("")?trim?split(",")/>
|
||||
<j-popup
|
||||
placeholder="请选择${po.filedComment}"
|
||||
v-model:value="formData.${po.fieldName}"
|
||||
code="${po.dictTable}"
|
||||
:fieldConfig="[
|
||||
<#list sourceFields as fieldName>
|
||||
{ source: '${fieldName}', target: '${dashedToCamel(targetFields[fieldName_index])}' },
|
||||
</#list>
|
||||
]"
|
||||
:multi="${po.extendParams.popupMulti?c}"
|
||||
:setFieldsValue="setFieldsValue"
|
||||
<#if po.readonly=='Y'>disabled</#if><#rt> allow-clear />
|
||||
<#elseif po.classType =='popup_dict'>
|
||||
<#assign need_popup_dict = true>
|
||||
<#assign sourceFields = po.dictField?default("")?trim?split(",")/>
|
||||
<#assign targetFields = po.dictText?default("")?trim?split(",")/>
|
||||
<j-popup-dict
|
||||
placeholder="请选择${po.filedComment}"
|
||||
v-model:value="formData.${po.fieldName}"
|
||||
dictCode="${po.dictTable},${po.dictText},${po.dictField}"
|
||||
:multi="${po.extendParams.popupMulti?c}" <#if po.readonly=='Y'>disabled</#if> />
|
||||
<#elseif po.classType =='sel_depart'>
|
||||
<#assign need_dept = true>
|
||||
<j-select-dept v-model:value="formData.${po.fieldName}" <#if po.extendParams?exists && po.extendParams.text?exists>labelKey="${po.extendParams.text}"</#if> <#if po.extendParams?exists && po.extendParams.store?exists>rowKey="${po.extendParams.store}"</#if> <#if po.readonly=='Y'>disabled</#if> :multiple="${po.extendParams.multi?default('true')}" checkStrictly <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType =='switch'>
|
||||
<#assign need_switch = true>
|
||||
<j-switch v-model:value="formData.${po.fieldName}" <#if po.dictField != 'is_open'>:options="${po.dictField}"</#if> <#if po.readonly=='Y'>disabled</#if>></j-switch>
|
||||
<#elseif po.classType =='pca'>
|
||||
<#assign need_pca = true>
|
||||
<j-area-linkage v-model:value="formData.${po.fieldName}" placeholder="请输入${po.filedComment}" saveCode="region" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType =='markdown'>
|
||||
<#assign need_markdown = true>
|
||||
<j-markdown-editor v-model:value="formData.${autoStringSuffixForModel(po)}" id="${po.fieldName}" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if>></j-markdown-editor>
|
||||
<#elseif po.classType =='password'>
|
||||
<a-input-password v-model:value="formData.${po.fieldName}" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType =='sel_user'>
|
||||
<#assign need_dept_user = true>
|
||||
<#-- update-begin---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
<j-select-user v-model:value="formData.${po.fieldName}" <#if po.extendParams?exists && po.extendParams.text?exists>labelKey="${po.extendParams.text}"</#if> <#if po.extendParams?exists && po.extendParams.store?exists>rowKey="${po.extendParams.store}"</#if> <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#-- update-end---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
<#elseif po.classType =='textarea'>
|
||||
<a-textarea v-model:value="formData.${autoStringSuffixForModel(po)}" :rows="4" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType=='radio'>
|
||||
<#assign need_select_tag = true>
|
||||
<j-dict-select-tag type='radio' v-model:value="formData.${po.fieldName}" dictCode="${form_field_dictCode}" placeholder="请选择${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType=='list'>
|
||||
<#assign need_select_tag = true>
|
||||
<j-dict-select-tag v-model:value="formData.${po.fieldName}" dictCode="${form_field_dictCode}" placeholder="请选择${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType=='list_multi'>
|
||||
<#assign need_multi = true>
|
||||
<j-select-multiple type="${po.classType}" v-model:value="formData.${po.fieldName}" dictCode="${form_field_dictCode}" placeholder="请选择${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> :triggerChange="false"/>
|
||||
<#elseif po.classType=='checkbox'>
|
||||
<#assign need_checkbox = true>
|
||||
<j-checkbox type="${po.classType}" v-model:value="formData.${po.fieldName}" dictCode="${form_field_dictCode}" placeholder="请选择${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType=='sel_search'>
|
||||
<#assign need_search = true>
|
||||
<j-search-select v-model:value="formData.${po.fieldName}" dict="${form_field_dictCode}" <#if po.readonly=='Y'>disabled</#if> allow-clear />
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#assign need_category = true>
|
||||
<j-category-select v-model:value="formData.${po.fieldName}" pcode="${po.dictField?default("")}" placeholder="请选择${po.filedComment}" <#if po.dictText?default("")?trim?length gt 1>back="${dashedToCamel(po.dictText)}"</#if> <#if po.readonly=='Y'>disabled</#if> @change="(value) => handleFormChange('${po.fieldName}', value)" allow-clear />
|
||||
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
<a-input-number v-model:value="formData.${po.fieldName}" placeholder="请输入${po.filedComment}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType=='file'>
|
||||
<#assign need_upload = true>
|
||||
<j-upload v-model:value="formData.${po.fieldName}" <#if po.readonly=='Y'>disabled</#if> <#if po.uploadnum??>:maxCount=${po.uploadnum}</#if>></j-upload>
|
||||
<#elseif po.classType=='image'>
|
||||
<#assign need_image_upload = true>
|
||||
<j-image-upload <#if po.uploadnum??>:fileMax=${po.uploadnum}<#else>:fileMax="0"</#if> v-model:value="formData.${po.fieldName}" <#if po.readonly=='Y'>disabled</#if>></j-image-upload>
|
||||
<#elseif po.classType=='umeditor'>
|
||||
<#assign need_editor = true>
|
||||
<j-editor v-model:value="formData.${autoStringSuffixForModel(po)}" <#if po.readonly=='Y'>disabled</#if> :autoFocus="false"/>
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
<a-input v-model:value="formData.${autoStringSuffixForModel(po)}" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> allow-clear ></a-input>
|
||||
<#elseif po.classType == 'sel_tree'>
|
||||
<#assign need_select_tree = true>
|
||||
<j-tree-select
|
||||
<#if po.dictText??>
|
||||
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
|
||||
dict="${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}"
|
||||
<#elseif po.dictText?split(',')[1]??>
|
||||
pidField="${po.dictText?split(',')[1]}"
|
||||
<#elseif po.dictText?split(',')[3]??>
|
||||
hasChildField="${po.dictText?split(',')[3]}"
|
||||
</#if>
|
||||
</#if>
|
||||
pidValue="${po.dictField}"
|
||||
<#if po.readonly=='Y'>disabled</#if>
|
||||
v-model:value="formData.${po.fieldName}"
|
||||
@change="(value) => handleFormChange('${po.fieldName}', value)" allow-clear >
|
||||
</j-tree-select>
|
||||
<#else>
|
||||
<a-input v-model:value="formData.${po.fieldName}" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> allow-clear ></a-input>
|
||||
</#if>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</#if>
|
||||
@@ -0,0 +1,59 @@
|
||||
<#if need_select_tag>
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
</#if>
|
||||
<#if need_switch>
|
||||
import JSwitch from '/@/components/Form/src/jeecg/components/JSwitch.vue';
|
||||
</#if>
|
||||
<#if need_multi>
|
||||
import JSelectMultiple from '/@/components/Form/src/jeecg/components/JSelectMultiple.vue';
|
||||
</#if>
|
||||
<#if need_search>
|
||||
import JSearchSelect from '/@/components/Form/src/jeecg/components/JSearchSelect.vue';
|
||||
</#if>
|
||||
<#if need_popup>
|
||||
import JPopup from '/@/components/Form/src/jeecg/components/JPopup.vue';
|
||||
</#if>
|
||||
<#if need_popup_dict>
|
||||
import JPopupDict from '/@/components/Form/src/jeecg/components/JPopupDict.vue';
|
||||
</#if>
|
||||
<#if need_category>
|
||||
import JCategorySelect from '/@/components/Form/src/jeecg/components/JCategorySelect.vue';
|
||||
</#if>
|
||||
<#if need_dept>
|
||||
import JSelectDept from '/@/components/Form/src/jeecg/components/JSelectDept.vue';
|
||||
</#if>
|
||||
<#if need_dept_user>
|
||||
<#-- update-begin---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
import JSelectUser from '/@/components/Form/src/jeecg/components/JSelectUser.vue';
|
||||
<#-- update-end---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
</#if>
|
||||
<#if need_select_tree>
|
||||
import JTreeSelect from '/@/components/Form/src/jeecg/components/JTreeSelect.vue';
|
||||
</#if>
|
||||
<#if need_time>
|
||||
import { TimePicker } from 'ant-design-vue';
|
||||
</#if>
|
||||
<#if need_pca>
|
||||
import JAreaLinkage from '/@/components/Form/src/jeecg/components/JAreaLinkage.vue';
|
||||
</#if>
|
||||
<#if need_upload>
|
||||
import JUpload from '/@/components/Form/src/jeecg/components/JUpload/JUpload.vue';
|
||||
</#if>
|
||||
<#if need_image_upload>
|
||||
import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
|
||||
</#if>
|
||||
<#if need_markdown>
|
||||
import JMarkdownEditor from '/@/components/Form/src/jeecg/components/JMarkdownEditor.vue';
|
||||
</#if>
|
||||
<#if need_editor>
|
||||
import JEditor from '/@/components/Form/src/jeecg/components/JEditor.vue';
|
||||
</#if>
|
||||
<#if need_checkbox>
|
||||
import JCheckbox from "/@/components/Form/src/jeecg/components/JCheckbox.vue";
|
||||
</#if>
|
||||
<#if need_range_number>
|
||||
import JRangeNumber from "/@/components/Form/src/jeecg/components/JRangeNumber.vue";
|
||||
</#if>
|
||||
<#if is_like>
|
||||
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
|
||||
</#if>
|
||||
@@ -0,0 +1,108 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#-- update-begin---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#if po.isQuery=='Y' && po.fieldName !='delFlag'>
|
||||
<#-- update-end---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#assign query_flag=true>
|
||||
<#if query_field_no==2>
|
||||
<template v-if="toggleSearchStatus">
|
||||
</#if>
|
||||
<#assign query_field_dictCode="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
<#assign need_select_tag = true>
|
||||
<#assign need_multi = true>
|
||||
<#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign need_select_tag = true>
|
||||
<#assign need_multi = true>
|
||||
<#assign query_field_dictCode="${po.dictField}">
|
||||
</#if>
|
||||
<#if po.queryMode=='single'>
|
||||
<#if query_field_no gt 1> </#if><a-col :lg="6">
|
||||
<#if query_field_no gt 1> </#if><a-form-item name="${autoStringSuffixForModel(po)}">
|
||||
<#if query_field_no gt 1> </#if><template #label><span title="${po.filedComment}"><#if po.filedComment?default("")?trim?length gt 4>${po.filedComment?substring(0,4)}<#else>${po.filedComment}</#if></span></template>
|
||||
<#if po.classType=='sel_search'>
|
||||
<#if query_field_no gt 1> </#if><j-search-select placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" dict="${po.dictTable},${po.dictText},${po.dictField}" allow-clear />
|
||||
<#elseif po.classType=='sel_user'>
|
||||
<#-- update-begin---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
<#if query_field_no gt 1> </#if><j-select-user placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" @change="(value)=>handleFormJoinChange('${po.fieldName}',value)" allow-clear />
|
||||
<#-- update-end---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
<#elseif po.classType=='switch'>
|
||||
<#if query_field_no gt 1> </#if><j-switch placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" <#if po.dictField!= 'is_open'>:options="${po.dictField}"</#if> query />
|
||||
<#elseif po.classType=='sel_depart'>
|
||||
<#if query_field_no gt 1> </#if><j-select-dept placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" checkStrictly allow-clear />
|
||||
<#elseif po.classType=='list_multi'>
|
||||
<#if query_field_no gt 1> </#if><j-select-multiple placeholder="请选择${po.filedComment}" dictCode="${query_field_dictCode?default("")}" v-model:value="queryParam.${po.fieldName}" allow-clear />
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#if query_field_no gt 1> </#if><j-category-select placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" pcode="${po.dictField?default("")}" @change="(value) => handleFormChange('${po.fieldName}', value)" allow-clear />
|
||||
<#elseif po.classType=='date'>
|
||||
<#if query_field_no gt 1> </#if><a-date-picker valueFormat="YYYY-MM-DD" placeholder="请选择${po.filedComment}" <#if po.extendParams?exists && po.extendParams.picker?exists>picker="${po.extendParams.picker}"</#if> v-model:value="queryParam.${po.fieldName}" allow-clear />
|
||||
<#elseif po.classType=='datetime'>
|
||||
<#if query_field_no gt 1> </#if><a-date-picker showTime valueFormat="YYYY-MM-DD HH:mm:ss" placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" allow-clear />
|
||||
<#elseif po.classType=='time'>
|
||||
<#if query_field_no gt 1> </#if><time-picker valueFormat="HH:mm:ss" placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" allow-clear />
|
||||
<#elseif po.classType=='pca'>
|
||||
<#if query_field_no gt 1> </#if><j-area-linkage v-model:value="queryParam.${po.fieldName}" placeholder="请选择${po.filedComment}" saveCode="region" @change="(value)=>handleFormJoinChange('${po.fieldName}',value)" allow-clear />
|
||||
<#elseif po.classType=='sel_tree'>
|
||||
<#if query_field_no gt 1> </#if><j-tree-select v-model:value="queryParam.${po.fieldName}" placeholder="请选择${po.filedComment}" <#if po.dictText??><#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>dict="${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}" <#elseif po.dictText?split(',')[1]??>pidField:"${po.dictText?split(',')[1]}", <#elseif po.dictText?split(',')[3]??>hasChildField:"${po.dictText?split(',')[3]}"</#if> </#if>pidValue="${po.dictField}" allow-clear />
|
||||
<#elseif po.classType=='popup'>
|
||||
<#assign sourceFields = po.dictField?default("")?trim?split(",")/>
|
||||
<#assign targetFields = po.dictText?default("")?trim?split(",")/>
|
||||
<#if query_field_no gt 1> </#if><j-popup
|
||||
<#if query_field_no gt 1> </#if>placeholder="请选择${po.filedComment}"
|
||||
<#if query_field_no gt 1> </#if>v-model:value="queryParam.${po.fieldName}"
|
||||
<#if query_field_no gt 1> </#if>code="${po.dictTable}"
|
||||
<#if query_field_no gt 1> </#if>:fieldConfig="[
|
||||
<#list sourceFields as fieldName>
|
||||
<#if query_field_no gt 1> </#if>{ source: '${fieldName}', target: '${dashedToCamel(targetFields[fieldName_index])}' },
|
||||
</#list>
|
||||
<#if query_field_no gt 1> </#if>]"
|
||||
<#if query_field_no gt 1> </#if>:multi="${po.extendParams.popupMulti?c}"
|
||||
<#if query_field_no gt 1> </#if>:setFieldsValue="setFieldsValue" allow-clear />
|
||||
<#elseif po.classType=='popup_dict'>
|
||||
<#if query_field_no gt 1> </#if><j-popup-dict
|
||||
<#if query_field_no gt 1> </#if>placeholder="请选择${po.filedComment}"
|
||||
<#if query_field_no gt 1> </#if>v-model:value="queryParam.${po.fieldName}"
|
||||
<#if query_field_no gt 1> </#if>dictCode="${po.dictTable},${po.dictText},${po.dictField}"
|
||||
<#if query_field_no gt 1> </#if>:multi="${po.extendParams.popupMulti?c}"
|
||||
<#if query_field_no gt 1> </#if><#if po.readonly=='Y'>disabled</#if> />
|
||||
<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
|
||||
<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
<#if query_field_no gt 1> </#if><j-select-multiple placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" dictCode="${po.dictTable},${po.dictText},${po.dictField}" allow-clear />
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#if query_field_no gt 1> </#if><j-select-multiple placeholder="请选择${po.filedComment}" v-model:value="queryParam.${po.fieldName}" dictCode="${po.dictField}" allow-clear />
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><a-input placeholder="请输入${po.filedComment}" v-model:value="queryParam.${po.fieldName}" allow-clear ></a-input>
|
||||
</#if>
|
||||
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
<#if query_field_no gt 1> </#if><a-input-number placeholder="请输入${po.filedComment}" v-model:value="queryParam.${po.fieldName}"></a-input-number>
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><a-input placeholder="请输入${po.filedComment}" v-model:value="queryParam.${autoStringSuffixForModel(po)}" allow-clear ></a-input>
|
||||
</#if>
|
||||
<#if query_field_no gt 1> </#if></a-form-item>
|
||||
<#if query_field_no gt 1> </#if></a-col>
|
||||
<#elseif po.queryMode=='like'>
|
||||
<#if query_field_no gt 1> </#if><a-col :lg="6">
|
||||
<#if query_field_no gt 1> </#if><a-form-item name="${autoStringSuffixForModel(po)}">
|
||||
<#if query_field_no gt 1> </#if><template #label><span title="${po.filedComment}"><#if po.filedComment?default("")?trim?length gt 4>${po.filedComment?substring(0,4)}<#else>${po.filedComment}</#if></span></template>
|
||||
<#if query_field_no gt 1> </#if><JInput v-model:value="queryParam.${po.fieldName}"/>
|
||||
<#if query_field_no gt 1> </#if></a-form-item>
|
||||
<#if query_field_no gt 1> </#if></a-col>
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><a-col :lg="6">
|
||||
<#if query_field_no gt 1> </#if><a-form-item name="${autoStringSuffixForModel(po)}">
|
||||
<#if query_field_no gt 1> </#if><template #label><span title="${po.filedComment}"><#if po.filedComment?default("")?trim?length gt 4>${po.filedComment?substring(0,4)}<#else>${po.filedComment}</#if></span></template>
|
||||
<#if po.classType=='date'>
|
||||
<#if query_field_no gt 1> </#if><a-range-picker value-format="YYYY-MM-DD" <#if po.extendParams?exists && po.extendParams.picker?exists>picker="${po.extendParams.picker}"</#if> v-model:value="queryParam.${po.fieldName}" class="query-group-cust"/>
|
||||
<#elseif po.classType=='time'>
|
||||
<#if query_field_no gt 1> </#if><a-time-range-picker value-format="HH:mm:ss" v-model:value="queryParam.${po.fieldName}" class="query-group-cust" />
|
||||
<#elseif po.classType=='datetime'>
|
||||
<#if query_field_no gt 1> </#if><a-range-picker showTime value-format="YYYY-MM-DD HH:mm:ss" v-model:value="queryParam.${po.fieldName}" class="query-group-cust"/>
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><JRangeNumber v-model:value="queryParam.${po.fieldName}" class="query-group-cust"></JRangeNumber>
|
||||
</#if>
|
||||
<#if query_field_no gt 1> </#if></a-form-item>
|
||||
<#if query_field_no gt 1> </#if></a-col>
|
||||
</#if>
|
||||
<#assign query_field_no=query_field_no+1>
|
||||
</#if>
|
||||
@@ -0,0 +1,25 @@
|
||||
<#-- 原生查询区域样式 -->
|
||||
.jeecg-basic-table-form-container {
|
||||
padding: 0;
|
||||
.table-page-search-submitButtons {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.query-group-cust{
|
||||
min-width: 100px !important;
|
||||
}
|
||||
.query-group-split-cust{
|
||||
width: 30px;
|
||||
display: inline-block;
|
||||
text-align: center
|
||||
}
|
||||
.ant-form-item:not(.ant-form-item-with-help){
|
||||
margin-bottom: 16px;
|
||||
height: 32px;
|
||||
}
|
||||
:deep(.ant-picker),:deep(.ant-input-number){
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<#assign sourceFields = col.dictField?default("")?trim?split(",")/>
|
||||
<#assign targetFields = col.dictText?default("")?trim?split(",")/>
|
||||
type: JVxeTypes.popup,
|
||||
popupCode:"${col.dictTable}",
|
||||
fieldConfig: [
|
||||
<#list sourceFields as fieldName>
|
||||
{ source: '${fieldName}', target: '${dashedToCamel(targetFields[fieldName_index])}' },
|
||||
</#list>
|
||||
],
|
||||
props:{
|
||||
multi: ${col.extendParams.popupMulti?c},
|
||||
},
|
||||
<#if col.readonly=='Y'>
|
||||
disabled:true,
|
||||
</#if>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<#-- 非原生查询区域样式 -->
|
||||
:deep(.ant-picker),:deep(.ant-input-number){
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<#assign sourceFields = po.dictField?default("")?trim?split(",")/>
|
||||
<#assign targetFields = po.dictText?default("")?trim?split(",")/>
|
||||
component: 'JPopup',
|
||||
componentProps: ({ formActionType }) => {
|
||||
const {setFieldsValue} = formActionType;
|
||||
return{
|
||||
setFieldsValue:setFieldsValue,
|
||||
code:"${po.dictTable}",
|
||||
fieldConfig: [
|
||||
<#list sourceFields as fieldName>
|
||||
{ source: '${fieldName}', target: '${dashedToCamel(targetFields[fieldName_index])}' },
|
||||
</#list>
|
||||
],
|
||||
multi:${po.extendParams.popupMulti?c}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<#list columns as po>
|
||||
<#if po.isShow == 'Y'>
|
||||
<#if po.fieldName != 'id'>
|
||||
<#if po.defaultVal??>
|
||||
<#if po.fieldDbType=="BigDecimal" || po.fieldDbType=="double" || po.fieldDbType=="int">
|
||||
${po.fieldName}:${po.defaultVal},
|
||||
<#else>
|
||||
${po.fieldName}:"${po.defaultVal}",
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
@@ -0,0 +1,13 @@
|
||||
<#list sub.colums as po>
|
||||
<#if po.isShow == 'Y'>
|
||||
<#if po.fieldName != 'id'>
|
||||
<#if po.defaultVal??>
|
||||
<#if po.fieldDbType=="BigDecimal" || po.fieldDbType=="double" || po.fieldDbType=="int">
|
||||
${po.fieldName}:${po.defaultVal},
|
||||
<#else>
|
||||
${po.fieldName}:"${po.defaultVal}",
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
@@ -0,0 +1,11 @@
|
||||
<#list columns as po>
|
||||
<#if po.isShow == 'Y' && po.fieldName != 'id'>
|
||||
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
${po.fieldName}: <#if po.defaultVal??>${po.defaultVal}<#else>undefined</#if>,
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
${po.fieldName}String: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,
|
||||
<#else>
|
||||
${po.fieldName}: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
@@ -0,0 +1,11 @@
|
||||
<#list columns as po>
|
||||
<#if po.isShow == 'Y' && po.fieldName != 'id'>
|
||||
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
${po.fieldName}: <#if po.defaultVal??>${po.defaultVal}<#else>undefined</#if>,
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
${po.fieldName}String: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,
|
||||
<#else>
|
||||
${po.fieldName}: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
@@ -0,0 +1,11 @@
|
||||
<#list sub.colums as po>
|
||||
<#if po.isShow == 'Y' && po.fieldName != 'id'>
|
||||
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
${po.fieldName}: <#if po.defaultVal??>${po.defaultVal}<#else>undefined</#if>,
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
${po.fieldName}String: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,
|
||||
<#else>
|
||||
${po.fieldName}: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
@@ -0,0 +1,47 @@
|
||||
-- 注意:该页面对应的前台目录为views/${entityPackagePath}文件夹下
|
||||
-- 如果你想更改到其他目录,请修改sql中component字段对应的值
|
||||
|
||||
<#assign mainId = "${.now?long}01">
|
||||
<#assign addId = "${.now?long}02">
|
||||
<#assign editId = "${.now?long}03">
|
||||
<#assign delId = "${.now?long}04">
|
||||
<#assign batchDelId = "${.now?long}05">
|
||||
<#assign exportId = "${.now?long}06">
|
||||
<#assign importId = "${.now?long}07">
|
||||
|
||||
-- 主菜单
|
||||
INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external)
|
||||
VALUES ('${mainId}', NULL, '${tableVo.ftlDescription}', '/${entityPackagePath}/${entityName?uncap_first}List', '${entityPackagePath}/${entityName}List', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0);
|
||||
|
||||
-- 新增
|
||||
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
|
||||
VALUES ('${addId}', '${mainId}', '添加${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${entityPackage}:${tableName}:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
|
||||
|
||||
-- 编辑
|
||||
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
|
||||
VALUES ('${editId}', '${mainId}', '编辑${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${entityPackage}:${tableName}:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
|
||||
|
||||
-- 删除
|
||||
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
|
||||
VALUES ('${delId}', '${mainId}', '删除${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${entityPackage}:${tableName}:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
|
||||
|
||||
-- 批量删除
|
||||
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
|
||||
VALUES ('${batchDelId}', '${mainId}', '批量删除${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${entityPackage}:${tableName}:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
|
||||
|
||||
-- 导出excel
|
||||
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
|
||||
VALUES ('${exportId}', '${mainId}', '导出excel_${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${entityPackage}:${tableName}:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
|
||||
|
||||
-- 导入excel
|
||||
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
|
||||
VALUES ('${importId}', '${mainId}', '导入excel_${tableVo.ftlDescription}', NULL, NULL, 0, NULL, NULL, 2, '${entityPackage}:${tableName}:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '${.now?string["yyyy-MM-dd HH:mm:ss"]}', NULL, NULL, 0, 0, '1', 0);
|
||||
|
||||
-- 角色授权(以 admin 角色为例,role_id 可替换)
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('${.now?long}08', 'f6817f48af4fb3af11b9e8bf182f618b', '${mainId}', NULL, '${.now?string["yyyy-MM-dd HH:mm:ss"]}', '127.0.0.1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('${.now?long}09', 'f6817f48af4fb3af11b9e8bf182f618b', '${addId}', NULL, '${.now?string["yyyy-MM-dd HH:mm:ss"]}', '127.0.0.1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('${.now?long}10', 'f6817f48af4fb3af11b9e8bf182f618b', '${editId}', NULL, '${.now?string["yyyy-MM-dd HH:mm:ss"]}', '127.0.0.1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('${.now?long}11', 'f6817f48af4fb3af11b9e8bf182f618b', '${delId}', NULL, '${.now?string["yyyy-MM-dd HH:mm:ss"]}', '127.0.0.1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('${.now?long}12', 'f6817f48af4fb3af11b9e8bf182f618b', '${batchDelId}', NULL, '${.now?string["yyyy-MM-dd HH:mm:ss"]}', '127.0.0.1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('${.now?long}13', 'f6817f48af4fb3af11b9e8bf182f618b', '${exportId}', NULL, '${.now?string["yyyy-MM-dd HH:mm:ss"]}', '127.0.0.1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('${.now?long}14', 'f6817f48af4fb3af11b9e8bf182f618b', '${importId}', NULL, '${.now?string["yyyy-MM-dd HH:mm:ss"]}', '127.0.0.1');
|
||||
@@ -0,0 +1,254 @@
|
||||
<#---->
|
||||
<#-- freemarker 的一些工具方法 -->
|
||||
<#---->
|
||||
<#-- 驼峰转其他字符 -->
|
||||
<#-- @param str 待转换的文本 -->
|
||||
<#-- @param character 要转换成的字符 -->
|
||||
<#-- @param case 转换大小写(normal 不转换,lower 小写,upper 大写) -->
|
||||
<#function camelToChar(str, character, case='normal')>
|
||||
<#assign text=str?replace("([a-z])([A-Z]+)","$1${character}$2","r")/>
|
||||
<#if case=="upper">
|
||||
<#return text?upper_case>
|
||||
<#elseif case=="lower">
|
||||
<#return text?lower_case>
|
||||
<#else>
|
||||
<#return text>
|
||||
</#if>
|
||||
</#function>
|
||||
<#--下划线转驼峰-->
|
||||
<#function dashedToCamel(str)>
|
||||
<#assign text=""/>
|
||||
<#assign strlist = str?split("_")/>
|
||||
<#list strlist as v>
|
||||
<#assign text=text+v?cap_first/>
|
||||
</#list>
|
||||
<#return text?uncap_first>
|
||||
</#function>
|
||||
<#-- 驼峰转下划线 -->
|
||||
<#function camelToDashed(str, case='lower')>
|
||||
<#return camelToChar(str, "_", case)>
|
||||
</#function>
|
||||
<#---->
|
||||
<#-- 驼峰转横线 -->
|
||||
<#function camelToHorizontal(str, case='normal')>
|
||||
<#return camelToChar(str, "-", case)>
|
||||
</#function>
|
||||
<#---->
|
||||
<#-- 获取 v-model 属性 -->
|
||||
<#function getVModel po,suffix="">
|
||||
<#return "v-model=\"queryParam.${po.fieldName}${suffix}\"">
|
||||
</#function>
|
||||
<#-- 获取 placeholder 属性 -->
|
||||
<#function getPlaceholder po,prefix,fillComment=true>
|
||||
<#if fillComment>
|
||||
<#return "placeholder=\"${prefix}${po.filedComment}\"">
|
||||
<#else>
|
||||
<#return "placeholder=\"${prefix}\"">
|
||||
</#if>
|
||||
</#function>
|
||||
<#-- ** 判断某字段是否配置了校验 * -->
|
||||
<#function poHasCheck po>
|
||||
<#if (po.fieldValidType!'')?trim?length gt 0 || po.nullable == 'N'>
|
||||
<#if po.fieldName != 'id'>
|
||||
<#if po.nullable == 'N'
|
||||
|| po.fieldValidType == '*'
|
||||
|| po.fieldValidType == 'only'
|
||||
|| po.fieldValidType == 'n6-16'
|
||||
|| po.fieldValidType == '*6-16'
|
||||
|| po.fieldValidType == 's6-18'
|
||||
|| po.fieldValidType == 'url'
|
||||
|| po.fieldValidType == 'e'
|
||||
|| po.fieldValidType == 'm'
|
||||
|| po.fieldValidType == 'p'
|
||||
|| po.fieldValidType == 's'
|
||||
|| po.fieldValidType == 'n'
|
||||
|| po.fieldValidType == 'z'
|
||||
|| po.fieldValidType == 'money'
|
||||
|| po.fieldValidType != ''
|
||||
>
|
||||
<#return true>
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
<#return false>
|
||||
</#function>
|
||||
<#-- ** 如果配置了校验就显示 validatorRules * -->
|
||||
<#function autoWriteRules po>
|
||||
<#if poHasCheck(po)>
|
||||
<#return ", validatorRules.${po.fieldName}">
|
||||
<#else>
|
||||
<#return "">
|
||||
</#if>
|
||||
</#function>
|
||||
|
||||
<#-- ** 如果Blob就显示 String * -->
|
||||
<#function autoStringSuffix po>
|
||||
<#if po.fieldDbType=='Blob'>
|
||||
<#return "'${po.fieldName}String'">
|
||||
<#else>
|
||||
<#return "'${po.fieldName}'">
|
||||
</#if>
|
||||
</#function>
|
||||
|
||||
<#-- ** 如果Blob就显示model方式 String * -->
|
||||
<#function autoStringSuffixForModel po>
|
||||
<#if po.fieldDbType=='Blob'>
|
||||
<#return "${po.fieldName}String">
|
||||
<#else>
|
||||
<#return "${po.fieldName}">
|
||||
</#if>
|
||||
</#function>
|
||||
|
||||
<#-- ** 高级查询生成 * -->
|
||||
<#function superQueryFieldList po>
|
||||
<#assign superQuery_dictTable="">
|
||||
<#assign superQuery_dictText="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
<#assign superQuery_dictTable="${po.dictTable}">
|
||||
</#if>
|
||||
<#if po.dictText?default("")?trim?length gt 1>
|
||||
<#assign superQuery_dictText="${po.dictText}">
|
||||
</#if>
|
||||
<#if po.classType=="popup">
|
||||
<#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}', popup:{code:'${po.dictTable}',field:'${po.dictField?split(',')[0]}',orgFields:'${po.dictField?split(',')[0]}',destFields:'${po.dictText?split(',')[0]}'}}">
|
||||
<#elseif po.classType=="sel_user" || po.classType=="sel_depart" || po.classType=="datetime" || po.classType=="date" || po.classType=="pca" || po.classType=="switch">
|
||||
<#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}'}">
|
||||
<#else>
|
||||
<#if po.classType=="sel_search" || po.classType=="list_multi">
|
||||
<#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}',dictTable:\"${superQuery_dictTable}\", dictText:'${superQuery_dictText}', dictCode:'${po.dictField}'}">
|
||||
<#elseif po.dictTable?? && po.dictTable!="" && po.classType!="sel_tree" && po.classType!="cat_tree" && po.classType!="link_down">
|
||||
<#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:\"${po.dictTable},${po.dictText},${po.dictField}\"}">
|
||||
<#elseif po.dictField?? && po.classType!="sel_tree" && po.classType!="cat_tree" && po.classType!="link_down">
|
||||
<#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:'${po.dictField}'}">
|
||||
<#elseif po.fieldDbType=="Text" || po.fieldDbType=="LongText">
|
||||
<#return "{type:'string',value:'${po.fieldName}',text:'${po.filedComment}'}">
|
||||
<#elseif po.fieldDbType=="Blob">
|
||||
<#return "{type:'byte',value:'${po.fieldName}',text:'${po.filedComment}'}">
|
||||
<#elseif po.fieldDbType=="BigDecimal" || po.fieldDbType=="double">
|
||||
<#return "{type:'number',value:'${po.fieldName}',text:'${po.filedComment}'}">
|
||||
<#else>
|
||||
<#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}'}">
|
||||
</#if>
|
||||
</#if>
|
||||
</#function>
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
<#-- ** 高级查询生成(Vue3 * -->
|
||||
<#function superQueryFieldListForVue3(po,order)>
|
||||
<#-- 高级查询日期格式化 -->
|
||||
<#assign picker=''>
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
<#assign picker='fieldExtendJson:"{\\"picker\\":\\"${po.extendParams.picker}\\"}",'>
|
||||
</#if>
|
||||
<#-- 字段展示/DB类型 -->
|
||||
<#assign baseAttrs="view: '${po.classType}', type: 'string',">
|
||||
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
<#assign baseAttrs="view: 'number', type: 'number',">
|
||||
</#if>
|
||||
|
||||
<#-- 特殊类型控件扩展字段 -->
|
||||
<#assign extAttrs="">
|
||||
<#assign dictCode="">
|
||||
<#if po.dictTable?default('')?trim?length gt 1 && po.dictText?default('')?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:fix 带条件字典存在单引号导致js编译错误---------- -->
|
||||
<#assign dictCode="dictTable: \"${po.dictTable}\", dictCode: '${po.dictField}', dictText: '${po.dictText}'">
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:fix 带条件字典存在单引号导致js编译错误---------- -->
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign dictCode="dictCode: '${po.dictField}'">
|
||||
<#else>
|
||||
<#assign dictCode="dictCode: ''">
|
||||
</#if>
|
||||
|
||||
<#if po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='checkbox' || po.classType=='radio'>
|
||||
<#assign extAttrs="${dictCode},">
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#-- 分类字典树 -->
|
||||
<#-- update-begin---author:chenrui ---date:20240109 for:[issue/5787]增加非空判断防止代码生成时空指针异常---------- -->
|
||||
<#assign extAttrs="pcode: '${po.dictField?default('')}',">
|
||||
<#-- update-end---author:chenrui ---date:20240109 for:[issue/5787]增加非空判断防止代码生成时空指针异常---------- -->
|
||||
<#elseif po.classType=='sel_tree'>
|
||||
<#-- 自定义树 -->
|
||||
<#if po.dictText??>
|
||||
<#-- dictText示例:id,pid,name,has_child -->
|
||||
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
|
||||
<#assign extAttrs="dict: '${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}'">
|
||||
<#elseif po.dictText?split(',')[1]??>
|
||||
<#assign extAttrs="pidField: '${po.dictText?split(',')[1]}'">
|
||||
<#elseif po.dictText?split(',')[3]??>
|
||||
<#assign extAttrs="hasChildField: '${po.dictText?split(',')[3]}'">
|
||||
</#if>
|
||||
</#if>
|
||||
<#-- update-begin---author:chenrui ---date:20240109 for:[issue/5787]增加非空判断防止代码生成时空指针异常---------- -->
|
||||
<#assign extAttrs="${extAttrs}, pidValue: '${po.dictField?default('')}',">
|
||||
<#-- update-end---author:chenrui ---date:20240109 for:[issue/5787]增加非空判断防止代码生成时空指针异常---------- -->
|
||||
<#elseif po.classType=='popup'>
|
||||
<#-- popup -->
|
||||
<#-- update-begin---author:chenrui ---date:20240109 for:[issue/5787]增加非空判断防止代码生成时空指针异常---------- -->
|
||||
<#if po.dictText?default("")?trim?length gt 1 && po.dictText?index_of(',') gt 0 && po.dictField?default("")?trim?length gt 1>
|
||||
<#-- update-begin---author:chenrui ---date:20240109 for:[issue/5787]增加非空判断防止代码生成时空指针异常---------- -->
|
||||
<#-- 如果有多个回填字段,找到popup字段对应的来源字段 -->
|
||||
<#assign orgFieldIx=po.dictText?split(',')?seq_index_of(po.fieldDbName)>
|
||||
<#assign orgField=po.dictField?split(',')[orgFieldIx]>
|
||||
<#else>
|
||||
<#assign orgField=po.dictField?default("")>
|
||||
</#if>
|
||||
<#assign extAttrs="code: '${po.dictTable?default('')}', orgFields: '${orgField}', destFields: '${po.fieldName}', popupMulti: false,">
|
||||
</#if>
|
||||
|
||||
<#return "${po.fieldName}: {title: '${po.filedComment}',order: ${order},${baseAttrs}${extAttrs}${picker}}" >
|
||||
</#function>
|
||||
<#-- update-end---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
|
||||
|
||||
<#-- vue3 获取表单modal的宽度-->
|
||||
<#function getModalWidth fieldRowNum>
|
||||
<#assign modal_width = 800>
|
||||
<#if fieldRowNum==2>
|
||||
<#assign modal_width = 896>
|
||||
<#elseif fieldRowNum==3>
|
||||
<#assign modal_width = 1024>
|
||||
<#elseif fieldRowNum==4>
|
||||
<#assign modal_width = 1280>
|
||||
</#if>
|
||||
<#return modal_width>
|
||||
</#function>
|
||||
|
||||
<#-- vue3 获取表单 colspan -->
|
||||
<#function getFormSpan fieldRowNum>
|
||||
<#assign form_span = 24>
|
||||
<#if fieldRowNum==2>
|
||||
<#assign form_span = 12>
|
||||
<#elseif fieldRowNum==3>
|
||||
<#assign form_span = 8>
|
||||
<#elseif fieldRowNum==4>
|
||||
<#assign form_span = 6>
|
||||
</#if>
|
||||
<#return form_span>
|
||||
</#function>
|
||||
|
||||
<#-- vue3 native 判断字段名不是 pidField -->
|
||||
<#function isNotPidField(tableVo, fieldDbName) >
|
||||
<#assign flag = true>
|
||||
<#if tableVo??>
|
||||
<#if tableVo.extendParams??>
|
||||
<#if tableVo.extendParams.pidField?default("")?trim == fieldDbName>
|
||||
<#assign flag = false>
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
<#return flag>
|
||||
</#function>
|
||||
|
||||
<#-- vue3 native 获取范围字段 -->
|
||||
<#function getRangeField(columns) >
|
||||
<#assign rangeField = "">
|
||||
<#list columns as po>
|
||||
<#if po.isQuery=='Y'>
|
||||
<#if po.queryMode=='group'>
|
||||
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal' || po.classType=='time' || po.classType=='date' || po.classType=='datetime'>
|
||||
<#assign rangeField = rangeField + "${po.fieldName},">
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
<#return rangeField>
|
||||
</#function>
|
||||
@@ -0,0 +1,57 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#if po.isShow == 'Y' && poHasCheck(po)>
|
||||
<#if po.fieldName != 'id'>
|
||||
${po.fieldName}: [
|
||||
<#assign fieldValidType = po.fieldValidType!''>
|
||||
<#-- 非空校验 -->
|
||||
<#if po.nullable == 'N' || fieldValidType == '*'>
|
||||
{ required: true, message: '请输入${po.filedComment}!'},
|
||||
<#elseif fieldValidType!=''>
|
||||
{ required: false},
|
||||
</#if>
|
||||
<#-- 唯一校验 -->
|
||||
<#if fieldValidType == 'only'>
|
||||
{ validator: (rule, value, callback) => validateDuplicateValue(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}', value, this.model.id, callback)},
|
||||
<#-- 6到16位数字 -->
|
||||
<#elseif fieldValidType == 'n6-16'>
|
||||
{ pattern: /^\d{6,16}$|^(?=\d+\.\d+)[\d.]{7,17}$/, message: '请输入6到16位数字!'},
|
||||
<#-- 6到16位任意字符 -->
|
||||
<#elseif fieldValidType == '*6-16'>
|
||||
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
|
||||
<#-- 6到18位字符串 -->
|
||||
<#elseif fieldValidType == 's6-18'>
|
||||
{ pattern: /^[a-z|A-Z]{6,18}$/, message: '请输入6到18位字母!'},
|
||||
<#-- 网址 -->
|
||||
<#elseif fieldValidType == 'url'>
|
||||
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
|
||||
<#-- 电子邮件 -->
|
||||
<#elseif fieldValidType == 'e'>
|
||||
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
|
||||
<#-- 手机号码 -->
|
||||
<#elseif fieldValidType == 'm'>
|
||||
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
|
||||
<#-- 邮政编码 -->
|
||||
<#elseif fieldValidType == 'p'>
|
||||
{ pattern: /^[0-9]\d{5}$/, message: '请输入正确的邮政编码!'},
|
||||
<#-- 字母 -->
|
||||
<#elseif fieldValidType == 's'>
|
||||
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
|
||||
<#-- 数字 -->
|
||||
<#elseif fieldValidType == 'n'>
|
||||
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
|
||||
<#-- 整数 -->
|
||||
<#elseif fieldValidType == 'z'>
|
||||
{ pattern: /^-?\d+$/, message: '请输入整数!'},
|
||||
<#-- 金额 -->
|
||||
<#elseif fieldValidType == 'money'>
|
||||
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
|
||||
<#-- 正则校验 -->
|
||||
<#elseif fieldValidType != '' && fieldValidType != '*'>
|
||||
{ pattern: '${fieldValidType}', message: '不符合校验规则!'},
|
||||
<#-- 无校验 -->
|
||||
<#else>
|
||||
<#t>
|
||||
</#if>
|
||||
],
|
||||
</#if>
|
||||
</#if>
|
||||
@@ -0,0 +1,5 @@
|
||||
validatorRules: {
|
||||
<#list columns as po>
|
||||
<#include "core.ftl">
|
||||
</#list>
|
||||
},
|
||||
@@ -0,0 +1,49 @@
|
||||
<#assign fieldValidType = po.fieldValidType!''>
|
||||
<#-- 非空校验 -->
|
||||
<#if po.nullable == 'N' || fieldValidType == '*'>
|
||||
{ required: true, message: '请输入${po.filedComment}!'}<#rt>,
|
||||
<#elseif fieldValidType!=''>
|
||||
{ required: false}<#rt>,
|
||||
</#if>
|
||||
<#-- 唯一校验 -->
|
||||
<#if fieldValidType == 'only'>
|
||||
{ validator: ${po.fieldName}Duplicatevalidate }<#rt>
|
||||
<#-- 6到16位数字 -->
|
||||
<#elseif fieldValidType == 'n6-16'>
|
||||
{ pattern: /^\d{6,16}$|^(?=\d+\.\d+)[\d.]{7,17}$/, message: '请输入6到16位数字!'}<#rt>,
|
||||
<#-- 6到16位任意字符 -->
|
||||
<#elseif fieldValidType == '*6-16'>
|
||||
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}<#rt>,
|
||||
<#-- 6到18位字符串 -->
|
||||
<#elseif fieldValidType == 's6-18'>
|
||||
{ pattern: /^[a-z|A-Z]{6,18}$/, message: '请输入6到18位字母!'},<#rt>,
|
||||
<#-- 网址 -->
|
||||
<#elseif fieldValidType == 'url'>
|
||||
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}<#rt>,
|
||||
<#-- 电子邮件 -->
|
||||
<#elseif fieldValidType == 'e'>
|
||||
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}<#rt>,
|
||||
<#-- 手机号码 -->
|
||||
<#elseif fieldValidType == 'm'>
|
||||
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}<#rt>,
|
||||
<#-- 邮政编码 -->
|
||||
<#elseif fieldValidType == 'p'>
|
||||
{ pattern: /^[0-9]\d{5}$/, message: '请输入正确的邮政编码!'}<#rt>,
|
||||
<#-- 字母 -->
|
||||
<#elseif fieldValidType == 's'>
|
||||
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}<#rt>,
|
||||
<#-- 数字 -->
|
||||
<#elseif fieldValidType == 'n'>
|
||||
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}<#rt>,
|
||||
<#-- 整数 -->
|
||||
<#elseif fieldValidType == 'z'>
|
||||
{ pattern: /^-?\d+$/, message: '请输入整数!'}<#rt>,
|
||||
<#-- 金额 -->
|
||||
<#elseif fieldValidType == 'money'>
|
||||
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}<#rt>,
|
||||
<#-- 正则校验 -->
|
||||
<#elseif fieldValidType != '' && fieldValidType != '*'>
|
||||
{ pattern: '${fieldValidType}', message: '不符合校验规则!'}<#rt>,
|
||||
<#else>
|
||||
<#t>
|
||||
</#if>
|
||||
@@ -0,0 +1,6 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#list columns as po>
|
||||
<#if po.isShow == 'Y' && poHasCheck(po)>
|
||||
${po.fieldName}: [<#include "vue3CoreNative.ftl">],
|
||||
</#if>
|
||||
</#list>
|
||||
@@ -0,0 +1,23 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#if col.isShow == 'Y' && poHasCheck(col)>
|
||||
validateRules: [
|
||||
<#if col.fieldName != 'id'>
|
||||
<#assign subFieldValidType = col.fieldValidType!''>
|
||||
<#-- 非空校验 -->
|
||||
<#if col.nullable == 'N' || subFieldValidType == '*'>
|
||||
{ required: true, message: '${'$'}{title}不能为空' },
|
||||
<#elseif subFieldValidType!=''>
|
||||
{ required: false},
|
||||
</#if>
|
||||
<#-- 其他情况下,只要有值就被认为是正则校验 -->
|
||||
<#if subFieldValidType?length gt 0>
|
||||
<#assign subMessage = '格式不正确'>
|
||||
<#if subFieldValidType == 'only' >
|
||||
<#assign subMessage = '不能重复'>
|
||||
</#if>
|
||||
{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }
|
||||
<#t>
|
||||
</#if>
|
||||
</#if>
|
||||
],
|
||||
</#if>
|
||||
@@ -0,0 +1,5 @@
|
||||
validatorRules: {
|
||||
<#list sub.colums as po>
|
||||
<#include "core.ftl">
|
||||
</#list>
|
||||
},
|
||||
@@ -0,0 +1,275 @@
|
||||
package ${bussiPackage}.${entityPackage}.controller;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.system.query.QueryRuleEnum;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import ${bussiPackage}.${entityPackage}.entity.${entityName};
|
||||
import ${bussiPackage}.${entityPackage}.service.I${entityName}Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
||||
import org.jeecgframework.poi.excel.entity.ExportParams;
|
||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
<#assign bpm_flag=false>
|
||||
<#assign has_multi_query_field=false>
|
||||
<#list originalColumns as po>
|
||||
<#if po.fieldDbName=='bpm_status'>
|
||||
<#assign bpm_flag=true>
|
||||
</#if>
|
||||
<#if po.isQuery=='Y' && (po.classType=='list' || po.classType=='list_multi' || po.classType=='radio' || po.classType=='checkbox')>
|
||||
<#assign has_multi_query_field=true>
|
||||
</#if>
|
||||
</#list>
|
||||
<#assign enhanceJavaList=[]>
|
||||
<#if tableVo.extendParams?? && tableVo.extendParams.enhanceJavaList??>
|
||||
<#assign enhanceJavaList = tableVo.extendParams.enhanceJavaList?filter(enhance -> enhance??)>
|
||||
</#if>
|
||||
/**
|
||||
* @Description: ${tableVo.ftlDescription}
|
||||
* @Author: jeecg-boot
|
||||
* @Date: ${.now?string["yyyy-MM-dd"]}
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Tag(name="${tableVo.ftlDescription}")
|
||||
@RestController
|
||||
@RequestMapping("/${entityPackagePath}/${entityName?uncap_first}")
|
||||
@Slf4j
|
||||
public class ${entityName}Controller extends JeecgController<${entityName}, I${entityName}Service> {
|
||||
@Autowired
|
||||
private I${entityName}Service ${entityName?uncap_first}Service;
|
||||
|
||||
/**
|
||||
* 分页列表查询
|
||||
*
|
||||
* @param ${entityName?uncap_first}
|
||||
* @param pageNo
|
||||
* @param pageSize
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "${tableVo.ftlDescription}-分页列表查询")
|
||||
@Operation(summary="${tableVo.ftlDescription}-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<IPage<${entityName}>> queryPageList(${entityName} ${entityName?uncap_first},
|
||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='query' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 查询前触发的方法,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.beforeQuery()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if has_multi_query_field>
|
||||
// 自定义查询规则
|
||||
Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
|
||||
// 自定义多选的查询规则为:LIKE_WITH_OR
|
||||
<#list originalColumns as po>
|
||||
<#if po.isQuery=='Y' && (po.classType=='list' || po.classType=='list_multi' || po.classType=='radio' || po.classType=='checkbox')>
|
||||
customeRuleMap.put("${po.fieldName}", QueryRuleEnum.LIKE_WITH_OR);
|
||||
</#if>
|
||||
</#list>
|
||||
QueryWrapper<${entityName}> queryWrapper = QueryGenerator.initQueryWrapper(${entityName?uncap_first}, req.getParameterMap(),customeRuleMap);
|
||||
<#else>
|
||||
QueryWrapper<${entityName}> queryWrapper = QueryGenerator.initQueryWrapper(${entityName?uncap_first}, req.getParameterMap());
|
||||
</#if>
|
||||
Page<${entityName}> page = new Page<${entityName}>(pageNo, pageSize);
|
||||
IPage<${entityName}> pageList = ${entityName?uncap_first}Service.page(page, queryWrapper);
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='query' && enhanceJava.event=='end' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 查询后触发的方法,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.afterQuery()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param ${entityName?uncap_first}
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "${tableVo.ftlDescription}-添加")
|
||||
@Operation(summary="${tableVo.ftlDescription}-添加")
|
||||
@RequiresPermissions("${entityPackage}:${tableName}:add")
|
||||
@PostMapping(value = "/add")
|
||||
public Result<String> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='add' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 新增前的处理方法,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.beforeAdd()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
<#if bpm_flag>
|
||||
${entityName?uncap_first}.setBpmStatus("1");
|
||||
</#if>
|
||||
${entityName?uncap_first}Service.save(${entityName?uncap_first});
|
||||
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='add' && enhanceJava.event=='end' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 新增后的处理方法,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.afterAdd()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
return Result.OK("添加成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*
|
||||
* @param ${entityName?uncap_first}
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "${tableVo.ftlDescription}-编辑")
|
||||
@Operation(summary="${tableVo.ftlDescription}-编辑")
|
||||
@RequiresPermissions("${entityPackage}:${tableName}:edit")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||
public Result<String> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='edit' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 编辑前,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.beforeEdit()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='edit' && enhanceJava.event=='end' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 编辑后,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.afterEdit()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
return Result.OK("编辑成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
|
||||
@Operation(summary="${tableVo.ftlDescription}-通过id删除")
|
||||
@RequiresPermissions("${entityPackage}:${tableName}:delete")
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
|
||||
${entityName?uncap_first}Service.removeById(id);
|
||||
return Result.OK("删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
|
||||
@Operation(summary="${tableVo.ftlDescription}-批量删除")
|
||||
@RequiresPermissions("${entityPackage}:${tableName}:deleteBatch")
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||
this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(",")));
|
||||
return Result.OK("批量删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id查询
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "${tableVo.ftlDescription}-通过id查询")
|
||||
@Operation(summary="${tableVo.ftlDescription}-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<${entityName}> queryById(@RequestParam(name="id",required=true) String id) {
|
||||
${entityName} ${entityName?uncap_first} = ${entityName?uncap_first}Service.getById(id);
|
||||
if(${entityName?uncap_first}==null) {
|
||||
return Result.error("未找到对应数据");
|
||||
}
|
||||
return Result.OK(${entityName?uncap_first});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel
|
||||
*
|
||||
* @param request
|
||||
* @param ${entityName?uncap_first}
|
||||
*/
|
||||
@RequiresPermissions("${entityPackage}:${tableName}:exportXls")
|
||||
@RequestMapping(value = "/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='export' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 导出前,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.beforeExport()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过excel导入数据
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequiresPermissions("${entityPackage}:${tableName}:importExcel")
|
||||
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
||||
<#if enhanceJavaList?size gt 0>
|
||||
<#list enhanceJavaList as enhanceJava>
|
||||
<#if enhanceJava.buttonCode=='import' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'>
|
||||
//TODO 导入前,代码生成后,请手工实现增强类逻辑;
|
||||
//${entityName?uncap_first}Service.beforeImport()
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
return super.importExcel(request, response, ${entityName}.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<#include "/common/utils.ftl">
|
||||
package ${bussiPackage}.${entityPackage}.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Date;
|
||||
import java.math.BigDecimal;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import org.jeecg.common.constant.ProvinceCityArea;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import org.jeecg.common.aspect.annotation.Dict;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @Description: ${tableVo.ftlDescription}
|
||||
* @Author: jeecg-boot
|
||||
* @Date: ${.now?string["yyyy-MM-dd"]}
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Data
|
||||
@TableName("${tableName}")
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(description="${tableVo.ftlDescription}")
|
||||
public class ${entityName} implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
<#assign excel_ignore_arr=['createBy','createTime','updateBy','updateTime','sysOrgCode']>
|
||||
<#assign excel_ignore_classType_arr=['pca','switch','cat_tree']>
|
||||
<#list originalColumns as po>
|
||||
<#-- 生成字典Code -->
|
||||
<#assign list_field_dictCode="">
|
||||
<#if po.classType='sel_user'>
|
||||
<#assign list_field_dictCode=', dictTable = "sys_user", dicText = "${camelToDashed(po.extendParams.text?default(\"realname\")?trim)}", dicCode = "${camelToDashed(po.extendParams.store?default(\"username\")?trim)}"'>
|
||||
<#elseif po.classType='sel_depart'>
|
||||
<#assign list_field_dictCode=', dictTable = "sys_depart", dicText = "${camelToDashed(po.extendParams.text?default(\"depart_name\")?trim)}", dicCode = "${camelToDashed(po.extendParams.store?default(\"id\")?trim)}"'>
|
||||
<#elseif po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox'>
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
<#assign list_field_dictCode=', dictTable = "${po.dictTable}", dicText = "${po.dictText}", dicCode = "${po.dictField}"'>
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign list_field_dictCode=', dicCode = "${po.dictField}"'>
|
||||
</#if>
|
||||
<#elseif po.classType=='sel_tree'>
|
||||
<#assign list_field_dictCode=', dictTable = "${po.dictTable}", dicText = "${po.dictText?split(",")[2]}", dicCode = "${po.dictText?split(",")[0]}"'>
|
||||
<#elseif po.classType=='link_table'>
|
||||
<#assign list_field_dictCode=', dictTable = "${po.dictTable}", dicCode = "${po.dictField}", dicText = "${po.dictText?split(",")[0]}"'>
|
||||
</#if>
|
||||
/**${po.filedComment}*/
|
||||
<#if po.fieldName == primaryKeyField>
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
<#else>
|
||||
<#if po.fieldDbType =='Date' || po.fieldDbType =='Datetime'>
|
||||
<#if po.classType=='date'>
|
||||
<#if !excel_ignore_arr?seq_contains("${po.fieldName}")>
|
||||
@Excel(name = "${po.filedComment}", width = 15, format = "yyyy-MM-dd")
|
||||
</#if>
|
||||
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
|
||||
@DateTimeFormat(pattern="yyyy-MM-dd")
|
||||
<#else>
|
||||
<#if !excel_ignore_arr?seq_contains("${po.fieldName}")>
|
||||
@Excel(name = "${po.filedComment}", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
</#if>
|
||||
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
|
||||
</#if>
|
||||
<#else>
|
||||
<#if !excel_ignore_arr?seq_contains("${po.fieldName}") && !excel_ignore_classType_arr?seq_contains("${po.classType}")>
|
||||
@Excel(name = "${po.filedComment}", width = 15${list_field_dictCode})
|
||||
</#if>
|
||||
</#if>
|
||||
<#if list_field_dictCode?length gt 1>
|
||||
@Dict(${list_field_dictCode?substring(2)})
|
||||
</#if>
|
||||
<#-- <#if po.classType!='popup'>
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
@Dict(dicCode="${po.dictField}",dicText="${po.dictText}",dictTable="${po.dictTable}")
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
@Dict(dicCode="${po.dictField}")
|
||||
</#if>
|
||||
</#if>-->
|
||||
</#if>
|
||||
<#include "/common/blob.ftl">
|
||||
</#list>
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package ${bussiPackage}.${entityPackage}.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import ${bussiPackage}.${entityPackage}.entity.${entityName};
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @Description: ${tableVo.ftlDescription}
|
||||
* @Author: jeecg-boot
|
||||
* @Date: ${.now?string["yyyy-MM-dd"]}
|
||||
* @Version: V1.0
|
||||
*/
|
||||
public interface ${entityName}Mapper extends BaseMapper<${entityName}> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="${bussiPackage}.${entityPackage}.mapper.${entityName}Mapper">
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,14 @@
|
||||
package ${bussiPackage}.${entityPackage}.service;
|
||||
|
||||
import ${bussiPackage}.${entityPackage}.entity.${entityName};
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @Description: ${tableVo.ftlDescription}
|
||||
* @Author: jeecg-boot
|
||||
* @Date: ${.now?string["yyyy-MM-dd"]}
|
||||
* @Version: V1.0
|
||||
*/
|
||||
public interface I${entityName}Service extends IService<${entityName}> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package ${bussiPackage}.${entityPackage}.service.impl;
|
||||
|
||||
import ${bussiPackage}.${entityPackage}.entity.${entityName};
|
||||
import ${bussiPackage}.${entityPackage}.mapper.${entityName}Mapper;
|
||||
import ${bussiPackage}.${entityPackage}.service.I${entityName}Service;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
/**
|
||||
* @Description: ${tableVo.ftlDescription}
|
||||
* @Author: jeecg-boot
|
||||
* @Date: ${.now?string["yyyy-MM-dd"]}
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Service
|
||||
public class ${entityName}ServiceImpl extends ServiceImpl<${entityName}Mapper, ${entityName}> implements I${entityName}Service {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<view>
|
||||
<!--标题和返回-->
|
||||
<cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName">
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">${tableVo.ftlDescription}</block>
|
||||
</cu-custom>
|
||||
<!--表单区域-->
|
||||
<view>
|
||||
<form>
|
||||
<#list columns as po><#rt/>
|
||||
<#if po.fieldName !='id'><#rt/>
|
||||
<#if po.classType =='date'>
|
||||
<my-date label="${po.filedComment}:" fields="day" v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}"></my-date>
|
||||
<#elseif po.classType =='datetime'>
|
||||
<my-date label="${po.filedComment}:" v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}"></my-date>
|
||||
<#else>
|
||||
<view class="cu-form-group">
|
||||
<view class="flex align-center">
|
||||
<view class="title"><text space="ensp">${po.filedComment}:</text></view>
|
||||
<input <#if "int,BigDecimal,double,"?contains(po.fieldDbType)>type="number"</#if> placeholder="请输入${po.filedComment}" v-model="model.${po.fieldName}"/>
|
||||
</view>
|
||||
</view>
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
<view class="padding">
|
||||
<button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit">
|
||||
<text v-if="loading" class="cuIcon-loading2 cuIconfont-spin"></text>提交
|
||||
</button>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myDate from '@/components/my-componets/my-date.vue'
|
||||
|
||||
export default {
|
||||
name: "${entityName}Form",
|
||||
components:{ myDate },
|
||||
props:{
|
||||
formData:{
|
||||
type:Object,
|
||||
default:()=>{},
|
||||
required:false
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
CustomBar: this.CustomBar,
|
||||
NavBarColor: this.NavBarColor,
|
||||
loading:false,
|
||||
model: {},
|
||||
backRouteName:'index',
|
||||
url: {
|
||||
queryById: "/${entityPackagePath}/${entityName?uncap_first}/queryById",
|
||||
add: "/${entityPackagePath}/${entityName?uncap_first}/add",
|
||||
edit: "/${entityPackagePath}/${entityName?uncap_first}/edit",
|
||||
},
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.initFormData();
|
||||
},
|
||||
methods:{
|
||||
initFormData(){
|
||||
if(this.formData){
|
||||
let dataId = this.formData.dataId;
|
||||
this.$http.get(this.url.queryById,{params:{id:dataId}}).then((res)=>{
|
||||
if(res.data.success){
|
||||
console.log("表单数据",res);
|
||||
this.model = res.data.result;
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
onSubmit() {
|
||||
let myForm = {...this.model};
|
||||
this.loading = true;
|
||||
let url = myForm.id?this.url.edit:this.url.add;
|
||||
this.$http.post(url,myForm).then(res=>{
|
||||
console.log("res",res)
|
||||
this.loading = false
|
||||
this.$Router.push({name:this.backRouteName})
|
||||
}).catch(()=>{
|
||||
this.loading = false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<view>
|
||||
<!--标题和返回-->
|
||||
<cu-custom :bgColor="NavBarColor" isBack>
|
||||
<block slot="backText">返回</block>
|
||||
<block slot="content">${tableVo.ftlDescription}</block>
|
||||
</cu-custom>
|
||||
<!--滚动加载列表-->
|
||||
<mescroll-body ref="mescrollRef" bottom="88" @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback">
|
||||
<view class="cu-list menu">
|
||||
<view class="cu-item" v-for="(item,index) in list" :key="index" @click="goHome">
|
||||
<view class="flex" style="width:100%">
|
||||
<text class="text-lg" style="color: #000;">
|
||||
{{ item.createBy}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js";
|
||||
import Mixin from "@/common/mixin/Mixin.js";
|
||||
|
||||
export default {
|
||||
name: '${tableVo.ftlDescription}',
|
||||
mixins: [MescrollMixin,Mixin],
|
||||
data() {
|
||||
return {
|
||||
CustomBar:this.CustomBar,
|
||||
NavBarColor:this.NavBarColor,
|
||||
url: "/${entityPackagePath}/${entityName?uncap_first}/list",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
goHome(){
|
||||
this.$Router.push({name: "index"})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { render } from '@/common/renderUtils';
|
||||
//列表数据
|
||||
export const columns = [
|
||||
<#list columns as po>
|
||||
<#if po.isShowList =='Y' && po.fieldName !='id' && po.fieldName !='delFlag'>
|
||||
{
|
||||
title: '${po.filedComment}',
|
||||
align:"center",
|
||||
<#if po.sort=='Y'>
|
||||
sorter: true,
|
||||
</#if>
|
||||
<#if po.classType=='date'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
dataIndex: '${po.fieldName}String'
|
||||
<#elseif po.classType=='umeditor'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#elseif po.classType=='pca'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#elseif po.classType=='file'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#elseif po.classType=='image'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
customRender:render.renderImage,
|
||||
<#elseif po.classType=='switch'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#assign switch_extend_arr=['Y','N']>
|
||||
<#if po.dictField?default("")?contains("[")>
|
||||
<#assign switch_extend_arr=po.dictField?eval>
|
||||
</#if>
|
||||
<#list switch_extend_arr as a>
|
||||
<#if a_index == 0>
|
||||
<#assign switch_extend_arr1=a>
|
||||
<#else>
|
||||
<#assign switch_extend_arr2=a>
|
||||
</#if>
|
||||
</#list>
|
||||
customRender:({text}) => {
|
||||
return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
|
||||
},
|
||||
<#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user' || po.classType=='popup_dict'>
|
||||
dataIndex: '${po.fieldName}_dictText'
|
||||
<#else>
|
||||
dataIndex: '${po.fieldName}'
|
||||
</#if>
|
||||
},
|
||||
</#if>
|
||||
</#list>
|
||||
];
|
||||
@@ -0,0 +1,560 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<route lang="json5" type="page">
|
||||
{
|
||||
layout: 'default',
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
navigationBarTitleText: '${tableVo.ftlDescription}',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
<template>
|
||||
<#assign onlyFields = []>
|
||||
<PageLayout :navTitle="navTitle" :backRouteName="backRouteName">
|
||||
<scroll-view class="scrollArea" scroll-y>
|
||||
<view class="form-container">
|
||||
<wd-form ref="form" :model="myFormData">
|
||||
<wd-cell-group border>
|
||||
<#list columns as po><#rt/>
|
||||
<#assign form_field_dictCode="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictField}">
|
||||
</#if>
|
||||
<view class="{ 'mt-14px': ${po_index % 2} == 0 }">
|
||||
<#if po.fieldName !='id' && po.isShow =='Y' && po.fieldName !='delFlag'><#rt/>
|
||||
<#if po.classType =='image'>
|
||||
<!-- 图片 -->
|
||||
<wd-cell
|
||||
:title="get4Label('${po.filedComment}')"
|
||||
title-width="100px"
|
||||
<#if po.nullable == 'N'>
|
||||
:required="true"
|
||||
</#if>
|
||||
>
|
||||
<online-image
|
||||
v-model:value="myFormData[${autoStringSuffix(po)}]"
|
||||
name=${autoStringSuffix(po)}
|
||||
<#if po.uploadnum??>
|
||||
:maxNum="${po.uploadnum}"
|
||||
</#if>
|
||||
/>
|
||||
</wd-cell>
|
||||
<#elseif po.classType =='file'>
|
||||
<wd-cell
|
||||
:title="get4Label('${po.filedComment}')"
|
||||
title-width="100px"
|
||||
<#if po.nullable == 'N'>
|
||||
:required="true"
|
||||
</#if>
|
||||
>
|
||||
|
||||
<online-file-custom
|
||||
v-model:value="myFormData[${autoStringSuffix(po)}]"
|
||||
name=${autoStringSuffix(po)}
|
||||
></online-file-custom>
|
||||
</wd-cell>
|
||||
<#elseif po.classType =='datetime' || po.classType =='time'>
|
||||
<DateTime
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
type="${po.classType}"
|
||||
<#if po.classType =='datetime'>
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
<#else>
|
||||
format="HH:mm:ss"
|
||||
</#if>
|
||||
name=${autoStringSuffix(po)}
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
></DateTime>
|
||||
<#elseif po.classType =='date'>
|
||||
<online-date
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
:type="getDateExtendType('${po.extendParams.picker}')"
|
||||
<#else>
|
||||
type="${po.classType}"
|
||||
</#if>
|
||||
name=${autoStringSuffix(po)}
|
||||
v-model:value="myFormData[${autoStringSuffix(po)}]"
|
||||
></online-date>
|
||||
<#elseif po.classType =='switch'>
|
||||
<#assign switch_extend_arr=['Y','N']>
|
||||
<#if po.dictField?default("")?contains("[")>
|
||||
<#assign switch_extend_arr=po.dictField?eval>
|
||||
</#if>
|
||||
<!-- 开关 -->
|
||||
<wd-cell
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
name=${autoStringSuffix(po)}
|
||||
title-width="100px"
|
||||
center
|
||||
>
|
||||
<wd-switch
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
name=${autoStringSuffix(po)}
|
||||
size="18px"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
active-value="${switch_extend_arr[0]}"
|
||||
inactive-value="${switch_extend_arr[1]}"
|
||||
/>
|
||||
</wd-cell>
|
||||
<#elseif po.classType =='list' || po.classType =='sel_search'>
|
||||
<online-select
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
type="${po.classType}"
|
||||
name=${autoStringSuffix(po)}
|
||||
dict="${form_field_dictCode}"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
></online-select>
|
||||
<#elseif po.classType =='checkbox'>
|
||||
<online-checkbox
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
type="${po.classType}"
|
||||
name=${autoStringSuffix(po)}
|
||||
dict="${form_field_dictCode}"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
></online-checkbox>
|
||||
<#elseif po.classType =='radio'>
|
||||
<online-radio
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
type="${po.classType}"
|
||||
name=${autoStringSuffix(po)}
|
||||
dict="${form_field_dictCode}"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
></online-radio>
|
||||
<#elseif po.classType =='list_multi'>
|
||||
<online-multi
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
type="${po.classType}"
|
||||
name=${autoStringSuffix(po)}
|
||||
dict="${form_field_dictCode}"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
></online-multi>
|
||||
<#elseif po.classType =='textarea' || po.classType =='markdown' || po.classType =='umeditor'>
|
||||
<wd-textarea
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
type="${po.classType}"
|
||||
name=${autoStringSuffix(po)}
|
||||
prop=${autoStringSuffix(po)}
|
||||
clearable
|
||||
:maxlength="300"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
></wd-textarea>
|
||||
<#elseif po.classType =='password'>
|
||||
<wd-input
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
show-password
|
||||
name=${autoStringSuffix(po)}
|
||||
prop=${autoStringSuffix(po)}
|
||||
clearable
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
></wd-input>
|
||||
<#elseif po.classType =='pca'>
|
||||
<online-pca
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
name=${autoStringSuffix(po)}
|
||||
prop=${autoStringSuffix(po)}
|
||||
clearable
|
||||
v-model:value="myFormData[${autoStringSuffix(po)}]"
|
||||
></online-pca>
|
||||
<#elseif po.classType =='popup_dict'>
|
||||
<PopupDict
|
||||
labelWidth="100px"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
:multi="${po.extendParams.popupMulti?c}"
|
||||
dictCode="${po.dictTable},${po.dictText},${po.dictField}"
|
||||
></PopupDict>
|
||||
<#elseif po.classType =='popup'>
|
||||
<#assign sourceFields = po.dictField?default("")?trim?split(",")/>
|
||||
<#assign targetFields = po.dictText?default("")?trim?split(",")/>
|
||||
<Popup
|
||||
labelWidth="100px"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
:multi="${po.extendParams.popupMulti?c}"
|
||||
code="${po.dictTable}"
|
||||
:setFieldsValue="setFieldsValue"
|
||||
:fieldConfig="[
|
||||
<#list sourceFields as fieldName>
|
||||
{ source: '${fieldName}', target: '${dashedToCamel(targetFields[fieldName_index])}' },
|
||||
</#list>
|
||||
]"
|
||||
></Popup>
|
||||
<#elseif po.classType =='link_table'>
|
||||
<online-popup-link-record
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
labelWidth="100px"
|
||||
name=${autoStringSuffix(po)}
|
||||
:formSchema="getFormSchema('${po.dictTable}','${po.dictField}','${po.dictText}')"
|
||||
v-model:value="myFormData[${autoStringSuffix(po)}]"
|
||||
></online-popup-link-record>
|
||||
<#elseif po.classType =='sel_user'>
|
||||
<select-user
|
||||
labelWidth="100px"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
name=${autoStringSuffix(po)}
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
<#if po.extendParams?exists && po.extendParams.text?exists>labelKey="${po.extendParams.text}"</#if>
|
||||
<#if po.extendParams?exists && po.extendParams.store?exists>rowKey="${po.extendParams.store}"</#if>
|
||||
></select-user>
|
||||
<#elseif po.classType =='sel_depart'>
|
||||
<select-dept
|
||||
labelWidth="100px"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
name=${autoStringSuffix(po)}
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
<#if po.extendParams?exists && po.extendParams.text?exists>labelKey="${po.extendParams.text}"</#if>
|
||||
<#if po.extendParams?exists && po.extendParams.store?exists>rowKey="${po.extendParams.store}"</#if>
|
||||
:multiple="${po.extendParams.multi?default('true')}"
|
||||
></select-dept>
|
||||
<#elseif po.classType =='cat_tree'>
|
||||
<CategorySelect
|
||||
labelWidth="100px"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
pcode="${po.dictField?default("")}"
|
||||
></CategorySelect>
|
||||
<#elseif po.classType =='sel_tree'>
|
||||
<TreeSelect
|
||||
labelWidth="100px"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
<#if po.dictText??>
|
||||
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
|
||||
dict="${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}"
|
||||
<#elseif po.dictText?split(',')[1]??>
|
||||
pidField="${po.dictText?split(',')[1]}"
|
||||
<#elseif po.dictText?split(',')[3]??>
|
||||
hasChildField="${po.dictText?split(',')[3]}"
|
||||
</#if>
|
||||
</#if>
|
||||
:pidValue="`${po.dictField}`"
|
||||
></TreeSelect>
|
||||
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
<wd-input
|
||||
label-width="100px"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
name=${autoStringSuffix(po)}
|
||||
prop=${autoStringSuffix(po)}
|
||||
placeholder="请选择${po.filedComment}"
|
||||
inputMode="numeric"
|
||||
:rules="[
|
||||
<#if po.fieldName != 'id'>
|
||||
<#assign fieldValidType = po.fieldValidType!''>
|
||||
<#-- 非空校验 -->
|
||||
<#if po.nullable == 'N' || fieldValidType == '*'>
|
||||
{ required: true, message: '请输入${po.filedComment}!'},
|
||||
<#elseif fieldValidType!=''>
|
||||
{ required: false},
|
||||
</#if>
|
||||
<#-- 6到16位数字 -->
|
||||
<#if fieldValidType == 'n6-16'>
|
||||
{ pattern: /^\d{6,16}$|^(?=\d+\.\d+)[\d.]{7,17}$/, message: '请输入6到16位数字!'},
|
||||
<#-- 6到16位任意字符 -->
|
||||
<#elseif fieldValidType == '*6-16'>
|
||||
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
|
||||
<#-- 6到18位字母 -->
|
||||
<#elseif fieldValidType == 's6-18'>
|
||||
{ pattern: /^[a-z|A-Z]{6,18}$/, message: '请输入6到18位字母!'},
|
||||
<#-- 网址 -->
|
||||
<#elseif fieldValidType == 'url'>
|
||||
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
|
||||
<#-- 电子邮件 -->
|
||||
<#elseif fieldValidType == 'e'>
|
||||
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
|
||||
<#-- 手机号码 -->
|
||||
<#elseif fieldValidType == 'm'>
|
||||
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
|
||||
<#-- 邮政编码 -->
|
||||
<#elseif fieldValidType == 'p'>
|
||||
{ pattern: /^[0-9]\d{5}$/, message: '请输入正确的邮政编码!'},
|
||||
<#-- 字母 -->
|
||||
<#elseif fieldValidType == 's'>
|
||||
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
|
||||
<#-- 数字 -->
|
||||
<#elseif fieldValidType == 'n'>
|
||||
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
|
||||
<#-- 整数 -->
|
||||
<#elseif fieldValidType == 'z'>
|
||||
{ pattern: /^-?\d+$/, message: '请输入整数!'},
|
||||
<#-- 金额 -->
|
||||
<#elseif fieldValidType == 'money'>
|
||||
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
|
||||
<#-- 唯一校验 -->
|
||||
<#elseif fieldValidType != '' && fieldValidType == 'only'>
|
||||
<#assign onlyFields = onlyFields + [autoStringSuffix(po)]>
|
||||
<#-- 正则校验 -->
|
||||
<#elseif fieldValidType != '' && fieldValidType != '*'>
|
||||
{ pattern: /${fieldValidType}/, message: '不符合校验规则!'},
|
||||
<#-- 无校验 -->
|
||||
<#else>
|
||||
<#t>
|
||||
</#if>
|
||||
</#if>
|
||||
]"
|
||||
clearable
|
||||
/>
|
||||
<#else>
|
||||
<wd-input
|
||||
label-width="100px"
|
||||
v-model="myFormData[${autoStringSuffix(po)}]"
|
||||
:label="get4Label('${po.filedComment}')"
|
||||
name=${autoStringSuffix(po)}
|
||||
prop=${autoStringSuffix(po)}
|
||||
placeholder="请选择${po.filedComment}"
|
||||
:rules="[
|
||||
<#if po.fieldName != 'id'>
|
||||
<#assign fieldValidType = po.fieldValidType!''>
|
||||
<#-- 非空校验 -->
|
||||
<#if po.nullable == 'N' || fieldValidType == '*'>
|
||||
{ required: true, message: '请输入${po.filedComment}!'},
|
||||
<#elseif fieldValidType!=''>
|
||||
{ required: false},
|
||||
</#if>
|
||||
<#-- 6到16位数字 -->
|
||||
<#if fieldValidType == 'n6-16'>
|
||||
{ pattern: /^\d{6,16}$|^(?=\d+\.\d+)[\d.]{7,17}$/, message: '请输入6到16位数字!'},
|
||||
<#-- 6到16位任意字符 -->
|
||||
<#elseif fieldValidType == '*6-16'>
|
||||
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
|
||||
<#-- 6到18位字母 -->
|
||||
<#elseif fieldValidType == 's6-18'>
|
||||
{ pattern: /^[a-z|A-Z]{6,18}$/, message: '请输入6到18位字母!'},
|
||||
<#-- 网址 -->
|
||||
<#elseif fieldValidType == 'url'>
|
||||
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
|
||||
<#-- 电子邮件 -->
|
||||
<#elseif fieldValidType == 'e'>
|
||||
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
|
||||
<#-- 手机号码 -->
|
||||
<#elseif fieldValidType == 'm'>
|
||||
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
|
||||
<#-- 邮政编码 -->
|
||||
<#elseif fieldValidType == 'p'>
|
||||
{ pattern: /^[0-9]\d{5}$/, message: '请输入正确的邮政编码!'},
|
||||
<#-- 字母 -->
|
||||
<#elseif fieldValidType == 's'>
|
||||
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
|
||||
<#-- 数字 -->
|
||||
<#elseif fieldValidType == 'n'>
|
||||
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
|
||||
<#-- 整数 -->
|
||||
<#elseif fieldValidType == 'z'>
|
||||
{ pattern: /^-?\d+$/, message: '请输入整数!'},
|
||||
<#-- 金额 -->
|
||||
<#elseif fieldValidType == 'money'>
|
||||
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
|
||||
<#-- 唯一校验 -->
|
||||
<#elseif fieldValidType != '' && fieldValidType == 'only'>
|
||||
<#assign onlyFields = onlyFields + [autoStringSuffix(po)]>
|
||||
<#-- 正则校验 -->
|
||||
<#elseif fieldValidType != '' && fieldValidType != '*'>
|
||||
{ pattern: /${fieldValidType}/, message: '不符合校验规则!'},
|
||||
<#-- 无校验 -->
|
||||
<#else>
|
||||
<#t>
|
||||
</#if>
|
||||
</#if>
|
||||
]"
|
||||
clearable
|
||||
/>
|
||||
</#if>
|
||||
</#if>
|
||||
</view>
|
||||
</#list>
|
||||
</wd-cell-group>
|
||||
</wd-form>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="footer">
|
||||
<wd-button :disabled="loading" block :loading="loading" @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</PageLayout>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { http } from '@/utils/http'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
import { useRouter } from '@/plugin/uni-mini-router'
|
||||
import { ref, onMounted, computed,reactive } from 'vue'
|
||||
import OnlineImage from '@/components/online/view/online-image.vue'
|
||||
import OnlineFile from '@/components/online/view/online-file.vue'
|
||||
import OnlineFileCustom from '@/components/online/view/online-file-custom.vue'
|
||||
import OnlineSelect from '@/components/online/view/online-select.vue'
|
||||
import OnlineTime from '@/components/online/view/online-time.vue'
|
||||
import OnlineDate from '@/components/online/view/online-date.vue'
|
||||
import OnlineRadio from '@/components/online/view/online-radio.vue'
|
||||
import OnlineCheckbox from '@/components/online/view/online-checkbox.vue'
|
||||
import OnlineMulti from '@/components/online/view/online-multi.vue'
|
||||
import OnlinePopupLinkRecord from '@/components/online/view/online-popup-link-record.vue'
|
||||
import OnlinePca from '@/components/online/view/online-pca.vue'
|
||||
import SelectDept from '@/components/SelectDept/SelectDept.vue'
|
||||
import SelectUser from '@/components/SelectUser/SelectUser.vue'
|
||||
import {duplicateCheck} from "@/service/api";
|
||||
defineOptions({
|
||||
name: '${entityName}Form',
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
})
|
||||
const toast = useToast()
|
||||
const router = useRouter()
|
||||
const form = ref(null)
|
||||
// 定义响应式数据
|
||||
const myFormData = reactive({})
|
||||
const loading = ref(false)
|
||||
const navTitle = ref('新增')
|
||||
const dataId = ref('')
|
||||
const backRouteName = ref('${entityName}List')
|
||||
// 定义 initForm 方法
|
||||
const initForm = (item) => {
|
||||
console.log('initForm item', item)
|
||||
if(item?.dataId){
|
||||
dataId.value = item.dataId;
|
||||
navTitle.value = item.dataId?'编辑':'新增';
|
||||
initData();
|
||||
}
|
||||
}
|
||||
// 初始化数据
|
||||
const initData = () => {
|
||||
http.get("/${entityPackagePath}/${entityName?uncap_first}/queryById",{id:dataId.value}).then((res) => {
|
||||
if (res.success) {
|
||||
let obj = res.result
|
||||
Object.assign(myFormData, { ...obj })
|
||||
}else{
|
||||
toast.error(res?.message || '表单加载失败!')
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleSuccess = () => {
|
||||
uni.$emit('refreshList');
|
||||
router.back()
|
||||
}
|
||||
/**
|
||||
* 校验唯一
|
||||
* @param values
|
||||
* @returns {boolean}
|
||||
*/
|
||||
async function fieldCheck(values: any) {
|
||||
const onlyField = [
|
||||
<#list onlyFields as field>
|
||||
${field}<#sep>, </#sep>
|
||||
</#list>
|
||||
];
|
||||
for (const field of onlyField) {
|
||||
if (values[field]) {
|
||||
// 仅校验有值的字段
|
||||
const res: any = await duplicateCheck({
|
||||
tableName: '${tableName}',
|
||||
fieldName: field, // 使用处理后的字段名
|
||||
fieldVal: values[field],
|
||||
dataId: values.id,
|
||||
});
|
||||
if (!res.success) {
|
||||
toast.warning(res.message);
|
||||
return true; // 校验失败
|
||||
}
|
||||
}
|
||||
}
|
||||
return false; // 校验通过
|
||||
}
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
// 判断字段必填和正则
|
||||
if (await fieldCheck(myFormData)) {
|
||||
return
|
||||
}
|
||||
let url = dataId.value?'/${entityPackagePath}/${entityName?uncap_first}/edit':'/${entityPackagePath}/${entityName?uncap_first}/add';
|
||||
form.value
|
||||
.validate()
|
||||
.then(({ valid, errors }) => {
|
||||
if (valid) {
|
||||
loading.value = true;
|
||||
http.post(url,myFormData).then((res) => {
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
toast.success('保存成功');
|
||||
handleSuccess()
|
||||
}else{
|
||||
toast.error(res?.message || '表单保存失败!')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error, 'error')
|
||||
loading.value = false;
|
||||
})
|
||||
}
|
||||
// 标题
|
||||
const get4Label = computed(() => {
|
||||
return (label) => {
|
||||
return label && label.length > 4 ? label.substring(0, 4) : label;
|
||||
}
|
||||
})
|
||||
|
||||
// 标题
|
||||
const getFormSchema = computed(() => {
|
||||
return (dictTable,dictCode,dictText) => {
|
||||
return {
|
||||
dictCode,
|
||||
dictTable,
|
||||
dictText
|
||||
};
|
||||
}
|
||||
})
|
||||
/**
|
||||
* 获取日期控件的扩展类型
|
||||
* @param picker
|
||||
* @returns {string}
|
||||
*/
|
||||
const getDateExtendType = (picker: string) => {
|
||||
let mapField = {
|
||||
month: 'year-month',
|
||||
year: 'year',
|
||||
quarter: 'quarter',
|
||||
week: 'week',
|
||||
day: 'date',
|
||||
}
|
||||
return picker && mapField[picker]
|
||||
? mapField[picker]
|
||||
: 'date'
|
||||
}
|
||||
//设置pop返回值
|
||||
const setFieldsValue = (data) => {
|
||||
Object.assign(myFormData, {...data })
|
||||
}
|
||||
// onLoad 生命周期钩子
|
||||
onLoad((option) => {
|
||||
initForm(option)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
padding-bottom: calc(constant(safe-area-inset-bottom) + 10px);
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 10px);
|
||||
}
|
||||
:deep(.wd-cell__label) {
|
||||
font-size: 14px;
|
||||
color: #444;
|
||||
}
|
||||
:deep(.wd-cell__value) {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,148 @@
|
||||
<route lang="json5" type="page">
|
||||
{
|
||||
layout: 'default',
|
||||
style: {
|
||||
navigationBarTitleText: '${tableVo.ftlDescription}',
|
||||
navigationStyle: 'custom',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
<template>
|
||||
<PageLayout navTitle="${tableVo.ftlDescription}" backRouteName="index" routeMethod="pushTab">
|
||||
<view class="wrap">
|
||||
<z-paging
|
||||
ref="paging"
|
||||
:fixed="false"
|
||||
v-model="dataList"
|
||||
@query="queryList"
|
||||
:default-page-size="15"
|
||||
>
|
||||
<template v-for="item in dataList" :key="item.id">
|
||||
<wd-swipe-action>
|
||||
<view class="list" @click="handleEdit(item)">
|
||||
<template v-for="(cItem, cIndex) in columns" :key="cIndex">
|
||||
<view v-if="cIndex < 3" class="box" :style="getBoxStyle">
|
||||
<view class="field ellipsis">{{ cItem.title }}</view>
|
||||
<view class="value cu-text-grey">{{ item[cItem.dataIndex] }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<template #right>
|
||||
<view class="action">
|
||||
<view class="button" @click="handleAction('del', item)">删除</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-swipe-action>
|
||||
</template>
|
||||
</z-paging>
|
||||
<view class="add u-iconfont u-icon-add" @click="handleAdd"></view>
|
||||
</view>
|
||||
</PageLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { http } from '@/utils/http'
|
||||
import usePageList from '@/hooks/usePageList'
|
||||
import {columns} from './${entityName}Data';
|
||||
defineOptions({
|
||||
name: '${entityName}List',
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
}
|
||||
})
|
||||
//分页加载配置
|
||||
let { toast, router, paging, dataList, queryList } = usePageList('/${entityPackagePath}/${entityName?uncap_first}/list');
|
||||
|
||||
//样式
|
||||
const getBoxStyle = computed(() => {
|
||||
return { width: "calc(33% - 5px)" }
|
||||
})
|
||||
|
||||
// 其他操作
|
||||
const handleAction = (val, item) => {
|
||||
if (val == 'del') {
|
||||
http.delete("/${entityPackagePath}/${entityName?uncap_first}/delete?id="+item.id,{id:item.id}).then((res) => {
|
||||
toast.success('删除成功~')
|
||||
paging.value.reload()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// go 新增页
|
||||
const handleAdd = () => {
|
||||
router.push({
|
||||
name: '${entityName}Form'
|
||||
})
|
||||
}
|
||||
|
||||
//go 编辑页
|
||||
const handleEdit = (record) => {
|
||||
router.push({
|
||||
name: '${entityName}Form',
|
||||
params: {dataId: record.id},
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 监听刷新列表事件
|
||||
uni.$on('refreshList', () => {
|
||||
queryList(1,10)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wrap {
|
||||
height: 100%;
|
||||
}
|
||||
:deep(.wd-swipe-action) {
|
||||
margin-top: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.list {
|
||||
padding: 10px 10px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.box {
|
||||
width: 33%;
|
||||
.field {
|
||||
margin-bottom: 10px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.action {
|
||||
width: 60px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
&:first-child {
|
||||
background-color: #fa4350;
|
||||
}
|
||||
}
|
||||
}
|
||||
.add {
|
||||
height: 70upx;
|
||||
width: 70upx;
|
||||
text-align: center;
|
||||
line-height: 70upx;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
position: fixed;
|
||||
bottom: 80upx;
|
||||
right: 30upx;
|
||||
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1);
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,426 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<!-- 查询区域 -->
|
||||
<div class="table-page-search-wrapper">
|
||||
<a-form layout="inline" @keyup.enter.native="searchQuery">
|
||||
<a-row :gutter="24">
|
||||
<#assign query_field_no=0>
|
||||
<#assign query_flag=false>
|
||||
<#assign list_need_dict=false>
|
||||
<#assign list_need_category=false>
|
||||
<#assign list_need_pca=false>
|
||||
<#assign list_need_switch=false>
|
||||
<#assign bpm_flag=false>
|
||||
|
||||
<#-- 开始循环 -->
|
||||
<#list columns as po>
|
||||
<#if po.fieldDbName=='bpm_status'>
|
||||
<#assign bpm_flag=true>
|
||||
</#if>
|
||||
<#if po.isQuery=='Y'>
|
||||
<#assign query_flag=true>
|
||||
<#if query_field_no==2>
|
||||
<template v-if="toggleSearchStatus">
|
||||
</#if>
|
||||
<#assign query_field_dictCode="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
<#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign query_field_dictCode="${po.dictField}">
|
||||
</#if>
|
||||
<#if po.queryMode=='single'>
|
||||
<#if query_field_no gt 1> </#if><a-col :xl="6" :lg="7" :md="8" :sm="24">
|
||||
<#if query_field_no gt 1> </#if><a-form-item label="${po.filedComment}">
|
||||
<#if po.classType=='sel_search'>
|
||||
<#if query_field_no gt 1> </#if><j-search-select-tag placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}" dict="${po.dictTable},${po.dictText},${po.dictField}"/>
|
||||
<#elseif po.classType=='sel_user'>
|
||||
<#if query_field_no gt 1> </#if><j-select-user-by-dep placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}"/>
|
||||
<#elseif po.classType=='switch'>
|
||||
<#if query_field_no gt 1> </#if><j-switch placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}" <#if po.dictField!= 'is_open'>:options="${po.dictField}"</#if> query></j-switch>
|
||||
<#elseif po.classType=='sel_depart'>
|
||||
<#if query_field_no gt 1> </#if><j-select-depart placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}"/>
|
||||
<#elseif po.classType=='list_multi'>
|
||||
<#if query_field_no gt 1> </#if><j-multi-select-tag placeholder="请选择${po.filedComment}" dictCode="${query_field_dictCode?default("")}" v-model="queryParam.${po.fieldName}"/>
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#if query_field_no gt 1> </#if><j-category-select placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}" pcode="${po.dictField?default("")}"/>
|
||||
<#elseif po.classType=='date'>
|
||||
<#if query_field_no gt 1> </#if><j-date placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}"></j-date>
|
||||
<#elseif po.classType=='datetime'>
|
||||
<#if query_field_no gt 1> </#if><j-date :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}"></j-date>
|
||||
<#elseif po.classType=='pca'>
|
||||
<#if query_field_no gt 1> </#if><j-area-linkage type="cascader" v-model="queryParam.${po.fieldName}" placeholder="请选择省市区"/>
|
||||
<#elseif po.classType=='popup'>
|
||||
<#if query_field_no gt 1> </#if><j-popup placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}" code="${po.dictTable}" org-fields="${po.dictField}" dest-fields="${po.dictText}" :field="getPopupField('${po.dictText}')" :multi="${po.extendParams.popupMulti?c}"/>
|
||||
<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
|
||||
<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
<#if query_field_no gt 1> </#if><j-dict-select-tag placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}" dictCode="${po.dictTable},${po.dictText},${po.dictField}"/>
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#if query_field_no gt 1> </#if><j-dict-select-tag placeholder="请选择${po.filedComment}" v-model="queryParam.${po.fieldName}" dictCode="${po.dictField}"/>
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
|
||||
</#if>
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
|
||||
</#if>
|
||||
<#if query_field_no gt 1> </#if></a-form-item>
|
||||
<#if query_field_no gt 1> </#if></a-col>
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><a-col :xl="10" :lg="11" :md="12" :sm="24">
|
||||
<#if query_field_no gt 1> </#if><a-form-item label="${po.filedComment}">
|
||||
<#if po.classType=='date'>
|
||||
<#if query_field_no gt 1> </#if><j-date placeholder="请选择开始日期" class="query-group-cust" v-model="queryParam.${po.fieldName}_begin"></j-date>
|
||||
<#if query_field_no gt 1> </#if><span class="query-group-split-cust"></span>
|
||||
<#if query_field_no gt 1> </#if><j-date placeholder="请选择结束日期" class="query-group-cust" v-model="queryParam.${po.fieldName}_end"></j-date>
|
||||
<#elseif po.classType=='datetime'>
|
||||
<#if query_field_no gt 1> </#if><j-date :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" class="query-group-cust" v-model="queryParam.${po.fieldName}_begin"></j-date>
|
||||
<#if query_field_no gt 1> </#if><span class="query-group-split-cust"></span>
|
||||
<#if query_field_no gt 1> </#if><j-date :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" class="query-group-cust" v-model="queryParam.${po.fieldName}_end"></j-date>
|
||||
<#else>
|
||||
<#if query_field_no gt 1> </#if><a-input placeholder="请输入最小值" class="query-group-cust" v-model="queryParam.${po.fieldName}_begin"></a-input>
|
||||
<#if query_field_no gt 1> </#if><span class="query-group-split-cust"></span>
|
||||
<#if query_field_no gt 1> </#if><a-input placeholder="请输入最大值" class="query-group-cust" v-model="queryParam.${po.fieldName}_end"></a-input>
|
||||
</#if>
|
||||
<#if query_field_no gt 1> </#if></a-form-item>
|
||||
<#if query_field_no gt 1> </#if></a-col>
|
||||
</#if>
|
||||
<#assign query_field_no=query_field_no+1>
|
||||
</#if>
|
||||
<#if !list_need_dict && po.fieldShowType!='popup' && po.dictField?default("")?trim?length gt 1>
|
||||
<#assign list_need_dict=true>
|
||||
</#if>
|
||||
<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
|
||||
<#assign list_need_category=true>
|
||||
</#if>
|
||||
<#if po.classType=='pca'>
|
||||
<#assign list_need_pca=true>
|
||||
</#if>
|
||||
<#if po.classType=='switch'>
|
||||
<#assign list_need_switch=true>
|
||||
</#if>
|
||||
</#list>
|
||||
<#-- 结束循环 -->
|
||||
<#t>
|
||||
<#if query_field_no gt 2>
|
||||
</template>
|
||||
</#if>
|
||||
<#if query_flag>
|
||||
<a-col :xl="6" :lg="7" :md="8" :sm="24">
|
||||
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
|
||||
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
|
||||
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
|
||||
<a @click="handleToggleSearch" style="margin-left: 8px">
|
||||
{{ toggleSearchStatus ? '收起' : '展开' }}
|
||||
<a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
|
||||
</a>
|
||||
</span>
|
||||
</a-col>
|
||||
</#if>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
<!-- 查询区域-END -->
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<div class="table-operator">
|
||||
<a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
|
||||
<a-button type="primary" icon="download" @click="handleExportXls('${tableVo.ftlDescription}')">导出</a-button>
|
||||
<a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
|
||||
<a-button type="primary" icon="import">导入</a-button>
|
||||
</a-upload>
|
||||
<!-- 高级查询区域 -->
|
||||
<j-super-query :fieldList="superFieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
|
||||
</a-menu>
|
||||
<a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
|
||||
<!-- table区域-begin -->
|
||||
<div>
|
||||
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
|
||||
<i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项
|
||||
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
|
||||
</div>
|
||||
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
<#if tableVo.extendParams.scroll=='1'>
|
||||
:scroll="{x:true}"
|
||||
</#if>
|
||||
bordered
|
||||
rowKey="id"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:pagination="ipagination"
|
||||
:loading="loading"
|
||||
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
|
||||
class="j-table-force-nowrap"
|
||||
@change="handleTableChange">
|
||||
|
||||
<template slot="htmlSlot" slot-scope="text">
|
||||
<div v-html="text"></div>
|
||||
</template>
|
||||
<template slot="imgSlot" slot-scope="text,record">
|
||||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span>
|
||||
<img v-else :src="getImgView(text)" :preview="record.id" height="25px" alt="" style="max-width:80px;font-size: 12px;font-style: italic;"/>
|
||||
</template>
|
||||
<#if list_need_pca>
|
||||
<template slot="pcaSlot" slot-scope="text">
|
||||
<div>{{ getPcaText(text) }}</div>
|
||||
</template>
|
||||
</#if>
|
||||
<template slot="fileSlot" slot-scope="text">
|
||||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<a-button
|
||||
v-else
|
||||
:ghost="true"
|
||||
type="primary"
|
||||
icon="download"
|
||||
size="small"
|
||||
@click="downloadFile(text)">
|
||||
下载
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<span slot="action" slot-scope="text, record">
|
||||
<a @click="handleEdit(record)">编辑</a>
|
||||
|
||||
<a-divider type="vertical" />
|
||||
<a-dropdown>
|
||||
<a class="ant-dropdown-link">更多 <a-icon type="down" /></a>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item>
|
||||
<a @click="handleDetail(record)">详情</a>
|
||||
</a-menu-item>
|
||||
<#if bpm_flag>
|
||||
<a-menu-item v-if="record.bpmStatus === '1'">
|
||||
<a @click="startProcess(record)">发起流程</a>
|
||||
</a-menu-item>
|
||||
</#if>
|
||||
<a-menu-item>
|
||||
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
|
||||
<a>删除</a>
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
</span>
|
||||
|
||||
</a-table>
|
||||
</div>
|
||||
|
||||
<${Format.humpToShortbar(entityName)}-modal ref="modalForm" @ok="modalFormOk"></${Format.humpToShortbar(entityName)}-modal>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import '@/assets/less/TableExpand.less'
|
||||
import { mixinDevice } from '@/utils/mixin'
|
||||
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
|
||||
import ${entityName}Modal from './modules/${entityName}Modal'
|
||||
<#if bpm_flag>
|
||||
import { postAction } from '@/api/manage'
|
||||
</#if>
|
||||
<#if list_need_category>
|
||||
import { loadCategoryData } from '@/api/api'
|
||||
</#if>
|
||||
<#if list_need_dict>
|
||||
import {filterMultiDictText} from '@/components/dict/JDictSelectUtil'
|
||||
</#if>
|
||||
<#if list_need_pca>
|
||||
import Area from '@/components/_util/Area'
|
||||
</#if>
|
||||
|
||||
export default {
|
||||
name: '${entityName}List',
|
||||
mixins:[JeecgListMixin, mixinDevice],
|
||||
components: {
|
||||
${entityName}Modal
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
description: '${tableVo.ftlDescription}管理页面',
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: '',
|
||||
key:'rowIndex',
|
||||
width:60,
|
||||
align:"center",
|
||||
customRender:function (t,r,index) {
|
||||
return parseInt(index)+1;
|
||||
}
|
||||
},
|
||||
<#assign showColNum=0>
|
||||
<#list columns as po>
|
||||
<#if po.isShowList =='Y' && po.fieldName !='id'>
|
||||
<#assign showColNum=showColNum+1>
|
||||
{
|
||||
title:'${po.filedComment}',
|
||||
align:"center",
|
||||
<#if po.sort=='Y'>
|
||||
sorter: true,
|
||||
</#if>
|
||||
<#if po.classType=='date'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
customRender:function (text) {
|
||||
return !text?"":(text.length>10?text.substr(0,10):text)
|
||||
}
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
dataIndex: '${po.fieldName}String'
|
||||
<#elseif po.classType=='umeditor'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
scopedSlots: {customRender: 'htmlSlot'}
|
||||
<#elseif po.classType=='pca'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
scopedSlots: {customRender: 'pcaSlot'}
|
||||
<#elseif po.classType=='file'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
scopedSlots: {customRender: 'fileSlot'}
|
||||
<#elseif po.classType=='image'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
scopedSlots: {customRender: 'imgSlot'}
|
||||
<#elseif po.classType=='switch'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
customRender: (text) => (text ? filterMultiDictText(this.dictOptions['${po.fieldName}'], text) : ''),
|
||||
<#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
|
||||
dataIndex: '${po.fieldName}_dictText'
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#if list_need_category>
|
||||
dataIndex: '${po.fieldName}',
|
||||
customRender: (text) => (text ? filterMultiDictText(this.dictOptions['${po.fieldName}'], text) : '')
|
||||
<#else>
|
||||
dataIndex: '${po.fieldName}',
|
||||
customRender: (text, record) => (text ? record['${dashedToCamel(po.dictText)}'] : '')
|
||||
</#if>
|
||||
<#else>
|
||||
dataIndex: '${po.fieldName}'
|
||||
</#if>
|
||||
},
|
||||
</#if>
|
||||
</#list>
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align:"center",
|
||||
<#if tableVo.extendParams.scroll=='1'>
|
||||
fixed:"right",
|
||||
width:147,
|
||||
</#if>
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
url: {
|
||||
list: "/${entityPackagePath}/${entityName?uncap_first}/list",
|
||||
delete: "/${entityPackagePath}/${entityName?uncap_first}/delete",
|
||||
deleteBatch: "/${entityPackagePath}/${entityName?uncap_first}/deleteBatch",
|
||||
exportXlsUrl: "/${entityPackagePath}/${entityName?uncap_first}/exportXls",
|
||||
importExcelUrl: "${entityPackagePath}/${entityName?uncap_first}/importExcel",
|
||||
<#if bpm_flag>startProcess: '/act/process/extActProcess/startMutilProcess'</#if>
|
||||
},
|
||||
<#if bpm_flag>
|
||||
//代码生成后需手动设置流程编码
|
||||
flowCode: 'dev_${tableName}_001',
|
||||
</#if>
|
||||
dictOptions:{},
|
||||
<#if list_need_pca>
|
||||
pcaData:'',
|
||||
</#if>
|
||||
superFieldList:[],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
<#if list_need_pca>
|
||||
this.pcaData = new Area()
|
||||
</#if>
|
||||
<#if list_need_switch>
|
||||
<#list columns as po>
|
||||
<#if po.classType=='switch'>
|
||||
<#assign switch_extend_arr=['Y','N']>
|
||||
<#if po.dictField?default("")?contains("[")>
|
||||
<#assign switch_extend_arr=po.dictField?eval>
|
||||
</#if>
|
||||
<#list switch_extend_arr as a>
|
||||
<#if a_index == 0>
|
||||
<#assign switch_extend_arr1=a>
|
||||
<#else>
|
||||
<#assign switch_extend_arr2=a>
|
||||
</#if>
|
||||
</#list>
|
||||
this.$set(this.dictOptions, '${po.fieldName}', [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
this.getSuperFieldList();
|
||||
},
|
||||
computed: {
|
||||
importExcelUrl: function(){
|
||||
<#noparse>return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;</#noparse>
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
<#if list_need_pca>
|
||||
getPcaText(code){
|
||||
return this.pcaData.getText(code);
|
||||
},
|
||||
</#if>
|
||||
<#if bpm_flag>
|
||||
startProcess(record){
|
||||
this.$confirm({
|
||||
title:'提示',
|
||||
content:'确认提交流程吗?',
|
||||
onOk:()=>{
|
||||
let params = {
|
||||
flowCode: this.flowCode,
|
||||
id: record.id,
|
||||
formUrl: '${entityPackagePath}/modules/${entityName}Form',
|
||||
formUrlMobile: ''
|
||||
}
|
||||
postAction(this.url.startProcess, params).then(res=>{
|
||||
if(res.success){
|
||||
this.$message.success(res.message);
|
||||
this.loadData();
|
||||
this.onClearSelected();
|
||||
}else{
|
||||
this.$message.warning(res.message);
|
||||
}
|
||||
}).catch((e)=>{
|
||||
this.$message.warning('不识别的请求!');
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
</#if>
|
||||
initDictConfig(){
|
||||
<#list columns as po>
|
||||
<#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
|
||||
<#if po.classType=='cat_tree' && list_need_category==true>
|
||||
loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
|
||||
if (res.success) {
|
||||
this.$set(this.dictOptions, '${po.fieldName}', res.result)
|
||||
}
|
||||
})
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
},
|
||||
getSuperFieldList(){
|
||||
let fieldList=[];
|
||||
<#list columns as po>
|
||||
fieldList.push(${superQueryFieldList(po)})
|
||||
</#list>
|
||||
this.superFieldList = fieldList
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
@import '~@assets/less/common.less';
|
||||
</style>
|
||||
@@ -0,0 +1 @@
|
||||
<#include "/common/sql/menu_insert.ftl">
|
||||
@@ -0,0 +1,266 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<template>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<j-form-container :disabled="formDisabled">
|
||||
<a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail">
|
||||
<a-row>
|
||||
<#assign form_popup = false>
|
||||
<#assign form_cat_tree = false>
|
||||
<#assign form_cat_back = "">
|
||||
<#assign bpm_flag=false>
|
||||
<#assign form_span = 24>
|
||||
<#if tableVo.fieldRowNum==2>
|
||||
<#assign form_span = 12>
|
||||
<#elseif tableVo.fieldRowNum==3>
|
||||
<#assign form_span = 8>
|
||||
<#elseif tableVo.fieldRowNum==4>
|
||||
<#assign form_span = 6>
|
||||
</#if>
|
||||
<#list columns as po>
|
||||
<#if po.fieldDbName=='bpm_status'>
|
||||
<#assign bpm_flag=true>
|
||||
</#if>
|
||||
<#if po.isShow =='Y' && po.fieldName != 'id'>
|
||||
<#assign form_field_dictCode="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictField}">
|
||||
</#if>
|
||||
<a-col :span="${form_span}">
|
||||
<a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
|
||||
<#if po.classType =='date'>
|
||||
<j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType =='datetime'>
|
||||
<j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType =='time'>
|
||||
<j-time placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType =='popup'>
|
||||
<#assign form_popup=true>
|
||||
<j-popup
|
||||
v-model="model.${po.fieldName}"
|
||||
field="${po.fieldName}"
|
||||
org-fields="${po.dictField}"
|
||||
dest-fields="${Format.underlineToHump(po.dictText)}"
|
||||
code="${po.dictTable}"
|
||||
:multi="${po.extendParams.popupMulti?c}"
|
||||
@input="popupCallback"
|
||||
<#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType =='sel_depart'>
|
||||
<j-select-depart v-model="model.${po.fieldName}" :multi="${po.extendParams.multi?default('true')}"<#if po.extendParams.store?default("")?trim?length gt 0> store="${po.extendParams.store}"</#if><#if po.extendParams.text?default("")?trim?length gt 0> text="${po.extendParams.text}"</#if> <#if po.readonly=='Y'>disabled</#if> />
|
||||
<#elseif po.classType =='switch'>
|
||||
<j-switch v-model="model.${po.fieldName}" <#if po.dictField != 'is_open'>:options="${po.dictField}"</#if> <#if po.readonly=='Y'>disabled</#if>></j-switch>
|
||||
<#elseif po.classType =='pca'>
|
||||
<j-area-linkage type="cascader" v-model="model.${po.fieldName}" placeholder="请输入省市区" <#if po.readonly=='Y'>disabled</#if> />
|
||||
<#elseif po.classType =='markdown'>
|
||||
<j-markdown-editor v-model="model.${autoStringSuffixForModel(po)}" id="${po.fieldName}"></j-markdown-editor>
|
||||
<#elseif po.classType =='password'>
|
||||
<a-input-password v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType =='sel_user'>
|
||||
<j-select-user-by-dep v-model="model.${po.fieldName}" :multi="${po.extendParams.multi?default('true')}"<#if po.extendParams.store?default("")?trim?length gt 0> store="${po.extendParams.store}"</#if><#if po.extendParams.text?default("")?trim?length gt 0> text="${po.extendParams.text}"</#if> <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType =='textarea'>
|
||||
<a-textarea v-model="model.${autoStringSuffixForModel(po)}" rows="4" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType=='list' || po.classType=='radio'>
|
||||
<j-dict-select-tag type="${po.classType}" v-model="model.${po.fieldName}" dictCode="${form_field_dictCode}" placeholder="请选择${po.filedComment}" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType=='list_multi' || po.classType=='checkbox'>
|
||||
<j-multi-select-tag type="${po.classType}" v-model="model.${po.fieldName}" dictCode="${form_field_dictCode}" placeholder="请选择${po.filedComment}" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType=='sel_search'>
|
||||
<j-search-select-tag v-model="model.${po.fieldName}" dict="${form_field_dictCode}" <#if po.readonly=='Y'>disabled</#if> />
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#assign form_cat_tree = true>
|
||||
<j-category-select v-model="model.${po.fieldName}" pcode="${po.dictField?default("")}" placeholder="请选择${po.filedComment}" <#if po.dictText?default("")?trim?length gt 1>back="${dashedToCamel(po.dictText)}" @change="handleCategoryChange"</#if> <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#if po.dictText?default("")?trim?length gt 1>
|
||||
<#assign form_cat_back = "${po.dictText}">
|
||||
</#if>
|
||||
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
<a-input-number v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.classType=='file'>
|
||||
<j-upload v-model="model.${po.fieldName}" <#if po.readonly=='Y'>disabled</#if> <#if po.uploadnum??>:number=${po.uploadnum}</#if>></j-upload>
|
||||
<#elseif po.classType=='image'>
|
||||
<j-image-upload isMultiple <#if po.uploadnum??>:number=${po.uploadnum}</#if> v-model="model.${po.fieldName}" <#if po.readonly=='Y'>disabled</#if>></j-image-upload>
|
||||
<#elseif po.classType=='umeditor'>
|
||||
<j-editor v-model="model.${autoStringSuffixForModel(po)}" <#if po.readonly=='Y'>disabled</#if>/>
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
<a-input v-model="model.${autoStringSuffixForModel(po)}" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if>></a-input>
|
||||
<#elseif po.classType == 'sel_tree'>
|
||||
<j-tree-select
|
||||
ref="treeSelect"
|
||||
placeholder="请选择${po.filedComment}"
|
||||
v-model="model.${po.fieldName}"
|
||||
<#if po.dictText??>
|
||||
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
|
||||
dict="${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}"
|
||||
<#elseif po.dictText?split(',')[1]??>
|
||||
pidField="${po.dictText?split(',')[1]}"
|
||||
<#elseif po.dictText?split(',')[3]??>
|
||||
hasChildField="${po.dictText?split(',')[3]}"
|
||||
</#if>
|
||||
</#if>
|
||||
pidValue="${po.dictField}"
|
||||
<#if po.readonly=='Y'>disabled</#if>>
|
||||
</j-tree-select>
|
||||
<#else>
|
||||
<a-input v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}" <#if po.readonly=='Y'>disabled</#if> ></a-input>
|
||||
</#if>
|
||||
</a-form-model-item>
|
||||
</a-col>
|
||||
</#if>
|
||||
</#list>
|
||||
<#if bpm_flag>
|
||||
<a-col v-if="showFlowSubmitButton" :span="24" style="width: 100%;text-align: center;">
|
||||
<a-button icon="check" style="width: 126px" type="primary" @click="submitForm">提 交</a-button>
|
||||
</a-col>
|
||||
</#if>
|
||||
</a-row>
|
||||
</a-form-model>
|
||||
</j-form-container>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { httpAction, getAction } from '@/api/manage'
|
||||
import { validateDuplicateValue } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
name: '${entityName}Form',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
<#if bpm_flag>
|
||||
//流程表单data
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
required: false
|
||||
},
|
||||
//表单模式:true流程表单 false普通表单
|
||||
formBpm: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
},
|
||||
</#if>
|
||||
//表单禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
model:{
|
||||
<#include "/common/init/initValue.ftl">
|
||||
},
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 16 },
|
||||
},
|
||||
confirmLoading: false,
|
||||
<#include "/common/validatorRulesTemplate/main.ftl">
|
||||
url: {
|
||||
add: "/${entityPackagePath}/${entityName?uncap_first}/add",
|
||||
edit: "/${entityPackagePath}/${entityName?uncap_first}/edit",
|
||||
queryById: "/${entityPackagePath}/${entityName?uncap_first}/queryById"
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formDisabled(){
|
||||
<#if bpm_flag>
|
||||
if(this.formBpm===true){
|
||||
if(this.formData.disabled===false){
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
</#if>
|
||||
return this.disabled
|
||||
},
|
||||
<#if bpm_flag>
|
||||
showFlowSubmitButton(){
|
||||
if(this.formBpm===true){
|
||||
if(this.formData.disabled===false){
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
</#if>
|
||||
},
|
||||
created () {
|
||||
//备份model原始值
|
||||
this.modelDefault = JSON.parse(JSON.stringify(this.model));
|
||||
<#if bpm_flag>
|
||||
//如果是流程中表单,则需要加载流程表单data
|
||||
this.showFlowData();
|
||||
</#if>
|
||||
},
|
||||
methods: {
|
||||
add () {
|
||||
this.edit(this.modelDefault);
|
||||
},
|
||||
edit (record) {
|
||||
this.model = Object.assign({}, record);
|
||||
this.visible = true;
|
||||
},
|
||||
<#if bpm_flag>
|
||||
//渲染流程表单数据
|
||||
showFlowData(){
|
||||
if(this.formBpm === true){
|
||||
let params = {id:this.formData.dataId};
|
||||
getAction(this.url.queryById,params).then((res)=>{
|
||||
if(res.success){
|
||||
this.edit (res.result);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
</#if>
|
||||
submitForm () {
|
||||
const that = this;
|
||||
// 触发表单验证
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
that.confirmLoading = true;
|
||||
let httpurl = '';
|
||||
let method = '';
|
||||
if(!this.model.id){
|
||||
httpurl+=this.url.add;
|
||||
method = 'post';
|
||||
}else{
|
||||
httpurl+=this.url.edit;
|
||||
method = 'put';
|
||||
}
|
||||
httpAction(httpurl,this.model,method).then((res)=>{
|
||||
if(res.success){
|
||||
that.$message.success(res.message);
|
||||
that.$emit('ok');
|
||||
}else{
|
||||
that.$message.warning(res.message);
|
||||
}
|
||||
}).finally(() => {
|
||||
that.confirmLoading = false;
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
<#if form_popup>
|
||||
popupCallback(value,row){
|
||||
this.model = Object.assign(this.model, row);
|
||||
},
|
||||
</#if>
|
||||
<#if form_cat_tree>
|
||||
handleCategoryChange(value,backObj){
|
||||
this.model = Object.assign(this.model, backObj);
|
||||
}
|
||||
</#if>
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,69 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#assign modal_width = 800>
|
||||
<#if tableVo.fieldRowNum==2>
|
||||
<#assign modal_width = 896>
|
||||
<#elseif tableVo.fieldRowNum==3>
|
||||
<#assign modal_width = 1024>
|
||||
<#elseif tableVo.fieldRowNum==4>
|
||||
<#assign modal_width = 1280>
|
||||
</#if>
|
||||
<template>
|
||||
<j-modal
|
||||
:title="title"
|
||||
:width="width"
|
||||
:visible="visible"
|
||||
switchFullscreen
|
||||
@ok="handleOk"
|
||||
:okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
|
||||
@cancel="handleCancel"
|
||||
cancelText="关闭">
|
||||
<${Format.humpToShortbar(entityName)}-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></${Format.humpToShortbar(entityName)}-form>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ${entityName}Form from './${entityName}Form'
|
||||
export default {
|
||||
name: '${entityName}Modal',
|
||||
components: {
|
||||
${entityName}Form
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
title:'',
|
||||
width:${modal_width},
|
||||
visible: false,
|
||||
disableSubmit: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
add () {
|
||||
this.visible=true
|
||||
this.$nextTick(()=>{
|
||||
this.$refs.realForm.add();
|
||||
})
|
||||
},
|
||||
edit (record) {
|
||||
this.visible=true
|
||||
this.$nextTick(()=>{
|
||||
this.$refs.realForm.edit(record);
|
||||
})
|
||||
},
|
||||
close () {
|
||||
this.$emit('close');
|
||||
this.visible = false;
|
||||
},
|
||||
handleOk () {
|
||||
this.$refs.realForm.submitForm();
|
||||
},
|
||||
submitCallback(){
|
||||
this.$emit('ok');
|
||||
this.visible = false;
|
||||
},
|
||||
handleCancel () {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,93 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#assign modal_width = 800>
|
||||
<#if tableVo.fieldRowNum==2>
|
||||
<#assign modal_width = 896>
|
||||
<#elseif tableVo.fieldRowNum==3>
|
||||
<#assign modal_width = 1024>
|
||||
<#elseif tableVo.fieldRowNum==4>
|
||||
<#assign modal_width = 1280>
|
||||
</#if>
|
||||
<template>
|
||||
<a-drawer
|
||||
:title="title"
|
||||
:width="width"
|
||||
placement="right"
|
||||
:closable="false"
|
||||
@close="close"
|
||||
destroyOnClose
|
||||
:visible="visible">
|
||||
<${Format.humpToShortbar(entityName)}-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit" normal></${Format.humpToShortbar(entityName)}-form>
|
||||
<div class="drawer-footer">
|
||||
<a-button @click="handleCancel" style="margin-bottom: 0;">关闭</a-button>
|
||||
<a-button v-if="!disableSubmit" @click="handleOk" type="primary" style="margin-bottom: 0;">提交</a-button>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ${entityName}Form from './${entityName}Form'
|
||||
|
||||
export default {
|
||||
name: '${entityName}Modal',
|
||||
components: {
|
||||
${entityName}Form
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
title:"操作",
|
||||
width:${modal_width},
|
||||
visible: false,
|
||||
disableSubmit: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
add () {
|
||||
this.visible=true
|
||||
this.$nextTick(()=>{
|
||||
this.$refs.realForm.add();
|
||||
})
|
||||
},
|
||||
edit (record) {
|
||||
this.visible=true
|
||||
this.$nextTick(()=>{
|
||||
this.$refs.realForm.edit(record);
|
||||
});
|
||||
},
|
||||
close () {
|
||||
this.$emit('close');
|
||||
this.visible = false;
|
||||
},
|
||||
submitCallback(){
|
||||
this.$emit('ok');
|
||||
this.visible = false;
|
||||
},
|
||||
handleOk () {
|
||||
this.$refs.realForm.submitForm();
|
||||
},
|
||||
handleCancel () {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
/** Button按钮间距 */
|
||||
.ant-btn {
|
||||
margin-left: 30px;
|
||||
margin-bottom: 30px;
|
||||
float: right;
|
||||
}
|
||||
.drawer-footer{
|
||||
position: absolute;
|
||||
bottom: -8px;
|
||||
width: 100%;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding: 10px 16px;
|
||||
text-align: right;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
border-radius: 0 0 2px 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,443 @@
|
||||
<template>
|
||||
<div>
|
||||
<#assign list_need_category=false>
|
||||
<#assign list_need_pca=false>
|
||||
<#assign list_has_popup_dict=false>
|
||||
<#assign bpm_flag=false>
|
||||
|
||||
<#-- 开始循环 -->
|
||||
<#list columns as po>
|
||||
<#if po.fieldDbName=='bpm_status'>
|
||||
<#assign bpm_flag=true>
|
||||
</#if>
|
||||
<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
|
||||
<#assign list_need_category=true>
|
||||
</#if>
|
||||
<#if po.classType=='popup_dict'>
|
||||
<#assign list_has_popup_dict=true>
|
||||
</#if>
|
||||
<#if po.classType=='pca'>
|
||||
<#assign list_need_pca=true>
|
||||
</#if>
|
||||
</#list>
|
||||
<#assign buttonList=[]>
|
||||
<#if tableVo.extendParams?? && tableVo.extendParams.cgButtonList??>
|
||||
<#assign buttonList = tableVo.extendParams.cgButtonList?filter(btn -> btn??)>
|
||||
</#if>
|
||||
<#-- 结束循环 -->
|
||||
<!--引用表格-->
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<!--插槽:table标题-->
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" v-auth="'${entityPackage}:${tableName}:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
|
||||
<a-button type="primary" v-auth="'${entityPackage}:${tableName}:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
|
||||
<j-upload-button type="primary" v-auth="'${entityPackage}:${tableName}:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle == 'button'>
|
||||
<a-button type="primary" @click="handle${btn.buttonCode?cap_first}" <#if btn.buttonIcon??> preIcon="ant-design:${btn.buttonIcon}" </#if>>${btn.buttonName}</a-button>
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button v-auth="'${entityPackage}:${tableName}:deleteBatch'">批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
<!-- 高级查询 -->
|
||||
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
|
||||
<#-- update-end---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
|
||||
</template>
|
||||
<!--字段回显插槽-->
|
||||
<template v-slot:bodyCell="{ column, record, index, text }">
|
||||
<#list columns as po>
|
||||
<#if po.classType=='umeditor' || po.classType=='pca' || po.classType=='file'>
|
||||
<template v-if="column.dataIndex==='${po.fieldName}'">
|
||||
<#if po.classType=='umeditor'>
|
||||
<!--富文本件字段回显插槽-->
|
||||
<div v-html="text"></div>
|
||||
</#if>
|
||||
<#if po.classType=='pca'>
|
||||
<!--省市区字段回显插槽-->
|
||||
{{ getAreaTextByCode(text) }}
|
||||
</#if>
|
||||
<#if po.classType=='file'>
|
||||
<!--文件字段回显插槽-->
|
||||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
|
||||
</#if>
|
||||
</template>
|
||||
</#if>
|
||||
</#list>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!-- 表单区域 -->
|
||||
<${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
|
||||
<#if bpm_flag==true>
|
||||
<!-- 审批记录 -->
|
||||
<BpmPictureModal @register="registerBpmModal" />
|
||||
</#if>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
|
||||
import {ref, reactive, computed, unref} from 'vue';
|
||||
import {BasicTable, useTable, TableAction} from '/@/components/Table';
|
||||
import {useModal} from '/@/components/Modal';
|
||||
import { useListPage } from '/@/hooks/system/useListPage'
|
||||
import ${entityName}Modal from './components/${entityName}Modal.vue'
|
||||
import {columns, searchFormSchema, superQuerySchema} from './${entityName}.data';
|
||||
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName}.api';
|
||||
import { downloadFile } from '/@/utils/common/renderUtils';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
<#if list_need_pca>
|
||||
import { getAreaTextByCode } from '/@/components/Form/src/utils/Area';
|
||||
</#if>
|
||||
<#if list_need_category>
|
||||
import { loadCategoryData } from '/@/api/common/api'
|
||||
import { getAuthCache, setAuthCache } from '/@/utils/auth';
|
||||
import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
|
||||
</#if>
|
||||
<#if list_has_popup_dict>
|
||||
import {getPopDictByCode} from "@/utils/dict";
|
||||
import {filterMultiDictText} from "@/utils/dict/JDictSelectUtil";
|
||||
</#if>
|
||||
import { getDateByPicker } from '/@/utils';
|
||||
//日期个性化选择
|
||||
const fieldPickers = reactive({
|
||||
<#list columns as po>
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
${po.fieldName}: '${po.extendParams.picker}',
|
||||
</#if>
|
||||
</#list>
|
||||
});
|
||||
<#if bpm_flag==true>
|
||||
import { startProcess } from '/@/api/common/api';
|
||||
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
|
||||
</#if>
|
||||
const queryParam = reactive<any>({});
|
||||
const checkedKeys = ref<Array<string | number>>([]);
|
||||
const userStore = useUserStore();
|
||||
const { createMessage } = useMessage();
|
||||
//注册model
|
||||
const [registerModal, {openModal}] = useModal();
|
||||
//注册table数据
|
||||
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
|
||||
tableProps:{
|
||||
title: '${tableVo.ftlDescription}',
|
||||
api: list,
|
||||
columns,
|
||||
canResize:true,
|
||||
formConfig: {
|
||||
//labelWidth: 120,
|
||||
schemas: searchFormSchema,
|
||||
autoSubmitOnEnter:true,
|
||||
showAdvancedButton:true,
|
||||
fieldMapToNumber: [
|
||||
<#list columns as po>
|
||||
<#if po.isQuery=='Y'>
|
||||
<#if po.queryMode=='group'>
|
||||
<#-- update-begin---author:chenrui ---date:20240527 for:[TV360X-388]时间范围查询控件---------- -->
|
||||
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal' || po.classType=='time'>
|
||||
<#-- update-end---author:chenrui ---date:20240527 for:[TV360X-388]时间范围查询控件---------- -->
|
||||
['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end']],
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
],
|
||||
fieldMapToTime: [
|
||||
<#list columns as po>
|
||||
<#if po.isQuery=='Y'>
|
||||
<#if po.queryMode=='group'>
|
||||
<#if po.classType=='date'>
|
||||
['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
|
||||
<#elseif po.classType=='datetime'>
|
||||
['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
|
||||
</#if>
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
],
|
||||
},
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed:'right'
|
||||
},
|
||||
beforeFetch: (params) => {
|
||||
if (params && fieldPickers) {
|
||||
for (let key in fieldPickers) {
|
||||
if (params[key]) {
|
||||
params[key] = getDateByPicker(params[key], fieldPickers[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.assign(params, queryParam);
|
||||
},
|
||||
<#if list_has_popup_dict>
|
||||
afterFetch: afterFetch
|
||||
</#if>
|
||||
},
|
||||
exportConfig: {
|
||||
name:"${tableVo.ftlDescription}",
|
||||
url: getExportUrl,
|
||||
params: queryParam,
|
||||
},
|
||||
importConfig: {
|
||||
url: getImportUrl,
|
||||
success: handleSuccess
|
||||
},
|
||||
})
|
||||
|
||||
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
|
||||
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
// 高级查询配置
|
||||
const superQueryConfig = reactive(superQuerySchema);
|
||||
|
||||
/**
|
||||
* 高级查询事件
|
||||
*/
|
||||
function handleSuperQuery(params) {
|
||||
Object.keys(params).map((k) => {
|
||||
queryParam[k] = params[k];
|
||||
});
|
||||
reload();
|
||||
}
|
||||
<#-- update-end---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
function handleAdd() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
function handleDetail(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
showFooter: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteOne({id: record.id}, handleSuccess);
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
|
||||
}
|
||||
/**
|
||||
* 成功回调
|
||||
*/
|
||||
function handleSuccess() {
|
||||
(selectedRowKeys.value = []) && reload();
|
||||
}
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record){
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
auth: '${entityPackage}:${tableName}:edit'
|
||||
}
|
||||
]
|
||||
}
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record){
|
||||
<#if bpm_flag==true>
|
||||
let dropDownAction = [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
placement: 'topLeft',
|
||||
},
|
||||
auth: '${entityPackage}:${tableName}:delete'
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handlePreviewPic.bind(null, record),
|
||||
ifShow: !!record.bpmStatus && record.bpmStatus !== '1',
|
||||
}
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle == 'link'>
|
||||
,{
|
||||
label: '${btn.buttonName}',
|
||||
onClick: handle${btn.buttonCode?cap_first}.bind(null, record),
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
];
|
||||
if(record.bpmStatus == '1'){
|
||||
dropDownAction.push({
|
||||
label: '发起流程',
|
||||
popConfirm: {
|
||||
title: '确认提交流程吗?',
|
||||
confirm: handleProcess.bind(null, record),
|
||||
placement: 'topLeft',
|
||||
}
|
||||
})
|
||||
}
|
||||
return dropDownAction;
|
||||
<#else>
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
placement: 'topLeft',
|
||||
},
|
||||
auth: '${entityPackage}:${tableName}:delete'
|
||||
}
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle == 'link'>
|
||||
,{
|
||||
label: '${btn.buttonName}',
|
||||
onClick: handle${btn.buttonCode?cap_first}.bind(null, record),
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
]
|
||||
</#if>
|
||||
}
|
||||
|
||||
<#if bpm_flag==true>
|
||||
/**
|
||||
* 提交流程
|
||||
*/
|
||||
async function handleProcess(record) {
|
||||
let params = {
|
||||
flowCode: 'dev_${tableName}_001',
|
||||
id: record.id,
|
||||
formUrl: '${entityPackagePath}/components/${entityName}Form',
|
||||
formUrlMobile: ''
|
||||
}
|
||||
await startProcess(params);
|
||||
handleSuccess();
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
*/
|
||||
async function handlePreviewPic(record) {
|
||||
bpmPicModal(true, {
|
||||
flowCode: 'dev_${tableName}_001',
|
||||
dataId: record.id,
|
||||
});
|
||||
}
|
||||
</#if>
|
||||
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle=='button'>
|
||||
function handle${btn.buttonCode?cap_first}(){
|
||||
createMessage.info('点击了${btn.buttonName}按钮,对应的业务逻辑需自行实现!');
|
||||
}
|
||||
</#if>
|
||||
<#if btn.buttonStyle=='link'>
|
||||
function handle${btn.buttonCode?cap_first}(record){
|
||||
createMessage.info('点击了${btn.buttonName}按钮,对应的业务逻辑需自行实现!');
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if list_need_category>
|
||||
/**
|
||||
* 初始化字典配置
|
||||
*/
|
||||
function initDictConfig(){
|
||||
<#list columns as po>
|
||||
<#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
|
||||
<#if po.classType=='cat_tree' && list_need_category==true>
|
||||
loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
|
||||
if (res) {
|
||||
const allDictDate = userStore.getAllDictItems;
|
||||
if(!allDictDate['${po.dictField?default("")}']){
|
||||
userStore.setAllDictItems({...allDictDate,'${po.dictField?default("")}':res});
|
||||
}
|
||||
}
|
||||
})
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
}
|
||||
initDictConfig();
|
||||
</#if>
|
||||
|
||||
<#if list_has_popup_dict>
|
||||
/**
|
||||
* 翻译Popup字典配置
|
||||
*/
|
||||
async function afterFetch(records){
|
||||
<#list columns as po>
|
||||
<#if po.isQuery=='Y' || po.isShowList=='Y'>
|
||||
<#if po.classType=='popup_dict' && list_has_popup_dict==true>
|
||||
const ${po.fieldName}Keys = [...new Set(records.map((item) => item['${po.fieldName}']).flatMap((item) => item && item.split(',')))];
|
||||
if(${po.fieldName}Keys && ${po.fieldName}Keys.length){
|
||||
const dictOptions = await getPopDictByCode(${po.fieldName}Keys.join(','), '${po.dictTable},${po.dictField},${po.dictText}');
|
||||
records.forEach((item) => {
|
||||
item['${po.fieldName}_dictText'] = filterMultiDictText(dictOptions, item['${po.fieldName}']);
|
||||
});
|
||||
}
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
return records;
|
||||
}
|
||||
</#if>
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
<#include "/common/form/vue3SearchStyle.ftl">
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
import {defHttp} from '/@/utils/http/axios';
|
||||
import { useMessage } from "/@/hooks/web/useMessage";
|
||||
|
||||
const { createConfirm } = useMessage();
|
||||
|
||||
enum Api {
|
||||
list = '/${entityPackagePath}/${entityName?uncap_first}/list',
|
||||
save='/${entityPackagePath}/${entityName?uncap_first}/add',
|
||||
edit='/${entityPackagePath}/${entityName?uncap_first}/edit',
|
||||
deleteOne = '/${entityPackagePath}/${entityName?uncap_first}/delete',
|
||||
deleteBatch = '/${entityPackagePath}/${entityName?uncap_first}/deleteBatch',
|
||||
importExcel = '/${entityPackagePath}/${entityName?uncap_first}/importExcel',
|
||||
exportXls = '/${entityPackagePath}/${entityName?uncap_first}/exportXls',
|
||||
}
|
||||
/**
|
||||
* 导出api
|
||||
* @param params
|
||||
*/
|
||||
export const getExportUrl = Api.exportXls;
|
||||
/**
|
||||
* 导入api
|
||||
*/
|
||||
export const getImportUrl = Api.importExcel;
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) =>
|
||||
defHttp.get({url: Api.list, params});
|
||||
|
||||
/**
|
||||
* 删除单个
|
||||
*/
|
||||
export const deleteOne = (params,handleSuccess) => {
|
||||
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate,showTip = true) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({url: url, params},{successMessageMode:showTip?'success':'none'});
|
||||
}
|
||||
@@ -0,0 +1,538 @@
|
||||
<#include "/common/utils.ftl">
|
||||
import {BasicColumn} from '/@/components/Table';
|
||||
import {FormSchema} from '/@/components/Table';
|
||||
import { rules} from '/@/utils/helper/validator';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
import { getWeekMonthQuarterYear } from '/@/utils';
|
||||
//列表数据
|
||||
export const columns: BasicColumn[] = [
|
||||
<#list columns as po>
|
||||
<#-- update-begin---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#if po.isShowList =='Y' && po.fieldName !='id' && po.fieldName !='delFlag'>
|
||||
<#-- update-end---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
{
|
||||
title: '${po.filedComment}',
|
||||
align:"center",
|
||||
<#if po.sort=='Y'>
|
||||
sorter: true,
|
||||
</#if>
|
||||
<#if po.classType=='date'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
customRender:({text}) =>{
|
||||
text = !text ? "" : (text.length > 10 ? text.substr(0,10) : text);
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
if(text) {
|
||||
return getWeekMonthQuarterYear(text)['${po.extendParams.picker}'];
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
<#else>
|
||||
return text;
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.fieldDbType=='Blob'>
|
||||
dataIndex: '${po.fieldName}String'
|
||||
<#elseif po.classType=='umeditor'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#elseif po.classType=='pca'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#elseif po.classType=='file'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#elseif po.classType=='image'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
customRender:render.renderImage,
|
||||
<#elseif po.classType=='switch'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#assign switch_extend_arr=['Y','N']>
|
||||
<#if po.dictField?default("")?contains("[")>
|
||||
<#assign switch_extend_arr=po.dictField?eval>
|
||||
</#if>
|
||||
<#list switch_extend_arr as a>
|
||||
<#if a_index == 0>
|
||||
<#assign switch_extend_arr1=a>
|
||||
<#else>
|
||||
<#assign switch_extend_arr2=a>
|
||||
</#if>
|
||||
</#list>
|
||||
customRender:({text}) => {
|
||||
return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
|
||||
},
|
||||
<#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user' || po.classType=='popup_dict' || po.classType=='link_table'>
|
||||
dataIndex: '${po.fieldName}_dictText'
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
dataIndex: '${po.fieldName}',
|
||||
<#if po.dictText?default("")?trim?length == 0>
|
||||
customRender:({text}) => {
|
||||
return render.renderCategoryTree(text,'${po.dictField?default("")}')
|
||||
},
|
||||
<#else>
|
||||
customRender: ({text, record}) => (text ? record['${po.dictText}'] : '')
|
||||
</#if>
|
||||
<#else>
|
||||
dataIndex: '${po.fieldName}'
|
||||
</#if>
|
||||
},
|
||||
</#if>
|
||||
</#list>
|
||||
];
|
||||
//查询数据
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
<#-- 开始循环 -->
|
||||
<#list columns as po>
|
||||
<#if po.fieldDbName=='bpm_status'>
|
||||
<#assign bpm_flag=true>
|
||||
</#if>
|
||||
<#-- update-begin---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#if po.isQuery=='Y' && po.fieldName !='delFlag'>
|
||||
<#-- update-end---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#assign query_flag=true>
|
||||
<#assign query_field_dictCode="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
<#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign query_field_dictCode="${po.dictField}">
|
||||
</#if>
|
||||
<#if po.queryMode=='single'>
|
||||
{
|
||||
label: "${po.filedComment}",
|
||||
field: ${autoStringSuffix(po)},
|
||||
<#if po.classType=='sel_search'>
|
||||
component: 'JSearchSelect',
|
||||
componentProps:{
|
||||
dict:"${query_field_dictCode}"
|
||||
},
|
||||
<#elseif po.classType=='sel_user'>
|
||||
<#-- update-begin---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
component: 'JSelectUser',
|
||||
componentProps:{
|
||||
<#if po.extendParams?exists && po.extendParams.text?exists>
|
||||
labelKey: '${po.extendParams.text}',
|
||||
</#if>
|
||||
<#if po.extendParams?exists && po.extendParams.store?exists>
|
||||
rowKey: '${po.extendParams.store}',
|
||||
</#if>
|
||||
},
|
||||
<#-- update-end---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
<#elseif po.classType=='switch'>
|
||||
component: 'JSwitch',
|
||||
componentProps:{
|
||||
query:true,
|
||||
<#if po.dictField != 'is_open'>
|
||||
options:${po.dictField}
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType=='sel_depart'>
|
||||
component: 'JSelectDept',
|
||||
componentProps:{
|
||||
<#if po.extendParams?exists && po.extendParams.text?exists>
|
||||
labelKey: '${po.extendParams.text}',
|
||||
</#if>
|
||||
<#if po.extendParams?exists && po.extendParams.store?exists>
|
||||
rowKey: '${po.extendParams.store}',
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType=='list_multi'>
|
||||
component: 'JSelectMultiple',
|
||||
componentProps:{
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
dictCode:"${po.dictTable},${po.dictText},${po.dictField}",
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
dictCode:"${po.dictField}",
|
||||
</#if>
|
||||
triggerChange: true
|
||||
},
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
component: 'JCategorySelect',
|
||||
componentProps:{
|
||||
pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题
|
||||
},
|
||||
<#elseif po.classType=='date'>
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
picker: '${po.extendParams.picker}',
|
||||
</#if>
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
},
|
||||
<#elseif po.classType=='datetime'>
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime:true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss'
|
||||
},
|
||||
<#elseif po.classType =='time'>
|
||||
component: 'TimePicker',
|
||||
componentProps: {
|
||||
valueFormat: 'HH:mm:ss'
|
||||
},
|
||||
<#elseif po.classType=='pca'>
|
||||
component: 'JAreaLinkage',
|
||||
componentProps: {
|
||||
saveCode: 'region',
|
||||
},
|
||||
<#elseif po.classType=='popup'>
|
||||
<#include "/common/form/vue3popup.ftl">
|
||||
<#elseif po.classType=='popup_dict'>
|
||||
component: 'JPopupDict',
|
||||
componentProps: {
|
||||
placeholder: '请选择${po.filedComment}',
|
||||
dictCode: '${po.dictTable},${po.dictText},${po.dictField}',
|
||||
multi: ${po.extendParams.popupMulti?c}
|
||||
},
|
||||
<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
|
||||
<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
|
||||
component: 'JSelectMultiple',
|
||||
componentProps:{
|
||||
<#if po.dictTable?default("")?trim?length gt 1>
|
||||
dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
dictCode:"${po.dictField}"
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType == 'sel_tree'>
|
||||
component: 'JTreeSelect',
|
||||
componentProps:{
|
||||
<#if po.dictText??>
|
||||
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
|
||||
dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
|
||||
<#elseif po.dictText?split(',')[1]??>
|
||||
pidField:"${po.dictText?split(',')[1]}",
|
||||
<#elseif po.dictText?split(',')[3]??>
|
||||
hasChildField:"${po.dictText?split(',')[3]}",
|
||||
</#if>
|
||||
</#if>
|
||||
pidValue:"${po.dictField}",
|
||||
},
|
||||
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
component: 'InputNumber',
|
||||
<#else>
|
||||
component: 'Input',
|
||||
</#if>
|
||||
//colProps: {span: 6},
|
||||
},
|
||||
<#elseif po.queryMode=='like'>
|
||||
{
|
||||
label: "${po.filedComment}",
|
||||
field: "${po.fieldName}",
|
||||
component: 'JInput',
|
||||
},
|
||||
<#else>
|
||||
{
|
||||
label: "${po.filedComment}",
|
||||
field: "${po.fieldName}",
|
||||
<#if po.classType=='date'>
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
picker: '${po.extendParams.picker}',
|
||||
</#if>
|
||||
valueType: 'Date',
|
||||
},
|
||||
<#elseif po.classType=='datetime'>
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
valueType: 'Date',
|
||||
showTime:true
|
||||
},
|
||||
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
component: 'JRangeNumber',
|
||||
<#-- update-begin---author:chenrui ---date:20240527 for:[TV360X-388]时间范围查询控件---------- -->
|
||||
<#elseif po.classType=='time'>
|
||||
component: 'RangeTime',
|
||||
<#-- update-end---author:chenrui ---date:20240527 for:[TV360X-388]时间范围查询控件---------- -->
|
||||
<#else>
|
||||
component: 'Input', //TODO 范围查询
|
||||
</#if>
|
||||
//colProps: {span: 6},
|
||||
},
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
<#-- 结束循环 -->
|
||||
];
|
||||
//表单数据
|
||||
export const formSchema: FormSchema[] = [
|
||||
<#assign form_cat_tree = false>
|
||||
<#assign form_cat_back = "">
|
||||
<#assign bpm_flag=false>
|
||||
<#assign id_exists = false>
|
||||
<#list columns as po><#rt/>
|
||||
<#if po.fieldDbName=='bpm_status'>
|
||||
<#assign bpm_flag=true>
|
||||
</#if>
|
||||
<#if po.fieldDbName == 'id'>
|
||||
<#assign id_exists = true>
|
||||
</#if>
|
||||
<#-- update-begin---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#if po.isShow =='Y' && po.fieldName !='delFlag'>
|
||||
<#-- update-end---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#assign form_field_dictCode="">
|
||||
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
|
||||
<#elseif po.dictField?default("")?trim?length gt 1>
|
||||
<#assign form_field_dictCode="${po.dictField}">
|
||||
</#if>
|
||||
{
|
||||
label: '${po.filedComment}',
|
||||
field: ${autoStringSuffix(po)},
|
||||
<#-- update-begin-author:taoyan date:2022-6-24 for: VUEN-1190【代码生成】默认值未生成 -->
|
||||
<#if po.defaultVal??>
|
||||
<#if po.fieldDbType=="BigDecimal" || po.fieldDbType=="double" || po.fieldDbType=="int">
|
||||
defaultValue: ${po.defaultVal},
|
||||
<#else>
|
||||
defaultValue: "${po.defaultVal}",
|
||||
</#if>
|
||||
</#if>
|
||||
<#-- update-end-author:taoyan date:2022-6-24 for: VUEN-1190【代码生成】默认值未生成 -->
|
||||
<#if po.classType =='date'>
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
picker: '${po.extendParams.picker}',
|
||||
</#if>
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
},
|
||||
<#elseif po.classType =='datetime'>
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss'
|
||||
},
|
||||
<#elseif po.classType =='time'>
|
||||
component: 'TimePicker',
|
||||
componentProps: {
|
||||
valueFormat: 'HH:mm:ss'
|
||||
},
|
||||
<#elseif po.classType =='popup'>
|
||||
<#include "/common/form/vue3popup.ftl">
|
||||
<#elseif po.classType=='popup_dict'>
|
||||
component: 'JPopupDict',
|
||||
componentProps: {
|
||||
placeholder: '请选择${po.filedComment}',
|
||||
dictCode: '${po.dictTable},${po.dictText},${po.dictField}',
|
||||
multi: ${po.extendParams.popupMulti?c}
|
||||
},
|
||||
<#elseif po.classType =='sel_depart'>
|
||||
component: 'JSelectDept',
|
||||
componentProps:{
|
||||
<#if po.extendParams?exists && po.extendParams.text?exists>
|
||||
labelKey: '${po.extendParams.text}',
|
||||
</#if>
|
||||
<#if po.extendParams?exists && po.extendParams.store?exists>
|
||||
rowKey: '${po.extendParams.store}',
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType =='switch'>
|
||||
component: 'JSwitch',
|
||||
componentProps:{
|
||||
<#if po.dictField != 'is_open'>
|
||||
options:${po.dictField}
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType =='pca'>
|
||||
component: 'JAreaLinkage',
|
||||
componentProps: {
|
||||
saveCode: 'region',
|
||||
},
|
||||
<#elseif po.classType =='markdown'>
|
||||
component: 'JMarkdownEditor',//注意string转换问题
|
||||
<#elseif po.classType =='password'>
|
||||
component: 'InputPassword',
|
||||
<#elseif po.classType =='sel_user'>
|
||||
<#-- update-begin---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
component: 'JSelectUser',
|
||||
<#-- update-end---author:chenrui ---date:20240102 for:[issue/#5711]修复用户选择组件在生成代码后变成部门用户选择组件---------- -->
|
||||
componentProps:{
|
||||
<#if po.extendParams?exists && po.extendParams.text?exists>
|
||||
labelKey: '${po.extendParams.text}',
|
||||
</#if>
|
||||
<#if po.extendParams?exists && po.extendParams.store?exists>
|
||||
rowKey: '${po.extendParams.store}',
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType =='textarea'>
|
||||
component: 'InputTextArea',
|
||||
<#elseif po.classType=='list'>
|
||||
component: 'JDictSelectTag',
|
||||
componentProps:{
|
||||
dictCode:"${form_field_dictCode}",
|
||||
<#if po.fieldDbType=='int'>
|
||||
stringToNumber: true
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType=='radio'>
|
||||
component: 'JDictSelectTag',
|
||||
componentProps:{
|
||||
dictCode:"${form_field_dictCode}",
|
||||
type: "radio",
|
||||
<#if po.fieldDbType=='int'>
|
||||
stringToNumber: true
|
||||
</#if>
|
||||
},
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:[QQYUN-7583] Vue3风格表单页面多选控件渲染成了下拉多选---------- -->
|
||||
<#elseif po.classType=='list_multi'>
|
||||
component: 'JSelectMultiple',
|
||||
componentProps:{
|
||||
dictCode:"${form_field_dictCode}"
|
||||
},
|
||||
<#elseif po.classType=='checkbox'>
|
||||
component: 'JCheckbox',
|
||||
componentProps:{
|
||||
dictCode:"${form_field_dictCode}"
|
||||
},
|
||||
<#-- update-end---author:chenrui ---date:20231228 for:[QQYUN-7583] Vue3风格表单页面多选控件渲染成了下拉多选---------- -->
|
||||
<#elseif po.classType=='sel_search'>
|
||||
component: 'JSearchSelect',
|
||||
componentProps:{
|
||||
dict:"${form_field_dictCode}"
|
||||
},
|
||||
<#elseif po.classType=='cat_tree'>
|
||||
<#assign form_cat_tree = true>
|
||||
component: 'JCategorySelect',
|
||||
componentProps:{
|
||||
pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
|
||||
},
|
||||
<#if po.dictText?default("")?trim?length gt 1>
|
||||
<#assign form_cat_back = "${po.dictText}">
|
||||
</#if>
|
||||
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
|
||||
component: 'InputNumber',
|
||||
<#elseif po.classType=='file'>
|
||||
component: 'JUpload',
|
||||
componentProps:{
|
||||
<#if po.uploadnum??>
|
||||
maxCount:${po.uploadnum}
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType=='image'>
|
||||
component: 'JImageUpload',
|
||||
componentProps:{
|
||||
<#if po.uploadnum??>
|
||||
fileMax:${po.uploadnum}
|
||||
<#else>
|
||||
fileMax: 0
|
||||
</#if>
|
||||
},
|
||||
<#elseif po.classType=='umeditor'>
|
||||
component: 'JEditor',
|
||||
<#elseif po.classType == 'sel_tree'>
|
||||
component: 'JTreeSelect',
|
||||
componentProps:{
|
||||
<#if po.dictText??>
|
||||
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
|
||||
dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
|
||||
<#elseif po.dictText?split(',')[1]??>
|
||||
pidField:"${po.dictText?split(',')[1]}",
|
||||
<#elseif po.dictText?split(',')[3]??>
|
||||
hasChildField:"${po.dictText?split(',')[3]}",
|
||||
</#if>
|
||||
</#if>
|
||||
pidValue:"${po.dictField}",
|
||||
},
|
||||
<#elseif po.classType=='link_table'>
|
||||
component: 'JLinkTableCard',
|
||||
componentProps: {
|
||||
valueField: '${po.dictField}',
|
||||
textField: '${po.dictText}',
|
||||
tableName: '${po.dictTable}',
|
||||
multi: <#if (po.queryMode!"") == "multi">true<#else>false</#if>
|
||||
},
|
||||
<#else>
|
||||
component: 'Input',
|
||||
</#if>
|
||||
<#if po.isShow == 'Y' && poHasCheck(po)>
|
||||
dynamicRules: ({model,schema}) => {
|
||||
<#if po.fieldName != 'id'>
|
||||
<#assign fieldValidType = po.fieldValidType!''>
|
||||
return [
|
||||
<#-- 非空校验 -->
|
||||
<#if po.nullable == 'N' || fieldValidType == '*'>
|
||||
{ required: true, message: '请输入${po.filedComment}!'},
|
||||
<#elseif fieldValidType!=''>
|
||||
{ required: false},
|
||||
</#if>
|
||||
<#-- 唯一校验 -->
|
||||
<#if fieldValidType == 'only'>
|
||||
{...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema)[0]},
|
||||
<#-- 6到16位数字 -->
|
||||
<#elseif fieldValidType == 'n6-16'>
|
||||
{ pattern: /^\d{6,16}$|^(?=\d+\.\d+)[\d.]{7,17}$/, message: '请输入6到16位数字!'},
|
||||
<#-- 6到16位任意字符 -->
|
||||
<#elseif fieldValidType == '*6-16'>
|
||||
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
|
||||
<#-- 6到18位字母 -->
|
||||
<#elseif fieldValidType == 's6-18'>
|
||||
{ pattern: /^[a-z|A-Z]{6,18}$/, message: '请输入6到18位字母!'},
|
||||
<#-- 网址 -->
|
||||
<#elseif fieldValidType == 'url'>
|
||||
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
|
||||
<#-- 电子邮件 -->
|
||||
<#elseif fieldValidType == 'e'>
|
||||
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
|
||||
<#-- 手机号码 -->
|
||||
<#elseif fieldValidType == 'm'>
|
||||
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
|
||||
<#-- 邮政编码 -->
|
||||
<#elseif fieldValidType == 'p'>
|
||||
{ pattern: /^[0-9]\d{5}$/, message: '请输入正确的邮政编码!'},
|
||||
<#-- 字母 -->
|
||||
<#elseif fieldValidType == 's'>
|
||||
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
|
||||
<#-- 数字 -->
|
||||
<#elseif fieldValidType == 'n'>
|
||||
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
|
||||
<#-- 整数 -->
|
||||
<#elseif fieldValidType == 'z'>
|
||||
{ pattern: /^-?\d+$/, message: '请输入整数!'},
|
||||
<#-- 金额 -->
|
||||
<#elseif fieldValidType == 'money'>
|
||||
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
|
||||
<#-- 正则校验 -->
|
||||
<#elseif fieldValidType != '' && fieldValidType != '*'>
|
||||
{ pattern: '${fieldValidType}', message: '不符合校验规则!'},
|
||||
<#-- 无校验 -->
|
||||
<#else>
|
||||
<#t>
|
||||
</#if>
|
||||
];
|
||||
</#if>
|
||||
},
|
||||
</#if>
|
||||
<#if po.readonly=='Y'>
|
||||
dynamicDisabled:true
|
||||
</#if>
|
||||
},
|
||||
</#if>
|
||||
</#list>
|
||||
<#if id_exists == false>
|
||||
// TODO 主键隐藏字段,目前写死为ID
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false
|
||||
},
|
||||
</#if>
|
||||
];
|
||||
|
||||
<#-- update-begin-author:chenrui date:2023-12-28 for:[QQYUN-7527]vue3代码生成默认带上高级查询 -->
|
||||
// 高级查询数据
|
||||
export const superQuerySchema = {
|
||||
<#list columns as po>
|
||||
<#-- update-begin---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
<#if po.isShowList =='Y' && po.fieldName !='id' && po.fieldName !='delFlag'>
|
||||
<#-- update-end---author:chenrui ---date:20240108 for:[issues/5755]vue代码不加入逻辑删除字段---------- -->
|
||||
${superQueryFieldListForVue3(po,po_index)},
|
||||
</#if>
|
||||
</#list>
|
||||
};
|
||||
<#-- update-end-author:chenrui date:2023-12-28 for:[QQYUN-7527]vue3代码生成默认带上高级查询 -->
|
||||
|
||||
/**
|
||||
* 流程表单调用这个方法获取formSchema
|
||||
* @param param
|
||||
*/
|
||||
export function getBpmFormSchema(_formData): FormSchema[]{
|
||||
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
|
||||
return formSchema;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<#include "/common/sql/menu_insert.ftl">
|
||||
@@ -0,0 +1,82 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<template>
|
||||
<div style="min-height: 400px">
|
||||
<BasicForm @register="registerForm"></BasicForm>
|
||||
<div style="width: 100%;text-align: center" v-if="!formDisabled && showSubmitButton">
|
||||
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary">提 交</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {BasicForm, useForm} from '/@/components/Form/index';
|
||||
import {computed, defineComponent} from 'vue';
|
||||
import {defHttp} from '/@/utils/http/axios';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import {getBpmFormSchema} from '../${entityName}.data';
|
||||
import {saveOrUpdate} from '../${entityName}.api';
|
||||
|
||||
export default defineComponent({
|
||||
name: "${entityName}Form",
|
||||
components:{
|
||||
BasicForm
|
||||
},
|
||||
props:{
|
||||
formData: propTypes.object.def({}),
|
||||
formBpm: propTypes.bool.def(true),
|
||||
showSubmitButton: propTypes.bool.def(true),
|
||||
},
|
||||
setup(props){
|
||||
const [registerForm, { setFieldsValue, setProps,validate, scrollToField, getFieldsValue }] = useForm({
|
||||
labelWidth: 150,
|
||||
schemas: getBpmFormSchema(props.formData),
|
||||
showActionButtonGroup: false,
|
||||
baseColProps: {span: ${getFormSpan(tableVo.fieldRowNum?default(1))}}
|
||||
});
|
||||
|
||||
const formDisabled = computed(()=>{
|
||||
if(props.formData.disabled === false){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
let formData = {};
|
||||
const queryByIdUrl = '/${entityPackagePath}/${entityName?uncap_first}/queryById';
|
||||
async function initFormData(){
|
||||
let params = {id: props.formData.dataId};
|
||||
const data = await defHttp.get({url: queryByIdUrl, params});
|
||||
formData = {...data}
|
||||
//设置表单的值
|
||||
await setFieldsValue(formData);
|
||||
//默认是禁用
|
||||
await setProps({disabled: formDisabled.value})
|
||||
}
|
||||
|
||||
async function submitForm(showTip = true) {
|
||||
try {
|
||||
let values = await validate();
|
||||
console.log('表单数据', values)
|
||||
//提交表单
|
||||
await saveOrUpdate(values, true,showTip);
|
||||
} catch ({ errorFields }) {
|
||||
if (errorFields) {
|
||||
const firstField = errorFields[0];
|
||||
if (firstField) {
|
||||
scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
return Promise.reject(errorFields);
|
||||
}
|
||||
}
|
||||
|
||||
initFormData();
|
||||
|
||||
return {
|
||||
registerForm,
|
||||
formDisabled,
|
||||
submitForm,
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,130 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<#assign buttonList=[]>
|
||||
<#if tableVo.extendParams?? && tableVo.extendParams.cgButtonList??>
|
||||
<#assign buttonList = tableVo.extendParams.cgButtonList?filter(btn -> btn??)>
|
||||
</#if>
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :maxHeight="500" :width="${getModalWidth(tableVo.fieldRowNum?default(1))}" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" name="${entityName}Form" />
|
||||
<#if buttonList?? && buttonList?size gt 0>
|
||||
<template #insertFooter>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle=='form'>
|
||||
<a-button type="primary" @click="handle${btn.buttonCode?cap_first}" <#if btn.buttonIcon??> preIcon="ant-design:${btn.buttonIcon}" </#if>>${btn.buttonName}</a-button>
|
||||
</#if>
|
||||
</#list>
|
||||
</template>
|
||||
</#if>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, computed, unref, reactive} from 'vue';
|
||||
import {BasicModal, useModalInner} from '/@/components/Modal';
|
||||
import {BasicForm, useForm} from '/@/components/Form/index';
|
||||
import {formSchema} from '../${entityName}.data';
|
||||
import {saveOrUpdate} from '../${entityName}.api';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getDateByPicker } from '/@/utils';
|
||||
const { createMessage } = useMessage();
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register','success']);
|
||||
const isUpdate = ref(true);
|
||||
const isDetail = ref(false);
|
||||
//表单配置
|
||||
const [registerForm, { setProps,resetFields, setFieldsValue, validate, scrollToField }] = useForm({
|
||||
<#if tableVo.fieldRowNum == 1>
|
||||
labelWidth: 150,
|
||||
</#if>
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
baseColProps: {span: ${getFormSpan(tableVo.fieldRowNum?default(1))}},
|
||||
baseRowStyle: { padding: "0 20px" }
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
isDetail.value = !!data?.showFooter;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
// 隐藏底部时禁用整个表单
|
||||
setProps({ disabled: !data?.showFooter })
|
||||
});
|
||||
//日期个性化选择
|
||||
const fieldPickers = reactive({
|
||||
<#list columns as po>
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
${po.fieldName}: '${po.extendParams.picker}',
|
||||
</#if>
|
||||
</#list>
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
|
||||
//表单提交事件
|
||||
async function handleSubmit(v) {
|
||||
try {
|
||||
let values = await validate();
|
||||
// 预处理日期数据
|
||||
changeDateValue(values);
|
||||
setModalProps({confirmLoading: true});
|
||||
//提交表单
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} catch ({ errorFields }) {
|
||||
if (errorFields) {
|
||||
const firstField = errorFields[0];
|
||||
if (firstField) {
|
||||
scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
return Promise.reject(errorFields);
|
||||
} finally {
|
||||
setModalProps({confirmLoading: false});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理日期值
|
||||
* @param formData 表单数据
|
||||
*/
|
||||
const changeDateValue = (formData) => {
|
||||
if (formData && fieldPickers) {
|
||||
for (let key in fieldPickers) {
|
||||
if (formData[key]) {
|
||||
formData[key] = getDateByPicker(formData[key], fieldPickers[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle=='form'>
|
||||
function handle${btn.buttonCode?cap_first}(){
|
||||
createMessage.info('点击了${btn.buttonName}按钮,对应的业务逻辑需自行实现!');
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-calendar-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,583 @@
|
||||
<#include "/common/utils.ftl">
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<#assign query_field_no=0>
|
||||
<#assign need_category = false>
|
||||
<#assign need_pca = false>
|
||||
<#assign need_search = false>
|
||||
<#assign need_dept_user = false>
|
||||
<#assign need_switch = false>
|
||||
<#assign need_dept = false>
|
||||
<#assign need_multi = false>
|
||||
<#assign need_popup = false>
|
||||
<#assign need_popup_dict = false>
|
||||
<#assign need_select_tag = false>
|
||||
<#assign need_select_tree = false>
|
||||
<#assign need_time = false>
|
||||
<#assign bpm_flag=false>
|
||||
<#assign need_markdown = false>
|
||||
<#assign need_upload = false>
|
||||
<#assign need_image_upload = false>
|
||||
<#assign need_editor = false>
|
||||
<#assign need_checkbox = false>
|
||||
<#assign need_range_number = false>
|
||||
<#assign is_range = false>
|
||||
<#assign query_flag = false>
|
||||
<#assign buttonList=[]>
|
||||
<#if tableVo.extendParams?? && tableVo.extendParams.cgButtonList??>
|
||||
<#assign buttonList = tableVo.extendParams.cgButtonList?filter(btn -> btn??)>
|
||||
</#if>
|
||||
<#assign is_like = false>
|
||||
<!--查询区域-->
|
||||
<div class="jeecg-basic-table-form-container">
|
||||
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-row :gutter="24">
|
||||
<#-- 开始循环 -->
|
||||
<#list columns as po>
|
||||
<#if po.fieldDbName=='bpm_status'>
|
||||
<#assign bpm_flag=true>
|
||||
</#if>
|
||||
<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
|
||||
<#assign need_category=true>
|
||||
</#if>
|
||||
<#if po.classType=='pca'>
|
||||
<#assign need_pca=true>
|
||||
</#if>
|
||||
<#if po.classType=='sel_search'>
|
||||
<#assign need_search = true>
|
||||
</#if>
|
||||
<#if po.classType=='sel_user'>
|
||||
<#assign need_dept_user = true>
|
||||
</#if>
|
||||
<#if po.classType=='sel_depart'>
|
||||
<#assign need_dept = true>
|
||||
</#if>
|
||||
<#if po.classType=='switch'>
|
||||
<#assign need_switch = true>
|
||||
</#if>
|
||||
<#if po.classType=='list_multi'>
|
||||
<#assign need_multi = true>
|
||||
</#if>
|
||||
<#if po.classType=='popup'>
|
||||
<#assign need_popup = true>
|
||||
</#if>
|
||||
<#if po.classType=='popup_dict'>
|
||||
<#assign need_popup_dict = true>
|
||||
</#if>
|
||||
<#if po.classType=='sel_tree'>
|
||||
<#assign need_select_tree = true>
|
||||
</#if>
|
||||
<#if po.classType=='time'>
|
||||
<#assign need_time = true>
|
||||
</#if>
|
||||
<#if po.queryMode=='group' && (po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal')>
|
||||
<#assign need_range_number = true>
|
||||
</#if>
|
||||
<#if po.queryMode=='group'>
|
||||
<#assign is_range = true>
|
||||
</#if>
|
||||
<#if po.queryMode=='like'>
|
||||
<#assign is_like = true>
|
||||
</#if>
|
||||
<#include "/common/form/native/vue3NativeSearch.ftl">
|
||||
</#list>
|
||||
<#if query_field_no gt 2>
|
||||
</template>
|
||||
</#if>
|
||||
<#if query_flag>
|
||||
<a-col :xl="6" :lg="7" :md="8" :sm="24">
|
||||
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
|
||||
<a-col :lg="6">
|
||||
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
|
||||
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
|
||||
<a @click="toggleSearchStatus = !toggleSearchStatus" style="margin-left: 8px">
|
||||
{{ toggleSearchStatus ? '收起' : '展开' }}
|
||||
<Icon :icon="toggleSearchStatus ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
|
||||
</a>
|
||||
</a-col>
|
||||
</span>
|
||||
</a-col>
|
||||
</#if>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
<#-- 结束循环 -->
|
||||
<!--引用表格-->
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<!--插槽:table标题-->
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" v-auth="'${entityPackage}:${tableName}:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
|
||||
<a-button type="primary" v-auth="'${entityPackage}:${tableName}:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
|
||||
<j-upload-button type="primary" v-auth="'${entityPackage}:${tableName}:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle == 'button'>
|
||||
<a-button type="primary" @click="handle${btn.buttonCode?cap_first}" <#if btn.buttonIcon??> preIcon="ant-design:${btn.buttonIcon}" </#if>>${btn.buttonName}</a-button>
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button v-auth="'${entityPackage}:${tableName}:deleteBatch'">批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
<!-- 高级查询 -->
|
||||
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
|
||||
<#-- update-end---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
|
||||
</template>
|
||||
<template v-slot:bodyCell="{ column, record, index, text }">
|
||||
<#list columns as po>
|
||||
<#if po.classType=='umeditor' || po.classType=='pca' || po.classType=='file'>
|
||||
<template v-if="column.dataIndex==='${po.fieldName}'">
|
||||
<#if po.classType=='umeditor'>
|
||||
<!--富文本件字段回显插槽-->
|
||||
<div v-html="text"></div>
|
||||
</#if>
|
||||
<#if po.classType=='pca'>
|
||||
<!--省市区字段回显插槽-->
|
||||
{{ getAreaTextByCode(text) }}
|
||||
</#if>
|
||||
<#if po.classType=='file'>
|
||||
<!--文件字段回显插槽-->
|
||||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
|
||||
</#if>
|
||||
</template>
|
||||
</#if>
|
||||
</#list>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!-- 表单区域 -->
|
||||
<${entityName}Modal ref="registerModal" @success="handleSuccess"></${entityName}Modal>
|
||||
<#if bpm_flag==true>
|
||||
<!-- 审批记录 -->
|
||||
<BpmPictureModal @register="registerBpmModal" />
|
||||
</#if>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { columns, superQuerySchema } from './${entityName}.data';
|
||||
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './${entityName}.api';
|
||||
import { downloadFile } from '/@/utils/common/renderUtils';
|
||||
import ${entityName}Modal from './components/${entityName}Modal.vue'
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import {useModal} from '/@/components/Modal';
|
||||
<#include "/common/form/native/vue3NativeImport.ftl">
|
||||
<#if need_category>
|
||||
import { loadCategoryData } from '/@/api/common/api';
|
||||
import { getAuthCache, setAuthCache } from '/@/utils/auth';
|
||||
import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
|
||||
</#if>
|
||||
<#if need_pca>
|
||||
import { getAreaTextByCode } from '/@/components/Form/src/utils/Area';
|
||||
</#if>
|
||||
import { getDateByPicker } from '/@/utils';
|
||||
<#if need_popup_dict>
|
||||
import {getPopDictByCode} from "@/utils/dict";
|
||||
import {filterMultiDictText} from "@/utils/dict/JDictSelectUtil";
|
||||
</#if>
|
||||
<#if bpm_flag==true>
|
||||
import { startProcess } from '/@/api/common/api';
|
||||
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
|
||||
</#if>
|
||||
<#if is_range>
|
||||
import { cloneDeep } from "lodash-es";
|
||||
</#if>
|
||||
|
||||
const fieldPickers = reactive({
|
||||
<#list columns as po>
|
||||
<#if po.extendParams?exists && po.extendParams.picker?exists>
|
||||
${po.fieldName}: '${po.extendParams.picker}',
|
||||
</#if>
|
||||
</#list>
|
||||
});
|
||||
|
||||
const formRef = ref();
|
||||
const queryParam = reactive<any>({});
|
||||
const toggleSearchStatus = ref<boolean>(false);
|
||||
const registerModal = ref();
|
||||
const userStore = useUserStore();
|
||||
const { createMessage } = useMessage();
|
||||
//注册table数据
|
||||
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
|
||||
tableProps: {
|
||||
title: '${tableVo.ftlDescription}',
|
||||
api: list,
|
||||
columns,
|
||||
canResize:true,
|
||||
useSearchForm: false,
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
beforeFetch: async (params) => {
|
||||
<#if is_range>
|
||||
let rangerQuery = await setRangeQuery();
|
||||
return Object.assign(params, rangerQuery);
|
||||
<#else>
|
||||
for (let key in fieldPickers) {
|
||||
if (queryParam[key] && fieldPickers[key]) {
|
||||
queryParam[key] = getDateByPicker(queryParam[key], fieldPickers[key]);
|
||||
}
|
||||
}
|
||||
return Object.assign(params, queryParam);
|
||||
</#if>
|
||||
},
|
||||
<#if need_popup_dict>
|
||||
afterFetch: afterFetch
|
||||
</#if>
|
||||
},
|
||||
exportConfig: {
|
||||
name: "${tableVo.ftlDescription}",
|
||||
url: getExportUrl,
|
||||
<#if is_range>
|
||||
params: setRangeQuery,
|
||||
<#else>
|
||||
params: queryParam,
|
||||
</#if>
|
||||
},
|
||||
importConfig: {
|
||||
url: getImportUrl,
|
||||
success: handleSuccess
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
const labelCol = reactive({
|
||||
xs:24,
|
||||
sm:4,
|
||||
xl:6,
|
||||
xxl:4
|
||||
});
|
||||
const wrapperCol = reactive({
|
||||
xs: 24,
|
||||
sm: 20,
|
||||
});
|
||||
|
||||
<#-- update-begin---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
// 高级查询配置
|
||||
const superQueryConfig = reactive(superQuerySchema);
|
||||
|
||||
/**
|
||||
* 高级查询事件
|
||||
*/
|
||||
function handleSuperQuery(params) {
|
||||
Object.keys(params).map((k) => {
|
||||
queryParam[k] = params[k];
|
||||
});
|
||||
searchQuery();
|
||||
}
|
||||
<#-- update-end---author:chenrui ---date:20231228 for:[QQYUN-7527]vue3代码生成默认带上高级查询---------- -->
|
||||
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
function handleAdd() {
|
||||
registerModal.value.disableSubmit = false;
|
||||
registerModal.value.add();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
function handleEdit(record: Recordable) {
|
||||
registerModal.value.disableSubmit = false;
|
||||
registerModal.value.edit(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
function handleDetail(record: Recordable) {
|
||||
registerModal.value.disableSubmit = true;
|
||||
registerModal.value.edit(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteOne({ id: record.id }, handleSuccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功回调
|
||||
*/
|
||||
function handleSuccess() {
|
||||
(selectedRowKeys.value = []) && reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
auth: '${entityPackage}:${tableName}:edit'
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
<#if bpm_flag==true>
|
||||
let dropDownAction = [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
placement: 'topLeft',
|
||||
},
|
||||
auth: '${entityPackage}:${tableName}:delete'
|
||||
},
|
||||
{
|
||||
label: '审批进度',
|
||||
onClick: handlePreviewPic.bind(null, record),
|
||||
ifShow: !!record.bpmStatus && record.bpmStatus !== '1',
|
||||
}
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle == 'link'>
|
||||
,{
|
||||
label: '${btn.buttonName}',
|
||||
onClick: handle${btn.buttonCode?cap_first}.bind(null, record),
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
];
|
||||
if(record.bpmStatus == '1'){
|
||||
dropDownAction.push({
|
||||
label: '发起流程',
|
||||
popConfirm: {
|
||||
title: '确认提交流程吗?',
|
||||
confirm: handleProcess.bind(null, record),
|
||||
placement: 'topLeft',
|
||||
}
|
||||
})
|
||||
}
|
||||
return dropDownAction;
|
||||
<#else>
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
placement: 'topLeft',
|
||||
},
|
||||
auth: '${entityPackage}:${tableName}:delete'
|
||||
}
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle == 'link'>
|
||||
,{
|
||||
label: '${btn.buttonName}',
|
||||
onClick: handle${btn.buttonCode?cap_first}.bind(null, record),
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
]
|
||||
</#if>
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
function searchQuery() {
|
||||
reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
function searchReset() {
|
||||
formRef.value.resetFields();
|
||||
selectedRowKeys.value = [];
|
||||
//刷新数据
|
||||
reload();
|
||||
}
|
||||
|
||||
<#if need_popup>
|
||||
/**
|
||||
* popup组件值改变事件
|
||||
*/
|
||||
function setFieldsValue(map) {
|
||||
Object.keys(map).map((key) => {
|
||||
queryParam[key] = map[key];
|
||||
});
|
||||
}
|
||||
</#if>
|
||||
|
||||
<#if need_pca || need_dept_user>
|
||||
/**
|
||||
* form点击事件(以逗号分割)
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
function handleFormJoinChange(key, value) {
|
||||
if (typeof value != 'string') {
|
||||
queryParam[key] = value.join(',');
|
||||
}
|
||||
}
|
||||
</#if>
|
||||
|
||||
<#if bpm_flag==true>
|
||||
/**
|
||||
* 提交流程
|
||||
*/
|
||||
async function handleProcess(record) {
|
||||
let params = {
|
||||
flowCode: 'dev_${tableName}_001',
|
||||
id: record.id,
|
||||
formUrl: '${entityPackagePath}/components/${entityName}Form',
|
||||
formUrlMobile: ''
|
||||
}
|
||||
await startProcess(params);
|
||||
handleSuccess();
|
||||
}
|
||||
/**
|
||||
* 审批进度
|
||||
*/
|
||||
async function handlePreviewPic(record) {
|
||||
bpmPicModal(true, {
|
||||
flowCode: 'dev_${tableName}_001',
|
||||
dataId: record.id,
|
||||
});
|
||||
}
|
||||
</#if>
|
||||
|
||||
<#if buttonList?size gt 0>
|
||||
<#list buttonList as btn>
|
||||
<#if btn.buttonStyle=='button'>
|
||||
function handle${btn.buttonCode?cap_first}(){
|
||||
createMessage.info('点击了${btn.buttonName}按钮,对应的业务逻辑需自行实现!');
|
||||
}
|
||||
</#if>
|
||||
<#if btn.buttonStyle=='link'>
|
||||
function handle${btn.buttonCode?cap_first}(record){
|
||||
createMessage.info('点击了${btn.buttonName}按钮,对应的业务逻辑需自行实现!');
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if need_category>
|
||||
/**
|
||||
* form点击事件
|
||||
* @param value
|
||||
*/
|
||||
function handleFormChange(key, value) {
|
||||
queryParam[key] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化字典配置
|
||||
*/
|
||||
function initDictConfig() {
|
||||
<#list columns as po>
|
||||
<#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
|
||||
<#if po.classType=='cat_tree' && need_category==true>
|
||||
loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
|
||||
if (res) {
|
||||
const allDictDate = userStore.getAllDictItems;
|
||||
if(!allDictDate['${po.dictField?default("")}']){
|
||||
userStore.setAllDictItems({...allDictDate,'${po.dictField?default("")}':res});
|
||||
}
|
||||
}
|
||||
});
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
}
|
||||
initDictConfig();
|
||||
</#if>
|
||||
<#if is_range>
|
||||
|
||||
let rangeField = '${getRangeField(columns)}'
|
||||
|
||||
/**
|
||||
* 设置范围查询条件
|
||||
*/
|
||||
async function setRangeQuery(){
|
||||
let queryParamClone = cloneDeep(queryParam);
|
||||
if (rangeField) {
|
||||
let fieldsValue = rangeField.split(',');
|
||||
fieldsValue.forEach(item => {
|
||||
if (queryParamClone[item]) {
|
||||
let range = queryParamClone[item];
|
||||
queryParamClone[item+'_begin'] = range[0];
|
||||
queryParamClone[item+'_end'] = range[1];
|
||||
delete queryParamClone[item];
|
||||
} else {
|
||||
queryParamClone[item+'_begin'] = '';
|
||||
queryParamClone[item+'_end'] = '';
|
||||
}
|
||||
})
|
||||
}
|
||||
return queryParamClone;
|
||||
}
|
||||
</#if>
|
||||
|
||||
<#if need_popup_dict>
|
||||
/**
|
||||
* 翻译Popup字典配置
|
||||
*/
|
||||
async function afterFetch(records){
|
||||
<#list columns as po>
|
||||
<#if po.isQuery=='Y' || po.isShowList=='Y'>
|
||||
<#if po.classType=='popup_dict'>
|
||||
const ${po.fieldName}Keys = [...new Set(records.map((item) => item['${po.fieldName}']).flatMap((item) => item && item.split(',')))];
|
||||
if(${po.fieldName}Keys && ${po.fieldName}Keys.length){
|
||||
const dictOptions = await getPopDictByCode(${po.fieldName}Keys.join(','), '${po.dictTable},${po.dictField},${po.dictText}');
|
||||
records.forEach((item) => {
|
||||
item['${po.fieldName}_dictText'] = filterMultiDictText(dictOptions, item['${po.fieldName}']);
|
||||
});
|
||||
}
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
return records;
|
||||
}
|
||||
</#if>
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
<#include "/common/form/native/vueNativeSearchStyle.ftl">
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user