【代码评审】BPM:review simple 表单的转化

This commit is contained in:
YunaiV 2024-05-27 21:18:59 +08:00
parent 95bbf749a1
commit 1ae06b89e4
2 changed files with 57 additions and 23 deletions

View File

@ -15,9 +15,9 @@ import lombok.Getter;
public enum BpmApproveMethodEnum { public enum BpmApproveMethodEnum {
SINGLE_PERSON_APPROVE(1, "单人审批"), SINGLE_PERSON_APPROVE(1, "单人审批"),
ALL_APPROVE(2, "多人会签(需所有审批人同意)"), ALL_APPROVE(2, "多人会签(需所有审批人同意)"), // 会签
ANY_OF_APPROVE(3, "多人或签(一名审批人同意即可)"), ANY_OF_APPROVE(3, "多人或签(一名审批人同意即可)"), // 或签
SEQUENTIAL_APPROVE(4, "依次审批"); SEQUENTIAL_APPROVE(4, "依次审批"); // 依次审批
/** /**
* 审批方式 * 审批方式
@ -31,4 +31,5 @@ public enum BpmApproveMethodEnum {
public static BpmApproveMethodEnum valueOf(Integer method) { public static BpmApproveMethodEnum valueOf(Integer method) {
return ArrayUtil.firstMatch(item -> item.getMethod().equals(method), values()); return ArrayUtil.firstMatch(item -> item.getMethod().equals(method), values());
} }
} }

View File

@ -49,6 +49,8 @@ public class SimpleModelUtils {
*/ */
public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }"; public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }";
// TODO @jason建议方法名改成 buildBpmnModel
// TODO @yunai注释需要完善下
/** /**
* 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善 * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善
* *
@ -59,28 +61,31 @@ public class SimpleModelUtils {
*/ */
public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) {
BpmnModel bpmnModel = new BpmnModel(); BpmnModel bpmnModel = new BpmnModel();
bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason待定是不是搞个自定义的 namespace
// TODO 芋艿后续在 review
// 不加这个 解析 Message 会报 NPE 异常 // 不加这个 解析 Message 会报 NPE 异常
bpmnModel.setTargetNamespace(BPMN2_NAMESPACE);
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);
Process mainProcess = new Process(); Process process = new Process();
mainProcess.setId(processId); process.setId(processId);
mainProcess.setName(processName); process.setName(processName);
mainProcess.setExecutable(Boolean.TRUE); process.setExecutable(Boolean.TRUE); // TODO @jason这个是必须设置的么
bpmnModel.addProcess(mainProcess); bpmnModel.addProcess(process);
// 前端模型数据结构
// 前端模型数据结构
// SimpleModel 构建 FlowNode 并添加到 Main Process // SimpleModel 构建 FlowNode 并添加到 Main Process
buildAndAddBpmnFlowNode(simpleModelNode, mainProcess); buildAndAddBpmnFlowNode(simpleModelNode, process);
// 找到 end event // 找到 end event
EndEvent endEvent = (EndEvent) CollUtil.findOne(mainProcess.getFlowElements(), item -> item instanceof EndEvent); EndEvent endEvent = (EndEvent) CollUtil.findOne(process.getFlowElements(), item -> item instanceof EndEvent);
if (endEvent == null) { if (endEvent == null) {
// TODO 暂时为了兼容 单独构建 end event 节点. 后面去掉 // TODO 暂时为了兼容 单独构建 end event 节点. 后面去掉
endEvent = buildAndAddBpmnEndEvent(mainProcess); endEvent = buildAndAddBpmnEndEvent(process);
} }
// 构建并添加节点之间的连线 Sequence Flow // 构建并添加节点之间的连线 Sequence Flow
buildAndAddBpmnSequenceFlow(mainProcess, simpleModelNode, endEvent.getId()); buildAndAddBpmnSequenceFlow(process, simpleModelNode, endEvent.getId());
// 自动布局 // 自动布局
new BpmnAutoLayout(bpmnModel).execute(); new BpmnAutoLayout(bpmnModel).execute();
return bpmnModel; return bpmnModel;
@ -197,20 +202,27 @@ public class SimpleModelUtils {
return sequenceFlow; return sequenceFlow;
} }
// TODO @jason要不改成 recursionNode 递归节点然后把 build 名字让出来专门用于构建各种 Node
// TODO @jasonsimpleModelNode 改成 nodemainProcess 改成 process更符合递归的感觉哈处理当前节点
private static void buildAndAddBpmnFlowNode(BpmSimpleModelNodeVO simpleModelNode, Process mainProcess) { private static void buildAndAddBpmnFlowNode(BpmSimpleModelNodeVO simpleModelNode, Process mainProcess) {
// 节点为 null 退出 // 节点为 null 退出
// TODO @jason是不是写个 isValidNode 方法判断是否为有效节点
if (simpleModelNode == null || simpleModelNode.getId() == null) { if (simpleModelNode == null || simpleModelNode.getId() == null) {
return; return;
} }
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType());
Assert.notNull(nodeType, "模型节点类型不支持"); Assert.notNull(nodeType, "模型节点类型不支持");
// TODO @jason要不抽个 buildNode 方法然后返回一个 List<FlowElement>之后这个方法 addFlowElement原因是让当前这个方法有主干逻辑不然现在太长了
switch (nodeType) { switch (nodeType) {
case START_EVENT: { case START_EVENT: {
// TODO @jason每个 nodeTypebuildXXX 方法要不更明确并且去掉 Bpmn
StartEvent startEvent = buildBpmnStartEvent(simpleModelNode); StartEvent startEvent = buildBpmnStartEvent(simpleModelNode);
mainProcess.addFlowElement(startEvent); mainProcess.addFlowElement(startEvent);
break; break;
} }
case USER_TASK: { case USER_TASK: {
// TODO @jason这个搞成一个 buildUserTask然后把下面这 2 种节点搞在一起实现类这样 buildNode 里面可以更简洁
// TODO @jason这里还有个想法是不是可以所有的都叫 buildXXXNode然后里面有一些是 bpmn 相关的构建叫做 buildBpmnUserTask用于区分
// 获取用户任务的配置 // 获取用户任务的配置
SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(simpleModelNode.getAttributes(), SimpleModelUserTaskConfig.class); SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(simpleModelNode.getAttributes(), SimpleModelUserTaskConfig.class);
UserTask userTask = buildBpmnUserTask(simpleModelNode, userTaskConfig); UserTask userTask = buildBpmnUserTask(simpleModelNode, userTaskConfig);
@ -259,18 +271,23 @@ public class SimpleModelUtils {
} }
// 如果不是网关类型的接口 并且chileNode为空退出 // 如果不是网关类型的接口 并且chileNode为空退出
// TODO @jason建议这个判断去掉可以更简洁一点因为往下走如果不成功本身也就会结束哈主要是这里多了一个这样的判断增加了理解成本
if (!BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) { if (!BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) {
return; return;
} }
// 如果是网关类型接口. 递归添加条件节点 // 如果是条件节点则递归处理条件
if (BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) { if (BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType())
&& ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) {
// TODO @jason可以搞成 stream 写成一行哈
for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) { for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) {
buildAndAddBpmnFlowNode(node.getChildNode(), mainProcess); buildAndAddBpmnFlowNode(node.getChildNode(), mainProcess);
} }
} }
// 如果有节点则递归处理子节点
// chileNode不为空递归添加子节点 // chileNode不为空递归添加子节点
// TODO @jason这个是不是不写判断直接继续调用因为本身 buildAndAddBpmnFlowNode 就会最开始判断了哈就不重复判断了
if (simpleModelNode.getChildNode() != null) { if (simpleModelNode.getChildNode() != null) {
buildAndAddBpmnFlowNode(simpleModelNode.getChildNode(), mainProcess); buildAndAddBpmnFlowNode(simpleModelNode.getChildNode(), mainProcess);
} }
@ -301,30 +318,33 @@ public class SimpleModelUtils {
private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) { private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) {
ParallelGateway parallelGateway = new ParallelGateway(); ParallelGateway parallelGateway = new ParallelGateway();
parallelGateway.setId(node.getId()); parallelGateway.setId(node.getId());
// TODO @jasonsetName
// TODO @芋艿 + jason合并网关是不是要有条件啥的微信讨论
return parallelGateway; return parallelGateway;
} }
private static ServiceTask buildBpmnServiceTask(BpmSimpleModelNodeVO node) { private static ServiceTask buildBpmnServiceTask(BpmSimpleModelNodeVO node) {
ServiceTask serviceTask = new ServiceTask(); ServiceTask serviceTask = new ServiceTask();
serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION);
serviceTask.setImplementation(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT);
serviceTask.setId(node.getId()); serviceTask.setId(node.getId());
serviceTask.setName(node.getName()); serviceTask.setName(node.getName());
// TODO @jason建议使用 ServiceTask通过 executionListeners 实现 // TODO @jason建议用 delegateExpression原因是直接走 bpmSimpleNodeService.copy(execution) 的话万一后续抄送改实现可能比较麻烦最好是搞个独立的 bean然后它去调用抄 bpmSimpleNodeService
// @芋艿 ServiceTask 就可以了吧 不需要 executionListeners serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION);
serviceTask.setImplementation(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT);
// 添加抄送候选人元素 // 添加抄送候选人元素
addCandidateElements(MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY), addCandidateElements(MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY),
MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM), MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM),
serviceTask); serviceTask);
// 添加表单字段权限属性元素 // 添加表单字段权限属性元素
// TODO @芋艿这块关注下哈
List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(), List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(),
FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() { FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() {});
});
addFormFieldsPermission(fieldsPermissions, serviceTask); addFormFieldsPermission(fieldsPermissions, serviceTask);
return serviceTask; return serviceTask;
} }
/** /**
* 给节点添加候选人元素 * 给节点添加候选人元素
*/ */
@ -350,6 +370,9 @@ public class SimpleModelUtils {
private static InclusiveGateway buildBpmnInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) { private static InclusiveGateway buildBpmnInclusiveGateway(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是不是搞个合并网关这里微信讨论下有点奇怪
if (isFork) { if (isFork) {
Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");
// 网关的最后一个条件为 网关的 default sequence flow // 网关的最后一个条件为 网关的 default sequence flow
@ -375,6 +398,9 @@ public class SimpleModelUtils {
userTask.setDueDate(userTaskConfig.getTimeoutHandler().getTimeDuration()); userTask.setDueDate(userTaskConfig.getTimeoutHandler().getTimeDuration());
} }
// TODO 芋艿 + jason要不要基于服务任务实现或签下的审批不通过或者说按比例审批
// TODO @jasonaddCandidateElementsprocessMultiInstanceLoopCharacteristics 建议一起搞哈
// 添加候选人元素 // 添加候选人元素
addCandidateElements(userTaskConfig.getCandidateStrategy(), userTaskConfig.getCandidateParam(), userTask); addCandidateElements(userTaskConfig.getCandidateStrategy(), userTaskConfig.getCandidateParam(), userTask);
// 添加表单字段权限属性元素 // 添加表单字段权限属性元素
@ -455,10 +481,14 @@ public class SimpleModelUtils {
element.addExtensionElement(extensionElement); element.addExtensionElement(extensionElement);
} }
// ========== 各种 build 节点的方法 ==========
private static StartEvent buildBpmnStartEvent(BpmSimpleModelNodeVO node) { private static StartEvent buildBpmnStartEvent(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要不要在开启节点后面加一个发起人任务节点然后自动审批通过
return startEvent; return startEvent;
} }
@ -466,6 +496,9 @@ public class SimpleModelUtils {
EndEvent endEvent = new EndEvent(); EndEvent endEvent = new EndEvent();
endEvent.setId(node.getId()); endEvent.setId(node.getId());
endEvent.setName(node.getName()); endEvent.setName(node.getName());
// TODO @芋艿 + jason要不要加一个终止定义
return endEvent; return endEvent;
} }
} }