仿钉钉流程设计-排他网关实现

This commit is contained in:
jason 2024-04-02 20:50:49 +08:00
parent 1b708ccd55
commit d88718071d
3 changed files with 58 additions and 20 deletions

View File

@ -18,8 +18,7 @@ import java.util.Objects;
public enum BpmSimpleModelNodeType implements IntArrayValuable {
// TODO @jaosn-1014-2 是前端已经定义好的么感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈类似 usertask 用户审批
START_NODE(-1, "开始节点"),
START_USER_NODE(0, "发起人结点"),
START_EVENT_NODE(0, "开始节点"),
APPROVE_USER_NODE (1, "审批人节点"),
EXCLUSIVE_GATEWAY_NODE(4, "排他网关"),
END_NODE(-2, "结束节点");

View File

@ -358,44 +358,72 @@ public class BpmnModelUtils {
// 单独添加 end event 节点
addBpmnEndEventNode(mainProcess);
// 添加节点之间的连线 Sequence Flow
addBpmnSequenceFlow(mainProcess, simpleModelNode);
addBpmnSequenceFlow(mainProcess, simpleModelNode, BpmnModelConstants.END_EVENT_ID);
// 自动布局
new BpmnAutoLayout(bpmnModel).execute();
return bpmnModel;
}
private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node) {
private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String endId) {
// 节点为 null 退出
if (node == null || node.getId() == null) {
return;
}
BpmSimpleModelNodeVO childNode = node.getChildNode();
// 如果后续节点为 null. 添加与结束节点的连线
if (childNode == null || childNode.getId() == null) {
addBpmnSequenceFlowElement(mainProcess, node.getId(), BpmnModelConstants.END_EVENT_ID, null);
// 如果不是网关节点后续节点为 null. 添加与结束节点的连线
if (!BpmSimpleModelNodeType.isGatewayNode(node.getType()) && (childNode == null || childNode.getId() == null)) {
addBpmnSequenceFlowElement(mainProcess, node.getId(), endId, null, null);
return;
}
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
Assert.notNull(nodeType, "模型节点类型不支持");
switch (nodeType) {
case START_NODE:
case START_USER_NODE:
case APPROVE_USER_NODE:
addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null);
case START_EVENT_NODE:
case APPROVE_USER_NODE: {
addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null, null);
// 递归调用后续节点
addBpmnSequenceFlow(mainProcess, childNode,endId);
break;
}
case EXCLUSIVE_GATEWAY_NODE: {
String gateWayEndId = ( childNode == null || childNode.getId() == null ) ? BpmnModelConstants.END_EVENT_ID : childNode.getId();
List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();
Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空");
for (int i = 0; i < conditionNodes.size(); i++) {
BpmSimpleModelNodeVO item = conditionNodes.get(i);
BpmSimpleModelNodeVO nextNodeOnCondition = getNextNodeOnCondition(item);
if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) {
addBpmnSequenceFlowElement(mainProcess, node.getId(), nextNodeOnCondition.getId(),
String.format("%s_SequenceFlow_%d", node.getId(), i+1), null);
addBpmnSequenceFlow(mainProcess, nextNodeOnCondition, gateWayEndId);
} else {
addBpmnSequenceFlowElement(mainProcess, node.getId(), gateWayEndId,
String.format("%s_SequenceFlow_%d", node.getId(), i+1), null);
}
}
// 递归调用后续节点
addBpmnSequenceFlow(mainProcess, childNode, endId);
break;
}
default: {
// TODO 其它节点类型的实现
}
}
// 递归调用后续节点
addBpmnSequenceFlow(mainProcess, childNode);
}
private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String conditionExpression) {
private static BpmSimpleModelNodeVO getNextNodeOnCondition(BpmSimpleModelNodeVO conditionNode) {
return conditionNode.getChildNode();
}
private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String seqFlowId, String conditionExpression) {
SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId);
if (StrUtil.isNotEmpty(conditionExpression)) {
sequenceFlow.setConditionExpression(conditionExpression);
}
if (StrUtil.isNotEmpty(seqFlowId)) {
sequenceFlow.setId(seqFlowId);
}
mainProcess.addFlowElement(sequenceFlow);
}
@ -407,13 +435,15 @@ public class BpmnModelUtils {
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType());
Assert.notNull(nodeType, "模型节点类型不支持");
switch (nodeType) {
case START_NODE:
case START_EVENT_NODE:
addBpmnStartEventNode(mainProcess, simpleModelNode);
break;
case START_USER_NODE:
case APPROVE_USER_NODE:
addBpmnUserTaskEventNode(mainProcess, simpleModelNode);
break;
case EXCLUSIVE_GATEWAY_NODE:
addBpmnExclusiveGatewayNode(mainProcess, simpleModelNode);
break;
default: {
// TODO 其它节点类型的实现
}
@ -427,7 +457,7 @@ public class BpmnModelUtils {
// 如果是网关类型接口. 递归添加条件节点
if (BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) {
for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) {
addBpmnFlowNode(mainProcess, node);
addBpmnFlowNode(mainProcess, node.getChildNode());
}
}
@ -437,6 +467,15 @@ public class BpmnModelUtils {
}
}
private static void addBpmnExclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) {
Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");
ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
exclusiveGateway.setId(node.getId());
// 条件节点的最后一个条件为 网关的 default sequence flow
exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size()));
mainProcess.addFlowElement(exclusiveGateway);
}
private static void addBpmnEndEventNode(Process mainProcess) {
EndEvent endEvent = new EndEvent();
endEvent.setId(BpmnModelConstants.END_EVENT_ID);

View File

@ -20,7 +20,7 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_NODE;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT_NODE;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY;
@ -85,7 +85,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService {
return null;
}
BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO();
rootNode.setType(START_NODE.getType());
rootNode.setType(START_EVENT_NODE.getType());
rootNode.setId(startEvent.getId());
rootNode.setName(startEvent.getName());
recursiveBuildSimpleModelNode(startEvent, rootNode);
@ -129,7 +129,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService {
private List<SequenceFlow> validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) {
switch (nodeType) {
case START_NODE:
case START_EVENT_NODE:
case APPROVE_USER_NODE: {
List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows();
if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) {