Commit 65a09182e714f25f8696300c14a06263f042ae4b

Authored by jason
1 parent d9ca52a4

仿钉钉流程设计- code review 构建节点连线修改

yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -25,7 +25,7 @@ import java.util.Map; @@ -25,7 +25,7 @@ import java.util.Map;
25 import java.util.Objects; 25 import java.util.Objects;
26 26
27 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT; 27 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT;
28 -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_NODE; 28 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*;
29 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER; 29 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER;
30 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; 30 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
31 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*; 31 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*;
@@ -84,78 +84,128 @@ public class SimpleModelUtils { @@ -84,78 +84,128 @@ public class SimpleModelUtils {
84 EndEvent endEvent = (EndEvent) CollUtil.findOne(process.getFlowElements(), item -> item instanceof EndEvent); 84 EndEvent endEvent = (EndEvent) CollUtil.findOne(process.getFlowElements(), item -> item instanceof EndEvent);
85 85
86 // 构建并添加节点之间的连线 Sequence Flow 86 // 构建并添加节点之间的连线 Sequence Flow
87 - buildAndAddBpmnSequenceFlow(process, simpleModelNode, endEvent.getId()); 87 + traverseNodeToBuildSequenceFlow(process, simpleModelNode, endEvent.getId());
88 // 自动布局 88 // 自动布局
89 new BpmnAutoLayout(bpmnModel).execute(); 89 new BpmnAutoLayout(bpmnModel).execute();
90 return bpmnModel; 90 return bpmnModel;
91 } 91 }
92 92
93 - private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) {  
94 - // 节点为 null 或者 为END_EVENT 退出  
95 - // TODO @jason:isValidNode;然后把 END_NODE 是不是拿到 switch (nodeType) { 那 return 哈?这样出口更统一一点?  
96 - if (node == null || node.getId() == null || END_NODE.getType().equals(node.getType())) { 93 + private static void traverseNodeToBuildSequenceFlow(Process process, BpmSimpleModelNodeVO node, String targetNodeId) {
  94 + // 1.无效节点返回
  95 + if (!isValidNode(node)) {
97 return; 96 return;
98 } 97 }
99 - BpmSimpleModelNodeVO childNode = node.getChildNode(); 98 +
100 // 如果是网关分支节点. 后续节点可能为 null。但不是 END_EVENT 节点 99 // 如果是网关分支节点. 后续节点可能为 null。但不是 END_EVENT 节点
101 - // TODO @芋艿:这个要不要挪到 START_NODE - INCLUSIVE_BRANCH_JOIN_NODE 待定;感觉 switch 那最终是分三个情况;branch、子节点、结束了;(每种情况的注释,需要写的更完整)  
102 - if (!BpmSimpleModelNodeType.isBranchNode(node.getType()) && (childNode == null || childNode.getId() == null)) {  
103 - SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetId, null, null, null);  
104 - mainProcess.addFlowElement(sequenceFlow);  
105 - return;  
106 - } 100 + // TODO-DONE @芋艿:这个要不要挪到 START_NODE - INCLUSIVE_BRANCH_JOIN_NODE 待定;感觉 switch 那最终是分三个情况;branch、子节点、结束了;(每种情况的注释,需要写的更完整)
  101 +// if (!BpmSimpleModelNodeType.isBranchNode(node.getType()) && (childNode == null || childNode.getId() == null)) {
  102 +// SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetNodeId, null, null, null);
  103 +// process.addFlowElement(sequenceFlow);
  104 +// return;
  105 +// }
107 BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); 106 BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
108 Assert.notNull(nodeType, "模型节点类型不支持"); 107 Assert.notNull(nodeType, "模型节点类型不支持");
109 - // TODO @jason:下面的 PARALLEL_BRANCH_FORK_NODE、CONDITION_BRANCH_NODE、INCLUSIVE_BRANCH_FORK_NODE 是不是就是 isBranchNode?如果是的话,貌似不用 swtich,而是 if else 分类处理呢。  
110 - switch (nodeType) {  
111 - case START_NODE:  
112 - case APPROVE_NODE:  
113 - case COPY_NODE:  
114 - case PARALLEL_BRANCH_JOIN_NODE:  
115 - case INCLUSIVE_BRANCH_JOIN_NODE: { 108 + BpmSimpleModelNodeVO childNode = node.getChildNode();
  109 + // 2.1 普通节点
  110 + if (!BpmSimpleModelNodeType.isBranchNode(node.getType())) {
  111 + // 2.1.1 结束节点退出递归
  112 + if (nodeType == END_NODE) {
  113 + return;
  114 + }
  115 + if (!isValidNode(childNode)) {
  116 + // 2.1.2 普通节点且无孩子节点。分两种情况
  117 + // a.结束节点 b. 条件分支的最后一个节点.与分支节点的孩子节点或聚合节点建立连线。
  118 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetNodeId, null, null, null);
  119 + process.addFlowElement(sequenceFlow);
  120 + } else {
  121 + // 2.1.3 普通节点且有孩子节点。建立连线
116 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null); 122 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null);
117 - mainProcess.addFlowElement(sequenceFlow); 123 + process.addFlowElement(sequenceFlow);
118 // 递归调用后续节点 124 // 递归调用后续节点
119 - buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId);  
120 - break; 125 + traverseNodeToBuildSequenceFlow(process, childNode, targetNodeId);
121 } 126 }
122 - case PARALLEL_BRANCH_FORK_NODE:  
123 - case CONDITION_BRANCH_NODE:  
124 - case INCLUSIVE_BRANCH_FORK_NODE: {  
125 - // TODO @jason:这里 sequenceFlowTargetId 不建议做这样的 default。万一可能有 bug 哈;直接弄到对应的 136- 146 会更安全一点。  
126 - String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? targetId : childNode.getId();  
127 - List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();  
128 - Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空");  
129 - for (BpmSimpleModelNodeVO item : conditionNodes) {  
130 - // 构建表达式  
131 - // TODO @jason:条件分支的情况下,需要分 item 搞的条件,和 conditionNodes 搞的条件  
132 - String conditionExpression = buildConditionExpression(item);  
133 -  
134 - BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode();  
135 - // TODO @jason:isValidNode  
136 - if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) {  
137 - // TODO @jason:会存在 item.name 未空的情况么?这个时候,要不要兜底处理拼接  
138 - SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(),  
139 - item.getId(), item.getName(), conditionExpression);  
140 - mainProcess.addFlowElement(sequenceFlow);  
141 - // 递归调用后续节点  
142 - // TODO @jason:最好也有个例子,嘿嘿;S4  
143 - buildAndAddBpmnSequenceFlow(mainProcess, nextNodeOnCondition, sequenceFlowTargetId);  
144 - } else {  
145 - SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), sequenceFlowTargetId,  
146 - item.getId(), item.getName(), conditionExpression);  
147 - mainProcess.addFlowElement(sequenceFlow);  
148 - } 127 + } else {
  128 + // 2.2 分支节点
  129 + List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();
  130 + Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空");
  131 + // 4.1 分支节点,遍历分支节点. 如下情况:
  132 + // 分支1、A->B->C->D->E 和 分支2、A->D->E。 A为分支节点, D为A孩子节点
  133 + // 分支终点节点, 1. 分支节点有孩子节点时为孩子节点 2. 当分支节点孩子为无效节点时。分支嵌套时并且为分支最后一个节点
  134 + String branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId ;
  135 + for (BpmSimpleModelNodeVO item : conditionNodes) {
  136 + // TODO @jason:条件分支的情况下,需要分 item 搞的条件,和 conditionNodes 搞的条件
  137 + // 构建表达式
  138 + String conditionExpression = buildConditionExpression(item);
  139 + BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode();
  140 + // 4.2 分支有后续节点, 分支1: A->B->C->D
  141 + if (isValidNode(nextNodeOnCondition)) {
  142 + // 4.2.1 建立 A->B
  143 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(),
  144 + item.getId(), item.getName(), conditionExpression);
  145 + process.addFlowElement(sequenceFlow);
  146 + // 4.2.2 递归调用后续节点连线。 建立 B->C->D 的连线
  147 + traverseNodeToBuildSequenceFlow(process, nextNodeOnCondition, branchEndNodeId);
  148 + } else {
  149 + // 4.3 分支无后续节点 建立 A->D
  150 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId,
  151 + item.getId(), item.getName(), conditionExpression);
  152 + process.addFlowElement(sequenceFlow);
149 } 153 }
150 - // 递归调用后续节点 TODO @jason:最好有个例子哈  
151 - buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId);  
152 - break;  
153 - }  
154 - default: {  
155 - // TODO 其它节点类型的实现  
156 } 154 }
  155 + // 递归调用后续节点 继续递归建立 D->E 的连线
  156 + traverseNodeToBuildSequenceFlow(process, childNode, targetNodeId);
