Commit 34c8f4cae1b8539622b0d9e753e10d25fc494967

Authored by 芋道源码
Committed by Gitee
2 parents b5f6545d a13b5820

!1183 Simple设计器-路由分支

Merge pull request !1183 from Lesan/feature/bpm-路由分支
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventType.java
@@ -14,7 +14,7 @@ import lombok.Getter; @@ -14,7 +14,7 @@ import lombok.Getter;
14 public enum BpmBoundaryEventType { 14 public enum BpmBoundaryEventType {
15 15
16 USER_TASK_TIMEOUT(1, "用户任务超时"), 16 USER_TASK_TIMEOUT(1, "用户任务超时"),
17 - DELAY_TIMER_TIMEOUT(2, "触发器超时"); 17 + DELAY_TIMER_TIMEOUT(2, "延迟器超时");
18 18
19 private final Integer type; 19 private final Integer type;
20 private final String name; 20 private final String name;
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmDelayTimerType.java
@@ -7,7 +7,7 @@ import lombok.Getter; @@ -7,7 +7,7 @@ import lombok.Getter;
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 /** 9 /**
10 - * BPM 延时器类型枚举 10 + * BPM 延迟器类型枚举
11 * 11 *
12 * @author Lesan 12 * @author Lesan
13 */ 13 */
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
@@ -33,6 +33,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { @@ -33,6 +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 ; 37 ;
37 38
38 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();
@@ -49,7 +50,8 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { @@ -49,7 +50,8 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
49 public static boolean isBranchNode(Integer type) { 50 public static boolean isBranchNode(Integer type) {
50 return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) 51 return Objects.equals(CONDITION_BRANCH_NODE.getType(), type)
51 || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type) 52 || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type)
52 - || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type); 53 + || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type)
  54 + || Objects.equals(ROUTE_BRANCH_NODE.getType(), type);
53 } 55 }
54 56
55 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
@@ -271,4 +271,31 @@ public class BpmSimpleModelNodeVO { @@ -271,4 +271,31 @@ public class BpmSimpleModelNodeVO {
271 private String delayTime; 271 private String delayTime;
272 } 272 }
273 273
  274 + @Schema(description = "路由分支组", example = "[]")
  275 + private List<RouteCondition> routeGroup;
  276 +
  277 + @Schema(description = "默认分支id", example = "Flow_xxx")
  278 + private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE
  279 +
  280 + @Schema(description = "路由分支")
  281 + @Data
  282 + @Valid
  283 + public static class RouteCondition {
  284 +
  285 + @Schema(description = "节点Id", example = "Activity_xxx")
  286 + @NotEmpty(message = "节点Id不能为空")
  287 + private String nodeId;
  288 +
  289 + @Schema(description = "条件类型", example = "1")
  290 + @InEnum(BpmSimpleModeConditionType.class)
  291 + @NotNull(message = "条件类型不能为空")
  292 + private Integer conditionType;
  293 +
  294 + @Schema(description = "条件表达式", example = "${day>3}")
  295 + private String conditionExpression;
  296 +
  297 + @Schema(description = "条件组", example = "{}")
  298 + private ConditionGroups conditionGroups;
  299 + }
  300 +
274 } 301 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
@@ -106,7 +106,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { @@ -106,7 +106,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
106 BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE); 106 BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE);
107 String taskKey = boundaryEvent.getAttachedToRefId(); 107 String taskKey = boundaryEvent.getAttachedToRefId();
108 taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType)); 108 taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType));
109 - // 2.2 触发器超时处理 109 + // 2.2 延迟器超时处理
110 } else if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT)) { 110 } else if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT)) {
111 String taskKey = boundaryEvent.getAttachedToRefId(); 111 String taskKey = boundaryEvent.getAttachedToRefId();
112 taskService.processDelayTimerTimeout(event.getProcessInstanceId(), taskKey); 112 taskService.processDelayTimerTimeout(event.getProcessInstanceId(), taskKey);
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -42,7 +42,8 @@ public class SimpleModelUtils { @@ -42,7 +42,8 @@ public class SimpleModelUtils {
42 List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(), 42 List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(),
43 new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), 43 new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(),
44 new DelayTimerNodeConvert(), 44 new DelayTimerNodeConvert(),
45 - new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert()); 45 + new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(),
  46 + new RouteBranchNodeConvert());
