Commit 1784aab186bbbba85c7be2bcb5064283a75501b3

Authored by jason
2 parents 610f39de 31c2e81d

Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm

Showing 12 changed files with 101 additions and 84 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
@@ -54,6 +54,7 @@ public interface ErrorCodeConstants { @@ -54,6 +54,7 @@ public interface ErrorCodeConstants {
54 ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); 54 ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人");
55 ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); 55 ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在");
56 ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); 56 ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!");
  57 + ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!");
57 58
58 // ========== 动态表单模块 1-009-010-000 ========== 59 // ========== 动态表单模块 1-009-010-000 ==========
59 ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); 60 ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在");
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
@@ -33,7 +33,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { @@ -33,7 +33,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
33 CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), 33 CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"),
34 PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), 34 PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"),
35 INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), 35 INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"),
36 - ROUTE_BRANCH_NODE(54, "路由分支", "exclusiveGateway") 36 + ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway")
37 ; 37 ;
38 38
39 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); 39 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray();
@@ -51,7 +51,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { @@ -51,7 +51,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
51 return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) 51 return Objects.equals(CONDITION_BRANCH_NODE.getType(), type)
52 || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type) 52 || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type)
53 || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type) 53 || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type)
54 - || Objects.equals(ROUTE_BRANCH_NODE.getType(), type); 54 + || Objects.equals(ROUTER_BRANCH_NODE.getType(), type);
55 } 55 }
56 56
57 public static BpmSimpleModelNodeType valueOf(Integer type) { 57 public static BpmSimpleModelNodeType valueOf(Integer type) {
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
@@ -117,11 +117,10 @@ public class BpmSimpleModelNodeVO { @@ -117,11 +117,10 @@ public class BpmSimpleModelNodeVO {
117 private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE 117 private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
118 118
119 @Schema(description = "路由分支组", example = "[]") 119 @Schema(description = "路由分支组", example = "[]")
120 - private List<RouteCondition> routerGroups; 120 + private List<RouterCondition> routerGroups;
121 121
122 - // TODO @lesan:这个目前前端是随机生成的。可以后端来随机么?  
123 - @Schema(description = "默认分支 ID", example = "Flow_xxx")  
124 - private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE 122 + @Schema(description = "默认分支 ID", example = "Flow_xxx", hidden = true) // 由后端生成,所以 hidden = true
  123 + private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTER_BRANCH_NODE
125 124
126 @Schema(description = "任务监听器") 125 @Schema(description = "任务监听器")
127 @Valid 126 @Valid
@@ -290,11 +289,10 @@ public class BpmSimpleModelNodeVO { @@ -290,11 +289,10 @@ public class BpmSimpleModelNodeVO {
290 289
291 } 290 }
292 291
293 - // TODO @lesan:还有相关的也要改下哈。route 到 router  
294 @Schema(description = "路由分支") 292 @Schema(description = "路由分支")
295 @Data 293 @Data
296 @Valid 294 @Valid
297 - public static class RouteCondition { 295 + public static class RouterCondition {
298 296
299 @Schema(description = "节点 Id", example = "Activity_xxx") // 跳转到该节点 297 @Schema(description = "节点 Id", example = "Activity_xxx") // 跳转到该节点
300 @NotEmpty(message = "节点 Id 不能为空") 298 @NotEmpty(message = "节点 Id 不能为空")
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
@@ -101,6 +101,10 @@ public class BpmApprovalDetailRespVO { @@ -101,6 +101,10 @@ public class BpmApprovalDetailRespVO {
101 @Schema(description = "审批意见", example = "同意") 101 @Schema(description = "审批意见", example = "同意")
102 private String reason; 102 private String reason;
103 103
  104 + // TODO @lesan:改成 signPicUrl 会好点
  105 + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png")
  106 + private String sign;
  107 +
104 } 108 }
105 109
106 } 110 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
@@ -18,6 +18,10 @@ public class BpmTaskApproveReqVO { @@ -18,6 +18,10 @@ public class BpmTaskApproveReqVO {
18 @NotEmpty(message = "审批意见不能为空") 18 @NotEmpty(message = "审批意见不能为空")
19 private String reason; 19 private String reason;
20 20
  21 + // TODO @lesan:改成 signPicUrl 会好点
  22 + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png")
  23 + private String sign;
  24 +
21 @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) 25 @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED)
22 private Map<String, Object> variables; 26 private Map<String, Object> variables;
23 27
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
@@ -186,7 +186,8 @@ public interface BpmProcessInstanceConvert { @@ -186,7 +186,8 @@ public interface BpmProcessInstanceConvert {
186 return null; 186 return null;
187 } 187 }
188 return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class) 188 return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class)
189 - .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); 189 + .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task))
  190 + .setSign(FlowableUtils.getTaskSign(task));
