Commit a13b58200948bc269c1746073f79e7473cfbafe1
1 parent
8b91b471
feat: Simple设计器-路由分支
Showing
3 changed files
with
101 additions
and
24 deletions
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
| ... | ... | @@ -226,4 +226,31 @@ public class BpmSimpleModelNodeVO { |
| 226 | 226 | private String delayTime; |
| 227 | 227 | } |
| 228 | 228 | |
| 229 | + @Schema(description = "路由分支组", example = "[]") | |
| 230 | + private List<RouteCondition> routeGroup; | |
| 231 | + | |
| 232 | + @Schema(description = "默认分支id", example = "Flow_xxx") | |
| 233 | + private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE | |
| 234 | + | |
| 235 | + @Schema(description = "路由分支") | |
| 236 | + @Data | |
| 237 | + @Valid | |
| 238 | + public static class RouteCondition { | |
| 239 | + | |
| 240 | + @Schema(description = "节点Id", example = "Activity_xxx") | |
| 241 | + @NotEmpty(message = "节点Id不能为空") | |
| 242 | + private String nodeId; | |
| 243 | + | |
| 244 | + @Schema(description = "条件类型", example = "1") | |
| 245 | + @InEnum(BpmSimpleModeConditionType.class) | |
| 246 | + @NotNull(message = "条件类型不能为空") | |
| 247 | + private Integer conditionType; | |
| 248 | + | |
| 249 | + @Schema(description = "条件表达式", example = "${day>3}") | |
| 250 | + private String conditionExpression; | |
| 251 | + | |
| 252 | + @Schema(description = "条件组", example = "{}") | |
| 253 | + private ConditionGroups conditionGroups; | |
| 254 | + } | |
| 255 | + | |
| 229 | 256 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| ... | ... | @@ -38,7 +38,8 @@ public class SimpleModelUtils { |
| 38 | 38 | List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(), |
| 39 | 39 | new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), |
| 40 | 40 | new DelayTimerNodeConvert(), |
| 41 | - new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert()); | |
| 41 | + new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), | |
| 42 | + new RouteBranchNodeConvert()); | |
| 42 | 43 | converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); |
| 43 | 44 | } |
| 44 | 45 | |
| ... | ... | @@ -180,10 +181,12 @@ public class SimpleModelUtils { |
| 180 | 181 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); |
| 181 | 182 | BpmSimpleModelNodeVO childNode = node.getChildNode(); |
| 182 | 183 | List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); |
| 183 | - Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); | |
| 184 | + // TODO @芋艿 路由分支没有conditionNodes 这里注释会影响吗? | |
| 185 | +// Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); | |
| 184 | 186 | // 分支终点节点 ID |
| 185 | 187 | String branchEndNodeId = null; |
| 186 | - if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE) { // 条件分支 | |
| 188 | + if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE | |
| 189 | + || nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { // 条件分支或路由分支 | |
| 187 | 190 | // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID |
| 188 | 191 | branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; |
| 189 | 192 | } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE |
| ... | ... | @@ -194,31 +197,45 @@ public class SimpleModelUtils { |
| 194 | 197 | Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); |
| 195 | 198 | |
| 196 | 199 | // 3. 遍历分支节点 |
| 197 | - // 下面的注释,以如下情况举例子。分支 1:A->B->C->D->E,分支 2:A->D->E。其中,A 为分支节点, D 为 A 孩子节点 | |
| 198 | - for (BpmSimpleModelNodeVO item : conditionNodes) { | |
| 199 | - Assert.isTrue(Objects.equals(item.getType(), BpmSimpleModelNodeType.CONDITION_NODE.getType()), | |
| 200 | - "条件节点类型({})不符合", item.getType()); | |
| 201 | - BpmSimpleModelNodeVO conditionChildNode = item.getChildNode(); | |
| 202 | - // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况 | |
| 203 | - if (isValidNode(conditionChildNode)) { | |
| 204 | - // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线 | |
| 205 | - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item); | |
| 206 | - process.addFlowElement(sequenceFlow); | |
| 207 | - // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线 | |
| 208 | - traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId); | |
| 209 | - } else { | |
| 210 | - // 3.2 分支没有后续节点。例如说,建立 A->D 的连线 | |
| 211 | - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item); | |
| 212 | - process.addFlowElement(sequenceFlow); | |
| 200 | + if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { | |
| 201 | + // 路由分支遍历 | |
| 202 | + for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouteGroup()) { | |
| 203 | + SequenceFlow sFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route); | |
| 204 | + process.addFlowElement(sFlow); | |
| 205 | + } | |
| 206 | + } else { | |
| 207 | + // 下面的注释,以如下情况举例子。分支 1:A->B->C->D->E,分支 2:A->D->E。其中,A 为分支节点, D 为 A 孩子节点 | |
| 208 | + for (BpmSimpleModelNodeVO item : conditionNodes) { | |
| 209 | + Assert.isTrue(Objects.equals(item.getType(), BpmSimpleModelNodeType.CONDITION_NODE.getType()), | |
| 210 | + "条件节点类型({})不符合", item.getType()); | |
| 211 | + BpmSimpleModelNodeVO conditionChildNode = item.getChildNode(); | |
| 212 | + // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况 | |
| 213 | + if (isValidNode(conditionChildNode)) { | |
| 214 | + // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线 | |
| 215 | + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item); | |
| 216 | + process.addFlowElement(sequenceFlow); | |
| 217 | + // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线 | |
| 218 | + traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId); | |
| 219 | + } else { | |
| 220 | + // 3.2 分支没有后续节点。例如说,建立 A->D 的连线 | |
| 221 | + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item); | |
| 222 | + process.addFlowElement(sequenceFlow); | |
| 223 | + } | |
| 213 | 224 | } |
| 214 | 225 | } |
| 215 | 226 | |
| 216 | - // 4. 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线 | |
| 227 | + // 4. 各分支节点所需特殊处理 | |
| 217 | 228 | if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE |
| 218 | 229 | || nodeType == BpmSimpleModelNodeType.INCLUSIVE_BRANCH_NODE ) { |
| 230 | + // 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线 | |
| 219 | 231 | String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; |
| 220 | 232 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); |
| 221 | 233 | process.addFlowElement(sequenceFlow); |
| 234 | + } else if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { | |
| 235 | + // 如果是路由分支,需要连接后续节点为默认路由 | |
| 236 | + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(), | |
| 237 | + null, null); | |
| 238 | + process.addFlowElement(sequenceFlow); | |
| 222 | 239 | } |
| 223 | 240 | |
| 224 | 241 | // 5. 递归调用后续节点 继续递归。例如说,建立 D->E 的连线 |
| ... | ... | @@ -576,12 +593,20 @@ public class SimpleModelUtils { |
| 576 | 593 | * @param node 条件节点 |
| 577 | 594 | */ |
| 578 | 595 | public static String buildConditionExpression(BpmSimpleModelNodeVO node) { |
| 579 | - BpmSimpleModeConditionType conditionTypeEnum = BpmSimpleModeConditionType.valueOf(node.getConditionType()); | |
| 596 | + return buildConditionExpression(node.getConditionType(), node.getConditionExpression(), | |
| 597 | + node.getConditionGroups()); | |
| 598 | + } | |
| 599 | + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouteCondition route) { | |
| 600 | + return buildConditionExpression(route.getConditionType(), route.getConditionExpression(), | |
| 601 | + route.getConditionGroups()); | |
| 602 | + } | |
| 603 | + public static String buildConditionExpression(Integer conditionType, String conditionExpression, | |
| 604 | + ConditionGroups conditionGroups) { | |
| 605 | + BpmSimpleModeConditionType conditionTypeEnum = BpmSimpleModeConditionType.valueOf(conditionType); | |
| 580 | 606 | if (conditionTypeEnum == BpmSimpleModeConditionType.EXPRESSION) { |
| 581 | - return node.getConditionExpression(); | |
| 607 | + return conditionExpression; | |
| 582 | 608 | } |
| 583 | 609 | if (conditionTypeEnum == BpmSimpleModeConditionType.RULE) { |
| 584 | - ConditionGroups conditionGroups = node.getConditionGroups(); | |
| 585 | 610 | if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { |
| 586 | 611 | return null; |
| 587 | 612 | } |
| ... | ... | @@ -644,6 +669,29 @@ public class SimpleModelUtils { |
| 644 | 669 | } |
| 645 | 670 | } |
| 646 | 671 | |
| 672 | + public static class RouteBranchNodeConvert implements NodeConvert { | |
| 673 | + | |
| 674 | + @Override | |
| 675 | + public ExclusiveGateway convert(BpmSimpleModelNodeVO node) { | |
| 676 | + ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); | |
| 677 | + exclusiveGateway.setId(node.getId()); | |
| 678 | + | |
| 679 | + // 设置默认的序列流(条件) | |
| 680 | + exclusiveGateway.setDefaultFlow(node.getDefaultFlowId()); | |
| 681 | + return exclusiveGateway; | |
| 682 | + } | |
| 683 | + | |
| 684 | + @Override | |
| 685 | + public BpmSimpleModelNodeType getType() { | |
| 686 | + return BpmSimpleModelNodeType.ROUTE_BRANCH_NODE; | |
| 687 | + } | |
| 688 | + | |
| 689 | + public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouteCondition route) { | |
| 690 | + String conditionExpression = ConditionNodeConvert.buildConditionExpression(route); | |
| 691 | + return buildBpmnSequenceFlow(nodeId, route.getNodeId(), null, null, conditionExpression); | |
| 692 | + } | |
| 693 | + } | |
| 694 | + | |
| 647 | 695 | private static String buildGatewayJoinId(String id) { |
| 648 | 696 | return id + "_join"; |
| 649 | 697 | } | ... | ... |