【代码评审】BPM:review simple 表单的转化
This commit is contained in:
parent
95bbf749a1
commit
1ae06b89e4
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 @jason:simpleModelNode 改成 node,mainProcess 改成 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:每个 nodeType,buildXXX 方法要不更明确,并且去掉 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 @jason:setName
|
||||||
|
|
||||||
|
// 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 @jason:addCandidateElements、processMultiInstanceLoopCharacteristics 建议一起搞哈?
|
||||||
// 添加候选人元素
|
// 添加候选人元素
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue