Przeglądaj źródła

Update 优化工作流代码

Yue 6 miesięcy temu
rodzic
commit
b3aa2cc3ea
51 zmienionych plików z 1572 dodań i 641 usunięć
  1. 71 31
      SERVER/VberAdminPlusV3/.script/leave/leave1.json
  2. 99 44
      SERVER/VberAdminPlusV3/.script/leave/leave2.json
  3. 110 44
      SERVER/VberAdminPlusV3/.script/leave/leave3.json
  4. 82 35
      SERVER/VberAdminPlusV3/.script/leave/leave4.json
  5. 110 44
      SERVER/VberAdminPlusV3/.script/leave/leave5.json
  6. 179 69
      SERVER/VberAdminPlusV3/.script/leave/leave6.json
  7. 22 0
      SERVER/VberAdminPlusV3/.script/sql/flow.sql
  8. 4 8
      SERVER/VberAdminPlusV3/vber-admin/src/main/resources/application.yml
  9. 6 0
      SERVER/VberAdminPlusV3/vber-common/vber-common-core/src/main/java/com/vber/common/core/domain/dto/CompleteTaskDTO.java
  10. 44 0
      SERVER/VberAdminPlusV3/vber-common/vber-common-core/src/main/java/com/vber/common/core/domain/dto/FlowInstanceBizExtDTO.java
  11. 19 0
      SERVER/VberAdminPlusV3/vber-common/vber-common-core/src/main/java/com/vber/common/core/domain/dto/StartProcessDTO.java
  12. 6 3
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/common/constant/FlowConstant.java
  13. 20 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/common/enums/CopySettingEnum.java
  14. 20 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/common/enums/VariablesEnum.java
  15. 58 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/FlowInstanceBizExt.java
  16. 5 1
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/TestLeave.java
  17. 5 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/CompleteTaskBo.java
  18. 0 1
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/FlowSpelBo.java
  19. 19 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/StartProcessBo.java
  20. 5 1
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/TestLeaveBo.java
  21. 1 1
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowCategoryVo.java
  22. 36 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowCopyVo.java
  23. 12 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowHisTaskVo.java
  24. 13 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowInstanceVo.java
  25. 1 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowSpelVo.java
  26. 27 1
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowTaskVo.java
  27. 45 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/NodeExtVo.java
  28. 7 3
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/TestLeaveVo.java
  29. 33 10
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/listener/WorkflowGlobalListener.java
  30. 60 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/mapper/FlwInstanceBizExtMapper.java
  31. 16 6
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/IFlwNodeExtService.java
  32. 26 19
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwCategoryServiceImpl.java
  33. 20 9
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwChartExtServiceImpl.java
  34. 30 18
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwCommonServiceImpl.java
  35. 2 1
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwDefinitionServiceImpl.java
  36. 112 97
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwNodeExtServiceImpl.java
  37. 60 8
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwTaskServiceImpl.java
  38. 17 6
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/TestLeaveServiceImpl.java
  39. 16 10
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/WorkflowServiceImpl.java
  40. 7 0
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwInstanceBizExtMapper.xml
  41. 25 21
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml
  42. 1 1
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwSpelMapper.xml
  43. 91 81
      SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml
  44. 1 1
      UI/VAP_V3.VUE/src/components/process/MessageType.vue
  45. 7 1
      UI/VAP_V3.VUE/src/components/process/SubmitVerify.vue
  46. 1 1
      UI/VAP_V3.VUE/src/views/workflow/processDefinition/index.vue
  47. 5 9
      UI/VAP_V3.VUE/src/views/workflow/processInstance/index.vue
  48. 4 14
      UI/VAP_V3.VUE/src/views/workflow/task/allTaskWaiting.vue
  49. 4 14
      UI/VAP_V3.VUE/src/views/workflow/task/taskCopyList.vue
  50. 4 14
      UI/VAP_V3.VUE/src/views/workflow/task/taskFinish.vue
  51. 4 14
      UI/VAP_V3.VUE/src/views/workflow/task/taskWaiting.vue

+ 71 - 31
SERVER/VberAdminPlusV3/.script/leave/leave1.json

@@ -1,89 +1,129 @@
 {
-  "flowCode": "leave1",
-  "flowName": "请假申请-普通",
-  "category": "100",
-  "version": "1",
-  "formCustom": "N",
-  "formPath": "/workflow/leaveEdit/index",
   "nodeList": [
     {
-      "nodeType": 0,
+      "nodeType": "0",
       "nodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
       "nodeName": "开始",
-      "nodeRatio": 0.000,
-      "coordinate": "200,200|200,200",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "200,200|200,200",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
           "nextNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
-          "skipType": "PASS",
           "coordinate": "220,200;310,200"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
       "nodeName": "申请人",
-      "nodeRatio": 0.000,
-      "coordinate": "360,200|360,200",
+      "permissionFlag": "",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,copy\"}]",
+      "coordinate": "360,200|360,200",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
           "nextNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
-          "skipType": "PASS",
           "coordinate": "410,200;490,200"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
       "nodeName": "组长",
       "permissionFlag": "role:1",
-      "nodeRatio": 0.000,
-      "coordinate": "540,200|540,200",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]",
+      "coordinate": "540,200|540,200",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
           "nextNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
-          "skipType": "PASS",
           "coordinate": "590,200;670,200"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
-      "nodeName": "组织机构主管",
+      "nodeName": "部门主管",
       "permissionFlag": "role:3@@role:4",
-      "nodeRatio": 0.000,
-      "coordinate": "720,200|720,200",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]",
+      "coordinate": "720,200|720,200",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
           "nextNodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
-          "skipType": "PASS",
           "coordinate": "770,200;880,200"
         }
       ]
     },
     {
-      "nodeType": 2,
+      "nodeType": "2",
       "nodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
       "nodeName": "结束",
-      "nodeRatio": 0.000,
-      "coordinate": "900,200|900,200",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
-      "ext": "[]"
+      "formPath": null,
+      "ext": "[]",
+      "coordinate": "900,200|900,200",
+      "version": "1",
+      "skipList": []
     }
-  ]
+  ],
+  "flowCode": "leave1",
+  "flowName": "请假申请-普通",
+  "modelValue": "CLASSICS",
+  "category": "103",
+  "version": "1",
+  "formCustom": "N",
+  "formPath": "/workflow/leaveEdit/index",
+  "listenerType": null,
+  "listenerPath": null
 }

+ 99 - 44
SERVER/VberAdminPlusV3/.script/leave/leave2.json

@@ -1,132 +1,187 @@
 {
-  "flowCode": "leave2",
-  "flowName": "请假申请-排他网关",
-  "category": "100",
-  "version": "1",
-  "formCustom": "N",
-  "formPath": "/workflow/leaveEdit/index",
   "nodeList": [
     {
-      "nodeType": 0,
+      "nodeType": "0",
       "nodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
       "nodeName": "开始",
-      "nodeRatio": 0.000,
-      "coordinate": "300,240|300,240",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "300,240|300,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
           "nextNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
-          "skipType": "PASS",
           "coordinate": "320,240;390,240"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
       "nodeName": "申请人",
-      "nodeRatio": 0.000,
-      "coordinate": "440,240|440,240",
+      "permissionFlag": "",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
+      "coordinate": "440,240|440,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
           "nextNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
-          "skipType": "PASS",
           "coordinate": "490,240;535,240"
         }
       ]
     },
     {
-      "nodeType": 3,
+      "nodeType": "3",
       "nodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
-      "nodeRatio": 0.000,
-      "coordinate": "560,240",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "560,240",
+      "version": "1",
       "skipList": [
         {
-          "nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
-          "nextNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
           "skipType": "PASS",
           "skipCondition": "le@@leaveDays|2",
+          "skipName": null,
+          "nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
+          "nextNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
           "coordinate": "560,265;560,320;670,320"
         },
         {
-          "nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
-          "nextNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
-          "skipName": "大于两天",
           "skipType": "PASS",
           "skipCondition": "gt@@leaveDays|2",
+          "skipName": "大于两天",
+          "nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
+          "nextNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
           "coordinate": "560,215;560,160;670,160|560,187"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
       "nodeName": "组长",
       "permissionFlag": "3@@4",
-      "nodeRatio": 0.000,
-      "coordinate": "720,320|720,320",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "720,320|720,320",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
           "nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
-          "skipType": "PASS",
           "coordinate": "770,320;860,320;860,280"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
       "nodeName": "总经理",
       "permissionFlag": "role:1",
-      "nodeRatio": 0.000,
-      "coordinate": "860,240|860,240",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "860,240|860,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
           "nextNodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
-          "skipType": "PASS",
           "coordinate": "910,240;980,240"
         }
       ]
     },
     {
-      "nodeType": 2,
+      "nodeType": "2",
       "nodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
       "nodeName": "结束",
-      "nodeRatio": 0.000,
-      "coordinate": "1000,240|1000,240",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
-      "ext": "[]"
+      "formPath": null,
+      "ext": "[]",
+      "coordinate": "1000,240|1000,240",
+      "version": "1",
+      "skipList": []
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
-      "nodeName": "组织机构领导",
+      "nodeName": "部门领导",
       "permissionFlag": "role:1",
-      "nodeRatio": 0.000,
-      "coordinate": "720,160|720,160",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "720,160|720,160",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
           "nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
-          "skipType": "PASS",
+          "nextNodeType": "1",
           "coordinate": "770,160;860,160;860,200"
         }
       ]
     }
-  ]
+  ],
+  "flowCode": "leave2",
+  "flowName": "请假申请-排他网关",
+  "modelValue": "CLASSICS",
+  "category": "103",
+  "version": "1",
+  "formCustom": "N",
+  "formPath": "/workflow/leaveEdit/index",
+  "listenerType": null,
+  "listenerPath": null
 }

+ 110 - 44
SERVER/VberAdminPlusV3/.script/leave/leave3.json

@@ -1,145 +1,211 @@
 {
-  "flowCode": "leave3",
-  "flowName": "请假申请-并行网关",
-  "category": "100",
-  "version": "1",
-  "formCustom": "N",
-  "formPath": "/workflow/leaveEdit/index",
   "nodeList": [
     {
-      "nodeType": 0,
+      "nodeType": "0",
       "nodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
       "nodeName": "开始",
-      "nodeRatio": 0.000,
-      "coordinate": "380,220|380,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "380,220|380,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
           "nextNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
-          "skipType": "PASS",
           "coordinate": "400,220;470,220"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
       "nodeName": "申请人",
-      "nodeRatio": 0.000,
-      "coordinate": "520,220|520,220",
+      "permissionFlag": "",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
+      "coordinate": "520,220|520,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
           "nextNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
-          "skipType": "PASS",
           "coordinate": "570,220;655,220"
         }
       ]
     },
     {
-      "nodeType": 4,
+      "nodeType": "4",
       "nodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
-      "nodeRatio": 0.000,
-      "coordinate": "680,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "680,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
           "nextNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
-          "skipType": "PASS",
           "coordinate": "680,195;680,140;750,140"
         },
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
           "nextNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
-          "skipType": "PASS",
           "coordinate": "680,245;680,300;750,300"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
       "nodeName": "市场部",
       "permissionFlag": "role:1",
-      "nodeRatio": 0.000,
-      "coordinate": "800,140|800,140",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "800,140|800,140",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
           "nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
-          "skipType": "PASS",
           "coordinate": "850,140;920,140;920,195"
         }
       ]
     },
     {
-      "nodeType": 4,
+      "nodeType": "4",
       "nodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
-      "nodeRatio": 0.000,
-      "coordinate": "920,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "920,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
           "nextNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
-          "skipType": "PASS",
           "coordinate": "945,220;975,220;975,220;960,220;960,220;990,220"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
       "nodeName": "CEO",
       "permissionFlag": "1",
-      "nodeRatio": 0.000,
-      "coordinate": "1040,220|1040,220",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "1040,220|1040,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
           "nextNodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
-          "skipType": "PASS",
           "coordinate": "1090,220;1140,220"
         }
       ]
     },
     {
-      "nodeType": 2,
+      "nodeType": "2",
       "nodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
       "nodeName": "结束",
-      "nodeRatio": 0.000,
-      "coordinate": "1160,220|1160,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
-      "ext": "[]"
+      "formPath": null,
+      "ext": "[]",
+      "coordinate": "1160,220|1160,220",
+      "version": "1",
+      "skipList": []
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
       "nodeName": "综合部",
       "permissionFlag": "role:3@@role:4",
-      "nodeRatio": 0.000,
-      "coordinate": "800,300|800,300",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "800,300|800,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
           "nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
-          "skipType": "PASS",
+          "nextNodeType": "4",
           "coordinate": "850,300;920,300;920,245"
         }
       ]
     }
-  ]
+  ],
+  "flowCode": "leave3",
+  "flowName": "请假申请-并行网关",
+  "modelValue": "CLASSICS",
+  "category": "103",
+  "version": "1",
+  "formCustom": "N",
+  "formPath": "/workflow/leaveEdit/index",
+  "listenerType": null,
+  "listenerPath": null
 }

+ 82 - 35
SERVER/VberAdminPlusV3/.script/leave/leave4.json

@@ -1,107 +1,154 @@
 {
-  "flowCode": "leave4",
-  "flowName": "请假申请-会签",
-  "category": "100",
-  "version": "1",
-  "formCustom": "N",
-  "formPath": "/workflow/leaveEdit/index",
   "nodeList": [
     {
-      "nodeType": 0,
+      "nodeType": "0",
       "nodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
       "nodeName": "开始",
-      "nodeRatio": 0.000,
-      "coordinate": "320,240|320,240",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "320,240|320,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
           "nextNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
-          "skipType": "PASS",
           "coordinate": "340,240;410,240"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
       "nodeName": "申请人",
-      "nodeRatio": 0.000,
-      "coordinate": "460,240|460,240",
+      "permissionFlag": "",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
+      "coordinate": "460,240|460,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
           "nextNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
-          "skipType": "PASS",
           "coordinate": "510,240;590,240"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
       "nodeName": "百分之60通过",
       "permissionFlag": "${userList}",
-      "nodeRatio": 60.000,
-      "coordinate": "640,240|640,240",
+      "nodeRatio": "60.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
+      "coordinate": "640,240|640,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
           "nextNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
-          "skipType": "PASS",
           "coordinate": "690,240;770,240"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
       "nodeName": "全部审批通过",
       "permissionFlag": "role:1@@role:3",
-      "nodeRatio": 100.000,
-      "coordinate": "820,240|820,240",
+      "nodeRatio": "100.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
+      "coordinate": "820,240|820,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
           "nextNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
-          "skipType": "PASS",
           "coordinate": "870,240;950,240"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
       "nodeName": "CEO",
       "permissionFlag": "1",
-      "nodeRatio": 0.000,
-      "coordinate": "1000,240|1000,240",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "1000,240|1000,240",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
           "nextNodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
-          "skipType": "PASS",
           "coordinate": "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240"
         }
       ]
     },
     {
-      "nodeType": 2,
+      "nodeType": "2",
       "nodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
       "nodeName": "结束",
-      "nodeRatio": 0.000,
-      "coordinate": "1120,240|1120,240",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
-      "ext": "[]"
+      "formPath": null,
+      "ext": "[]",
+      "coordinate": "1120,240|1120,240",
+      "version": "1",
+      "skipList": []
     }
-  ]
+  ],
+  "flowCode": "leave4",
+  "flowName": "请假申请-会签",
+  "modelValue": "CLASSICS",
+  "category": "103",
+  "version": "1",
+  "formCustom": "N",
+  "formPath": "/workflow/leaveEdit/index",
+  "listenerType": null,
+  "listenerPath": null
 }

+ 110 - 44
SERVER/VberAdminPlusV3/.script/leave/leave5.json

@@ -1,145 +1,211 @@
 {
-  "flowCode": "leave5",
-  "flowName": "请假申请-并行会签网关",
-  "category": "100",
-  "version": "1",
-  "formCustom": "N",
-  "formPath": "/workflow/leaveEdit/index",
   "nodeList": [
     {
-      "nodeType": 0,
+      "nodeType": "0",
       "nodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
       "nodeName": "开始",
-      "nodeRatio": 0.000,
-      "coordinate": "300,220|300,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "300,220|300,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
           "nextNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
-          "skipType": "PASS",
           "coordinate": "320,220;350,220;350,220;340,220;340,220;370,220"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
       "nodeName": "申请人",
-      "nodeRatio": 0.000,
-      "coordinate": "420,220|420,220",
+      "permissionFlag": "",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
+      "coordinate": "420,220|420,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
           "nextNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
-          "skipType": "PASS",
           "coordinate": "470,220;535,220"
         }
       ]
     },
     {
-      "nodeType": 4,
+      "nodeType": "4",
       "nodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
-      "nodeRatio": 0.000,
-      "coordinate": "560,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "560,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
           "nextNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
-          "skipType": "PASS",
           "coordinate": "560,245;560,320;650,320"
         },
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
           "nextNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
-          "skipType": "PASS",
           "coordinate": "560,195;560,120;650,120"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
       "nodeName": "会签",
       "permissionFlag": "role:1@@role:3",
-      "nodeRatio": 100.000,
-      "coordinate": "700,320|700,320",
+      "nodeRatio": "100.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
+      "coordinate": "700,320|700,320",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
           "nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
-          "skipType": "PASS",
           "coordinate": "750,320;860,320;860,245"
         }
       ]
     },
     {
-      "nodeType": 4,
+      "nodeType": "4",
       "nodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
-      "nodeRatio": 0.000,
-      "coordinate": "860,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "860,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
           "nextNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
-          "skipType": "PASS",
           "coordinate": "885,220;950,220"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
       "nodeName": "CEO",
       "permissionFlag": "1",
-      "nodeRatio": 0.000,
-      "coordinate": "1000,220|1000,220",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
+      "coordinate": "1000,220|1000,220",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
           "nextNodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169",
-          "skipType": "PASS",
           "coordinate": "1050,220;1120,220"
         }
       ]
     },
     {
-      "nodeType": 2,
+      "nodeType": "2",
       "nodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169",
       "nodeName": "结束",
-      "nodeRatio": 0.000,
-      "coordinate": "1140,220|1140,220",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
-      "ext": "[]"
+      "formPath": null,
+      "ext": "[]",
+      "coordinate": "1140,220|1140,220",
+      "version": "1",
+      "skipList": []
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
       "nodeName": "百分之60票签",
       "permissionFlag": "${userList}",
-      "nodeRatio": 60.000,
-      "coordinate": "700,120|700,120",
+      "nodeRatio": "60.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
+      "coordinate": "700,120|700,120",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
           "nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
-          "skipType": "PASS",
+          "nextNodeType": "4",
           "coordinate": "750,120;860,120;860,195"
         }
       ]
     }
-  ]
+  ],
+  "flowCode": "leave5",
+  "flowName": "请假申请-并行会签网关",
+  "modelValue": "CLASSICS",
+  "category": "103",
+  "version": "1",
+  "formCustom": "N",
+  "formPath": "/workflow/leaveEdit/index",
+  "listenerType": null,
+  "listenerPath": null
 }

+ 179 - 69
SERVER/VberAdminPlusV3/.script/leave/leave6.json

@@ -1,258 +1,368 @@
 {
-  "flowCode": "leave6",
-  "flowName": "请假申请-排他并行会签",
-  "category": "100",
-  "version": "1",
-  "formCustom": "N",
-  "formPath": "/workflow/leaveEdit/index",
   "nodeList": [
     {
-      "nodeType": 0,
+      "nodeType": "0",
       "nodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054",
       "nodeName": "开始",
-      "nodeRatio": 0.000,
-      "coordinate": "240,300|240,300",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "240,300|240,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054",
           "nextNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
-          "skipType": "PASS",
           "coordinate": "260,300;350,300"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
       "nodeName": "申请人",
-      "nodeRatio": 0.000,
-      "coordinate": "400,300|400,300",
+      "permissionFlag": "",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
-      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "formPath": null,
+      "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
+      "coordinate": "400,300|400,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
           "nextNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
-          "skipType": "PASS",
           "coordinate": "450,300;510,300"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
       "nodeName": "副经理",
       "permissionFlag": "role:1@@role:3@@role:4",
-      "nodeRatio": 0.000,
-      "coordinate": "860,200|860,200",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
+      "formPath": null,
       "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "coordinate": "860,200|860,200",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
           "nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
-          "skipType": "PASS",
           "coordinate": "910,200;1000,200;1000,275"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
       "nodeName": "组长",
       "permissionFlag": "1",
-      "nodeRatio": 0.000,
-      "coordinate": "860,400|860,400",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
+      "formPath": null,
       "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "coordinate": "860,400|860,400",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
           "nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
-          "skipType": "PASS",
           "coordinate": "910,400;1000,400;1000,325"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
       "nodeName": "副组长",
       "permissionFlag": "1",
-      "nodeRatio": 0.000,
-      "coordinate": "560,300|560,300",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
+      "formPath": null,
       "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,transfer,copy,pop\"}]",
+      "coordinate": "560,300|560,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
           "nextNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
-          "skipType": "PASS",
           "coordinate": "610,300;675,300"
         }
       ]
     },
     {
-      "nodeType": 3,
+      "nodeType": "3",
       "nodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
-      "nodeRatio": 0.000,
-      "coordinate": "700,300",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "700,300",
+      "version": "1",
       "skipList": [
         {
-          "nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
-          "nextNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
-          "skipName": "大于两天",
           "skipType": "PASS",
           "skipCondition": "default@@${leaveDays > 2}",
+          "skipName": "大于两天",
+          "nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
+          "nextNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
+          "nextNodeType": "1",
           "coordinate": "700,275;700,200;810,200|700,237"
         },
         {
-          "nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
-          "nextNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
           "skipType": "PASS",
           "skipCondition": "spel@@#{@testLeaveServiceImpl.eval(#leaveDays)}",
+          "skipName": null,
+          "nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
+          "nextNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
+          "nextNodeType": "1",
           "coordinate": "700,325;700,400;810,400"
         }
       ]
     },
     {
-      "nodeType": 3,
+      "nodeType": "3",
       "nodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
-      "nodeRatio": 0.000,
-      "coordinate": "1000,300",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "1000,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
           "nextNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
-          "skipType": "PASS",
           "coordinate": "1025,300;1130,300"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
       "nodeName": "经理会签",
       "permissionFlag": "1@@3",
-      "nodeRatio": 100.000,
-      "coordinate": "1180,300|1180,300",
+      "nodeRatio": "100.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
+      "formPath": null,
       "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,pop,addSign,subSign\"}]",
+      "coordinate": "1180,300|1180,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
           "nextNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
-          "skipType": "PASS",
           "coordinate": "1230,300;1315,300"
         }
       ]
     },
     {
-      "nodeType": 4,
+      "nodeType": "4",
       "nodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
-      "nodeRatio": 0.000,
-      "coordinate": "1340,300",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "1340,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
           "nextNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
-          "skipType": "PASS",
           "coordinate": "1340,325;1340,400;1430,400"
         },
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
           "nextNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
-          "skipType": "PASS",
           "coordinate": "1340,275;1340,200;1430,200"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
       "nodeName": "总经理",
       "permissionFlag": "3@@1",
-      "nodeRatio": 0.000,
-      "coordinate": "1480,200|1480,200",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
+      "formPath": null,
       "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "coordinate": "1480,200|1480,200",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
           "nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
-          "skipType": "PASS",
           "coordinate": "1530,200;1640,200;1640,275"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
       "nodeName": "副总经理",
       "permissionFlag": "1@@3",
-      "nodeRatio": 0.000,
-      "coordinate": "1480,400|1480,400",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
+      "formPath": null,
       "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "coordinate": "1480,400|1480,400",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
           "nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
-          "skipType": "PASS",
           "coordinate": "1530,400;1640,400;1640,325"
         }
       ]
     },
     {
-      "nodeType": 4,
+      "nodeType": "4",
       "nodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
-      "nodeRatio": 0.000,
-      "coordinate": "1640,300",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
+      "formPath": null,
       "ext": "[]",
+      "coordinate": "1640,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
           "nextNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
-          "skipType": "PASS",
           "coordinate": "1665,300;1770,300"
         }
       ]
     },
     {
-      "nodeType": 1,
+      "nodeType": "1",
       "nodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
       "nodeName": "董事",
       "permissionFlag": "1",
-      "nodeRatio": 0.000,
-      "coordinate": "1820,300|1820,300",
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": "",
+      "listenerPath": "",
       "formCustom": "N",
+      "formPath": null,
       "ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
+      "coordinate": "1820,300|1820,300",
+      "version": "1",
       "skipList": [
         {
+          "skipType": "PASS",
+          "skipCondition": null,
+          "skipName": null,
           "nowNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
           "nextNodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
-          "skipType": "PASS",
           "coordinate": "1870,300;1960,300"
         }
       ]
     },
     {
-      "nodeType": 2,
+      "nodeType": "2",
       "nodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
       "nodeName": "结束",
-      "nodeRatio": 0.000,
-      "coordinate": "1980,300|1980,300",
+      "permissionFlag": null,
+      "nodeRatio": "0.000",
+      "anyNodeSkip": null,
+      "listenerType": null,
+      "listenerPath": null,
       "formCustom": "N",
-      "ext": "[]"
+      "formPath": null,
+      "ext": "[]",
+      "coordinate": "1980,300|1980,300",
+      "version": "1",
+      "skipList": []
     }
-  ]
+  ],
+  "flowCode": "leave6",
+  "flowName": "请假申请-排他并行会签",
+  "modelValue": "CLASSICS",
+  "category": "103",
+  "version": "1",
+  "formCustom": "N",
+  "formPath": "/workflow/leaveEdit/index",
+  "listenerType": null,
+  "listenerPath": null
 }

+ 22 - 0
SERVER/VberAdminPlusV3/.script/sql/flow.sql

@@ -162,6 +162,27 @@ VALUES (1, 'spelRuleComponent', 'selectOrgLeaderById', 'initiatorOrgId',
         1, sysdate(), 1, sysdate()),
        (2, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 103, 1, sysdate(), 1, sysdate());
 
+-- ----------------------------
+-- 流程实例业务扩展表
+-- ----------------------------
+
+create table flow_instance_biz_ext (
+   id             bigint                       not null comment '主键id',
+   tenant_id      varchar(20) default '000000' null comment '租户编号',
+   create_dept    bigint                       null comment '创建部门',
+   create_by      bigint                       null comment '创建者',
+   create_time    datetime                     null comment '创建时间',
+   update_by      bigint                       null comment '更新者',
+   update_time    datetime                     null comment '更新时间',
+   business_code  varchar(255)                 null comment '业务编码',
+   business_title varchar(1000)                null comment '业务标题',
+   del_flag       char        default '0'      null comment '删除标志(0代表存在 1代表删除)',
+   instance_id    bigint                       null comment '流程实例Id',
+   business_id    varchar(255)                 null comment '业务Id',
+   PRIMARY KEY (id)
+)  ENGINE = InnoDB COMMENT '流程实例业务扩展表';
+
+
 CREATE TABLE `flow_user`
 (
     `id`           bigint  NOT NULL AUTO_INCREMENT COMMENT '主键id',
@@ -228,6 +249,7 @@ create table test_leave
 (
     id          bigint(20)   not null AUTO_INCREMENT comment 'id',
     tenant_id   varchar(20) default '000000' comment '租户编号',
+    apply_code  varchar(50)  not null comment '申请编号',
     leave_type  varchar(255) not null comment '请假类型',
     start_date  datetime     not null comment '开始时间',
     end_date    datetime     not null comment '结束时间',

+ 4 - 8
SERVER/VberAdminPlusV3/vber-admin/src/main/resources/application.yml

@@ -275,14 +275,10 @@ warm-flow:
   enabled: ${vb.workflowEnabled:true}
   # 是否开启设计器ui
   ui: true
+  # 是否显示流程图顶部文字
+  top-text-show: true
+  # 是否渲染节点悬浮提示,默认true
+  node-tooltip: true
   # 默认Authorization,如果有多个token,用逗号分隔
   token-name: ${sa-token.token-name},clientid
-  # 流程状态对应的三元色
-  chart-status-color:
-    ## 未办理
-    - 62,62,62
-    ## 待办理
-    - 255,205,23
-    ## 已办理
-    - 157,255,0
 

+ 6 - 0
SERVER/VberAdminPlusV3/vber-common/vber-common-core/src/main/java/com/vber/common/core/domain/dto/CompleteTaskDTO.java

@@ -17,6 +17,7 @@ import java.util.Objects;
 @Data
 public class CompleteTaskDTO implements Serializable {
 
+
     @Serial
     private static final long serialVersionUID = 1L;
 
@@ -50,6 +51,11 @@ public class CompleteTaskDTO implements Serializable {
      */
     private String notice;
 
+    /**
+     * 办理人(可不填 用于覆盖当前节点办理人)
+     */
+    private String handler;
+
     /**
      * 流程变量
      */

+ 44 - 0
SERVER/VberAdminPlusV3/vber-common/vber-common-core/src/main/java/com/vber/common/core/domain/dto/FlowInstanceBizExtDTO.java

@@ -0,0 +1,44 @@
+package com.vber.common.core.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 流程实例业务扩展对象
+ *
+ * @author Iwb
+ */
+@Data
+public class FlowInstanceBizExtDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 流程实例ID
+     */
+    private Long instanceId;
+
+    /**
+     * 业务ID
+     */
+    private String businessId;
+
+    /**
+     * 业务编码
+     */
+    private String businessCode;
+
+    /**
+     * 业务标题
+     */
+    private String businessTitle;
+
+}

+ 19 - 0
SERVER/VberAdminPlusV3/vber-common/vber-common-core/src/main/java/com/vber/common/core/domain/dto/StartProcessDTO.java

@@ -1,6 +1,7 @@
 package com.vber.common.core.domain.dto;
 
 
+import cn.hutool.core.util.ObjectUtil;
 import lombok.Data;
 
 import java.io.Serial;
@@ -20,6 +21,7 @@ public class StartProcessDTO implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
 
+
     /**
      * 业务唯一值id
      */
@@ -30,11 +32,21 @@ public class StartProcessDTO implements Serializable {
      */
     private String flowCode;
 
+    /**
+     * 办理人(可不填 用于覆盖当前节点办理人)
+     */
+    private String handler;
+
     /**
      * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
      */
     private Map<String, Object> variables;
 
+    /**
+     * 流程业务扩展信息
+     */
+    private FlowInstanceBizExtDTO bizExt;
+
     public Map<String, Object> getVariables() {
         if (variables == null) {
             return new HashMap<>(16);
@@ -42,4 +54,11 @@ public class StartProcessDTO implements Serializable {
         variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
         return variables;
     }
+
+    public FlowInstanceBizExtDTO getBizExt() {
+        if (ObjectUtil.isNull(bizExt)) {
+            bizExt = new FlowInstanceBizExtDTO();
+        }
+        return bizExt;
+    }
 }

+ 6 - 3
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/common/constant/FlowConstant.java

@@ -18,11 +18,10 @@ public interface FlowConstant {
      */
     String BUSINESS_ID = "businessId";
 
-
     /**
-     * 组织机构id
+     * 部门id
      */
-    String INITIATOR_ORG_ID = "initiatorOrgId";
+    String INITIATOR_ORG_ID = "initiatorDeptId";
 
     /**
      * 委托
@@ -89,4 +88,8 @@ public interface FlowConstant {
      */
     String AUTO_PASS = "autoPass";
 
+    /**
+     * 业务编码
+     */
+    String BUSINESS_CODE = "businessCode";
 }

+ 20 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/common/enums/CopySettingEnum.java

@@ -0,0 +1,20 @@
+package com.vber.workflow.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 抄送设置枚举
+ *
+ * @author Iwb
+ */
+@Getter
+@AllArgsConstructor
+public enum CopySettingEnum implements NodeExtEnum {
+    ;
+    private final String label;
+    private final String value;
+    private final boolean selected;
+
+}
+

+ 20 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/common/enums/VariablesEnum.java

@@ -0,0 +1,20 @@
+package com.vber.workflow.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 变量枚举
+ *
+ * @author Iwb
+ */
+@Getter
+@AllArgsConstructor
+public enum VariablesEnum implements NodeExtEnum {
+    ;
+    private final String label;
+    private final String value;
+    private final boolean selected;
+
+}
+

+ 58 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/FlowInstanceBizExt.java

@@ -0,0 +1,58 @@
+package com.vber.workflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.vber.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 流程实例业务扩展对象 flow_instance_biz_ext
+ *
+ * @author Iwb
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("flow_instance_biz_ext")
+public class FlowInstanceBizExt extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 流程实例ID
+     */
+    private Long instanceId;
+
+    /**
+     * 业务ID
+     */
+    private String businessId;
+
+    /**
+     * 业务编码
+     */
+    private String businessCode;
+
+    /**
+     * 业务标题
+     */
+    private String businessTitle;
+
+    /**
+     * 删除标志(0代表存在 1代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+
+}

+ 5 - 1
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/TestLeave.java

@@ -22,13 +22,17 @@ public class TestLeave extends BaseEntity {
 
     @Serial
     private static final long serialVersionUID = 1L;
-
     /**
      * 主键
      */
     @TableId(value = "id")
     private Long id;
 
+    /**
+     * 申请编号
+     */
+    private String applyCode;
+
     /**
      * 请假类型
      */

+ 5 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/CompleteTaskBo.java

@@ -53,6 +53,11 @@ public class CompleteTaskBo implements Serializable {
      */
     private String notice;
 
+    /**
+     * 办理人(可不填 用于覆盖当前节点办理人)
+     */
+    private String handler;
+
     /**
      * 流程变量
      */

+ 0 - 1
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/FlowSpelBo.java

@@ -13,7 +13,6 @@ import lombok.EqualsAndHashCode;
  * 流程spel达式定义业务对象 flow_spel
  *
  * @author Iwb
- * @date 2025-07-04
  */
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 19 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/StartProcessBo.java

@@ -1,7 +1,9 @@
 package com.vber.workflow.domain.bo;
 
 
+import cn.hutool.core.util.ObjectUtil;
 import com.vber.common.core.validate.AddGroup;
+import com.vber.workflow.domain.FlowInstanceBizExt;
 import jakarta.validation.constraints.NotBlank;
 import lombok.Data;
 
@@ -34,11 +36,21 @@ public class StartProcessBo implements Serializable {
     @NotBlank(message = "流程定义编码不能为空", groups = {AddGroup.class})
     private String flowCode;
 
+    /**
+     * 办理人(可不填 用于覆盖当前节点办理人)
+     */
+    private String handler;
+
     /**
      * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
      */
     private Map<String, Object> variables;
 
+    /**
+     * 流程业务扩展信息
+     */
+    private FlowInstanceBizExt bizExt;
+
     public Map<String, Object> getVariables() {
         if (variables == null) {
             return new HashMap<>(16);
@@ -46,4 +58,11 @@ public class StartProcessBo implements Serializable {
         variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
         return variables;
     }
+
+    public FlowInstanceBizExt getBizExt() {
+        if (ObjectUtil.isNull(bizExt)) {
+            bizExt = new FlowInstanceBizExt();
+        }
+        return bizExt;
+    }
 }

+ 5 - 1
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/bo/TestLeaveBo.java

@@ -18,7 +18,6 @@ import java.util.Date;
  * 请假业务对象 test_leave
  *
  * @author Iwb
- * @date 2023-07-21
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -36,6 +35,11 @@ public class TestLeaveBo extends BaseEntity {
      */
     private String flowCode;
 
+    /**
+     * 申请编号
+     */
+    private String applyCode;
+
     /**
      * 请假类型
      */

+ 1 - 1
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowCategoryVo.java

@@ -27,6 +27,7 @@ public class FlowCategoryVo implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
 
+
     /**
      * 流程分类ID
      */
@@ -67,5 +68,4 @@ public class FlowCategoryVo implements Serializable {
     @ExcelProperty(value = "创建时间")
     private Date createTime;
 
-
 }

+ 36 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowCopyVo.java

@@ -0,0 +1,36 @@
+package com.vber.workflow.domain.vo;
+
+import com.vber.common.translation.annotation.Translation;
+import com.vber.common.translation.constant.TransConstant;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 抄送对象
+ *
+ * @author Iwb
+ */
+@Data
+public class FlowCopyVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户id
+     */
+    private Long userId;
+
+    /**
+     * 用户名称
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "userId")
+    private String userName;
+
+    public FlowCopyVo(Long userId) {
+        this.userId = userId;
+    }
+
+}

+ 12 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowHisTaskVo.java

@@ -203,6 +203,18 @@ public class FlowHisTaskVo implements Serializable {
      */
     private String runDuration;
 
+    //业务扩展信息开始
+    /**
+     * 业务编码
+     */
+    private String businessCode;
+
+    /**
+     * 业务标题
+     */
+    private String businessTitle;
+    //业务扩展信息结束
+
     /**
      * 设置创建时间并计算任务运行时长
      *

+ 13 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowInstanceVo.java

@@ -17,6 +17,7 @@ public class FlowInstanceVo {
 
     private Long id;
 
+
     /**
      * 创建时间
      */
@@ -134,4 +135,16 @@ public class FlowInstanceVo {
     @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
     private String categoryName;
 
+    //业务扩展信息开始
+    /**
+     * 业务编码
+     */
+    private String businessCode;
+
+    /**
+     * 业务标题
+     */
+    private String businessTitle;
+    //业务扩展信息结束
+
 }

+ 1 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowSpelVo.java

@@ -27,6 +27,7 @@ public class FlowSpelVo implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
 
+
     /**
      * 主键id
      */

+ 27 - 1
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/FlowTaskVo.java

@@ -11,6 +11,7 @@ import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 任务视图
@@ -22,7 +23,6 @@ public class FlowTaskVo implements Serializable {
 
     @Serial
     private static final long serialVersionUID = 1L;
-
     private Long id;
 
     /**
@@ -185,4 +185,30 @@ public class FlowTaskVo implements Serializable {
      */
     private List<ButtonPermissionVo> buttonList;
 
+    /**
+     * 抄送对象 ID 集合
+     * <p>
+     * 根据扩展属性中 CopySettingEnum 类型的数据生成,存储需要抄送的对象 ID
+     */
+    private List<FlowCopyVo> copyList;
+
+    /**
+     * 自定义参数 Map
+     * <p>
+     * 根据扩展属性中 VariablesEnum 类型的数据生成,存储 key=value 格式的自定义参数
+     */
+    private Map<String, String> varList;
+
+    //业务扩展信息开始
+    /**
+     * 业务编码
+     */
+    private String businessCode;
+
+    /**
+     * 业务标题
+     */
+    private String businessTitle;
+    //业务扩展信息结束
+
 }

+ 45 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/NodeExtVo.java

@@ -0,0 +1,45 @@
+package com.vber.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Node 扩展属性解析结果 VO
+ * <p>
+ * 用于封装从扩展属性 JSON 中解析出的各类信息,包括按钮权限、抄送对象和自定义参数。
+ *
+ * @author Iwb
+ */
+@Data
+public class NodeExtVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 按钮权限列表
+     * <p>
+     * 根据扩展属性中 ButtonPermissionEnum 类型的数据生成,每个元素表示一个按钮及其是否勾选。
+     */
+    private List<ButtonPermissionVo> buttonPermissions;
+
+    /**
+     * 抄送对象 ID 集合
+     * <p>
+     * 根据扩展属性中 CopySettingEnum 类型的数据生成,存储需要抄送的对象 ID
+     */
+    private Set<String> copySettings;
+
+    /**
+     * 自定义参数 Map
+     * <p>
+     * 根据扩展属性中 VariablesEnum 类型的数据生成,存储 key=value 格式的自定义参数
+     */
+    private Map<String, String> variables;
+
+}

+ 7 - 3
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/domain/vo/TestLeaveVo.java

@@ -2,7 +2,6 @@ package com.vber.workflow.domain.vo;
 
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
-import com.fasterxml.jackson.annotation.JsonFormat;
 import com.vber.workflow.domain.TestLeave;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
@@ -26,12 +25,19 @@ public class TestLeaveVo implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
 
+
     /**
      * 主键
      */
     @ExcelProperty(value = "主键")
     private Long id;
 
+    /**
+     * 申请编号
+     */
+    @ExcelProperty(value = "申请编号")
+    private String applyCode;
+
     /**
      * 请假类型
      */
@@ -42,14 +48,12 @@ public class TestLeaveVo implements Serializable {
      * 开始时间
      */
     @ExcelProperty(value = "开始时间")
-    @JsonFormat(pattern = "yyyy-MM-dd")
     private Date startDate;
 
     /**
      * 结束时间
      */
     @ExcelProperty(value = "结束时间")
-    @JsonFormat(pattern = "yyyy-MM-dd")
     private Date endDate;
 
     /**

+ 33 - 10
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/listener/WorkflowGlobalListener.java

@@ -1,33 +1,39 @@
 package com.vber.workflow.listener;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.lang.TypeReference;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.vber.common.core.enums.BusinessStatusEnum;
+import com.vber.common.core.service.UserService;
+import com.vber.common.core.utils.StreamUtils;
 import com.vber.common.core.utils.StringUtils;
 import com.vber.workflow.common.ConditionalOnEnable;
 import com.vber.workflow.common.constant.FlowConstant;
 import com.vber.workflow.common.enums.TaskStatusEnum;
 import com.vber.workflow.domain.bo.FlowCopyBo;
+import com.vber.workflow.domain.vo.NodeExtVo;
 import com.vber.workflow.handler.FlowProcessEventHandler;
 import com.vber.workflow.service.IFlwCommonService;
 import com.vber.workflow.service.IFlwInstanceService;
+import com.vber.workflow.service.IFlwNodeExtService;
 import com.vber.workflow.service.IFlwTaskService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.warm.flow.core.FlowEngine;
 import org.dromara.warm.flow.core.dto.FlowParams;
 import org.dromara.warm.flow.core.entity.Definition;
 import org.dromara.warm.flow.core.entity.Instance;
 import org.dromara.warm.flow.core.entity.Task;
 import org.dromara.warm.flow.core.listener.GlobalListener;
 import org.dromara.warm.flow.core.listener.ListenerVariable;
-import org.dromara.warm.flow.core.service.InsService;
 import org.springframework.stereotype.Component;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * 全局任务办理监听
@@ -41,10 +47,11 @@ import java.util.Map;
 public class WorkflowGlobalListener implements GlobalListener {
 
     private final IFlwTaskService flwTaskService;
-    private final IFlwInstanceService instanceService;
+    private final IFlwInstanceService flwInstanceService;
     private final FlowProcessEventHandler flowProcessEventHandler;
     private final IFlwCommonService flwCommonService;
-    private final InsService insService;
+    private final IFlwNodeExtService nodeExtService;
+    private final UserService userService;
 
     /**
      * 创建监听器,任务创建时执行
@@ -63,6 +70,25 @@ public class WorkflowGlobalListener implements GlobalListener {
      */
     @Override
     public void start(ListenerVariable listenerVariable) {
+        String ext = listenerVariable.getNode().getExt();
+        if (StringUtils.isNotBlank(ext)) {
+            NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext);
+            Map<String, Object> variable = listenerVariable.getVariable();
+            Set<String> copyList = nodeExt.getCopySettings();
+            if (CollUtil.isNotEmpty(copyList)) {
+                List<FlowCopyBo> list = StreamUtils.toList(copyList, x -> {
+                    FlowCopyBo bo = new FlowCopyBo();
+                    Long id = Convert.toLong(x);
+                    bo.setUserId(id);
+                    bo.setUserName(userService.selectUserNameById(id));
+                    return bo;
+                });
+                variable.put(FlowConstant.FLOW_COPY_LIST, list);
+            }
+            if (CollUtil.isNotEmpty(nodeExt.getVariables())) {
+                variable.putAll(nodeExt.getVariables());
+            }
+        }
     }
 
     /**
@@ -132,7 +158,7 @@ public class WorkflowGlobalListener implements GlobalListener {
                     flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, BusinessStatusEnum.BACK.getStatus(), params, false);
                     // 修改流程实例状态
                     instance.setFlowStatus(BusinessStatusEnum.BACK.getStatus());
-                    insService.updateById(instance);
+                    FlowEngine.insService().updateById(instance);
                 }
             }
         }
@@ -163,12 +189,9 @@ public class WorkflowGlobalListener implements GlobalListener {
             List<String> messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() {
             });
             String notice = MapUtil.getStr(variable, FlowConstant.MESSAGE_NOTICE);
-            // 消息通知
-            if (CollUtil.isNotEmpty(messageType)) {
-                flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
-            }
+            flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
         }
-        insService.removeVariables(instance.getId(),
+        FlowEngine.insService().removeVariables(instance.getId(),
                 FlowConstant.FLOW_COPY_LIST,
                 FlowConstant.MESSAGE_TYPE,
                 FlowConstant.MESSAGE_NOTICE,
@@ -192,7 +215,7 @@ public class WorkflowGlobalListener implements GlobalListener {
             if (flwTaskService.isTaskEnd(instanceId)) {
                 String status = BusinessStatusEnum.FINISH.getStatus();
                 // 更新流程状态为已完成
-                instanceService.updateStatus(instanceId, status);
+                flwInstanceService.updateStatus(instanceId, status);
                 log.info("流程已结束,状态更新为: {}", status);
                 return status;
             }

+ 60 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/mapper/FlwInstanceBizExtMapper.java

@@ -0,0 +1,60 @@
+package com.vber.workflow.mapper;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.vber.common.mybatis.core.mapper.BaseMapperPlus;
+import com.vber.workflow.domain.FlowInstanceBizExt;
+
+import java.util.List;
+
+/**
+ * 流程实例业务扩展Mapper接口
+ *
+ * @author Iwb
+ */
+public interface FlwInstanceBizExtMapper extends BaseMapperPlus<FlowInstanceBizExt, FlowInstanceBizExt> {
+
+    /**
+     * 根据 instanceId 保存或更新流程实例业务扩展
+     *
+     * @param entity 流程实例业务扩展实体
+     * @return 操作是否成功
+     */
+    default int saveOrUpdateByInstanceId(FlowInstanceBizExt entity) {
+        // 查询是否存在
+        FlowInstanceBizExt exist = this.selectOne(new LambdaQueryWrapper<FlowInstanceBizExt>()
+                .eq(FlowInstanceBizExt::getInstanceId, entity.getInstanceId()));
+
+        if (ObjectUtil.isNotNull(exist)) {
+            // 存在就带上主键更新
+            entity.setId(exist.getId());
+            return updateById(entity);
+        } else {
+            // 不存在就插入
+            return insert(entity);
+        }
+    }
+
+    /**
+     * 按照流程实例ID删除单个流程实例业务扩展
+     *
+     * @param instanceId 流程实例ID
+     * @return 删除的行数
+     */
+    default int deleteByInstId(Long instanceId) {
+        return this.delete(new LambdaQueryWrapper<FlowInstanceBizExt>()
+                .eq(FlowInstanceBizExt::getInstanceId, instanceId));
+    }
+
+    /**
+     * 按照流程实例ID批量删除流程实例业务扩展
+     *
+     * @param instanceIds 流程实例ID列表
+     * @return 删除的行数
+     */
+    default int deleteByInstIds(List<Long> instanceIds) {
+        return this.delete(new LambdaQueryWrapper<FlowInstanceBizExt>()
+                .in(FlowInstanceBizExt::getInstanceId, instanceIds));
+    }
+
+}

+ 16 - 6
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/IFlwNodeExtService.java

@@ -1,8 +1,6 @@
 package com.vber.workflow.service;
 
-import com.vber.workflow.domain.vo.ButtonPermissionVo;
-
-import java.util.List;
+import com.vber.workflow.domain.vo.NodeExtVo;
 
 /**
  * 流程节点扩展属性 服务层
@@ -12,11 +10,23 @@ import java.util.List;
 public interface IFlwNodeExtService {
 
     /**
-     * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
+     * 解析扩展属性 JSON 并构建 Node 扩展属性对象
+     * <p>
+     * 根据传入的 JSON 字符串,将扩展属性分为三类:
+     * 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选
+     * 2. CopySettingEnum:解析为抄送对象 ID 集合
+     * 3. VariablesEnum:解析为自定义参数 Map
+     *
+     * <p>示例 JSON:
+     * [
+     * {"code": "ButtonPermissionEnum", "value": "back,termination"},
+     * {"code": "CopySettingEnum", "value": "1"},
+     * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
+     * ]
      *
      * @param ext 扩展属性 JSON 字符串
-     * @return 按钮权限 VO 列表
+     * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
      */
-    List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext);
+    NodeExtVo parseNodeExt(String ext);
 
 }

+ 26 - 19
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwCategoryServiceImpl.java

@@ -1,16 +1,14 @@
 package com.vber.workflow.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.lang.tree.Tree;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.vber.common.core.constant.SystemConstants;
 import com.vber.common.core.exception.ServiceException;
-import com.vber.common.core.utils.MapstructUtils;
-import com.vber.common.core.utils.ObjectUtils;
-import com.vber.common.core.utils.StringUtils;
-import com.vber.common.core.utils.TreeBuildUtils;
+import com.vber.common.core.utils.*;
 import com.vber.common.mybatis.helper.DataBaseHelper;
 import com.vber.workflow.common.ConditionalOnEnable;
 import com.vber.workflow.common.constant.FlowConstant;
@@ -22,9 +20,11 @@ import com.vber.workflow.service.IFlwCategoryService;
 import lombok.RequiredArgsConstructor;
 import org.dromara.warm.flow.core.service.DefService;
 import org.dromara.warm.flow.orm.entity.FlowDefinition;
+import org.dromara.warm.flow.ui.service.CategoryService;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -37,7 +37,7 @@ import java.util.List;
 @ConditionalOnEnable
 @RequiredArgsConstructor
 @Service
-public class FlwCategoryServiceImpl implements IFlwCategoryService {
+public class FlwCategoryServiceImpl implements IFlwCategoryService, CategoryService {
 
     private final DefService defService;
     private final FlwCategoryMapper baseMapper;
@@ -90,24 +90,36 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
      */
     @Override
     public List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category) {
-        LambdaQueryWrapper<FlowCategory> lqw = buildQueryWrapper(category);
-        List<FlowCategoryVo> categorys = baseMapper.selectVoList(lqw);
         List<FlowCategoryVo> categoryList = this.queryList(category);
         if (CollUtil.isEmpty(categoryList)) {
             return CollUtil.newArrayList();
         }
         return TreeBuildUtils.buildMultiRoot(
                 categoryList,
-                node -> String.valueOf(node.getCategoryId()),
-                node -> String.valueOf(node.getParentId()),
+                node -> Convert.toStr(node.getCategoryId()),
+                node -> Convert.toStr(node.getParentId()),
                 (node, treeNode) -> treeNode
-                        .setId(String.valueOf(node.getCategoryId()))
-                        .setParentId(String.valueOf(node.getParentId()))
+                        .setId(Convert.toStr(node.getCategoryId()))
+                        .setParentId(Convert.toStr(node.getParentId()))
                         .setName(node.getCategoryName())
                         .setWeight(node.getOrderNum())
         );
     }
 
+    /**
+     * 工作流查询分类
+     *
+     * @return 分类树结构列表
+     */
+    @Override
+    public List<org.dromara.warm.flow.core.dto.Tree> queryCategory() {
+        List<FlowCategoryVo> list = this.queryList(new FlowCategoryBo());
+        return StreamUtils.toList(list, category -> new org.dromara.warm.flow.core.dto.Tree()
+                .setId(Convert.toStr(category.getCategoryId()))
+                .setName(category.getCategoryName())
+                .setParentId(Convert.toStr(category.getParentId()))
+        );
+    }
 
     /**
      * 校验流程分类名称是否唯一
@@ -175,14 +187,8 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
             throw new ServiceException("父级流程分类不存在!");
         }
         FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
-        if (ObjectUtil.isNull(info) && baseMapper.insert(category) > 0) {
-            category.setAncestors(category.getParentId() + StringUtils.SEPARATOR + category.getCategoryId().toString());
-            return baseMapper.updateById(category);
-        } else {
-            category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId());
-            return baseMapper.insert(category);
-
-        }
+        category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId());
+        return baseMapper.insert(category);
     }
 
     /**
@@ -193,6 +199,7 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
      */
     @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId")
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int updateByBo(FlowCategoryBo bo) {
         FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
         FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId());

+ 20 - 9
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwChartExtServiceImpl.java

@@ -10,7 +10,6 @@ import com.vber.common.core.service.DictService;
 import com.vber.common.core.service.OrgService;
 import com.vber.common.core.service.UserService;
 import com.vber.common.core.utils.DateUtils;
-import com.vber.common.core.utils.ServletUtils;
 import com.vber.common.core.utils.StreamUtils;
 import com.vber.common.core.utils.StringUtils;
 import com.vber.workflow.common.ConditionalOnEnable;
@@ -25,6 +24,7 @@ import org.dromara.warm.flow.core.utils.MapUtil;
 import org.dromara.warm.flow.orm.entity.FlowHisTask;
 import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
 import org.dromara.warm.flow.ui.service.ChartExtService;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
@@ -49,6 +49,8 @@ public class FlwChartExtServiceImpl implements ChartExtService {
     private final OrgService orgService;
     private final FlowHisTaskMapper flowHisTaskMapper;
     private final DictService dictService;
+    @Value("${warm-flow.node-tooltip:true}")
+    private boolean nodeTooltip;
 
     /**
      * 设置流程图提示信息
@@ -57,12 +59,13 @@ public class FlwChartExtServiceImpl implements ChartExtService {
      */
     @Override
     public void execute(DefJson defJson) {
-        // 临时修复 后续版本将通过defjson获取流程实例ID
-        String[] parts = ServletUtils.getRequest().getRequestURI().split("/");
-        Long instanceId = Convert.toLong(parts[parts.length - 1]);
+        // 配置关闭,直接返回,不渲染悬浮窗
+        if (!nodeTooltip) {
+            return;
+        }
 
         // 根据流程实例ID查询所有相关的历史任务列表
-        List<FlowHisTask> flowHisTasks = this.getHisTaskGroupedByNode(instanceId);
+        List<FlowHisTask> flowHisTasks = this.getHisTaskGroupedByNode(defJson.getInstance().getId());
         if (CollUtil.isEmpty(flowHisTasks)) {
             return;
         }
@@ -108,6 +111,11 @@ public class FlwChartExtServiceImpl implements ChartExtService {
      */
     @Override
     public void initPromptContent(DefJson defJson) {
+        // 配置关闭,直接返回,不渲染悬浮窗
+        if (!nodeTooltip) {
+            return;
+        }
+
         defJson.setTopText("流程名称: " + defJson.getFlowName());
         defJson.getNodeList().forEach(nodeJson -> {
             nodeJson.setPromptContent(
@@ -143,7 +151,8 @@ public class FlwChartExtServiceImpl implements ChartExtService {
                                     "fontSize", "14px",
                                     "zIndex", "1000",
                                     "maxWidth", "500px",
-                                    "overflowY", "visible",
+                                    "maxHeight", "300px",
+                                    "overflowY", "auto",
                                     "overflowX", "hidden",
                                     "color", "#333",
                                     "pointerEvents", "auto",
@@ -156,8 +165,10 @@ public class FlwChartExtServiceImpl implements ChartExtService {
     /**
      * 处理节点的扩展信息,构建用于流程图悬浮提示的内容
      *
-     * @param nodeJson 当前节点对象
-     * @param taskList 当前节点对应的历史审批任务列表
+     * @param nodeJson 当前流程节点对象,包含节点基础信息和提示内容容器
+     * @param taskList 当前节点关联的历史审批任务列表,用于生成提示信息
+     * @param userMap  用户信息映射表,key 为用户ID,value 为用户DTO对象,用于获取审批人信息
+     * @param dictType 数据字典映射表,key 为字典项编码,value 为对应显示值,用于翻译审批状态等
      */
     private void processNodeExtInfo(NodeJson nodeJson, List<FlowHisTask> taskList, Map<Long, UserDTO> userMap, Map<String, String> dictType) {
 
@@ -171,7 +182,7 @@ public class FlwChartExtServiceImpl implements ChartExtService {
                 continue;
             }
 
-            // 查询用户所属组织机构名称
+            // 查询用户所属部门名称
             String orgName = orgService.selectOrgNameByIds(Convert.toStr(userDTO.getOrgId()));
 
             // 添加标题项,如:👤 张三(市场部)

+ 30 - 18
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwCommonServiceImpl.java

@@ -15,14 +15,15 @@ import com.vber.workflow.service.IFlwCommonService;
 import com.vber.workflow.service.IFlwTaskService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.warm.flow.core.FlowEngine;
 import org.dromara.warm.flow.core.entity.Node;
-import org.dromara.warm.flow.core.enums.SkipType;
-import org.dromara.warm.flow.core.service.NodeService;
 import org.dromara.warm.flow.orm.entity.FlowTask;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
-import java.util.stream.Collectors;
+import java.util.Set;
 
 
 /**
@@ -35,19 +36,27 @@ import java.util.stream.Collectors;
 @RequiredArgsConstructor
 @Service
 public class FlwCommonServiceImpl implements IFlwCommonService {
-    private final NodeService nodeService;
+
+    private static final String DEFAULT_SUBJECT = "单据审批提醒";
 
     /**
-     * 发送消息
+     * 根据流程实例发送消息给当前处理人
      *
      * @param flowName    流程定义名称
-     * @param messageType 消息类型
-     * @param message     消息内容,为空则发送默认配置的消息内容
+     * @param instId      流程实例ID
+     * @param messageType 消息类型列表
+     * @param message     消息内容,为空则使用默认消息
      */
     @Override
     public void sendMessage(String flowName, Long instId, List<String> messageType, String message) {
+        if (CollUtil.isEmpty(messageType)) {
+            return;
+        }
         IFlwTaskService flwTaskService = SpringUtils.getBean(IFlwTaskService.class);
         List<FlowTask> list = flwTaskService.selectByInstId(instId);
+        if (CollUtil.isEmpty(list)) {
+            return;
+        }
         if (StringUtils.isBlank(message)) {
             message = "有新的【" + flowName + "】单据已经提交至您,请您及时处理。";
         }
@@ -55,19 +64,25 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
         if (CollUtil.isEmpty(userList)) {
             return;
         }
-        sendMessage(messageType, message, "单据审批提醒", userList);
+        sendMessage(messageType, message, DEFAULT_SUBJECT, userList);
     }
 
     /**
-     * 发送消息
+     * 发送消息给指定用户列表
      *
-     * @param messageType 消息类型
+     * @param messageType 消息类型列表
      * @param message     消息内容
      * @param subject     邮件标题
-     * @param userList    接收用户
+     * @param userList    接收用户列表
      */
     @Override
     public void sendMessage(List<String> messageType, String message, String subject, List<UserDTO> userList) {
+        if (CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) {
+            return;
+        }
+        List<Long> userIds = new ArrayList<>(StreamUtils.toSet(userList, UserDTO::getUserId));
+        Set<String> emails = StreamUtils.toSet(userList, UserDTO::getEmail);
+
         for (String code : messageType) {
             MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
             if (ObjectUtil.isEmpty(messageTypeEnum)) {
@@ -76,13 +91,11 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
             switch (messageTypeEnum) {
                 case SYSTEM_MESSAGE -> {
                     SseMessageDto dto = new SseMessageDto();
-                    dto.setUserIds(StreamUtils.toList(userList, UserDTO::getUserId).stream().distinct().collect(Collectors.toList()));
+                    dto.setUserIds(userIds);
                     dto.setMessage(message);
                     SseMessageUtils.publishMessage(dto);
                 }
-                case EMAIL_MESSAGE -> {
-                    MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), subject, message);
-                }
+                case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message);
                 case SMS_MESSAGE -> {
                     //todo 短信发送
                 }
@@ -100,8 +113,7 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
      */
     @Override
     public String applyNodeCode(Long definitionId) {
-        Node startNode = nodeService.getStartNode(definitionId);
-        Node nextNode = nodeService.getNextNode(definitionId, startNode.getNodeCode(), null, SkipType.PASS.getKey());
-        return nextNode.getNodeCode();
+        List<Node> firstBetweenNode = FlowEngine.nodeService().getFirstBetweenNode(definitionId, new HashMap<>());
+        return firstBetweenNode.get(0).getNodeCode();
     }
 }

+ 2 - 1
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwDefinitionServiceImpl.java

@@ -57,6 +57,7 @@ import static com.vber.common.core.constant.TenantConstants.DEFAULT_TENANT_ID;
 @RequiredArgsConstructor
 @Service
 public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
+
     private final DefService defService;
     private final FlowDefinitionMapper flowDefinitionMapper;
     private final FlowHisTaskMapper flowHisTaskMapper;
@@ -127,7 +128,7 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
                 }
             }
             if (CollUtil.isNotEmpty(errorMsg)) {
-                throw new ServiceException("节点【{}】未配置办理人!", String.join(",", errorMsg));
+                throw new ServiceException("节点【{}】未配置办理人!", StringUtils.joinComma(errorMsg));
             }
         }
         return defService.publish(id);

+ 112 - 97
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwNodeExtServiceImpl.java

@@ -1,16 +1,19 @@
 package com.vber.workflow.service.impl;
 
 import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Dict;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
 import com.vber.common.core.domain.dto.DictTypeDTO;
 import com.vber.common.core.service.DictService;
 import com.vber.common.core.utils.StringUtils;
 import com.vber.common.json.utils.JsonUtils;
 import com.vber.workflow.common.ConditionalOnEnable;
 import com.vber.workflow.common.enums.ButtonPermissionEnum;
+import com.vber.workflow.common.enums.CopySettingEnum;
 import com.vber.workflow.common.enums.NodeExtEnum;
+import com.vber.workflow.common.enums.VariablesEnum;
 import com.vber.workflow.domain.vo.ButtonPermissionVo;
+import com.vber.workflow.domain.vo.NodeExtVo;
 import com.vber.workflow.service.IFlwNodeExtService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -20,7 +23,6 @@ import org.springframework.stereotype.Service;
 
 import java.util.*;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * 流程设计器-节点扩展属性
@@ -33,14 +35,39 @@ import java.util.stream.Stream;
 @Service
 public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService {
 
+
     /**
      * 存储不同 dictType 对应的配置信息
      */
-    private static final Map<String, ButtonPermission> CHILD_NODE_MAP = new HashMap<>();
+    private static final Map<String, Map<String, Object>> CHILD_NODE_MAP;
 
     static {
-        CHILD_NODE_MAP.put(ButtonPermissionEnum.class.getSimpleName(),
-                new ButtonPermission("权限按钮", 4, false, true));
+        CHILD_NODE_MAP = Map.of(
+                CopySettingEnum.class.getSimpleName(),
+                Map.of(
+                        "label", "抄送对象",
+                        "type", 2,
+                        "must", false,
+                        "multiple", false,
+                        "desc", "设置该节点的抄送办理人"
+                ),
+                VariablesEnum.class.getSimpleName(),
+                Map.of(
+                        "label", "自定义参数",
+                        "type", 2,
+                        "must", false,
+                        "multiple", false,
+                        "desc", "节点执行时可以使用的自定义参数"
+                ),
+                ButtonPermissionEnum.class.getSimpleName(),
+                Map.of(
+                        "label", "权限按钮",
+                        "type", 4,
+                        "must", false,
+                        "multiple", true,
+                        "desc", "控制该节点的按钮权限"
+                )
+        );
     }
 
     private final DictService dictService;
@@ -53,6 +80,9 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
     @Override
     public List<NodeExt> getNodeExt() {
         List<NodeExt> nodeExtList = new ArrayList<>();
+        // 构建基础设置页面
+        nodeExtList.add(buildNodeExt("wf_basic_tab", "基础设置", 1,
+                List.of(CopySettingEnum.class, VariablesEnum.class)));
         // 构建按钮权限页面
         nodeExtList.add(buildNodeExt("wf_button_tab", "权限", 2,
                 List.of(ButtonPermissionEnum.class)));
@@ -102,9 +132,20 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
             return null;
         }
         String simpleName = enumClass.getSimpleName();
-        NodeExt.ChildNode childNode = buildChildNodeMap(simpleName);
+        NodeExt.ChildNode childNode = new NodeExt.ChildNode();
+        Map<String, Object> map = CHILD_NODE_MAP.get(simpleName);
         // 编码,此json中唯
         childNode.setCode(simpleName);
+        // label名称
+        childNode.setLabel(Convert.toStr(map.get("label")));
+        // 1:输入框 2:文本域 3:下拉框 4:选择框
+        childNode.setType(Convert.toInt(map.get("type"), 1));
+        // 是否必填
+        childNode.setMust(Convert.toBool(map.get("must"), false));
+        // 是否多选
+        childNode.setMultiple(Convert.toBool(map.get("multiple"), true));
+        // 描述
+        childNode.setDesc(Convert.toStr(map.get("desc"), null));
         // 字典,下拉框和复选框时用到
         childNode.setDict(Arrays.stream(enumClass.getEnumConstants())
                 .map(NodeExtEnum.class::cast)
@@ -125,12 +166,18 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
         if (ObjectUtil.isNull(dictTypeDTO)) {
             return null;
         }
-        NodeExt.ChildNode childNode = buildChildNodeMap(dictType);
+        NodeExt.ChildNode childNode = new NodeExt.ChildNode();
         // 编码,此json中唯一
         childNode.setCode(dictType);
         // label名称
         childNode.setLabel(dictTypeDTO.getDictName());
-        // 描述
+        // 1:输入框 2:文本域 3:下拉框 4:选择框
+        childNode.setType(3);
+        // 是否必填
+        childNode.setMust(false);
+        // 是否多选
+        childNode.setMultiple(true);
+        // 描述 (可根据描述参数解析更多配置,如type,must,multiple等)
         childNode.setDesc(dictTypeDTO.getRemark());
         // 字典,下拉框和复选框时用到
         childNode.setDict(dictService.getDictData(dictType)
@@ -141,103 +188,71 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
     }
 
     /**
-     * 根据 CHILD_NODE_MAP 中的配置信息,构建一个基本的 ChildNode 对象
-     * 该方法用于设置 ChildNode 的常规属性,例如 label、type、是否必填、是否多选等
+     * 解析扩展属性 JSON 并构建 Node 扩展属性对象
+     * <p>
+     * 根据传入的 JSON 字符串,将扩展属性分为三类:
+     * 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选
+     * 2. CopySettingEnum:解析为抄送对象 ID 集合
+     * 3. VariablesEnum:解析为自定义参数 Map
      *
-     * @param key CHILD_NODE_MAP 的 key
-     * @return 返回构建好的 ChildNode 对象
-     */
-    private NodeExt.ChildNode buildChildNodeMap(String key) {
-        NodeExt.ChildNode childNode = new NodeExt.ChildNode();
-        ButtonPermission bp = CHILD_NODE_MAP.get(key);
-        if (bp == null) {
-            childNode.setType(1);
-            childNode.setMust(false);
-            childNode.setMultiple(true);
-            return childNode;
-        }
-        // label名称
-        childNode.setLabel(bp.label());
-        // 1:输入框 2:输入框 3:下拉框 4:选择框
-        childNode.setType(bp.type());
-        // 是否必填
-        childNode.setMust(bp.must());
-        // 是否多选
-        childNode.setMultiple(bp.multiple());
-        return childNode;
-    }
-
-    /**
-     * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
+     * <p>示例 JSON:
+     * [
+     * {"code": "ButtonPermissionEnum", "value": "back,termination"},
+     * {"code": "CopySettingEnum", "value": "1"},
+     * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
+     * ]
      *
      * @param ext 扩展属性 JSON 字符串
-     * @return 按钮权限 VO 列表
+     * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
      */
     @Override
-    public List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext) {
-        // 解析 ext 为 Map<code, Set<value>>,用于标记权限
-        Map<String, Set<String>> permissionMap = JsonUtils.parseArray(ext, ButtonPermissionVo.class)
-                .stream()
-                .collect(Collectors.toMap(
-                        ButtonPermissionVo::getCode,
-                        item -> StringUtils.splitList(item.getValue()).stream()
-                                .map(String::trim)
-                                .filter(StrUtil::isNotBlank)
-                                .collect(Collectors.toSet()),
-                        (a, b) -> b,
-                        HashMap::new
-                ));
-
-        // 构建按钮权限列表,标记哪些按钮在 permissionMap 中出现(表示已勾选)
-        return buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class));
-    }
+    public NodeExtVo parseNodeExt(String ext) {
+        NodeExtVo nodeExtVo = new NodeExtVo();
 
-    /**
-     * 将权限映射与按钮权限来源(枚举类或字典类型)进行匹配,生成权限视图列表
-     * <p>
-     * 使用说明:
-     * - sources 支持传入多个来源类型,支持 NodeExtEnum 枚举类 或 字典类型字符串(dictType)
-     * - 若需要扩展更多按钮权限,只需在 sources 中新增对应的枚举类或字典类型
-     * <p>
-     * 示例:
-     * buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class, "custom_button_dict"));
-     *
-     * @param permissionMap 权限映射
-     * @param sources       枚举类或字典类型列表
-     * @return 按钮权限视图对象列表
-     */
-    @SuppressWarnings("unchecked cast")
-    private List<ButtonPermissionVo> buildPermissionsFromSources(Map<String, Set<String>> permissionMap, List<Object> sources) {
-        return sources.stream()
-                .flatMap(source -> {
-                    if (source instanceof Class<?> clazz && NodeExtEnum.class.isAssignableFrom(clazz)) {
-                        Set<String> selectedSet = permissionMap.getOrDefault(clazz.getSimpleName(), Collections.emptySet());
-                        return extractDictItems(this.buildChildNode((Class<? extends NodeExtEnum>) clazz), selectedSet).stream();
-                    } else if (source instanceof String dictType) {
-                        Set<String> selectedSet = permissionMap.getOrDefault(dictType, Collections.emptySet());
-                        return extractDictItems(this.buildChildNode(dictType), selectedSet).stream();
-                    }
-                    return Stream.empty();
-                }).toList();
-    }
+        // 解析 JSON 为 Dict 列表
+        List<Dict> nodeExtMap = JsonUtils.parseArrayMap(ext);
 
-    /**
-     * 从节点子项中提取字典项,并构建按钮权限视图对象列表
-     *
-     * @param childNode   子节点
-     * @param selectedSet 已选中的值集
-     * @return 按钮权限视图对象列表
-     */
-    private List<ButtonPermissionVo> extractDictItems(NodeExt.ChildNode childNode, Set<String> selectedSet) {
-        return Optional.ofNullable(childNode)
-                .map(NodeExt.ChildNode::getDict)
-                .orElse(List.of())
-                .stream()
-                .map(dict -> new ButtonPermissionVo(dict.getValue(), selectedSet.contains(dict.getValue())))
-                .toList();
-    }
+        for (Dict nodeExt : nodeExtMap) {
+            String code = nodeExt.getStr("code");
+            String value = nodeExt.getStr("value");
+
+            if (ButtonPermissionEnum.class.getSimpleName().equals(code)) {
+                // 解析按钮权限
+                // 将 value 拆分为 Set<String>,便于精确匹配
+                Set<String> buttonSet = StringUtils.str2Set(value, StringUtils.SEPARATOR);
+
+                // 获取按钮字典配置
+                NodeExt.ChildNode childNode = buildChildNode(ButtonPermissionEnum.class);
 
-    record ButtonPermission(String label, Integer type, Boolean must, Boolean multiple) {
+                // 构建 ButtonPermissionVo 列表
+                List<ButtonPermissionVo> buttonList = Optional.ofNullable(childNode)
+                        .map(NodeExt.ChildNode::getDict)
+                        .orElse(List.of())
+                        .stream()
+                        .map(dict -> new ButtonPermissionVo(dict.getValue(), buttonSet.contains(dict.getValue())))
+                        .toList();
+
+                nodeExtVo.setButtonPermissions(buttonList);
+
+            } else if (CopySettingEnum.class.getSimpleName().equals(code)) {
+                // 解析抄送对象 ID 集合
+                nodeExtVo.setCopySettings(StringUtils.str2Set(value, StringUtils.SEPARATOR));
+
+            } else if (VariablesEnum.class.getSimpleName().equals(code)) {
+                // 解析自定义参数
+                // 将 key=value 字符串拆分为 Map
+                Map<String, String> variables = Arrays.stream(StringUtils.split(value, StringUtils.SEPARATOR))
+                        .map(s -> StringUtils.split(s, "="))
+                        .filter(arr -> arr.length == 2)
+                        .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1]));
+
+                nodeExtVo.setVariables(variables);
+            } else {
+                // 未知扩展类型,记录日志
+                log.warn("未知扩展类型:code={}, value={}", code, value);
+            }
+        }
+        return nodeExtVo;
     }
 
 }

+ 60 - 8
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/FlwTaskServiceImpl.java

@@ -28,10 +28,14 @@ import com.vber.workflow.common.ConditionalOnEnable;
 import com.vber.workflow.common.constant.FlowConstant;
 import com.vber.workflow.common.enums.TaskAssigneeType;
 import com.vber.workflow.common.enums.TaskStatusEnum;
+import com.vber.workflow.domain.FlowInstanceBizExt;
 import com.vber.workflow.domain.bo.*;
+import com.vber.workflow.domain.vo.FlowCopyVo;
 import com.vber.workflow.domain.vo.FlowHisTaskVo;
 import com.vber.workflow.domain.vo.FlowTaskVo;
+import com.vber.workflow.domain.vo.NodeExtVo;
 import com.vber.workflow.mapper.FlwCategoryMapper;
+import com.vber.workflow.mapper.FlwInstanceBizExtMapper;
 import com.vber.workflow.mapper.FlwTaskMapper;
 import com.vber.workflow.service.IFlwCommonService;
 import com.vber.workflow.service.IFlwNodeExtService;
@@ -49,7 +53,10 @@ import org.dromara.warm.flow.core.service.*;
 import org.dromara.warm.flow.core.utils.ExpressionUtil;
 import org.dromara.warm.flow.core.utils.MapUtil;
 import org.dromara.warm.flow.orm.entity.*;
-import org.dromara.warm.flow.orm.mapper.*;
+import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
+import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
+import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
+import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -85,7 +92,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
     private final IFlwTaskAssigneeService flwTaskAssigneeService;
     private final IFlwCommonService flwCommonService;
     private final IFlwNodeExtService flwNodeExtService;
-    private final FlowDefinitionMapper flowDefinitionMapper;
+    private final FlwInstanceBizExtMapper flwInstanceBizExtMapper;
 
     /**
      * 启动任务
@@ -99,6 +106,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         if (StringUtils.isBlank(businessId)) {
             throw new ServiceException("启动工作流时必须包含业务ID");
         }
+
         // 启动流程实例(提交申请)
         Map<String, Object> variables = startProcessBo.getVariables();
         // 流程发起人
@@ -107,9 +115,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         variables.put(INITIATOR_ORG_ID, LoginHelper.getOrgId());
         // 业务id
         variables.put(BUSINESS_ID, businessId);
+        FlowInstanceBizExt bizExt = startProcessBo.getBizExt();
+
+        // 获取已有流程实例
         FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class)
                 .eq(FlowInstance::getBusinessId, businessId));
+
         if (ObjectUtil.isNotNull(flowInstance)) {
+            // 已存在流程
             BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus());
             List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId()));
             taskService.mergeVariable(flowInstance, variables);
@@ -117,15 +130,19 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
             StartProcessReturnDTO dto = new StartProcessReturnDTO();
             dto.setProcessInstanceId(taskList.get(0).getInstanceId());
             dto.setTaskId(taskList.get(0).getId());
+            // 保存流程实例业务信息
+            this.buildFlowInstanceBizExt(flowInstance, bizExt);
             return dto;
         }
+
         // 将流程定义内的扩展参数设置到变量中
         Definition definition = FlowEngine.defService().getPublishByFlowCode(startProcessBo.getFlowCode());
         Dict dict = JsonUtils.parseMap(definition.getExt());
         boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(FlowConstant.AUTO_PASS);
         variables.put(FlowConstant.AUTO_PASS, autoPass);
-
+        variables.put(FlowConstant.BUSINESS_CODE, this.generateBusinessCode(bizExt));
         FlowParams flowParams = FlowParams.build()
+                .handler(startProcessBo.getHandler())
                 .flowCode(startProcessBo.getFlowCode())
                 .variable(startProcessBo.getVariables())
                 .flowStatus(BusinessStatusEnum.DRAFT.getStatus());
@@ -135,6 +152,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         } catch (Exception e) {
             throw new ServiceException(e.getMessage());
         }
+        // 保存流程实例业务信息
+        this.buildFlowInstanceBizExt(instance, bizExt);
         // 申请人执行流程
         List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId()));
         if (taskList.size() > 1) {
@@ -146,6 +165,31 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         return dto;
     }
 
+    /**
+     * 生成业务编号,如果已有则直接返回已有值
+     */
+    private String generateBusinessCode(FlowInstanceBizExt bizExt) {
+        if (StringUtils.isBlank(bizExt.getBusinessCode())) {
+            // TODO: 按照自己业务规则生成编号
+            String businessCode = Convert.toStr(System.currentTimeMillis());
+            bizExt.setBusinessCode(businessCode);
+            return businessCode;
+        }
+        return bizExt.getBusinessCode();
+    }
+
+    /**
+     * 构建流程实例业务信息
+     *
+     * @param instance 流程实例
+     * @param bizExt   流程业务扩展信息
+     */
+    private void buildFlowInstanceBizExt(Instance instance, FlowInstanceBizExt bizExt) {
+        bizExt.setInstanceId(instance.getId());
+        bizExt.setBusinessId(instance.getBusinessId());
+        flwInstanceBizExtMapper.saveOrUpdateByInstanceId(bizExt);
+    }
+
     /**
      * 办理任务
      *
@@ -186,6 +230,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
             }
             // 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息
             FlowParams flowParams = FlowParams.build()
+                    .handler(completeTaskBo.getHandler())
                     .variable(variables)
                     .skipType(SkipType.PASS.getKey())
                     .message(completeTaskBo.getMessage())
@@ -440,9 +485,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
 
             Map<String, Object> variable = new HashMap<>();
             // 消息类型
-            variable.put("messageType", messageType);
+            variable.put(FlowConstant.MESSAGE_TYPE, messageType);
             // 消息通知
-            variable.put("notice", notice);
+            variable.put(FlowConstant.MESSAGE_NOTICE, notice);
 
             FlowParams flowParams = FlowParams.build()
                     .nodeCode(bo.getNodeCode())
@@ -554,8 +599,16 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         if (ObjectUtil.isNull(flowNode)) {
             throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
         }
+        NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt());
         //设置按钮权限
-        flowTaskVo.setButtonList(flwNodeExtService.buildButtonPermissionsFromExt(flowNode.getExt()));
+        flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions());
+        if (CollUtil.isNotEmpty(nodeExtVo.getCopySettings())) {
+            List<FlowCopyVo> list = StreamUtils.toList(nodeExtVo.getCopySettings(), x -> new FlowCopyVo(Convert.toLong(x)));
+            flowTaskVo.setCopyList(list);
+        } else {
+            flowTaskVo.setCopyList(new ArrayList<>());
+        }
+        flowTaskVo.setVarList(nodeExtVo.getVariables());
         flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
         flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
         return flowTaskVo;
@@ -593,7 +646,6 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
                                 flowNode.setPermissionFlag(StreamUtils.join(users, e -> Convert.toStr(e.getUserId())));
                             }
                         });
-
             }
         }
         return nextFlowNodes;
@@ -679,7 +731,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         Long taskId = bo.getTaskId();
         Task task = taskService.getById(taskId);
         FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId());
-        if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) {
+        if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) {
             if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
                 throw new ServiceException(task.getNodeName() + "不是会签节点!");
             }

+ 17 - 6
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/TestLeaveServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.convert.Convert;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -20,6 +21,7 @@ import com.vber.common.mybatis.core.domain.BaseEntity;
 import com.vber.common.mybatis.core.page.PageQuery;
 import com.vber.common.mybatis.core.page.TableDataInfo;
 import com.vber.workflow.common.ConditionalOnEnable;
+import com.vber.workflow.common.constant.FlowConstant;
 import com.vber.workflow.domain.TestLeave;
 import com.vber.workflow.domain.bo.TestLeaveBo;
 import com.vber.workflow.domain.vo.TestLeaveVo;
@@ -44,7 +46,6 @@ import java.util.Map;
 @Service
 @Slf4j
 public class TestLeaveServiceImpl implements ITestLeaveService {
-
     private final TestLeaveMapper baseMapper;
     private final WorkflowService workflowService;
 
@@ -105,6 +106,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
         long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true);
         // 截止日期也算一天
         bo.setLeaveDays((int) day + 1);
+        bo.setApplyCode(System.currentTimeMillis() + StrUtil.EMPTY);
         TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
         if (StringUtils.isBlank(add.getStatus())) {
             add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
@@ -122,6 +124,9 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
         long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true);
         // 截止日期也算一天
         bo.setLeaveDays((int) day + 1);
+        if (ObjectUtil.isNull(bo.getId())) {
+            bo.setApplyCode(System.currentTimeMillis() + StrUtil.EMPTY);
+        }
         TestLeave leave = MapstructUtils.convert(bo, TestLeave.class);
         boolean flag = baseMapper.insertOrUpdate(leave);
         if (flag) {
@@ -129,12 +134,14 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
             // 后端发起需要忽略权限
             bo.getParams().put("ignore", true);
 
+            StartProcessDTO startProcess = new StartProcessDTO();
+            startProcess.setBusinessId(leave.getId().toString());
+            startProcess.setFlowCode(StringUtils.isEmpty(bo.getFlowCode()) ? "leave1" : bo.getFlowCode());
+            startProcess.setVariables(bo.getParams());
+            // 后端发起 如果没有登录用户 比如定时任务 可以手动设置一个处理人id
+            // startProcess.setHandler("0");
 
-            boolean flag1 = workflowService.startCompleteTask(new StartProcessDTO() {{
-                setBusinessId(leave.getId().toString());
-                setFlowCode(StringUtils.isEmpty(bo.getFlowCode()) ? "leave1" : bo.getFlowCode());
-                setVariables(bo.getParams());
-            }});
+            boolean flag1 = workflowService.startCompleteTask(startProcess);
             if (!flag1) {
                 throw new ServiceException("流程发起异常");
             }
@@ -185,6 +192,10 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
             String message = Convert.toStr(params.get("message"));
         }
         if (processEvent.getSubmit()) {
+            if (StringUtils.isBlank(testLeave.getApplyCode())) {
+                String businessCode = MapUtil.getStr(params, FlowConstant.BUSINESS_CODE, StrUtil.EMPTY);
+                testLeave.setApplyCode(businessCode);
+            }
             testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
         }
         baseMapper.updateById(testLeave);

+ 16 - 10
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/java/com/vber/workflow/service/impl/WorkflowServiceImpl.java

@@ -10,6 +10,7 @@ import com.vber.common.core.service.WorkflowService;
 import com.vber.common.core.utils.StringUtils;
 import com.vber.workflow.common.ConditionalOnEnable;
 import com.vber.workflow.common.enums.MessageTypeEnum;
+import com.vber.workflow.domain.FlowInstanceBizExt;
 import com.vber.workflow.domain.bo.CompleteTaskBo;
 import com.vber.workflow.domain.bo.StartProcessBo;
 import com.vber.workflow.service.IFlwDefinitionService;
@@ -161,16 +162,21 @@ public class WorkflowServiceImpl implements WorkflowService {
     @Transactional(rollbackFor = Exception.class)
     public boolean startCompleteTask(StartProcessDTO startProcess) {
         try {
-            StartProcessReturnDTO result = flwTaskService.startWorkFlow(new StartProcessBo() {{
-                setBusinessId(startProcess.getBusinessId());
-                setFlowCode(startProcess.getFlowCode());
-                setVariables(startProcess.getVariables());
-            }});
-            boolean flag = flwTaskService.completeTask(new CompleteTaskBo() {{
-                setTaskId(result.getTaskId());
-                setMessageType(Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode()));
-                setVariables(startProcess.getVariables());
-            }});
+            StartProcessBo processBo = new StartProcessBo();
+            processBo.setBusinessId(startProcess.getBusinessId());
+            processBo.setFlowCode(startProcess.getFlowCode());
+            processBo.setVariables(startProcess.getVariables());
+            processBo.setHandler(startProcess.getHandler());
+            processBo.setBizExt(BeanUtil.toBean(startProcess.getBizExt(), FlowInstanceBizExt.class));
+
+            StartProcessReturnDTO result = flwTaskService.startWorkFlow(processBo);
+            CompleteTaskBo taskBo = new CompleteTaskBo();
+            taskBo.setTaskId(result.getTaskId());
+            taskBo.setMessageType(Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode()));
+            taskBo.setVariables(startProcess.getVariables());
+            taskBo.setHandler(startProcess.getHandler());
+
+            boolean flag = flwTaskService.completeTask(taskBo);
             if (!flag) {
                 throw new ServiceException("流程发起异常");
             }

+ 7 - 0
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwInstanceBizExtMapper.xml

@@ -0,0 +1,7 @@
+<?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="com.vber.workflow.mapper.FlwInstanceBizExtMapper">
+
+</mapper>

+ 25 - 21
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml

@@ -8,28 +8,32 @@
 
     <select id="selectInstanceList" resultMap="FlowInstanceResult">
         select fi.id,
-        fi.create_time,
-        fi.update_time,
-        fi.tenant_id,
-        fi.del_flag,
-        fi.definition_id,
-        fi.business_id,
-        fi.node_type,
-        fi.node_code,
-        fi.node_name,
-        fi.variable,
-        fi.flow_status,
-        fi.activity_status,
-        fi.create_by,
-        fi.ext,
-        fd.flow_name,
-        fd.flow_code,
-        fd.version,
-        fd.form_custom,
-        fd.form_path,
-        fd.category
+               fi.create_time,
+               fi.update_time,
+               fi.tenant_id,
+               fi.del_flag,
+               fi.definition_id,
+               fi.business_id,
+               fi.node_type,
+               fi.node_code,
+               fi.node_name,
+               fi.variable,
+               fi.flow_status,
+               fi.activity_status,
+               fi.create_by,
+               fi.ext,
+               fd.flow_name,
+               fd.flow_code,
+               fd.version,
+               fd.form_custom,
+               fd.form_path,
+               fd.category,
+               biz.business_code,
+               biz.business_title
         from flow_instance fi
-        left join flow_definition fd on fi.definition_id = fd.id ${ew.getCustomSqlSegment}
+                 left join flow_definition fd on fi.definition_id = fd.id
+                 left join flow_instance_biz_ext biz on biz.instance_id = fi.id ${ew.getCustomSqlSegment}
     </select>
 
+
 </mapper>

+ 1 - 1
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwSpelMapper.xml

@@ -2,6 +2,6 @@
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.FlwSpelMapper">
+<mapper namespace="com.vber.workflow.mapper.FlwSpelMapper">
 
 </mapper>

+ 91 - 81
SERVER/VberAdminPlusV3/vber-modules/vber-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml

@@ -11,96 +11,106 @@
     <select id="getListRunTask" resultMap="FlowTaskResult">
         select *
         from (select distinct t.id,
-        t.node_code,
-        t.node_name,
-        t.node_type,
-        t.definition_id,
-        t.instance_id,
-        t.create_time,
-        t.update_time,
-        t.tenant_id,
-        i.business_id,
-        i.flow_status,
-        i.create_by,
-        d.flow_name,
-        d.flow_code,
-        d.form_custom,
-        d.category,
-        COALESCE(t.form_path, d.form_path) as form_path,
-        d.version,
-        uu.processed_by,
-        uu.type
-        from flow_task t
-        left join flow_user uu on uu.associated = t.id
-        left join flow_definition d on t.definition_id = d.id
-        left join flow_instance i on t.instance_id = i.id
-        where t.node_type = 1
-        and t.del_flag = '0'
-        and uu.del_flag = '0'
-        and uu.type in ('1', '2', '3')) t ${ew.getCustomSqlSegment}
+                              t.node_code,
+                              t.node_name,
+                              t.node_type,
+                              t.definition_id,
+                              t.instance_id,
+                              t.create_time,
+                              t.update_time,
+                              t.tenant_id,
+                              i.business_id,
+                              i.flow_status,
+                              i.create_by,
+                              d.flow_name,
+                              d.flow_code,
+                              d.form_custom,
+                              d.category,
+                              COALESCE(t.form_path, d.form_path) as form_path,
+                              d.version,
+                              uu.processed_by,
+                              uu.type,
+                              biz.business_code,
+                              biz.business_title
+              from flow_task t
+                       left join flow_user uu on uu.associated = t.id
+                       left join flow_definition d on t.definition_id = d.id
+                       left join flow_instance i on t.instance_id = i.id
+                       left join flow_instance_biz_ext biz on biz.instance_id = i.id
+              where t.node_type = 1
+                and t.del_flag = '0'
+                and uu.del_flag = '0'
+                and uu.type in ('1', '2', '3')) t ${ew.getCustomSqlSegment}
     </select>
 
     <select id="getListFinishTask" resultMap="FlowHisTaskResult">
         select *
         from (select a.id,
-        a.node_code,
-        a.node_name,
-        a.cooperate_type,
-        a.approver,
-        a.collaborator,
-        a.node_type,
-        a.target_node_code,
-        a.target_node_name,
-        a.definition_id,
-        a.instance_id,
-        a.flow_status flow_task_status,
-        a.message,
-        a.ext,
-        a.create_time,
-        a.update_time,
-        a.tenant_id,
-        a.form_custom,
-        a.form_path,
-        b.flow_status,
-        b.business_id,
-        b.create_by,
-        c.flow_name,
-        c.flow_code,
-        c.category,
-        c.version
-        from flow_his_task a
-        left join flow_instance b on a.instance_id = b.id
-        left join flow_definition c on a.definition_id = c.id
-        where a.del_flag = '0'
-        and b.del_flag = '0'
-        and c.del_flag = '0'
-        and a.node_type in ('1', '3', '4')) t ${ew.getCustomSqlSegment}
+                     a.node_code,
+                     a.node_name,
+                     a.cooperate_type,
+                     a.approver,
+                     a.collaborator,
+                     a.node_type,
+                     a.target_node_code,
+                     a.target_node_name,
+                     a.definition_id,
+                     a.instance_id,
+                     a.flow_status flow_task_status,
+                     a.message,
+                     a.ext,
+                     a.create_time,
+                     a.update_time,
+                     a.tenant_id,
+                     a.form_custom,
+                     a.form_path,
+                     b.flow_status,
+                     b.business_id,
+                     b.create_by,
+                     c.flow_name,
+                     c.flow_code,
+                     c.category,
+                     c.version,
+                     biz.business_code,
+                     biz.business_title
+              from flow_his_task a
+                       left join flow_instance b on a.instance_id = b.id
+                       left join flow_definition c on a.definition_id = c.id
+                       left join flow_instance_biz_ext biz on biz.instance_id = b.id
+              where a.del_flag = '0'
+                and b.del_flag = '0'
+                and c.del_flag = '0'
+                and a.node_type in ('1', '3', '4')) t ${ew.getCustomSqlSegment}
     </select>
 
     <select id="getTaskCopyByPage" resultMap="FlowTaskResult">
         select *
         from (select b.id,
-        b.update_time,
-        c.business_id,
-        c.flow_status,
-        c.create_by,
-        a.processed_by,
-        a.create_time,
-        b.form_custom,
-        b.form_path,
-        b.node_name,
-        b.node_code,
-        d.flow_name,
-        d.flow_code,
-        d.category,
-        d.version
-        from flow_user a
-        left join flow_his_task b on a.associated = b.task_id
-        left join flow_instance c on b.instance_id = c.id
-        left join flow_definition d on c.definition_id = d.id
-        where a.type = '4'
-        and a.del_flag = '0'
-        and b.del_flag = '0'
-        and d.del_flag = '0') t ${ew.getCustomSqlSegment}
+                     b.update_time,
+                     c.business_id,
+                     c.flow_status,
+                     c.create_by,
+                     a.processed_by,
+                     a.create_time,
+                     b.form_custom,
+                     b.form_path,
+                     b.node_name,
+                     b.node_code,
+                     d.flow_name,
+                     d.flow_code,
+                     d.category,
+                     d.version,
+                     biz.business_code,
+                     biz.business_title
+              from flow_user a
+                       left join flow_his_task b on a.associated = b.task_id
+                       left join flow_instance c on b.instance_id = c.id
+                       left join flow_definition d on c.definition_id = d.id
+                       left join flow_instance_biz_ext biz on biz.instance_id = c.id
+              where a.type = '4'
+                and a.del_flag = '0'
+                and b.del_flag = '0'
+                and d.del_flag = '0') t ${ew.getCustomSqlSegment}
     </select>
+
 </mapper>

+ 1 - 1
UI/VAP_V3.VUE/src/components/process/MessageType.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-const props = withDefaults(defineProps<{ title: string }>(), { title: "提示" })
+const props = withDefaults(defineProps<{ title?: string }>(), { title: "提示" })
 const emits = defineEmits<{
 	(e: "submit", v: any): void
 	(e: "cancel"): void

+ 7 - 1
UI/VAP_V3.VUE/src/components/process/SubmitVerify.vue

@@ -34,6 +34,7 @@ const userSelectCopyRef = ref()
 const transferTaskRef = ref()
 const delegateTaskRef = ref()
 const multiInstanceUserRef = ref()
+const varNodeList = ref<Map<string, string>>(undefined)
 
 const nickName = ref({})
 //节点编码
@@ -340,9 +341,13 @@ function open(id?: string) {
 		apis.workflow.taskApi.getTask(taskId.value).then((res: any) => {
 			task.value = res.data
 			buttonObj.value = {}
-			task.value.buttonList.forEach((e) => {
+			task.value.buttonList?.forEach((e) => {
 				buttonObj.value[e.code] = e.show
 			})
+			selectCopyUserList.value = task.value.copyList
+			selectCopyUserIds.value = task.value.copyList.map((e) => e.userId).join(",")
+			varNodeList.value = task.value.varList
+
 			const data = {
 				taskId: taskId.value,
 				variables: props.taskVariables
@@ -520,6 +525,7 @@ defineExpose({
 	<UserSelect
 		ref="popUserRef"
 		:multiple="true"
+		:data="form.assigneeMap[nodeCode]"
 		:userIds="popUserIds"
 		@confirm="handlePopUser"></UserSelect>
 	<!-- 加签组件 -->

+ 1 - 1
UI/VAP_V3.VUE/src/views/workflow/processDefinition/index.vue

@@ -166,7 +166,7 @@ const opts = reactive({
 			placeholder: "请选择是否择动态表单",
 			component: "VS",
 			data: [
-				{ label: "是", value: "Y" },
+				{ label: "是", value: "Y", disebled: true },
 				{ label: "否", value: "N" }
 			],
 			props: {

+ 5 - 9
UI/VAP_V3.VUE/src/views/workflow/processInstance/index.vue

@@ -14,17 +14,13 @@ const opts = reactive<any>({
 	columnsFun: () => {
 		const cols: any[] = [
 			{ field: "id", name: "主键", width: 100, isSort: true, visible: false, tooltip: true },
-			{
-				field: "name",
-				name: "流程定义名称",
-				visible: true,
-				width: "auto",
-				tooltip: true
-			},
-			{ field: "nodeName", name: "任务名称", visible: true, width: 200, tooltip: true },
+			{ field: "businessCode", name: "业务编码", visible: true, width: "auto", tooltip: true },
+			{ field: "businessTitle", name: "业务标题", visible: true, width: "auto", tooltip: true },
 			{ field: "flowCode", name: "流程定义编码", visible: true, width: 150, tooltip: true },
+			{ field: "flowName", name: "流程定义名称", visible: true, width: 150, tooltip: true },
 			{ field: "categoryName", name: "流程分类", visible: true, width: 120, tooltip: false },
-			{ field: "createByName", name: "申请人", visible: true, width: 100, tooltip: false },
+			{ field: "nodeName", name: "任务名称", visible: true, width: 200, tooltip: false },
+			{ field: "createByName", name: "申请人", visible: true, width: 100, tooltip: true },
 			{ field: "flowStatus", name: "流程状态", visible: true, width: 80, tooltip: true }
 		]
 		if (queryParams.value.runStatus == "1") {

+ 4 - 14
UI/VAP_V3.VUE/src/views/workflow/task/allTaskWaiting.vue

@@ -6,20 +6,10 @@ const modalRef = ref()
 const opts = reactive({
 	columns: [
 		{ field: "id", name: "主键", width: 100, isSort: true, visible: false, tooltip: true },
-		{
-			field: "flowName",
-			name: "流程定义名称",
-			visible: true,
-			width: "auto",
-			tooltip: true
-		},
-		{
-			field: "flowCode",
-			name: "流程定义编码",
-			visible: true,
-			width: 150,
-			tooltip: true
-		},
+		{ field: "businessCode", name: "业务编码", visible: true, width: "auto", tooltip: true },
+		{ field: "businessTitle", name: "业务标题", visible: true, width: "auto", tooltip: true },
+		{ field: "flowName", name: "流程定义名称", visible: true, width: "auto", tooltip: true },
+		{ field: "flowCode", name: "流程定义编码", visible: true, width: 150, tooltip: true },
 		{ field: "nodeName", name: "任务名称", visible: true, width: 120, tooltip: true },
 		{ field: "createByName", name: "申请人", visible: true, width: 120, tooltip: true },
 		{ field: "categoryName", name: "流程分类", visible: true, width: 120, tooltip: true },

+ 4 - 14
UI/VAP_V3.VUE/src/views/workflow/task/taskCopyList.vue

@@ -7,20 +7,10 @@ const modalRef = ref()
 const opts = reactive({
 	columns: [
 		{ field: "id", name: "主键", width: 100, isSort: true, visible: false, tooltip: true },
-		{
-			field: "flowName",
-			name: "流程定义名称",
-			visible: true,
-			width: "auto",
-			tooltip: true
-		},
-		{
-			field: "flowCode",
-			name: "流程定义编码",
-			visible: true,
-			width: 180,
-			tooltip: true
-		},
+		{ field: "businessCode", name: "业务编码", visible: true, width: "auto", tooltip: true },
+		{ field: "businessTitle", name: "业务标题", visible: true, width: "auto", tooltip: true },
+		{ field: "flowName", name: "流程定义名称", visible: true, width: "auto", tooltip: true },
+		{ field: "flowCode", name: "流程定义编码", visible: true, width: 180, tooltip: true },
 		{ field: "categoryName", name: "流程分类", visible: true, width: 120, tooltip: true },
 		{ field: "nodeName", name: "任务名称", visible: true, width: 150, tooltip: true },
 		{ field: "flowStatus", name: "流程状态", width: 100, visible: true, tooltip: true },

+ 4 - 14
UI/VAP_V3.VUE/src/views/workflow/task/taskFinish.vue

@@ -7,20 +7,10 @@ const modalRef = ref()
 const opts = reactive({
 	columns: [
 		{ field: "id", name: "主键", width: 100, isSort: true, visible: false, tooltip: true },
-		{
-			field: "flowName",
-			name: "流程定义名称",
-			visible: true,
-			width: "auto",
-			tooltip: true
-		},
-		{
-			field: "flowCode",
-			name: "流程定义编码",
-			visible: true,
-			width: 180,
-			tooltip: true
-		},
+		{ field: "businessCode", name: "业务编码", visible: true, width: "auto", tooltip: true },
+		{ field: "businessTitle", name: "业务标题", visible: true, width: "auto", tooltip: true },
+		{ field: "flowName", name: "流程定义名称", visible: true, width: 120, tooltip: true },
+		{ field: "flowCode", name: "流程定义编码", visible: true, width: 120, tooltip: true },
 		{ field: "categoryName", name: "流程分类", visible: true, width: 120, tooltip: true },
 		{ field: "nodeName", name: "任务名称", visible: true, width: 150, tooltip: true },
 		{ field: "createByName", name: "申请人", width: 140, visible: true, tooltip: true },

+ 4 - 14
UI/VAP_V3.VUE/src/views/workflow/task/taskWaiting.vue

@@ -7,20 +7,10 @@ const modalRef = ref()
 const opts = reactive({
 	columns: [
 		{ field: "id", name: "主键", width: 100, isSort: true, visible: false, tooltip: true },
-		{
-			field: "flowName",
-			name: "流程定义名称",
-			visible: true,
-			width: "auto",
-			tooltip: true
-		},
-		{
-			field: "flowCode",
-			name: "流程定义编码",
-			visible: true,
-			width: 180,
-			tooltip: true
-		},
+		{ field: "businessCode", name: "业务编码", visible: true, width: "auto", tooltip: true },
+		{ field: "businessTitle", name: "业务标题", visible: true, width: "auto", tooltip: true },
+		{ field: "flowName", name: "流程定义名称", visible: true, width: "auto", tooltip: true },
+		{ field: "flowCode", name: "流程定义编码", visible: true, width: 150, tooltip: true },
 		{ field: "categoryName", name: "流程分类", visible: true, width: 120, tooltip: true },
 		{ field: "nodeName", name: "任务名称", visible: true, width: 150, tooltip: true },
 		{ field: "createByName", name: "申请人", width: 140, visible: true, tooltip: true },