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,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
| @@ -226,4 +226,31 @@ public class BpmSimpleModelNodeVO { | @@ -226,4 +226,31 @@ public class BpmSimpleModelNodeVO { | ||
| 226 | private String delayTime; | 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,7 +38,8 @@ public class SimpleModelUtils { | ||
| 38 | List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(), | 38 | List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(), |
| 39 | new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), | 39 | new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), |
| 40 | new DelayTimerNodeConvert(), | 40 | new DelayTimerNodeConvert(), |
| 41 | - new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert()); | 41 | + new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), |
| 42 | + new RouteBranchNodeConvert()); | ||
| 42 | converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); | 43 | converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); |
| 43 | } | 44 | } |
| 44 | 45 | ||
| @@ -180,10 +181,12 @@ public class SimpleModelUtils { | @@ -180,10 +181,12 @@ public class SimpleModelUtils { | ||
| 180 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); | 181 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); |
| 181 | BpmSimpleModelNodeVO childNode = node.getChildNode(); | 182 | BpmSimpleModelNodeVO childNode = node.getChildNode(); |
| 182 | List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); | 183 | List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); |
| 183 | - Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); | 184 | + // TODO @芋艿 路由分支没有conditionNodes 这里注释会影响吗? |
| 185 | +// Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); | ||
| 184 | // 分支终点节点 ID | 186 | // 分支终点节点 ID |
| 185 | String branchEndNodeId = null; | 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 | // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID | 190 | // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID |
| 188 | branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; | 191 | branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; |
| 189 | } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE | 192 | } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE |
| @@ -194,31 +197,45 @@ public class SimpleModelUtils { | @@ -194,31 +197,45 @@ public class SimpleModelUtils { | ||
| 194 | Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); | 197 | Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); |
| 195 | 198 | ||
| 196 | // 3. 遍历分支节点 | 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 | if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE | 228 | if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE |
| 218 | || nodeType == BpmSimpleModelNodeType.INCLUSIVE_BRANCH_NODE ) { | 229 | || nodeType == BpmSimpleModelNodeType.INCLUSIVE_BRANCH_NODE ) { |
| 230 | + // 如果是并行分支、包容分支,由于是程序创建的聚合网关,需要手工创建聚合网关和下一个节点的连线 | ||
| 219 | String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; | 231 | String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; |
| 220 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); | 232 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); |
| 221 | process.addFlowElement(sequenceFlow); | 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 | // 5. 递归调用后续节点 继续递归。例如说,建立 D->E 的连线 | 241 | // 5. 递归调用后续节点 继续递归。例如说,建立 D->E 的连线 |
| @@ -576,12 +593,20 @@ public class SimpleModelUtils { | @@ -576,12 +593,20 @@ public class SimpleModelUtils { | ||
| 576 | * @param node 条件节点 | 593 | * @param node 条件节点 |
| 577 | */ | 594 | */ |
| 578 | public static String buildConditionExpression(BpmSimpleModelNodeVO node) { | 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 | if (conditionTypeEnum == BpmSimpleModeConditionType.EXPRESSION) { | 606 | if (conditionTypeEnum == BpmSimpleModeConditionType.EXPRESSION) { |
| 581 | - return node.getConditionExpression(); | 607 | + return conditionExpression; |
| 582 | } | 608 | } |
| 583 | if (conditionTypeEnum == BpmSimpleModeConditionType.RULE) { | 609 | if (conditionTypeEnum == BpmSimpleModeConditionType.RULE) { |
| 584 | - ConditionGroups conditionGroups = node.getConditionGroups(); | ||
| 585 | if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { | 610 | if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { |
| 586 | return null; | 611 | return null; |
| 587 | } | 612 | } |
| @@ -644,6 +669,29 @@ public class SimpleModelUtils { | @@ -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 | private static String buildGatewayJoinId(String id) { | 695 | private static String buildGatewayJoinId(String id) { |
| 648 | return id + "_join"; | 696 | return id + "_join"; |
| 649 | } | 697 | } |