仿钉钉流程设计- 调整排他网关和条件节点

This commit is contained in:
jason 2024-04-30 00:07:58 +08:00
parent 1bd96eb13e
commit 4958aaea81
3 changed files with 81 additions and 15 deletions

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.bpm.enums.definition;
import cn.hutool.core.util.ArrayUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 仿钉钉的流程器设计器条件节点的条件类型
*
* @author jason
*/
@Getter
@AllArgsConstructor
public enum BpmSimpleModeConditionType {
CUSTOM_EXPRESSION(1, "自定义条件表达式");
private final Integer type;
private final String name;
public static BpmSimpleModeConditionType valueOf(Integer type) {
return ArrayUtil.firstMatch(nodeType -> nodeType.getType().equals(type), values());
}
}

View File

@ -12,4 +12,19 @@ public interface SimpleModelConstants {
* 审批方式属性 * 审批方式属性
*/ */
String APPROVE_METHOD_ATTRIBUTE = "approveMethod"; String APPROVE_METHOD_ATTRIBUTE = "approveMethod";
/**
* 网关节点默认序列流属性
*/
String DEFAULT_FLOW_ATTRIBUTE = "defaultFlow";
/**
* 条件节点的条件类型属性
*/
String CONDITION_TYPE_ATTRIBUTE = "conditionType";
/**
* 条件节点条件表达式属性
*/
String CONDITION_EXPRESSION_ATTRIBUTE = "conditionExpression";
} }

View File

