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
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 | 33 | CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), |
| 34 | 34 | PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), |
| 35 | 35 | INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), |
| 36 | + ROUTE_BRANCH_NODE(54, "路由分支", "exclusiveGateway") | |
| 36 | 37 | ; |
| 37 | 38 | |
| 38 | 39 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); |
| ... | ... | @@ -49,7 +50,8 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { |
| 49 | 50 | public static boolean isBranchNode(Integer type) { |
| 50 | 51 | return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) |
| 51 | 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 | 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 | 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 | 106 | BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_TYPE); |
| 107 | 107 | String taskKey = boundaryEvent.getAttachedToRefId(); |
| 108 | 108 | taskService.processTaskTimeout(event.getProcessInstanceId(), taskKey, NumberUtils.parseInt(timeoutHandlerType)); |
| 109 | - // 2.2 触发器超时处理 | |
| 109 | + // 2.2 延迟器超时处理 | |
| 110 | 110 | } else if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventType.DELAY_TIMER_TIMEOUT)) { |
| 111 | 111 | String taskKey = boundaryEvent.getAttachedToRefId(); |
| 112 | 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 | 42 | List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(), |
| 43 | 43 | new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), |
| 44 | 44 | new DelayTimerNodeConvert(), |
| 45 | - new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert()); | |
| 45 | + new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), | |
| 46 | + new RouteBranchNodeConvert()); | |
| 46 | 47 | converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); |
| 47 | 48 | } |
| 48 | 49 | |
| ... | ... | @@ -184,10 +185,12 @@ public class SimpleModelUtils { |
| 184 | 185 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); |
| 185 | 186 | BpmSimpleModelNodeVO childNode = node.getChildNode(); |
| 186 | 187 | List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); |
| 187 | - Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); | |
| 188 | + // TODO @芋艿 路由分支没有conditionNodes 这里注释会影响吗? | |
| 189 | +// Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); | |
| 188 | 190 | // 分支终点节点 ID |
| 189 | 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 | 194 | // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID |
| 192 | 195 | branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; |
| 193 | 196 | } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE |
| ... | ... | @@ -198,31 +201,45 @@ public class SimpleModelUtils { |
| 198 | 201 | Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); |
| 199 | 202 | |
| 200 | 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 | 232 | if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE |
| 222 | 233 | || nodeType == BpmSimpleModelNodeType.INCLUSIVE_BRANCH_NODE ) { |
| 234 | + // 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线 | |
| 223 | 235 | String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; |
| 224 | 236 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); |
| 225 | 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 | 245 | // 5. 递归调用后续节点 继续递归。例如说,建立 D->E 的连线 |
| ... | ... | @@ -597,12 +614,20 @@ public class SimpleModelUtils { |
| 597 | 614 | * @param node 条件节点 |
| 598 | 615 | */ |
| 599 | 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 | 627 | if (conditionTypeEnum == BpmSimpleModeConditionType.EXPRESSION) { |
| 602 | - return node.getConditionExpression(); | |
| 628 | + return conditionExpression; | |
| 603 | 629 | } |
| 604 | 630 | if (conditionTypeEnum == BpmSimpleModeConditionType.RULE) { |
| 605 | - ConditionGroups conditionGroups = node.getConditionGroups(); | |
| 606 | 631 | if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { |
| 607 | 632 | return null; |
| 608 | 633 | } |
| ... | ... | @@ -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 | 716 | private static String buildGatewayJoinId(String id) { |
| 669 | 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 | 276 | void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType); |
| 277 | 277 | |
| 278 | 278 | /** |
| 279 | - * 处理 延时器 超时事件 | |
| 279 | + * 处理 延迟器 超时事件 | |
| 280 | 280 | * |
| 281 | 281 | * @param processInstanceId 流程示例编号 |
| 282 | 282 | * @param taskDefineKey 任务 Key | ... | ... |