190 } 191 }
191 192
192 default Set<Long> parseUserIds(HistoricProcessInstance processInstance, 193 default Set<Long> parseUserIds(HistoricProcessInstance processInstance,
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java
@@ -59,4 +59,7 @@ public class BpmnVariableConstants { @@ -59,4 +59,7 @@ public class BpmnVariableConstants {
59 */ 59 */
60 public static final String TASK_VARIABLE_REASON = "TASK_REASON"; 60 public static final String TASK_VARIABLE_REASON = "TASK_REASON";
61 61
  62 + // TODO @lesan:TASK_SIGN_PIC_URL 。。。虽然长一点,嘿嘿
  63 + public static final String TASK_VARIABLE_SIGN = "TASK_SIGN";
  64 +
62 } 65 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
@@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.convert.Convert; 4 import cn.hutool.core.convert.Convert;
  5 +import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.map.MapUtil; 6 import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.*; 7 import cn.hutool.core.util.*;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  9 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 10 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
9 import cn.iocoder.yudao.framework.common.util.string.StrUtils; 11 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
@@ -21,6 +23,7 @@ import org.flowable.bpmn.model.Process; @@ -21,6 +23,7 @@ import org.flowable.bpmn.model.Process;
21 import org.flowable.bpmn.model.*; 23 import org.flowable.bpmn.model.*;
22 import org.flowable.common.engine.api.FlowableException; 24 import org.flowable.common.engine.api.FlowableException;
23 import org.flowable.common.engine.impl.util.io.BytesStreamSource; 25 import org.flowable.common.engine.impl.util.io.BytesStreamSource;
  26 +import org.flowable.engine.impl.el.FixedValue;
24 27
25 import java.util.*; 28 import java.util.*;
26 29
@@ -346,12 +349,8 @@ public class BpmnModelUtils { @@ -346,12 +349,8 @@ public class BpmnModelUtils {
346 } 349 }
347 350
348 public static void addSignEnable(Boolean signEnable, FlowElement userTask) { 351 public static void addSignEnable(Boolean signEnable, FlowElement userTask) {
349 - // TODO @lesan:是不是改成表达式会好点 addExtensionElement(userTask, SIGN_ENABLE, ObjUtil.isNotNull(signEnable) ? )  
350 - if (ObjUtil.isNotNull(signEnable)) {  
351 - addExtensionElement(userTask, SIGN_ENABLE, signEnable.toString());  
352 - } else {  
353 - addExtensionElement(userTask, SIGN_ENABLE, "false");  
354 - } 352 + addExtensionElement(userTask, SIGN_ENABLE,
  353 + ObjUtil.isNotNull(signEnable) ? signEnable.toString() : Boolean.FALSE.toString());
355 } 354 }
356 355
357 public static Boolean parseSignEnable(BpmnModel bpmnModel, String flowElementId) { 356 public static Boolean parseSignEnable(BpmnModel bpmnModel, String flowElementId) {
@@ -366,6 +365,19 @@ public class BpmnModelUtils { @@ -366,6 +365,19 @@ public class BpmnModelUtils {
366 return Convert.toBool(extensionElements.get(0).getElementText(), false); 365 return Convert.toBool(extensionElements.get(0).getElementText(), false);
367 } 366 }
368 367
  368 + public static void addListenerConfig(FlowableListener flowableListener, BpmSimpleModelNodeVO.ListenerHandler handler) {
  369 + FieldExtension fieldExtension = new FieldExtension();
  370 + fieldExtension.setFieldName("listenerConfig");
  371 + fieldExtension.setStringValue(JsonUtils.toJsonString(handler));
  372 + flowableListener.getFieldExtensions().add(fieldExtension);
  373 + }
  374 +
  375 + public static BpmSimpleModelNodeVO.ListenerHandler parseListenerConfig(FixedValue fixedValue) {
  376 + String expressionText = fixedValue.getExpressionText();
  377 + Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText);
  378 + return JsonUtils.parseObject(expressionText, BpmSimpleModelNodeVO.ListenerHandler.class);
  379 + }
  380 +
369 // ========== BPM 简单查找相关的方法 ========== 381 // ========== BPM 简单查找相关的方法 ==========
370 382
371 /** 383 /**
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
@@ -213,6 +213,11 @@ public class FlowableUtils { @@ -213,6 +213,11 @@ public class FlowableUtils {
213 return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_REASON); 213 return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_REASON);
214 } 214 }
215 215
  216 + // TODO @lesan:这个方法名,也改咧
  217 + public static String getTaskSign(TaskInfo task) {
  218 + return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_SIGN);
  219 + }
  220 +
216 /** 221 /**
217 * 获得任务的表单 222 * 获得任务的表单
218 * 223 *
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert; @@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.map.MapUtil; 5 import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.*; 6 import cn.hutool.core.util.*;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 8 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
11 import cn.iocoder.yudao.module.bpm.enums.definition.*; 10 import cn.iocoder.yudao.module.bpm.enums.definition.*;
@@ -188,7 +187,7 @@ public class SimpleModelUtils { @@ -188,7 +187,7 @@ public class SimpleModelUtils {
188 // 分支终点节点 ID 187 // 分支终点节点 ID
189 String branchEndNodeId = null; 188 String branchEndNodeId = null;
190 if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE 189 if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE
191 - || nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { // 条件分支或路由分支 190 + || nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { // 条件分支或路由分支
192 // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID 191 // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID
193 branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; 192 branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId;
194 } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE 193 } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE
@@ -199,10 +198,10 @@ public class SimpleModelUtils { @@ -199,10 +198,10 @@ public class SimpleModelUtils {
199 Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); 198 Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空");
200 199
201 // 3. 遍历分支节点 200 // 3. 遍历分支节点
202 - if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { 201 + if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) {
203 // 路由分支遍历 202 // 路由分支遍历
204 - for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouterGroups()) {  
205 - SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route); 203 + for (BpmSimpleModelNodeVO.RouterCondition router : node.getRouterGroups()) {
  204 + SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), router);
206 process.addFlowElement(sequenceFlow); 205 process.addFlowElement(sequenceFlow);
207 } 206 }
208 } else { 207 } else {
@@ -233,7 +232,7 @@ public class SimpleModelUtils { @@ -233,7 +232,7 @@ public class SimpleModelUtils {
233 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); 232 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId);
234 process.addFlowElement(sequenceFlow); 233 process.addFlowElement(sequenceFlow);
235 // 4.2 如果是路由分支,需要连接后续节点为默认路由 234 // 4.2 如果是路由分支,需要连接后续节点为默认路由
236 - } else if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { 235 + } else if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) {
237 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(), 236 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(),
238 null, null); 237 null, null);
239 process.addFlowElement(sequenceFlow); 238 process.addFlowElement(sequenceFlow);
@@ -453,10 +452,7 @@ public class SimpleModelUtils { @@ -453,10 +452,7 @@ public class SimpleModelUtils {
453 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE); 452 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
454 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 453 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
455 flowableListener.setImplementation(DELEGATE_EXPRESSION); 454 flowableListener.setImplementation(DELEGATE_EXPRESSION);
456 - FieldExtension fieldExtension = new FieldExtension();  
457 - fieldExtension.setFieldName("listenerConfig");  
458 - fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCreateListener()));  
459 - flowableListener.getFieldExtensions().add(fieldExtension); 455 + addListenerConfig(flowableListener, node.getTaskCreateListener());
460 flowableListeners.add(flowableListener); 456 flowableListeners.add(flowableListener);
461 } 457 }
462 if (node.getTaskAssignListener() != null 458 if (node.getTaskAssignListener() != null
@@ -465,11 +461,7 @@ public class SimpleModelUtils { @@ -465,11 +461,7 @@ public class SimpleModelUtils {
465 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT); 461 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
466 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 462 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
467 flowableListener.setImplementation(DELEGATE_EXPRESSION); 463 flowableListener.setImplementation(DELEGATE_EXPRESSION);
468 - // TODO @lesan:可以在 BpmnModelUtils 搞个方法,类似 public static Integer parseCandidateStrategy。这样,就收敛啦!  
469 - FieldExtension fieldExtension = new FieldExtension();  
470 - fieldExtension.setFieldName("listenerConfig");  
471 - fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskAssignListener()));  
472 - flowableListener.getFieldExtensions().add(fieldExtension); 464 + addListenerConfig(flowableListener, node.getTaskAssignListener());
473 flowableListeners.add(flowableListener); 465 flowableListeners.add(flowableListener);
474 } 466 }
475 if (node.getTaskCompleteListener() != null 467 if (node.getTaskCompleteListener() != null
@@ -478,10 +470,7 @@ public class SimpleModelUtils { @@ -478,10 +470,7 @@ public class SimpleModelUtils {
478 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE); 470 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
479 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 471 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
480 flowableListener.setImplementation(DELEGATE_EXPRESSION); 472 flowableListener.setImplementation(DELEGATE_EXPRESSION);
481 - FieldExtension fieldExtension = new FieldExtension();  
482 - fieldExtension.setFieldName("listenerConfig");  
483 - fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCompleteListener()));  
484 - flowableListener.getFieldExtensions().add(fieldExtension); 473 + addListenerConfig(flowableListener, node.getTaskCompleteListener());
485 flowableListeners.add(flowableListener); 474 flowableListeners.add(flowableListener);
486 } 475 }
487 if (CollUtil.isNotEmpty(flowableListeners)) { 476 if (CollUtil.isNotEmpty(flowableListeners)) {
@@ -646,9 +635,9 @@ public class SimpleModelUtils { @@ -646,9 +635,9 @@ public class SimpleModelUtils {
646 node.getConditionGroups()); 635 node.getConditionGroups());
647 } 636 }
648 637
649 - public static String buildConditionExpression(BpmSimpleModelNodeVO.RouteCondition route) {  
650 - return buildConditionExpression(route.getConditionType(), route.getConditionExpression(),  
651 - route.getConditionGroups()); 638 + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterCondition router) {
  639 + return buildConditionExpression(router.getConditionType(), router.getConditionExpression(),
  640 + router.getConditionGroups());
652 } 641 }
653 642
654 public static String buildConditionExpression(Integer conditionType, String conditionExpression, 643 public static String buildConditionExpression(Integer conditionType, String conditionExpression,
@@ -728,18 +717,19 @@ public class SimpleModelUtils { @@ -728,18 +717,19 @@ public class SimpleModelUtils {
728 exclusiveGateway.setId(node.getId()); 717 exclusiveGateway.setId(node.getId());
729 718
730 // 设置默认的序列流(条件) 719 // 设置默认的序列流(条件)
  720 + node.setDefaultFlowId("Flow_" + IdUtil.fastUUID());
731 exclusiveGateway.setDefaultFlow(node.getDefaultFlowId()); 721 exclusiveGateway.setDefaultFlow(node.getDefaultFlowId());
732 return exclusiveGateway; 722 return exclusiveGateway;
733 } 723 }
734 724
735 @Override 725 @Override
736 public BpmSimpleModelNodeType getType() { 726 public BpmSimpleModelNodeType getType() {
737 - return BpmSimpleModelNodeType.ROUTE_BRANCH_NODE; 727 + return BpmSimpleModelNodeType.ROUTER_BRANCH_NODE;
738 } 728 }
739 729
740 - public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouteCondition route) {  
741 - String conditionExpression = ConditionNodeConvert.buildConditionExpression(route);  
742 - return buildBpmnSequenceFlow(nodeId, route.getNodeId(), null, null, conditionExpression); 730 + public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterCondition router) {
  731 + String conditionExpression = ConditionNodeConvert.buildConditionExpression(router);
  732 + return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression);
743 } 733 }
744 734
745 } 735 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -482,6 +482,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -482,6 +482,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
482 if (instance == null) { 482 if (instance == null) {
483 throw exception(PROCESS_INSTANCE_NOT_EXISTS); 483 throw exception(PROCESS_INSTANCE_NOT_EXISTS);
484 } 484 }
  485 + // 1.3 校验签名
  486 + BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
  487 + Boolean signEnable = parseSignEnable(bpmnModel, task.getTaskDefinitionKey());
  488 + if (signEnable && StrUtil.isEmpty(reqVO.getSign())) {
  489 + throw exception(TASK_SIGNATURE_NOT_EXISTS);
  490 + }
485 491
486 // 情况一:被委派的任务,不调用 complete 去完成任务 492 // 情况一:被委派的任务,不调用 complete 去完成任务
487 if (DelegationState.PENDING.equals(task.getDelegationState())) { 493 if (DelegationState.PENDING.equals(task.getDelegationState())) {
@@ -496,8 +502,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -496,8 +502,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
496 } 502 }
497 503
498 // 情况三:审批普通的任务。大多数情况下,都是这样 504 // 情况三:审批普通的任务。大多数情况下,都是这样
499 - // 2.1 更新 task 状态、原因 505 + // 2.1 更新 task 状态、原因、签字
500 updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason()); 506 updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason());
  507 + if (signEnable) {
  508 + taskService.setVariableLocal(task.getId(), BpmnVariableConstants.TASK_VARIABLE_SIGN, reqVO.getSign());
  509 + }
501 // 2.2 添加评论 510 // 2.2 添加评论
502 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), 511 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(),
503 BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); 512 BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason()));
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java
1 package cn.iocoder.yudao.module.bpm.service.task.listener; 1 package cn.iocoder.yudao.module.bpm.service.task.listener;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.hutool.core.lang.Assert;  
5 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
6 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
7 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 5 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
8 import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerParamTypeEnum; 6 import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerParamTypeEnum;
9 -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;  
10 -import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;  
11 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; 7 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
12 import jakarta.annotation.Resource; 8 import jakarta.annotation.Resource;
  9 +import lombok.Setter;
13 import lombok.extern.slf4j.Slf4j; 10 import lombok.extern.slf4j.Slf4j;
14 -import org.flowable.bpmn.model.BpmnModel;  
15 -import org.flowable.bpmn.model.FieldExtension;  
16 -import org.flowable.bpmn.model.FlowableListener;  
17 -import org.flowable.bpmn.model.UserTask;  
18 import org.flowable.engine.delegate.TaskListener; 11 import org.flowable.engine.delegate.TaskListener;
19 import org.flowable.engine.history.HistoricProcessInstance; 12 import org.flowable.engine.history.HistoricProcessInstance;
  13 +import org.flowable.engine.impl.el.FixedValue;
20 import org.flowable.task.service.delegate.DelegateTask; 14 import org.flowable.task.service.delegate.DelegateTask;
  15 +import org.springframework.context.annotation.Scope;
21 import org.springframework.http.HttpEntity; 16 import org.springframework.http.HttpEntity;
22 import org.springframework.http.HttpMethod; 17 import org.springframework.http.HttpMethod;
23 import org.springframework.http.ResponseEntity; 18 import org.springframework.http.ResponseEntity;
24 import org.springframework.stereotype.Component; 19 import org.springframework.stereotype.Component;
25 import org.springframework.util.LinkedMultiValueMap; 20 import org.springframework.util.LinkedMultiValueMap;
26 import org.springframework.util.MultiValueMap; 21 import org.springframework.util.MultiValueMap;
  22 +import org.springframework.web.client.RestClientException;
27 import org.springframework.web.client.RestTemplate; 23 import org.springframework.web.client.RestTemplate;
28 24
29 import java.util.List; 25 import java.util.List;
30 import java.util.Map; 26 import java.util.Map;
31 27
32 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; 28 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  29 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseListenerConfig;
33 30
34 /** 31 /**
35 * BPM 用户任务通用监听器 32 * BPM 用户任务通用监听器
@@ -38,34 +35,32 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ @@ -38,34 +35,32 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_
38 */ 35 */
39 @Component 36 @Component
40 @Slf4j 37 @Slf4j
  38 +@Scope("prototype")
41 public class BpmUserTaskListener implements TaskListener { 39 public class BpmUserTaskListener implements TaskListener {
42 40
43 public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}"; 41 public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}";
44 42
45 @Resource 43 @Resource
46 - private BpmModelService modelService;  
47 -  
48 - @Resource  
49 private BpmProcessInstanceService processInstanceService; 44 private BpmProcessInstanceService processInstanceService;
50 45
51 @Resource 46 @Resource
52 private RestTemplate restTemplate; 47 private RestTemplate restTemplate;
53 48
  49 + @Setter
  50 + private FixedValue listenerConfig;
  51 +
54 @Override 52 @Override
55 public void notify(DelegateTask delegateTask) { 53 public void notify(DelegateTask delegateTask) {
56 // 1. 获取所需基础信息 54 // 1. 获取所需基础信息
57 HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId()); 55 HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId());
58 - BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId());  
59 - UserTask userTask = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());  
60 - BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(),  
61 - userTask.getTaskListeners()); 56 + BpmSimpleModelNodeVO.ListenerHandler listenerHandler = parseListenerConfig(listenerConfig);
62 57
63 // 2. 获取请求头和请求体 58 // 2. 获取请求头和请求体
64 Map<String, Object> processVariables = processInstance.getProcessVariables(); 59 Map<String, Object> processVariables = processInstance.getProcessVariables();
65 MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); 60 MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
66 MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); 61 MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
67 - parseListenerMap(listenerHandler.getHeader(), processVariables, headers);  
68 - parseListenerMap(listenerHandler.getBody(), processVariables, body); 62 + parseListenerParam(listenerHandler.getHeader(), processVariables, headers);
  63 + parseListenerParam(listenerHandler.getBody(), processVariables, body);