157 } 157 }
158 158
  159 + // TODO @jason:下面的 PARALLEL_BRANCH_FORK_NODE、CONDITION_BRANCH_NODE、INCLUSIVE_BRANCH_FORK_NODE 是不是就是 isBranchNode?如果是的话,貌似不用 swtich,而是 if else 分类处理呢。
  160 +// switch (nodeType) {
  161 +// case START_NODE:
  162 +// case APPROVE_NODE:
  163 +// case COPY_NODE:
  164 +// case PARALLEL_BRANCH_JOIN_NODE:
  165 +// case INCLUSIVE_BRANCH_JOIN_NODE: {
  166 +// SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null);
  167 +// process.addFlowElement(sequenceFlow);
  168 +// // 递归调用后续节点
  169 +// buildAndAddBpmnSequenceFlow(process, childNode, targetNodeId);
  170 +// break;
  171 +// }
  172 +// case PARALLEL_BRANCH_FORK_NODE:
  173 +// case CONDITION_BRANCH_NODE:
  174 +// case INCLUSIVE_BRANCH_FORK_NODE: {
  175 +// // TODO @jason:这里 sequenceFlowTargetId 不建议做这样的 default。万一可能有 bug 哈;直接弄到对应的 136- 146 会更安全一点。
  176 +// String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? targetNodeId : childNode.getId();
  177 +// List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();
  178 +// Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空");
  179 +// for (BpmSimpleModelNodeVO item : conditionNodes) {
  180 +// // 构建表达式
  181 +// // TODO @jason:条件分支的情况下,需要分 item 搞的条件,和 conditionNodes 搞的条件
  182 +// String conditionExpression = buildConditionExpression(item);
  183 +//
  184 +// BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode();
  185 +// // TODO @jason:isValidNode
  186 +// if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) {
  187 +// // TODO @jason:会存在 item.name 未空的情况么?这个时候,要不要兜底处理拼接
  188 +// SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(),
  189 +// item.getId(), item.getName(), conditionExpression);
  190 +// process.addFlowElement(sequenceFlow);
  191 +// // 递归调用后续节点
  192 +// // TODO @jason:最好也有个例子,嘿嘿;S4
  193 +// buildAndAddBpmnSequenceFlow(process, nextNodeOnCondition, sequenceFlowTargetId);
  194 +// } else {
  195 +// SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), sequenceFlowTargetId,
  196 +// item.getId(), item.getName(), conditionExpression);
  197 +// process.addFlowElement(sequenceFlow);
  198 +// }
  199 +// }
  200 +// // 递归调用后续节点 TODO @jason:最好有个例子哈
  201 +// buildAndAddBpmnSequenceFlow(process, childNode, targetNodeId);
  202 +// break;
  203 +// }
  204 +// default: {
  205 +// // TODO 其它节点类型的实现
  206 +// }
  207 +// }
  208 +
159 } 209 }
160 210
161 /** 211 /**
@@ -283,6 +333,7 @@ public class SimpleModelUtils { @@ -283,6 +333,7 @@ public class SimpleModelUtils {
283 list.add(parallelGateway); 333 list.add(parallelGateway);
284 break; 334 break;
285 } 335 }
  336 +
286 case INCLUSIVE_BRANCH_FORK_NODE: { 337 case INCLUSIVE_BRANCH_FORK_NODE: {
287 InclusiveGateway inclusiveGateway = convertInclusiveBranchNode(node, Boolean.TRUE); 338 InclusiveGateway inclusiveGateway = convertInclusiveBranchNode(node, Boolean.TRUE);
288 list.add(inclusiveGateway); 339 list.add(inclusiveGateway);