Commit d9a2849ccec0613bf55365be1048b11cd55518c1
1 parent
8a3b6c3e
仿钉钉流程设计- code review 修改。新增并行分支节点
Showing
2 changed files
with
51 additions
and
25 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
| @@ -25,12 +25,14 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | @@ -25,12 +25,14 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | ||
| 25 | APPROVE_NODE(1, "审批人节点"), // TODO @jaosn:是不是这里从 10 开始好点;相当于说,0-9 给开始和结束;10-19 给各种节点;20-29 给各种条件; TODO 后面改改 | 25 | APPROVE_NODE(1, "审批人节点"), // TODO @jaosn:是不是这里从 10 开始好点;相当于说,0-9 给开始和结束;10-19 给各种节点;20-29 给各种条件; TODO 后面改改 |
| 26 | COPY_NODE(2, "抄送人节点"), | 26 | COPY_NODE(2, "抄送人节点"), |
| 27 | 27 | ||
| 28 | + CONDITION_NODE(3, "条件节点"), // 用于构建流转条件的表达式 | ||
| 28 | CONDITION_BRANCH_NODE(4, "条件分支节点"), // TODO @jason:是不是改成叫 条件分支? | 29 | CONDITION_BRANCH_NODE(4, "条件分支节点"), // TODO @jason:是不是改成叫 条件分支? |
| 29 | - PARALLEL_BRANCH_FORK_NODE(5, "并行分支分叉节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦? 后面是否去掉并行网关。只用包容网关 | ||
| 30 | - PARALLEL_BRANCH_JOIN_NODE(6, "并行分支聚合节点"), | 30 | + PARALLEL_BRANCH_NODE(5, "并行分支节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦? 后面是否去掉并行网关。只用包容网关 |
| 31 | +// PARALLEL_BRANCH_JOIN_NODE(6, "并行分支聚合节点"), | ||
| 31 | INCLUSIVE_BRANCH_FORK_NODE(7, "包容网关分叉节点"), | 32 | INCLUSIVE_BRANCH_FORK_NODE(7, "包容网关分叉节点"), |
| 32 | INCLUSIVE_BRANCH_JOIN_NODE(8, "包容网关聚合节点"), | 33 | INCLUSIVE_BRANCH_JOIN_NODE(8, "包容网关聚合节点"), |
| 33 | // TODO @jason:建议整合 join,最终只有 条件分支、并行分支、包容分支,三种~ | 34 | // TODO @jason:建议整合 join,最终只有 条件分支、并行分支、包容分支,三种~ |
| 35 | + // TODO @芋艿。 感觉还是分开好理解一点,也好处理一点。前端结构中把聚合节点显示并传过来。 | ||
| 34 | ; | 36 | ; |
| 35 | 37 | ||
| 36 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); | 38 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); |
| @@ -45,7 +47,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | @@ -45,7 +47,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | ||
| 45 | */ | 47 | */ |
| 46 | public static boolean isBranchNode(Integer type) { | 48 | public static boolean isBranchNode(Integer type) { |
| 47 | return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) | 49 | return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) |
| 48 | - || Objects.equals(PARALLEL_BRANCH_FORK_NODE.getType(), type) | 50 | + || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type) |
| 49 | || Objects.equals(INCLUSIVE_BRANCH_FORK_NODE.getType(), type) ; | 51 | || Objects.equals(INCLUSIVE_BRANCH_FORK_NODE.getType(), type) ; |
| 50 | } | 52 | } |
| 51 | 53 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| @@ -38,6 +38,11 @@ import static org.flowable.bpmn.constants.BpmnXMLConstants.*; | @@ -38,6 +38,11 @@ import static org.flowable.bpmn.constants.BpmnXMLConstants.*; | ||
| 38 | */ | 38 | */ |
| 39 | public class SimpleModelUtils { | 39 | public class SimpleModelUtils { |
| 40 | 40 | ||
| 41 | + /** | ||
| 42 | + * 聚合网关节点 Id 后缀 | ||
| 43 | + */ | ||
| 44 | + public static final String JOIN_GATE_WAY_NODE_ID_SUFFIX = "_join"; | ||
| 45 | + | ||
| 41 | public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}"; | 46 | public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}"; |
| 42 | 47 | ||
| 43 | /** | 48 | /** |
| @@ -105,20 +110,20 @@ public class SimpleModelUtils { | @@ -105,20 +110,20 @@ public class SimpleModelUtils { | ||
| 105 | // } | 110 | // } |
| 106 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); | 111 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); |
| 107 | Assert.notNull(nodeType, "模型节点类型不支持"); | 112 | Assert.notNull(nodeType, "模型节点类型不支持"); |
| 113 | + | ||
| 114 | + if (nodeType == END_NODE) { | ||
| 115 | + return; | ||
| 116 | + } | ||
| 108 | BpmSimpleModelNodeVO childNode = node.getChildNode(); | 117 | BpmSimpleModelNodeVO childNode = node.getChildNode(); |
| 109 | // 2.1 普通节点 | 118 | // 2.1 普通节点 |
| 110 | if (!BpmSimpleModelNodeType.isBranchNode(node.getType())) { | 119 | if (!BpmSimpleModelNodeType.isBranchNode(node.getType())) { |
| 111 | - // 2.1.1 结束节点退出递归 | ||
| 112 | - if (nodeType == END_NODE) { | ||
| 113 | - return; | ||
| 114 | - } | ||
| 115 | if (!isValidNode(childNode)) { | 120 | if (!isValidNode(childNode)) { |
| 116 | - // 2.1.2 普通节点且无孩子节点。分两种情况 | 121 | + // 2.1.1 普通节点且无孩子节点。分两种情况 |
| 117 | // a.结束节点 b. 条件分支的最后一个节点.与分支节点的孩子节点或聚合节点建立连线。 | 122 | // a.结束节点 b. 条件分支的最后一个节点.与分支节点的孩子节点或聚合节点建立连线。 |
| 118 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetNodeId, null, null, null); | 123 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetNodeId, null, null, null); |
| 119 | process.addFlowElement(sequenceFlow); | 124 | process.addFlowElement(sequenceFlow); |
| 120 | } else { | 125 | } else { |
| 121 | - // 2.1.3 普通节点且有孩子节点。建立连线 | 126 | + // 2.1.2 普通节点且有孩子节点。建立连线 |
| 122 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null); | 127 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null); |
| 123 | process.addFlowElement(sequenceFlow); | 128 | process.addFlowElement(sequenceFlow); |
| 124 | // 递归调用后续节点 | 129 | // 递归调用后续节点 |
| @@ -128,31 +133,48 @@ public class SimpleModelUtils { | @@ -128,31 +133,48 @@ public class SimpleModelUtils { | ||
| 128 | // 2.2 分支节点 | 133 | // 2.2 分支节点 |
| 129 | List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); | 134 | List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); |
| 130 | Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); | 135 | Assert.notEmpty(conditionNodes, "分支节点的条件节点不能为空"); |
| 131 | - // 4.1 分支节点,遍历分支节点. 如下情况: | 136 | + // 分支终点节点 Id |
| 137 | + String branchEndNodeId = null; | ||
| 138 | + if (nodeType == CONDITION_BRANCH_NODE) { // 条件分支 | ||
| 139 | + // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点Id | ||
| 140 | + branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; | ||
| 141 | + } else if (nodeType == PARALLEL_BRANCH_NODE) { // 并行分支 | ||
| 142 | + // 分支节点:分支终点节点 Id 为程序创建的网关集合节点。目前不会从前端传入。 | ||
| 143 | + branchEndNodeId = node.getId() + JOIN_GATE_WAY_NODE_ID_SUFFIX; | ||
| 144 | + } | ||
| 145 | + // TODO 包容网关待实现 | ||
| 146 | + Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); | ||
| 147 | + // 3.1 遍历分支节点. 如下情况: | ||
| 132 | // 分支1、A->B->C->D->E 和 分支2、A->D->E。 A为分支节点, D为A孩子节点 | 148 | // 分支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) { | 149 | for (BpmSimpleModelNodeVO item : conditionNodes) { |
| 136 | // TODO @jason:条件分支的情况下,需要分 item 搞的条件,和 conditionNodes 搞的条件 | 150 | // TODO @jason:条件分支的情况下,需要分 item 搞的条件,和 conditionNodes 搞的条件 |
| 137 | - // 构建表达式 | 151 | + // @芋艿 这个是啥意思。 这里的 item 的节点类型为 BpmSimpleModelNodeType.CONDITION_NODE 类型,没有对应的 bpmn 的节点。 仅仅用于构建条件表达式。 |
| 152 | + Assert.isTrue(Objects.equals(item.getType(), CONDITION_NODE.getType()), "条件节点类型不符合"); | ||
| 153 | + // 构建表达式,可以为空. 并行分支为空 | ||
| 138 | String conditionExpression = buildConditionExpression(item); | 154 | String conditionExpression = buildConditionExpression(item); |
| 139 | BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode(); | 155 | BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode(); |
| 140 | - // 4.2 分支有后续节点, 分支1: A->B->C->D | 156 | + // 3.2 分支有后续节点, 分支1: A->B->C->D |
| 141 | if (isValidNode(nextNodeOnCondition)) { | 157 | if (isValidNode(nextNodeOnCondition)) { |
| 142 | - // 4.2.1 建立 A->B | 158 | + // 3.2.1 建立 A->B |
| 143 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(), | 159 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(), |
| 144 | item.getId(), item.getName(), conditionExpression); | 160 | item.getId(), item.getName(), conditionExpression); |
| 145 | process.addFlowElement(sequenceFlow); | 161 | process.addFlowElement(sequenceFlow); |
| 146 | - // 4.2.2 递归调用后续节点连线。 建立 B->C->D 的连线 | 162 | + // 3.2.2 递归调用后续节点连线。 建立 B->C->D 的连线 |
| 147 | traverseNodeToBuildSequenceFlow(process, nextNodeOnCondition, branchEndNodeId); | 163 | traverseNodeToBuildSequenceFlow(process, nextNodeOnCondition, branchEndNodeId); |
| 148 | } else { | 164 | } else { |
| 149 | - // 4.3 分支无后续节点 建立 A->D | 165 | + // 3.3 分支无后续节点 建立 A->D |
| 150 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, | 166 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, |
| 151 | item.getId(), item.getName(), conditionExpression); | 167 | item.getId(), item.getName(), conditionExpression); |
| 152 | process.addFlowElement(sequenceFlow); | 168 | process.addFlowElement(sequenceFlow); |
| 153 | } | 169 | } |
| 154 | } | 170 | } |
| 155 | - // 递归调用后续节点 继续递归建立 D->E 的连线 | 171 | + // 如果是并行分支。由于是程序创建的聚合网关。需要手工创建聚合网关和下一个节点的连线 |
| 172 | + if (nodeType == PARALLEL_BRANCH_NODE) { | ||
| 173 | + String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; | ||
| 174 | + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId, null, null, null); | ||
| 175 | + process.addFlowElement(sequenceFlow); | ||
| 176 | + } | ||
| 177 | + // 4.递归调用后续节点 继续递归建立 D->E 的连线 | ||
| 156 | traverseNodeToBuildSequenceFlow(process, childNode, targetNodeId); | 178 | traverseNodeToBuildSequenceFlow(process, childNode, targetNodeId); |
| 157 | } | 179 | } |
| 158 | 180 | ||
| @@ -328,10 +350,9 @@ public class SimpleModelUtils { | @@ -328,10 +350,9 @@ public class SimpleModelUtils { | ||
| 328 | list.add(exclusiveGateway); | 350 | list.add(exclusiveGateway); |
| 329 | break; | 351 | break; |
| 330 | } | 352 | } |
| 331 | - case PARALLEL_BRANCH_FORK_NODE: | ||
| 332 | - case PARALLEL_BRANCH_JOIN_NODE: { | ||
| 333 | - ParallelGateway parallelGateway = convertParallelBranchNode(node); | ||
| 334 | - list.add(parallelGateway); | 353 | + case PARALLEL_BRANCH_NODE: { |
| 354 | + List<ParallelGateway> parallelGateways = convertParallelBranchNode(node); | ||
| 355 | + list.addAll(parallelGateways); | ||
| 335 | break; | 356 | break; |
| 336 | } | 357 | } |
| 337 | 358 | ||
| @@ -392,14 +413,17 @@ public class SimpleModelUtils { | @@ -392,14 +413,17 @@ public class SimpleModelUtils { | ||
| 392 | return boundaryEvent; | 413 | return boundaryEvent; |
| 393 | } | 414 | } |
| 394 | 415 | ||
| 395 | - private static ParallelGateway convertParallelBranchNode(BpmSimpleModelNodeVO node) { | 416 | + private static List<ParallelGateway> convertParallelBranchNode(BpmSimpleModelNodeVO node) { |
| 396 | ParallelGateway parallelGateway = new ParallelGateway(); | 417 | ParallelGateway parallelGateway = new ParallelGateway(); |
| 397 | parallelGateway.setId(node.getId()); | 418 | parallelGateway.setId(node.getId()); |
| 398 | // TODO @jason:setName | 419 | // TODO @jason:setName |
| 399 | 420 | ||
| 400 | // TODO @芋艿 + jason:合并网关;是不是要有条件啥的。微信讨论 | 421 | // TODO @芋艿 + jason:合并网关;是不是要有条件啥的。微信讨论 |
| 401 | - // @芋艿 貌似并行网关没有条件的 | ||
| 402 | - return parallelGateway; | 422 | + // @芋艿 感觉聚合网关(合并网关)还是从前端传过来好理解一点。 |
| 423 | + // 并行聚合网关 | ||
| 424 | + ParallelGateway joinParallelGateway = new ParallelGateway(); | ||
| 425 | + joinParallelGateway.setId(node.getId() + JOIN_GATE_WAY_NODE_ID_SUFFIX); | ||
| 426 | + return CollUtil.newArrayList(parallelGateway, joinParallelGateway); | ||
| 403 | } | 427 | } |
| 404 | 428 | ||
| 405 | private static ServiceTask convertCopyNode(BpmSimpleModelNodeVO node) { | 429 | private static ServiceTask convertCopyNode(BpmSimpleModelNodeVO node) { |