69 // 2.1 请求头默认参数 64 // 2.1 请求头默认参数
70 if (StrUtil.isNotEmpty(delegateTask.getTenantId())) { 65 if (StrUtil.isNotEmpty(delegateTask.getTenantId())) {
71 headers.add(HEADER_TENANT_ID, delegateTask.getTenantId()); 66 headers.add(HEADER_TENANT_ID, delegateTask.getTenantId());
@@ -80,21 +75,29 @@ public class BpmUserTaskListener implements TaskListener { @@ -80,21 +75,29 @@ public class BpmUserTaskListener implements TaskListener {
80 // 3. 异步发起请求 75 // 3. 异步发起请求
81 // TODO @芋艿:确认要同步,还是异步 76 // TODO @芋艿:确认要同步,还是异步
82 HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers); 77 HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
83 - // TODO @lesan:可能需要 try catch 哇? RestClientException  
84 - ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST,  
85 - requestEntity, String.class);  
86 - log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]",  
87 - DELEGATE_EXPRESSION,  
88 - delegateTask.getEventName(),  
89 - headers,  
90 - body,  
91 - responseEntity); 78 + try {
  79 + ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST,
  80 + requestEntity, String.class);
  81 + log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]",
  82 + DELEGATE_EXPRESSION,
  83 + delegateTask.getEventName(),
  84 + headers,
  85 + body,
  86 + responseEntity);
  87 + } catch (RestClientException e) {
  88 + log.error("[error][监听器:{},事件类型:{},请求头:{},请求体:{},请求出错:{}]",
  89 + DELEGATE_EXPRESSION,
  90 + delegateTask.getEventName(),
  91 + headers,
  92 + body,
  93 + e.getMessage());
  94 + }