46 converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); 47 converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert));
47 } 48 }
48 49
@@ -184,10 +185,12 @@ public class SimpleModelUtils { @@ -184,10 +185,12 @@ public class SimpleModelUtils {
184 BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); 185 BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
185 BpmSimpleModelNodeVO childNode = node.getChildNode(); 186 BpmSimpleModelNodeVO childNode = node.getChildNode();
186 List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); 187 List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();
187 - Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); 188 + // TODO @芋艿 路由分支没有conditionNodes 这里注释会影响吗?
  189 +// Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空");
188 // 分支终点节点 ID 190 // 分支终点节点 ID
189 String branchEndNodeId = null; 191 String branchEndNodeId = null;
190 - if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE) { // 条件分支 192 + if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE
  193 + || nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { // 条件分支或路由分支
191 // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID 194 // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID
192 branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; 195 branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId;
193 } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE 196 } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE
@@ -198,31 +201,45 @@ public class SimpleModelUtils { @@ -198,31 +201,45 @@ public class SimpleModelUtils {
198 Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); 201 Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空");
199 202
200 // 3. 遍历分支节点 203 // 3. 遍历分支节点
201 - // 下面的注释,以如下情况举例子。分支 1:A->B->C->D->E,分支 2:A->D->E。其中,A 为分支节点, D 为 A 孩子节点  
202 - for (BpmSimpleModelNodeVO item : conditionNodes) {  
203 - Assert.isTrue(Objects.equals(item.getType(), BpmSimpleModelNodeType.CONDITION_NODE.getType()),  
204 - "条件节点类型({})不符合", item.getType());  
205 - BpmSimpleModelNodeVO conditionChildNode = item.getChildNode();  
206 - // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况  
207 - if (isValidNode(conditionChildNode)) {  
208 - // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线  
209 - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item);  
210 - process.addFlowElement(sequenceFlow);  
211 - // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线  
212 - traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId);  
213 - } else {  
214 - // 3.2 分支没有后续节点。例如说,建立 A->D 的连线  
215 - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item);  
216 - process.addFlowElement(sequenceFlow); 204 + if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) {
  205 + // 路由分支遍历
  206 + for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouteGroup()) {
  207 + SequenceFlow sFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route);
  208 + process.addFlowElement(sFlow);
  209 + }
  210 + } else {
  211 + // 下面的注释,以如下情况举例子。分支 1:A->B->C->D->E,分支 2:A->D->E。其中,A 为分支节点, D 为 A 孩子节点
  212 + for (BpmSimpleModelNodeVO item : conditionNodes) {
  213 + Assert.isTrue(Objects.equals(item.getType(), BpmSimpleModelNodeType.CONDITION_NODE.getType()),
  214 + "条件节点类型({})不符合", item.getType());
  215 + BpmSimpleModelNodeVO conditionChildNode = item.getChildNode();
  216 + // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况
  217 + if (isValidNode(conditionChildNode)) {
  218 + // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线
  219 + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item);
  220 + process.addFlowElement(sequenceFlow);
  221 + // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线
  222 + traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId);
  223 + } else {
  224 + // 3.2 分支没有后续节点。例如说,建立 A->D 的连线
  225 + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item);
  226 + process.addFlowElement(sequenceFlow);
  227 + }
217 } 228 }
218 } 229 }
219 230
220 - // 4. 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线 231 + // 4. 各分支节点所需特殊处理
221 if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE 232 if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE
222 || nodeType == BpmSimpleModelNodeType.INCLUSIVE_BRANCH_NODE ) { 233 || nodeType == BpmSimpleModelNodeType.INCLUSIVE_BRANCH_NODE ) {
  234 + // 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线
223 String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; 235 String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId;
224 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); 236 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId);
225 process.addFlowElement(sequenceFlow); 237 process.addFlowElement(sequenceFlow);
  238 + } else if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) {
  239 + // 如果是路由分支,需要连接后续节点为默认路由
  240 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(),
  241 + null, null);
  242 + process.addFlowElement(sequenceFlow);
