仿钉钉流程设计- code review 修改

This commit is contained in:
jason 2024-05-28 08:46:58 +08:00
parent 8f31e745dd
commit 4bd399cd32
2 changed files with 77 additions and 68 deletions

View File

@ -18,17 +18,18 @@ import java.util.Objects;
public enum BpmSimpleModelNodeType implements IntArrayValuable { public enum BpmSimpleModelNodeType implements IntArrayValuable {
// TODO @jaosn-1014-2 是前端已经定义好的么感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈类似 usertask 用户审批 // TODO @jaosn-1014-2 是前端已经定义好的么感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈类似 usertask 用户审批
START_EVENT(0, "开始节点"), // @芋艿 感觉还是用 START_NODE . END_NODE 比较好.
END_EVENT(-2, "结束节点"), // TODO @jaosn挪到 START_EVENT_NODE START_NODE(0, "开始节点"),
END_NODE(-2, "结束节点"), // TODO @jaosn挪到 START_EVENT_NODE
USER_TASK(1, "审批人节点"), // TODO @jaosn是不是这里从 10 开始好点相当于说0-9 给开始和结束10-19 给各种节点20-29 给各种条件 TODO 后面改改 APPROVE_NODE(1, "审批人节点"), // TODO @jaosn是不是这里从 10 开始好点相当于说0-9 给开始和结束10-19 给各种节点20-29 给各种条件 TODO 后面改改
COPY_TASK(2, "抄送人节点"), COPY_NODE(2, "抄送人节点"),
EXCLUSIVE_GATEWAY(4, "排他网关"), // TODO @jason是不是改成叫 条件分支 CONDITION_BRANCH_NODE(4, "条件分支节点"), // TODO @jason是不是改成叫 条件分支
PARALLEL_GATEWAY_FORK(5, "并行网关分叉节点"), // TODO @jason是不是一个 并行分支 就可以啦 后面是否去掉并行网关只用包容网关 PARALLEL_BRANCH_FORK_NODE(5, "并行分支分叉节点"), // TODO @jason是不是一个 并行分支 就可以啦 后面是否去掉并行网关只用包容网关
PARALLEL_GATEWAY_JOIN(6, "并行网关聚合节点"), PARALLEL_BRANCH_JOIN_NODE(6, "并行分支聚合节点"),
INCLUSIVE_GATEWAY_FORK(7, "包容网关分叉节点"), INCLUSIVE_BRANCH_FORK_NODE(7, "包容网关分叉节点"),
INCLUSIVE_GATEWAY_JOIN(8, "包容网关聚合节点"), INCLUSIVE_BRANCH_JOIN_NODE(8, "包容网关聚合节点"),
; ;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray();
@ -42,8 +43,8 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
* @param type 节点类型 * @param type 节点类型
*/ */
public static boolean isBranchNode(Integer type) { public static boolean isBranchNode(Integer type) {
return Objects.equals(EXCLUSIVE_GATEWAY.getType(), type) || Objects.equals(PARALLEL_GATEWAY_FORK.getType(), type) return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) || Objects.equals(PARALLEL_BRANCH_FORK_NODE.getType(), type)
|| Objects.equals(INCLUSIVE_GATEWAY_FORK.getType(), type) ; || Objects.equals(INCLUSIVE_BRANCH_FORK_NODE.getType(), type) ;
} }
public static BpmSimpleModelNodeType valueOf(Integer type) { public static BpmSimpleModelNodeType valueOf(Integer type) {

View File

@ -25,7 +25,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT; import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT; import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_NODE;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER; import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*;
@ -63,10 +63,10 @@ public class SimpleModelUtils {
*/ */
public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) {
BpmnModel bpmnModel = new BpmnModel(); BpmnModel bpmnModel = new BpmnModel();
// 不加这个 解析 Message 会报 NPE 异常 .
bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason待定是不是搞个自定义的 namespace bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason待定是不是搞个自定义的 namespace
// TODO 芋艿后续在 review // TODO 芋艿后续在 review
// @芋艿 这个 Message 可以去掉 暂时用不上 // @芋艿 这个 Message 可以去掉 暂时用不上
// 不加这个 解析 Message 会报 NPE 异常 .
Message rejectPostProcessMsg = new Message(); Message rejectPostProcessMsg = new Message();
rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME); rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME);
bpmnModel.addMessage(rejectPostProcessMsg); bpmnModel.addMessage(rejectPostProcessMsg);
@ -92,7 +92,7 @@ public class SimpleModelUtils {
private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) { private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) {
// 节点为 null 或者 为END_EVENT 退出 // 节点为 null 或者 为END_EVENT 退出
if (node == null || node.getId() == null || END_EVENT.getType().equals(node.getType())) { if (node == null || node.getId() == null || END_NODE.getType().equals(node.getType())) {
return; return;
} }
BpmSimpleModelNodeVO childNode = node.getChildNode(); BpmSimpleModelNodeVO childNode = node.getChildNode();
@ -105,20 +105,20 @@ public class SimpleModelUtils {
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
Assert.notNull(nodeType, "模型节点类型不支持"); Assert.notNull(nodeType, "模型节点类型不支持");
switch (nodeType) { switch (nodeType) {
case START_EVENT: case START_NODE:
case USER_TASK: case APPROVE_NODE:
case COPY_TASK: case COPY_NODE:
case PARALLEL_GATEWAY_JOIN: case PARALLEL_BRANCH_JOIN_NODE:
case INCLUSIVE_GATEWAY_JOIN: { case INCLUSIVE_BRANCH_JOIN_NODE: {
SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, 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);
break; break;
} }
case PARALLEL_GATEWAY_FORK: case PARALLEL_BRANCH_FORK_NODE:
case EXCLUSIVE_GATEWAY: case CONDITION_BRANCH_NODE:
case INCLUSIVE_GATEWAY_FORK: { case INCLUSIVE_BRANCH_FORK_NODE: {
String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? targetId : 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, "网关节点的条件节点不能为空");
@ -238,55 +238,50 @@ public class SimpleModelUtils {
private static List<FlowElement> buildFlowNode(BpmSimpleModelNodeVO node, BpmSimpleModelNodeType nodeType) { private static List<FlowElement> buildFlowNode(BpmSimpleModelNodeVO node, BpmSimpleModelNodeType nodeType) {
List<FlowElement> list = new ArrayList<>(); List<FlowElement> list = new ArrayList<>();
switch (nodeType) { switch (nodeType) {
case START_EVENT: { case START_NODE: {
// TODO-DONE @jason每个 nodeTypebuildXXX 方法要不更明确并且去掉 Bpmn // TODO-DONE @jason每个 nodeTypebuildXXX 方法要不更明确并且去掉 Bpmn
StartEvent startEvent = buildStartEvent(node); // @芋艿 改成 convert 是不是好理解一点
StartEvent startEvent = convertStartNode(node);
list.add(startEvent); list.add(startEvent);
break; break;
} }
case USER_TASK: { case APPROVE_NODE: {
// TODO @jason这个搞成一个 buildUserTask然后把下面这 2 种节点搞在一起实现类这样 buildNode 里面可以更简洁 // TODO-DONE @jason这个搞成一个 buildUserTask然后把下面这 2 种节点搞在一起实现类这样 buildNode 里面可以更简洁
// TODO @jason这里还有个想法是不是可以所有的都叫 buildXXXNode然后里面有一些是 bpmn 相关的构建叫做 buildBpmnUserTask用于区分 // TODO-DONE @jason这里还有个想法是不是可以所有的都叫 buildXXXNode然后里面有一些是 bpmn 相关的构建叫做 buildBpmnUserTask用于区分
// 获取用户任务的配置 // @芋艿 改成 convertXXXNode, 方面里面使用 buildBpmnXXXNode. 是否更好理解
SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(node.getAttributes(), SimpleModelUserTaskConfig.class); // 转换审批节点
UserTask userTask = buildBpmnUserTask(node, userTaskConfig); List<FlowElement> flowElements = convertApproveNode(node);
list.add(userTask); list.addAll(flowElements);
if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) {
// 添加用户任务的 Timer Boundary Event, 用于任务的超时处理
BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler());
//process.addFlowElement(boundaryEvent);
list.add(boundaryEvent);
}
break; break;
} }
case COPY_TASK: { case COPY_NODE: {
ServiceTask serviceTask = buildServiceTask(node); ServiceTask serviceTask = convertCopyNode(node);
list.add(serviceTask); list.add(serviceTask);
break; break;
} }
case EXCLUSIVE_GATEWAY: { case CONDITION_BRANCH_NODE: {
ExclusiveGateway exclusiveGateway = buildExclusiveGateway(node); ExclusiveGateway exclusiveGateway = convertConditionBranchNode(node);
list.add(exclusiveGateway); list.add(exclusiveGateway);
break; break;
} }
case PARALLEL_GATEWAY_FORK: case PARALLEL_BRANCH_FORK_NODE:
case PARALLEL_GATEWAY_JOIN: { case PARALLEL_BRANCH_JOIN_NODE: {
ParallelGateway parallelGateway = buildParallelGateway(node); ParallelGateway parallelGateway = convertParallelBranchNode(node);
list.add(parallelGateway); list.add(parallelGateway);
break; break;
} }
case INCLUSIVE_GATEWAY_FORK: { case INCLUSIVE_BRANCH_FORK_NODE: {
InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.TRUE); InclusiveGateway inclusiveGateway = convertInclusiveBranchNode(node, Boolean.TRUE);
list.add(inclusiveGateway); list.add(inclusiveGateway);
break; break;
} }
case INCLUSIVE_GATEWAY_JOIN: { case INCLUSIVE_BRANCH_JOIN_NODE: {
InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.FALSE); InclusiveGateway inclusiveGateway = convertInclusiveBranchNode(node, Boolean.FALSE);
list.add(inclusiveGateway); list.add(inclusiveGateway);
break; break;
} }
case END_EVENT: { case END_NODE: {
EndEvent endEvent = buildEndEvent(node); EndEvent endEvent = convertEndNode(node);
list.add(endEvent); list.add(endEvent);
break; break;
} }
@ -297,6 +292,19 @@ public class SimpleModelUtils {
return list; return list;
} }
private static List<FlowElement> convertApproveNode(BpmSimpleModelNodeVO node) {
List<FlowElement> flowElements = new ArrayList<>();
SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(node.getAttributes(), SimpleModelUserTaskConfig.class);
UserTask userTask = buildBpmnUserTask(node, userTaskConfig);
flowElements.add(userTask);
if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) {
// 添加用户任务的 Timer Boundary Event, 用于任务的超时处理
BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler());
flowElements.add(boundaryEvent);
}
return flowElements;
}
private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) { private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) {
// 定时器边界事件 // 定时器边界事件
BoundaryEvent boundaryEvent = new BoundaryEvent(); BoundaryEvent boundaryEvent = new BoundaryEvent();
@ -319,16 +327,17 @@ public class SimpleModelUtils {
return boundaryEvent; return boundaryEvent;
} }
private static ParallelGateway buildParallelGateway(BpmSimpleModelNodeVO node) { private static ParallelGateway convertParallelBranchNode(BpmSimpleModelNodeVO node) {
ParallelGateway parallelGateway = new ParallelGateway(); ParallelGateway parallelGateway = new ParallelGateway();
parallelGateway.setId(node.getId()); parallelGateway.setId(node.getId());
// TODO @jasonsetName // TODO @jasonsetName
// TODO @芋艿 + jason合并网关是不是要有条件啥的微信讨论 // TODO @芋艿 + jason合并网关是不是要有条件啥的微信讨论
// @芋艿 貌似并行网关没有条件的
return parallelGateway; return parallelGateway;
} }
private static ServiceTask buildServiceTask(BpmSimpleModelNodeVO node) { private static ServiceTask convertCopyNode(BpmSimpleModelNodeVO node) {
ServiceTask serviceTask = new ServiceTask(); ServiceTask serviceTask = new ServiceTask();
serviceTask.setId(node.getId()); serviceTask.setId(node.getId());
serviceTask.setName(node.getName()); serviceTask.setName(node.getName());
@ -359,8 +368,8 @@ public class SimpleModelUtils {
addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam); addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam);
} }
private static ExclusiveGateway buildExclusiveGateway(BpmSimpleModelNodeVO node) { private static ExclusiveGateway convertConditionBranchNode(BpmSimpleModelNodeVO node) {
Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); Assert.notEmpty(node.getConditionNodes(), "条件分支节点不能为空");
ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
exclusiveGateway.setId(node.getId()); exclusiveGateway.setId(node.getId());
// 寻找默认的序列流 // 寻找默认的序列流
@ -372,28 +381,25 @@ public class SimpleModelUtils {
return exclusiveGateway; return exclusiveGateway;
} }
private static InclusiveGateway buildInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) { private static InclusiveGateway convertInclusiveBranchNode(BpmSimpleModelNodeVO node, Boolean isFork) {
InclusiveGateway inclusiveGateway = new InclusiveGateway(); InclusiveGateway inclusiveGateway = new InclusiveGateway();
inclusiveGateway.setId(node.getId()); inclusiveGateway.setId(node.getId());
// TODO @jason这里是不是 setName // TODO @jason这里是不是 setName
// TODO @芋艿 + jason是不是搞个合并网关这里微信讨论下有点奇怪 // TODO @芋艿 + jason是不是搞个合并网关这里微信讨论下有点奇怪
// @芋艿 isFork false 就是合并网关由前端传入这个前端暂时还未实现
if (isFork) { if (isFork) {
Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); Assert.notEmpty(node.getConditionNodes(), "条件节点不能为空");
// 网关的最后一个条件为 网关的 default sequence flow // 寻找默认的序列流
inclusiveGateway.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) {
inclusiveGateway.setDefaultFlow(defaultSeqFlow.getId());
}
} }
return inclusiveGateway; return inclusiveGateway;
} }
private static EndEvent buildAndAddBpmnEndEvent(Process mainProcess) {
EndEvent endEvent = new EndEvent();
endEvent.setId(BpmnModelConstants.END_EVENT_ID);
endEvent.setName("结束");
mainProcess.addFlowElement(endEvent);
return endEvent;
}
private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node, SimpleModelUserTaskConfig userTaskConfig) { private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node, SimpleModelUserTaskConfig userTaskConfig) {
UserTask userTask = new UserTask(); UserTask userTask = new UserTask();
userTask.setId(node.getId()); userTask.setId(node.getId());
@ -488,16 +494,18 @@ public class SimpleModelUtils {
// ========== 各种 build 节点的方法 ========== // ========== 各种 build 节点的方法 ==========
private static StartEvent buildStartEvent(BpmSimpleModelNodeVO node) { private static StartEvent convertStartNode(BpmSimpleModelNodeVO node) {
StartEvent startEvent = new StartEvent(); StartEvent startEvent = new StartEvent();
startEvent.setId(node.getId()); startEvent.setId(node.getId());
startEvent.setName(node.getName()); startEvent.setName(node.getName());
// TODO 芋艿 + jason要不要在开启节点后面加一个发起人任务节点然后自动审批通过 // TODO 芋艿 + jason要不要在开启节点后面加一个发起人任务节点然后自动审批通过
// @芋艿 这个是不是由前端来实现 默认开始节点后面跟一个 发起人的审批节点(审批人是发起人自己
// 我看有些平台这个审批节点允许删除有些不允许由用户决定
return startEvent; return startEvent;
} }
private static EndEvent buildEndEvent(BpmSimpleModelNodeVO node) { private static EndEvent convertEndNode(BpmSimpleModelNodeVO node) {
EndEvent endEvent = new EndEvent(); EndEvent endEvent = new EndEvent();
endEvent.setId(node.getId()); endEvent.setId(node.getId());
endEvent.setName(node.getName()); endEvent.setName(node.getName());