92 // 4. 是否需要后续操作?TODO 芋艿:待定! 95 // 4. 是否需要后续操作?TODO 芋艿:待定!
93 } 96 }
94 97
95 - private void parseListenerMap(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list,  
96 - Map<String, Object> processVariables,  
97 - MultiValueMap<String, String> to) { 98 + private void parseListenerParam(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list,
  99 + Map<String, Object> processVariables,
  100 + MultiValueMap<String, String> to) {
98 if (CollUtil.isEmpty(list)) { 101 if (CollUtil.isEmpty(list)) {
99 return; 102 return;
100 } 103 }
@@ -107,17 +110,4 @@ public class BpmUserTaskListener implements TaskListener { @@ -107,17 +110,4 @@ public class BpmUserTaskListener implements TaskListener {
107 }); 110 });
108 } 111 }
109 112
110 - private BpmSimpleModelNodeVO.ListenerHandler getListenerHandlerByEvent(String eventName, List<FlowableListener> node) {  
111 - FlowableListener flowableListener = node.stream()  
112 - .filter(item -> item.getEvent().equals(eventName))  
113 - .findFirst().orElse(null);  
114 - Assert.notNull(flowableListener, "监听器({})不能为空", flowableListener);  
115 - // TODO @lesan:BpmnModelUtils 提供一个 BpmSimpleModelNodeVO.ListenerHandler 解析方法,尽量收敛掉。  
116 - FieldExtension fieldExtension = flowableListener.getFieldExtensions().stream()  
117 - .filter(item -> item.getFieldName().equals("listenerConfig"))  
118 - .findFirst().orElse(null);  
119 - Assert.notNull(fieldExtension, "监听器扩展字段({})不能为空", fieldExtension);  
120 - return JsonUtils.parseObject(fieldExtension.getStringValue(), BpmSimpleModelNodeVO.ListenerHandler.class);  
121 - }  
122 -  
123 } 113 }
124 \ No newline at end of file 114 \ No newline at end of file