226 } 243 }
227 244
228 // 5. 递归调用后续节点 继续递归。例如说,建立 D->E 的连线 245 // 5. 递归调用后续节点 继续递归。例如说,建立 D->E 的连线
@@ -597,12 +614,20 @@ public class SimpleModelUtils { @@ -597,12 +614,20 @@ public class SimpleModelUtils {
597 * @param node 条件节点 614 * @param node 条件节点
598 */ 615 */
599 public static String buildConditionExpression(BpmSimpleModelNodeVO node) { 616 public static String buildConditionExpression(BpmSimpleModelNodeVO node) {
600 - BpmSimpleModeConditionType conditionTypeEnum = BpmSimpleModeConditionType.valueOf(node.getConditionType()); 617 + return buildConditionExpression(node.getConditionType(), node.getConditionExpression(),
  618 + node.getConditionGroups());
  619 + }
  620 + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouteCondition route) {
  621 + return buildConditionExpression(route.getConditionType(), route.getConditionExpression(),
  622 + route.getConditionGroups());
  623 + }
  624 + public static String buildConditionExpression(Integer conditionType, String conditionExpression,
  625 + ConditionGroups conditionGroups) {
  626 + BpmSimpleModeConditionType conditionTypeEnum = BpmSimpleModeConditionType.valueOf(conditionType);
601 if (conditionTypeEnum == BpmSimpleModeConditionType.EXPRESSION) { 627 if (conditionTypeEnum == BpmSimpleModeConditionType.EXPRESSION) {
602 - return node.getConditionExpression(); 628 + return conditionExpression;
603 } 629 }
604 if (conditionTypeEnum == BpmSimpleModeConditionType.RULE) { 630 if (conditionTypeEnum == BpmSimpleModeConditionType.RULE) {
605 - ConditionGroups conditionGroups = node.getConditionGroups();  
606 if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { 631 if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) {
607 return null; 632 return null;
608 } 633 }
@@ -665,6 +690,29 @@ public class SimpleModelUtils { @@ -665,6 +690,29 @@ public class SimpleModelUtils {
665 } 690 }
666 } 691 }
667 692
  693 + public static class RouteBranchNodeConvert implements NodeConvert {
  694 +
  695 + @Override
  696 + public ExclusiveGateway convert(BpmSimpleModelNodeVO node) {
  697 + ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
  698 + exclusiveGateway.setId(node.getId());
  699 +
  700 + // 设置默认的序列流(条件)
  701 + exclusiveGateway.setDefaultFlow(node.getDefaultFlowId());
  702 + return exclusiveGateway;
  703 + }
  704 +
  705 + @Override
  706 + public BpmSimpleModelNodeType getType() {
  707 + return BpmSimpleModelNodeType.ROUTE_BRANCH_NODE;
  708 + }
  709 +
  710 + public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouteCondition route) {
  711 + String conditionExpression = ConditionNodeConvert.buildConditionExpression(route);
  712 + return buildBpmnSequenceFlow(nodeId, route.getNodeId(), null, null, conditionExpression);
  713 + }
  714 + }
  715 +
668 private static String buildGatewayJoinId(String id) { 716 private static String buildGatewayJoinId(String id) {
669 return id + "_join"; 717 return id + "_join";
670 } 718 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
@@ -276,7 +276,7 @@ public interface BpmTaskService { @@ -276,7 +276,7 @@ public interface BpmTaskService {
276 void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType); 276 void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType);
277 277
278 /** 278 /**
279 - * 处理 延时器 超时事件 279 + * 处理 延迟器 超时事件
280 * 280 *
281 * @param processInstanceId 流程示例编号 281 * @param processInstanceId 流程示例编号
282 * @param taskDefineKey 任务 Key 282 * @param taskDefineKey 任务 Key