Commit a13b58200948bc269c1746073f79e7473cfbafe1

Authored by Lesan
1 parent 8b91b471

feat: Simple设计器-路由分支

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 }