Commit d88718071d649146b428485fe02e51d40f72a47b
1 parent
1b708ccd
仿钉钉流程设计-排他网关实现
Showing
3 changed files
with
58 additions
and
20 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
| ... | ... | @@ -18,8 +18,7 @@ import java.util.Objects; |
| 18 | 18 | public enum BpmSimpleModelNodeType implements IntArrayValuable { |
| 19 | 19 | |
| 20 | 20 | // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批; |
| 21 | - START_NODE(-1, "开始节点"), | |
| 22 | - START_USER_NODE(0, "发起人结点"), | |
| 21 | + START_EVENT_NODE(0, "开始节点"), | |
| 23 | 22 | APPROVE_USER_NODE (1, "审批人节点"), |
| 24 | 23 | EXCLUSIVE_GATEWAY_NODE(4, "排他网关"), |
| 25 | 24 | END_NODE(-2, "结束节点"); | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
| ... | ... | @@ -358,44 +358,72 @@ public class BpmnModelUtils { |
| 358 | 358 | // 单独添加 end event 节点 |
| 359 | 359 | addBpmnEndEventNode(mainProcess); |
| 360 | 360 | // 添加节点之间的连线 Sequence Flow |
| 361 | - addBpmnSequenceFlow(mainProcess, simpleModelNode); | |
| 361 | + addBpmnSequenceFlow(mainProcess, simpleModelNode, BpmnModelConstants.END_EVENT_ID); | |
| 362 | 362 | // 自动布局 |
| 363 | 363 | new BpmnAutoLayout(bpmnModel).execute(); |
| 364 | 364 | return bpmnModel; |
| 365 | 365 | } |
| 366 | 366 | |
| 367 | - private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node) { | |
| 367 | + private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String endId) { | |
| 368 | 368 | // 节点为 null 退出 |
| 369 | 369 | if (node == null || node.getId() == null) { |
| 370 | 370 | return; |
| 371 | 371 | } |
| 372 | 372 | BpmSimpleModelNodeVO childNode = node.getChildNode(); |
| 373 | - // 如果后续节点为 null. 添加与结束节点的连线 | |
| 374 | - if (childNode == null || childNode.getId() == null) { | |
| 375 | - addBpmnSequenceFlowElement(mainProcess, node.getId(), BpmnModelConstants.END_EVENT_ID, null); | |
| 373 | + // 如果不是网关节点、且后续节点为 null. 添加与结束节点的连线 | |
| 374 | + if (!BpmSimpleModelNodeType.isGatewayNode(node.getType()) && (childNode == null || childNode.getId() == null)) { | |
| 375 | + addBpmnSequenceFlowElement(mainProcess, node.getId(), endId, null, null); | |
| 376 | 376 | return; |
| 377 | 377 | } |
| 378 | 378 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); |
| 379 | 379 | Assert.notNull(nodeType, "模型节点类型不支持"); |
| 380 | 380 | switch (nodeType) { |
| 381 | - case START_NODE: | |
| 382 | - case START_USER_NODE: | |
| 383 | - case APPROVE_USER_NODE: | |
| 384 | - addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null); | |
| 381 | + case START_EVENT_NODE: | |
| 382 | + case APPROVE_USER_NODE: { | |
| 383 | + addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null, null); | |
| 384 | + // 递归调用后续节点 | |
| 385 | + addBpmnSequenceFlow(mainProcess, childNode,endId); | |
| 386 | + break; | |
| 387 | + } | |
| 388 | + case EXCLUSIVE_GATEWAY_NODE: { | |
| 389 | + String gateWayEndId = ( childNode == null || childNode.getId() == null ) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); | |
| 390 | + List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); | |
| 391 | + Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); | |
| 392 | + for (int i = 0; i < conditionNodes.size(); i++) { | |
| 393 | + BpmSimpleModelNodeVO item = conditionNodes.get(i); | |
| 394 | + BpmSimpleModelNodeVO nextNodeOnCondition = getNextNodeOnCondition(item); | |
| 395 | + if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) { | |
| 396 | + addBpmnSequenceFlowElement(mainProcess, node.getId(), nextNodeOnCondition.getId(), | |
| 397 | + String.format("%s_SequenceFlow_%d", node.getId(), i+1), null); | |
| 398 | + addBpmnSequenceFlow(mainProcess, nextNodeOnCondition, gateWayEndId); | |
| 399 | + } else { | |
| 400 | + addBpmnSequenceFlowElement(mainProcess, node.getId(), gateWayEndId, | |
| 401 | + String.format("%s_SequenceFlow_%d", node.getId(), i+1), null); | |
| 402 | + } | |
| 403 | + } | |
| 404 | + // 递归调用后续节点 | |
| 405 | + addBpmnSequenceFlow(mainProcess, childNode, endId); | |
| 385 | 406 | break; |
| 407 | + } | |
| 386 | 408 | default: { |
| 387 | 409 | // TODO 其它节点类型的实现 |
| 388 | 410 | } |
| 389 | 411 | } |
| 390 | - // 递归调用后续节点 | |
| 391 | - addBpmnSequenceFlow(mainProcess, childNode); | |
| 412 | + | |
| 392 | 413 | } |
| 393 | 414 | |
| 394 | - private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String conditionExpression) { | |
| 415 | + private static BpmSimpleModelNodeVO getNextNodeOnCondition(BpmSimpleModelNodeVO conditionNode) { | |
| 416 | + return conditionNode.getChildNode(); | |
| 417 | + } | |
| 418 | + | |
| 419 | + private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String seqFlowId, String conditionExpression) { | |
| 395 | 420 | SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); |
| 396 | 421 | if (StrUtil.isNotEmpty(conditionExpression)) { |
| 397 | 422 | sequenceFlow.setConditionExpression(conditionExpression); |
| 398 | 423 | } |
| 424 | + if (StrUtil.isNotEmpty(seqFlowId)) { | |
| 425 | + sequenceFlow.setId(seqFlowId); | |
| 426 | + } | |
| 399 | 427 | mainProcess.addFlowElement(sequenceFlow); |
| 400 | 428 | } |
| 401 | 429 | |
| ... | ... | @@ -407,13 +435,15 @@ public class BpmnModelUtils { |
| 407 | 435 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); |
| 408 | 436 | Assert.notNull(nodeType, "模型节点类型不支持"); |
| 409 | 437 | switch (nodeType) { |
| 410 | - case START_NODE: | |
| 438 | + case START_EVENT_NODE: | |
| 411 | 439 | addBpmnStartEventNode(mainProcess, simpleModelNode); |
| 412 | 440 | break; |
| 413 | - case START_USER_NODE: | |
| 414 | 441 | case APPROVE_USER_NODE: |
| 415 | 442 | addBpmnUserTaskEventNode(mainProcess, simpleModelNode); |
| 416 | 443 | break; |
| 444 | + case EXCLUSIVE_GATEWAY_NODE: | |
| 445 | + addBpmnExclusiveGatewayNode(mainProcess, simpleModelNode); | |
| 446 | + break; | |
| 417 | 447 | default: { |
| 418 | 448 | // TODO 其它节点类型的实现 |
| 419 | 449 | } |
| ... | ... | @@ -427,7 +457,7 @@ public class BpmnModelUtils { |
| 427 | 457 | // 如果是网关类型接口. 递归添加条件节点 |
| 428 | 458 | if (BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) { |
| 429 | 459 | for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) { |
| 430 | - addBpmnFlowNode(mainProcess, node); | |
| 460 | + addBpmnFlowNode(mainProcess, node.getChildNode()); | |
| 431 | 461 | } |
| 432 | 462 | } |
| 433 | 463 | |
| ... | ... | @@ -437,6 +467,15 @@ public class BpmnModelUtils { |
| 437 | 467 | } |
| 438 | 468 | } |
| 439 | 469 | |
| 470 | + private static void addBpmnExclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) { | |
| 471 | + Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); | |
| 472 | + ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); | |
| 473 | + exclusiveGateway.setId(node.getId()); | |
| 474 | + // 条件节点的最后一个条件为 网关的 default sequence flow | |
| 475 | + exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); | |
| 476 | + mainProcess.addFlowElement(exclusiveGateway); | |
| 477 | + } | |
| 478 | + | |
| 440 | 479 | private static void addBpmnEndEventNode(Process mainProcess) { |
| 441 | 480 | EndEvent endEvent = new EndEvent(); |
| 442 | 481 | endEvent.setId(BpmnModelConstants.END_EVENT_ID); | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java
| ... | ... | @@ -20,7 +20,7 @@ import java.util.Map; |
| 20 | 20 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 21 | 21 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT; |
| 22 | 22 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; |
| 23 | -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_NODE; | |
| 23 | +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT_NODE; | |
| 24 | 24 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM; |
| 25 | 25 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY; |
| 26 | 26 | |
| ... | ... | @@ -85,7 +85,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { |
| 85 | 85 | return null; |
| 86 | 86 | } |
| 87 | 87 | BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO(); |
| 88 | - rootNode.setType(START_NODE.getType()); | |
| 88 | + rootNode.setType(START_EVENT_NODE.getType()); | |
| 89 | 89 | rootNode.setId(startEvent.getId()); |
| 90 | 90 | rootNode.setName(startEvent.getName()); |
| 91 | 91 | recursiveBuildSimpleModelNode(startEvent, rootNode); |
| ... | ... | @@ -129,7 +129,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { |
| 129 | 129 | |
| 130 | 130 | private List<SequenceFlow> validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) { |
| 131 | 131 | switch (nodeType) { |
| 132 | - case START_NODE: | |
| 132 | + case START_EVENT_NODE: | |
| 133 | 133 | case APPROVE_USER_NODE: { |
| 134 | 134 | List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows(); |
| 135 | 135 | if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) { | ... | ... |