@ -5,9 +5,11 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.TypeReference; import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum; import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModeConditionType;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants;
@ -20,6 +22,7 @@ import java.util.Map;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT; import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.FORM_FIELD_PERMISSION_ELEMENT; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.FORM_FIELD_PERMISSION_ELEMENT;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*;
import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE; import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;
import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX; import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX;
@ -57,16 +60,15 @@ public class SimpleModelUtils {
mainProcess.setName(processName); mainProcess.setName(processName);
mainProcess.setExecutable(Boolean.TRUE); mainProcess.setExecutable(Boolean.TRUE);
bpmnModel.addProcess(mainProcess); bpmnModel.addProcess(mainProcess);
// 前端模型数据结构 start event 节点. 没有 end event 节点 // 前端模型数据结构
// SimpleModel 构建 FlowNode 并添加到 Main Process // SimpleModel 构建 FlowNode 并添加到 Main Process
buildAndAddBpmnFlowNode(simpleModelNode, mainProcess); buildAndAddBpmnFlowNode(simpleModelNode, mainProcess);
// 找到 end event // 找到 end event
EndEvent endEvent = (EndEvent) CollUtil.findOne(mainProcess.getFlowElements(), item -> item instanceof EndEvent); EndEvent endEvent = (EndEvent) CollUtil.findOne(mainProcess.getFlowElements(), item -> item instanceof EndEvent);
if (endEvent == null) { if (endEvent == null) {
// 暂时为了兼容 单独构建 end event 节点 // TODO 暂时为了兼容 单独构建 end event 节点. 后面去掉
endEvent = buildAndAddBpmnEndEvent(mainProcess); endEvent = buildAndAddBpmnEndEvent(mainProcess);
} }
// 构建并添加节点之间的连线 Sequence Flow // 构建并添加节点之间的连线 Sequence Flow
buildAndAddBpmnSequenceFlow(mainProcess, simpleModelNode, endEvent.getId()); buildAndAddBpmnSequenceFlow(mainProcess, simpleModelNode, endEvent.getId());
// 自动布局 // 自动布局
@ -75,14 +77,14 @@ public class SimpleModelUtils {
} }
private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) { private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) {
// 节点为 null 退出 // 节点为 null 或者 为END_EVENT 退出
if (node == null || node.getId() == null || END_EVENT.getType().equals(node.getType())) { if (node == null || node.getId() == null || END_EVENT.getType().equals(node.getType())) {
return; return;
} }
BpmSimpleModelNodeVO childNode = node.getChildNode(); BpmSimpleModelNodeVO childNode = node.getChildNode();
// 如果不是网关节点且后续节点为 null. 添加与结束节点的连线 // 如果是网关分支节点. 后续节点可能为 null但不是 END_EVENT 节点
if (!BpmSimpleModelNodeType.isBranchNode(node.getType()) && (childNode == null || childNode.getId() == null)) { if (!BpmSimpleModelNodeType.isBranchNode(node.getType()) && (childNode == null || childNode.getId() == null)) {
SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetId, null, null); SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetId, null, null, null);
mainProcess.addFlowElement(sequenceFlow); mainProcess.addFlowElement(sequenceFlow);
return; return;
} }
@ -94,7 +96,7 @@ public class SimpleModelUtils {
case COPY_TASK: case COPY_TASK:
case PARALLEL_GATEWAY_JOIN: case PARALLEL_GATEWAY_JOIN:
case INCLUSIVE_GATEWAY_JOIN: { case INCLUSIVE_GATEWAY_JOIN: {
SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null); SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null);
mainProcess.addFlowElement(sequenceFlow); mainProcess.addFlowElement(sequenceFlow);
// 递归调用后续节点 // 递归调用后续节点
buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId); buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId);
@ -103,21 +105,21 @@ public class SimpleModelUtils {
case PARALLEL_GATEWAY_FORK: case PARALLEL_GATEWAY_FORK:
case EXCLUSIVE_GATEWAY: case EXCLUSIVE_GATEWAY:
case INCLUSIVE_GATEWAY_FORK: { case INCLUSIVE_GATEWAY_FORK: {
String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? targetId : childNode.getId();
List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();
Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空");
for (int i = 0; i < conditionNodes.size(); i++) { for (BpmSimpleModelNodeVO item : conditionNodes) {
BpmSimpleModelNodeVO item = conditionNodes.get(i); String conditionExpression = buildConditionExpression(item);
BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode(); BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode();
if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) { if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) {
SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(), SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(),
String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); item.getId(), item.getName(), conditionExpression);
mainProcess.addFlowElement(sequenceFlow); mainProcess.addFlowElement(sequenceFlow);
// 递归调用后续节点 // 递归调用后续节点
buildAndAddBpmnSequenceFlow(mainProcess, nextNodeOnCondition, sequenceFlowTargetId); buildAndAddBpmnSequenceFlow(mainProcess, nextNodeOnCondition, sequenceFlowTargetId);
} else { } else {
SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), sequenceFlowTargetId, SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), sequenceFlowTargetId,
String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); item.getId(), item.getName(), conditionExpression);
mainProcess.addFlowElement(sequenceFlow); mainProcess.addFlowElement(sequenceFlow);
} }
} }
@ -132,7 +134,24 @@ public class SimpleModelUtils {
} }
private static SequenceFlow buildBpmnSequenceFlow(String sourceId, String targetId, String seqFlowId, String conditionExpression) { /**
* 构造条件表达式
*
* @param conditionNode 条件节点
*/
private static String buildConditionExpression(BpmSimpleModelNodeVO conditionNode) {
Integer conditionType = MapUtil.getInt(conditionNode.getAttributes(), CONDITION_TYPE_ATTRIBUTE);
BpmSimpleModeConditionType conditionTypeEnum = BpmSimpleModeConditionType.valueOf(conditionType);
String conditionExpression = null;
if (conditionTypeEnum == BpmSimpleModeConditionType.CUSTOM_EXPRESSION) {
conditionExpression = MapUtil.getStr(conditionNode.getAttributes(), CONDITION_EXPRESSION_ATTRIBUTE);
}
// TODO 待增加其它类型
return conditionExpression;
}
private static SequenceFlow buildBpmnSequenceFlow(String sourceId, String targetId, String seqFlowId, String seqName, String conditionExpression) {
SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId);
if (StrUtil.isNotEmpty(conditionExpression)) { if (StrUtil.isNotEmpty(conditionExpression)) {
sequenceFlow.setConditionExpression(conditionExpression); sequenceFlow.setConditionExpression(conditionExpression);
@ -140,6 +159,9 @@ public class SimpleModelUtils {
if (StrUtil.isNotEmpty(seqFlowId)) { if (StrUtil.isNotEmpty(seqFlowId)) {
sequenceFlow.setId(seqFlowId); sequenceFlow.setId(seqFlowId);
} }
if (StrUtil.isNotEmpty(seqName)) {
sequenceFlow.setName(seqName);
}
return sequenceFlow; return sequenceFlow;
} }
@ -249,8 +271,12 @@ public class SimpleModelUtils {
Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");
ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
exclusiveGateway.setId(node.getId()); exclusiveGateway.setId(node.getId());
// 网关的最后一个条件为 网关的 default sequence flow // 寻找默认的序列流
exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); BpmSimpleModelNodeVO defaultSeqFlow = CollUtil.findOne(node.getConditionNodes(),
item -> BooleanUtil.isTrue(MapUtil.getBool(item.getAttributes(), DEFAULT_FLOW_ATTRIBUTE)));
if (defaultSeqFlow != null) {
exclusiveGateway.setDefaultFlow(defaultSeqFlow.getId());
}
return exclusiveGateway; return exclusiveGateway;
} }