Commit 34c8f4cae1b8539622b0d9e753e10d25fc494967
Committed by
Gitee
!1183 Simple设计器-路由分支
Merge pull request !1183 from Lesan/feature/bpm-路由分支
Showing
7 changed files
with
105 additions
and
28 deletions
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
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 |