Commit 2c2512e40550f0950202f5332b0b309f4375e999

Authored by YunaiV
1 parent 8469b2b8

【代码优化】工作流:将元素相关的操作,挪到 BpmnModelUtils 中

【代码优化】工作流:新增 NodeConvert 接口以及其实现,将 SimpleModelUtils 统一收敛
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailReqVO.java
... ... @@ -10,6 +10,8 @@ import lombok.Data;
10 10 @Data
11 11 public class BpmApprovalDetailReqVO {
12 12  
  13 + // TODO @jason:这里要不注释说明下,什么情况下,使用 processDefinitionId、processInstanceId、activityId、taskId。
  14 +
13 15 @Schema(description = "流程定义的编号", example = "1024")
14 16 private String processDefinitionId; // 发起流程的时候传流程定义 Id
15 17  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
... ... @@ -4,11 +4,14 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.map.MapUtil;
5 5 import cn.hutool.core.util.ArrayUtil;
6 6 import cn.hutool.core.util.StrUtil;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
8 9 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
  10 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
9 11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
10 12 import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
11 13 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
  14 +import com.google.common.collect.Maps;
12 15 import org.flowable.bpmn.converter.BpmnXMLConverter;
13 16 import org.flowable.bpmn.model.Process;
14 17 import org.flowable.bpmn.model.*;
... ... @@ -18,12 +21,67 @@ import java.util.*;
18 21  
19 22 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
20 23 import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;
  24 +import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX;
21 25  
22 26 /**
23 27 * 流程模型转操作工具类
24 28 */
25 29 public class BpmnModelUtils {
26 30  
  31 + public static void addExtensionElement(FlowElement element, String name, String value) {
  32 + if (value == null) {
  33 + return;
  34 + }
  35 + ExtensionElement extensionElement = new ExtensionElement();
  36 + extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
  37 + extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
  38 + extensionElement.setElementText(value);
  39 + extensionElement.setName(name);
  40 + element.addExtensionElement(extensionElement);
  41 + }
  42 +
  43 + public static void addExtensionElement(FlowElement element, String name, Integer value) {
  44 + if (value == null) {
  45 + return;
  46 + }
  47 + addExtensionElement(element, name, String.valueOf(value));
  48 + }
  49 +
  50 + public static void addExtensionElement(FlowElement element, String name, Map<String, String> attributes) {
  51 + if (attributes == null) {
  52 + return;
  53 + }
  54 + ExtensionElement extensionElement = new ExtensionElement();
  55 + extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
  56 + extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
  57 + extensionElement.setName(name);
  58 + attributes.forEach((key, value) -> {
  59 + ExtensionAttribute extensionAttribute = new ExtensionAttribute(key, value);
  60 + extensionAttribute.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
  61 + extensionElement.addAttribute(extensionAttribute);
  62 + });
  63 + element.addExtensionElement(extensionElement);
  64 + }
  65 +
  66 + /**
  67 + * 给节点添加候选人元素
  68 + *
  69 + * @param candidateStrategy 候选人策略
  70 + * @param candidateParam 候选人参数,允许空
  71 + * @param flowElement 节点
  72 + */
  73 + public static void addCandidateElements(Integer candidateStrategy, String candidateParam, FlowElement flowElement) {
  74 + addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,
  75 + candidateStrategy == null ? null : candidateStrategy.toString());
  76 + addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam);
  77 + }
  78 +
  79 + /**
  80 + * 解析候选人策略
  81 + *
  82 + * @param userTask 节点
  83 + * @return 候选人策略
  84 + */
27 85 public static Integer parseCandidateStrategy(FlowElement userTask) {
28 86 Integer candidateStrategy = NumberUtils.parseInt(userTask.getAttributeValue(
29 87 BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY));
... ... @@ -49,6 +107,14 @@ public class BpmnModelUtils {
49 107 return NumberUtils.parseInt(parseExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_TYPE));
50 108 }
51 109  
  110 + public static void addTaskRejectElements(BpmSimpleModelNodeVO.RejectHandler rejectHandler, UserTask userTask) {
  111 + if (rejectHandler == null) {
  112 + return;
  113 + }
  114 + addExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE, StrUtil.toStringOrNull(rejectHandler.getType()));
  115 + addExtensionElement(userTask, USER_TASK_REJECT_RETURN_TASK_ID, rejectHandler.getReturnNodeId());
  116 + }
  117 +
52 118 public static BpmUserTaskRejectHandlerType parseRejectHandlerType(FlowElement userTask) {
53 119 Integer rejectHandlerType = NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE));
54 120 return BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
... ... @@ -58,6 +124,21 @@ public class BpmnModelUtils {
58 124 return parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID);
59 125 }
60 126  
  127 + public static void addAssignStartUserHandlerType(Integer assignStartUserHandlerType, UserTask userTask) {
  128 + if (assignStartUserHandlerType == null) {
  129 + return;
  130 + }
  131 + addExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE, assignStartUserHandlerType.toString());
  132 + }
  133 +
  134 + public static void addAssignEmptyHandlerType(BpmSimpleModelNodeVO.AssignEmptyHandler emptyHandler, UserTask userTask) {
  135 + if (emptyHandler == null) {
  136 + return;
  137 + }
  138 + addExtensionElement(userTask, USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE, StrUtil.toStringOrNull(emptyHandler.getType()));
  139 + addExtensionElement(userTask, USER_TASK_ASSIGN_USER_IDS, StrUtil.join(",", emptyHandler.getUserIds()));
  140 + }
  141 +
61 142 public static Integer parseAssignStartUserHandlerType(FlowElement userTask) {
62 143 return NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE));
63 144 }
... ... @@ -78,6 +159,25 @@ public class BpmnModelUtils {
78 159 return element != null ? element.getElementText() : null;
79 160 }
80 161  
  162 + /**
  163 + * 给节点添加表单字段权限元素
  164 + *
  165 + * @param fieldsPermissions 表单字段权限
  166 + * @param flowElement 节点
  167 + */
  168 + public static void addFormFieldsPermission(List<Map<String, String>> fieldsPermissions, FlowElement flowElement) {
  169 + if (CollUtil.isNotEmpty(fieldsPermissions)) {
  170 + fieldsPermissions.forEach(item -> addExtensionElement(flowElement, FORM_FIELD_PERMISSION_ELEMENT, item));
  171 + }
  172 + }
  173 +
  174 + /**
  175 + * 解析表单字段权限
  176 + *
  177 + * @param bpmnModel bpmnModel 对象
  178 + * @param flowElementId 元素 ID
  179 + * @return 表单字段权限
  180 + */
81 181 public static Map<String, String> parseFormFieldsPermission(BpmnModel bpmnModel, String flowElementId) {
82 182 if (bpmnModel == null || StrUtil.isEmpty(flowElementId)) {
83 183 return null;
... ... @@ -101,6 +201,22 @@ public class BpmnModelUtils {
101 201 return fieldsPermission;
102 202 }
103 203  
  204 + /**
  205 + * 给节点添加操作按钮设置元素
  206 + */
  207 + public static void addButtonsSetting(List<BpmSimpleModelNodeVO.OperationButtonSetting> buttonsSetting, UserTask userTask) {
  208 + if (CollUtil.isNotEmpty(buttonsSetting)) {
  209 + List<Map<String, String>> list = CollectionUtils.convertList(buttonsSetting, item -> {
  210 + Map<String, String> settingMap = Maps.newHashMapWithExpectedSize(3);
  211 + settingMap.put(BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE, String.valueOf(item.getId()));
  212 + settingMap.put(BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE, item.getDisplayName());
  213 + settingMap.put(BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE, String.valueOf(item.getEnable()));
  214 + return settingMap;
  215 + });
  216 + list.forEach(item -> addExtensionElement(userTask, BUTTON_SETTING_ELEMENT, item));
  217 + }
  218 + }
  219 +
104 220 public static Map<Integer, BpmTaskRespVO.OperationButtonSetting> parseButtonsSetting(BpmnModel bpmnModel, String flowElementId) {
105 221 FlowElement flowElement = getFlowElementById(bpmnModel, flowElementId);
106 222 if (flowElement == null) {
... ... @@ -193,7 +309,7 @@ public class BpmnModelUtils {
193 309  
194 310 public static EndEvent getEndEvent(BpmnModel model) {
195 311 Process process = model.getMainProcess();
196   - // 从 flowElementList 找 endEvent. TODO 多个 EndEvent 会有问题
  312 + // 从 flowElementList 找 endEvent
197 313 return (EndEvent) CollUtil.findOne(process.getFlowElements(), flowElement -> flowElement instanceof EndEvent);
198 314 }
199 315  
... ... @@ -316,7 +432,6 @@ public class BpmnModelUtils {
316 432 return userTaskList;
317 433 }
318 434  
319   -
320 435 /**
321 436 * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
322 437 * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
... ... @@ -7,32 +7,24 @@ import cn.hutool.core.util.*;
7 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 8 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
9 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
10   -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.RejectHandler;
11   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType;
12   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModeConditionType;
13   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
14   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveMethodEnum;
  10 +import cn.iocoder.yudao.module.bpm.enums.definition.*;
  11 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
15 12 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
16 13 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate;
17 14 import org.flowable.bpmn.BpmnAutoLayout;
  15 +import org.flowable.bpmn.constants.BpmnXMLConstants;
18 16 import org.flowable.bpmn.model.Process;
19 17 import org.flowable.bpmn.model.*;
20 18  
21   -import java.util.ArrayList;
22   -import java.util.List;
23   -import java.util.Map;
24   -import java.util.Objects;
  19 +import java.util.*;
25 20  
26   -import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.OperationButtonSetting;
27 21 import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler;
28 22 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*;
29   -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveMethodEnum.*;
30 23 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveTypeEnum.USER;
31   -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP;
32 24 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutHandlerTypeEnum.REMINDER;
33   -import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum.START_USER;
34 25 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
35   -import static org.flowable.bpmn.constants.BpmnXMLConstants.*;
  26 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
  27 +import static java.util.Arrays.asList;
36 28  
37 29 /**
38 30 * 仿钉钉/飞书的模型相关的工具方法
... ... @@ -46,8 +38,17 @@ public class SimpleModelUtils {
46 38 */
47 39 public static final String JOIN_GATE_WAY_NODE_ID_SUFFIX = "_join";
48 40  
  41 + private static final Map<BpmSimpleModelNodeType, NodeConvert> NODE_CONVERTS = MapUtil.newHashMap();
  42 +
  43 + static {
  44 + List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(),
  45 + new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(),
  46 + new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert());
  47 + converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert));
  48 + }
  49 +
49 50 /**
50   - * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model
  51 + * 仿钉钉流程设计模型数据结构(json)转换成 Bpmn Model
51 52 *
52 53 * @param processId 流程标识
53 54 * @param processName 流程名称
... ... @@ -57,7 +58,7 @@ public class SimpleModelUtils {
57 58 public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) {
58 59 // 1. 创建 BpmnModel
59 60 BpmnModel bpmnModel = new BpmnModel();
60   - bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // 设置命名空间。不加这个,解析 Message 会报 NPE 异常
  61 + bpmnModel.setTargetNamespace(BpmnXMLConstants.BPMN2_NAMESPACE); // 设置命名空间。不加这个,解析 Message 会报 NPE 异常
61 62 // 创建 Process 对象
62 63 Process process = new Process();
63 64 process.setId(processId);
... ... @@ -69,14 +70,14 @@ public class SimpleModelUtils {
69 70 // 原因是:目前前端的第一个节点是“发起人节点”,所以这里构建一个 StartNode,用于创建 Bpmn 的 StartEvent 节点
70 71 BpmSimpleModelNodeVO startNode = buildStartNode();
71 72 startNode.setChildNode(simpleModelNode);
72   - // 从 前端模型数据结构 SimpleModel 构建 FlowNode 并添加到 Main Process
  73 + // 2.2 将前端传递的 simpleModelNode 数据结构(json),转换成从 BPMN FlowNode 元素,并添加到 Main Process 中
73 74 traverseNodeToBuildFlowNode(startNode, process);
74   - // 找到 end event
75   - EndEvent endEvent = (EndEvent) CollUtil.findOne(process.getFlowElements(), item -> item instanceof EndEvent);
76 75  
77   - // 构建并添加节点之间的连线 Sequence Flow
  76 + // 3. 构建并添加节点之间的连线 Sequence Flow
  77 + EndEvent endEvent = BpmnModelUtils.getEndEvent(bpmnModel);
78 78 traverseNodeToBuildSequenceFlow(process, startNode, endEvent.getId());
79   - // 自动布局
  79 +
  80 + // 3. 自动布局
80 81 new BpmnAutoLayout(bpmnModel).execute();
81 82 return bpmnModel;
82 83 }
... ... @@ -85,6 +86,31 @@ public class SimpleModelUtils {
85 86 return new BpmSimpleModelNodeVO().setId(START_EVENT_NODE_ID).setName(START_EVENT_NODE_NAME).setType(START_NODE.getType());
86 87 }
87 88  
  89 + private static void traverseNodeToBuildFlowNode(BpmSimpleModelNodeVO node, Process process) {
  90 + // 1. 判断是否有效节点
  91 + if (!isValidNode(node)) {
  92 + return;
  93 + }
  94 + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
  95 + Assert.notNull(nodeType, "模型节点类型({})不支持", node.getType());
  96 +
  97 + // 2. 处理当前节点
  98 + NodeConvert nodeConvert = NODE_CONVERTS.get(nodeType);
  99 + Assert.notNull(nodeConvert, "模型节点类型的转换器({})不存在", node.getType());
  100 + List<? extends FlowElement> flowElements = nodeConvert.convertList(node);
  101 + flowElements.forEach(process::addFlowElement);
  102 +
  103 + // 如果不是网关类型的接口, 并且chileNode为空退出
  104 + // 如果是“分支”节点,则递归处理条件
  105 + if (BpmSimpleModelNodeType.isBranchNode(node.getType())
  106 + && ArrayUtil.isNotEmpty(node.getConditionNodes())) {
  107 + node.getConditionNodes().forEach(item -> traverseNodeToBuildFlowNode(item.getChildNode(), process));
  108 + }
  109 +
  110 + // 如果有“子”节点,则递归处理子节点
  111 + traverseNodeToBuildFlowNode(node.getChildNode(), process);
  112 + }
  113 +
88 114 // TODO @芋艿:在优化下这个注释
89 115 private static void traverseNodeToBuildSequenceFlow(Process process, BpmSimpleModelNodeVO node, String targetNodeId) {
90 116 // 1.1 无效节点返回
... ... @@ -94,7 +120,7 @@ public class SimpleModelUtils {
94 120 // 1.2 END_NODE 直接返回
95 121 BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
96 122 Assert.notNull(nodeType, "模型节点类型不支持");
97   - if (nodeType == END_NODE) {
  123 + if (nodeType == BpmSimpleModelNodeType.END_NODE) {
98 124 return;
99 125 }
100 126 // 2.1 情况一:普通节点
... ... @@ -238,371 +264,295 @@ public class SimpleModelUtils {
238 264 return sequenceFlow;
239 265 }
240 266  
241   - // TODO @芋艿 改成了 traverseNodeToBuildFlowNode, 连线的叫 traverseNodeToBuildSequenceFlow
242   - private static void traverseNodeToBuildFlowNode(BpmSimpleModelNodeVO node, Process process) {
243   - // 判断是否有效节点
244   - if (!isValidNode(node)) {
245   - return;
246   - }
247   - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
248   - Assert.notNull(nodeType, "模型节点类型不支持");
249   -
250   - List<FlowElement> flowElements = buildFlowNode(node, nodeType);
251   - flowElements.forEach(process::addFlowElement);
252   -
253   - // 如果不是网关类型的接口, 并且chileNode为空退出
254   - // 如果是“分支”节点,则递归处理条件
255   - if (BpmSimpleModelNodeType.isBranchNode(node.getType())
256   - && ArrayUtil.isNotEmpty(node.getConditionNodes())) {
257   - node.getConditionNodes().forEach(item -> traverseNodeToBuildFlowNode(item.getChildNode(), process));
258   - }
259   -
260   - // 如果有“子”节点,则递归处理子节点
261   - traverseNodeToBuildFlowNode(node.getChildNode(), process);
262   - }
263   -
264 267 public static boolean isValidNode(BpmSimpleModelNodeVO node) {
265 268 return node != null && node.getId() != null;
266 269 }
267 270  
268 271 public static boolean isSequentialApproveNode(BpmSimpleModelNodeVO node) {
269   - return APPROVE_NODE.getType().equals(node.getType()) && SEQUENTIAL.getMethod().equals(node.getApproveMethod());
  272 + return APPROVE_NODE.getType().equals(node.getType())
  273 + && BpmUserTaskApproveMethodEnum.SEQUENTIAL.getMethod().equals(node.getApproveMethod());
270 274 }
271 275  
272   - private static List<FlowElement> buildFlowNode(BpmSimpleModelNodeVO node, BpmSimpleModelNodeType nodeType) {
273   - List<FlowElement> list = new ArrayList<>();
274   - switch (nodeType) {
275   - case START_NODE: { // 开始节点
276   - StartEvent startEvent = convertStartNode(node);
277   - list.add(startEvent);
278   - break;
279   - }
280   - case END_NODE: { // 结束节点
281   - EndEvent endEvent = convertEndNode(node);
282   - list.add(endEvent);
283   - break;
284   - }
285   - case START_USER_NODE: { // 发起人节点
286   - UserTask userTask = convertStartUserNode(node);
287   - list.add(userTask);
288   - break;
289   - }
290   - case APPROVE_NODE: { // 审批节点
291   - List<FlowElement> flowElements = convertApproveNode(node);
292   - list.addAll(flowElements);
293   - break;
294   - }
295   - case COPY_NODE: { // 抄送节点
296   - ServiceTask serviceTask = convertCopyNode(node);
297   - list.add(serviceTask);
298   - break;
299   - }
300   - case CONDITION_BRANCH_NODE: {
301   - ExclusiveGateway exclusiveGateway = convertConditionBranchNode(node);
302   - list.add(exclusiveGateway);
303   - break;
304   - }
305   - case PARALLEL_BRANCH_NODE: {
306   - List<ParallelGateway> parallelGateways = convertParallelBranchNode(node);
307   - list.addAll(parallelGateways);
308   - break;
309   - }
310   - case INCLUSIVE_BRANCH_NODE: {
311   - // TODO jason 待实现
312   - break;
313   - }
314   - default: {
315   - // TODO 其它节点类型的实现
  276 + private static InclusiveGateway convertInclusiveBranchNode(BpmSimpleModelNodeVO node, Boolean isFork) {
  277 + InclusiveGateway inclusiveGateway = new InclusiveGateway();
  278 + inclusiveGateway.setId(node.getId());
  279 + // TODO @jason:这里是不是 setName 哈;
  280 +
  281 + // @芋艿 isFork 为 false 就是合并网关。由前端传入。这个前端暂时还未实现
  282 + if (isFork) {
  283 + Assert.notEmpty(node.getConditionNodes(), "条件节点不能为空");
  284 + // 寻找默认的序列流
  285 + BpmSimpleModelNodeVO defaultSeqFlow = CollUtil.findOne(
  286 + node.getConditionNodes(), item -> BooleanUtil.isTrue(item.getDefaultFlow()));
  287 + if (defaultSeqFlow != null) {
  288 + inclusiveGateway.setDefaultFlow(defaultSeqFlow.getId());
316 289 }
317 290 }
318   - return list;
  291 + return inclusiveGateway;
319 292 }
320 293  
321   - private static UserTask convertStartUserNode(BpmSimpleModelNodeVO node) {
322   - return buildBpmnStartUserTask(node);
323   - }
  294 + // ========== 各种 convert 节点的方法: BpmSimpleModelNodeVO => BPMN FlowElement ==========
324 295  
325   - private static List<FlowElement> convertApproveNode(BpmSimpleModelNodeVO node) {
326   - List<FlowElement> flowElements = new ArrayList<>();
327   - UserTask userTask = buildBpmnUserTask(node);
328   - flowElements.add(userTask);
  296 + private interface NodeConvert {
329 297  
330   - // 添加用户任务的 Timer Boundary Event, 用于任务的审批超时处理
331   - if (node.getTimeoutHandler() != null && node.getTimeoutHandler().getEnable()) {
332   - BoundaryEvent boundaryEvent = buildUserTaskTimeoutBoundaryEvent(userTask, node.getTimeoutHandler());
333   - flowElements.add(boundaryEvent);
  298 + default List<? extends FlowElement> convertList(BpmSimpleModelNodeVO node) {
  299 + return Collections.singletonList(convert(node));
334 300 }
335   - return flowElements;
336   - }
337 301  
338   - /**
339   - * 添加 UserTask 用户的审批超时 BoundaryEvent 事件
340   - *
341   - * @param userTask 审批任务
342   - * @param timeoutHandler 超时处理器
343   - * @return BoundaryEvent 超时事件
344   - */
345   - private static BoundaryEvent buildUserTaskTimeoutBoundaryEvent(UserTask userTask, TimeoutHandler timeoutHandler) {
346   - // 1.1 定时器边界事件
347   - BoundaryEvent boundaryEvent = new BoundaryEvent();
348   - boundaryEvent.setId("Event-" + IdUtil.fastUUID());
349   - boundaryEvent.setCancelActivity(false); // 设置关联的任务为不会被中断
350   - boundaryEvent.setAttachedToRef(userTask);
351   - // 1.2 定义超时时间、最大提醒次数
352   - TimerEventDefinition eventDefinition = new TimerEventDefinition();
353   - eventDefinition.setTimeDuration(timeoutHandler.getTimeDuration());
354   - if (Objects.equals(REMINDER.getType(), timeoutHandler.getType()) &&
355   - timeoutHandler.getMaxRemindCount() != null && timeoutHandler.getMaxRemindCount() > 1) {
356   - eventDefinition.setTimeCycle(String.format("R%d/%s",
357   - timeoutHandler.getMaxRemindCount(), timeoutHandler.getTimeDuration()));
  302 + default FlowElement convert(BpmSimpleModelNodeVO node) {
  303 + throw new UnsupportedOperationException("请实现该方法");
358 304 }
359   - boundaryEvent.addEventDefinition(eventDefinition);
360 305  
361   - // 2.1 添加定时器边界事件类型
362   - addExtensionElement(boundaryEvent, BOUNDARY_EVENT_TYPE, BpmBoundaryEventType.USER_TASK_TIMEOUT.getType().toString());
363   - // 2.2 添加超时执行动作元素
364   - addExtensionElement(boundaryEvent, USER_TASK_TIMEOUT_HANDLER_TYPE, StrUtil.toStringOrNull(timeoutHandler.getType()));
365   - return boundaryEvent;
366   - }
  306 + BpmSimpleModelNodeType getType();
367 307  
368   - private static List<ParallelGateway> convertParallelBranchNode(BpmSimpleModelNodeVO node) {
369   - ParallelGateway parallelGateway = new ParallelGateway();
370   - parallelGateway.setId(node.getId());
371   - // TODO @jason:setName
372   -
373   - // TODO @芋艿 + jason:合并网关;是不是要有条件啥的。微信讨论
374   - // 并行聚合网关有程序创建。前端不需要传入
375   - ParallelGateway joinParallelGateway = new ParallelGateway();
376   - joinParallelGateway.setId(node.getId() + JOIN_GATE_WAY_NODE_ID_SUFFIX);
377   - return CollUtil.newArrayList(parallelGateway, joinParallelGateway);
378 308 }
379 309  
380   - private static ServiceTask convertCopyNode(BpmSimpleModelNodeVO node) {
381   - ServiceTask serviceTask = new ServiceTask();
382   - serviceTask.setId(node.getId());
383   - serviceTask.setName(node.getName());
384   - serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
385   - serviceTask.setImplementation("${" + BpmCopyTaskDelegate.BEAN_NAME + "}");
386   -
387   - // 添加抄送候选人元素
388   - addCandidateElements(node.getCandidateStrategy(), node.getCandidateParam(), serviceTask);
389   - // 添加表单字段权限属性元素
390   - addFormFieldsPermission(node.getFieldsPermission(), serviceTask);
391   - return serviceTask;
392   - }
  310 + private static class StartNodeConvert implements NodeConvert {
393 311  
394   - /**
395   - * 给节点添加候选人元素
396   - */
397   - private static void addCandidateElements(Integer candidateStrategy, String candidateParam, FlowElement flowElement) {
398   - addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,
399   - candidateStrategy == null ? null : candidateStrategy.toString());
400   - addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam);
401   - }
  312 + @Override
  313 + public StartEvent convert(BpmSimpleModelNodeVO node) {
  314 + StartEvent startEvent = new StartEvent();
  315 + startEvent.setId(node.getId());
  316 + startEvent.setName(node.getName());
  317 + return startEvent;
  318 + }
402 319  
403   - private static ExclusiveGateway convertConditionBranchNode(BpmSimpleModelNodeVO node) {
404   - Assert.notEmpty(node.getConditionNodes(), "条件分支节点不能为空");
405   - ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
406   - exclusiveGateway.setId(node.getId());
407   - // 寻找默认的序列流
408   - BpmSimpleModelNodeVO defaultSeqFlow = CollUtil.findOne(node.getConditionNodes(),
409   - item -> BooleanUtil.isTrue(item.getDefaultFlow()));
410   - if (defaultSeqFlow != null) {
411   - exclusiveGateway.setDefaultFlow(defaultSeqFlow.getId());
  320 + @Override
  321 + public BpmSimpleModelNodeType getType() {
  322 + return BpmSimpleModelNodeType.START_NODE;
412 323 }
413   - return exclusiveGateway;
  324 +
414 325 }
415 326  
416   - private static InclusiveGateway convertInclusiveBranchNode(BpmSimpleModelNodeVO node, Boolean isFork) {
417   - InclusiveGateway inclusiveGateway = new InclusiveGateway();
418   - inclusiveGateway.setId(node.getId());
419   - // TODO @jason:这里是不是 setName 哈;
  327 + private static class EndNodeConvert implements NodeConvert {
420 328  
421   - // TODO @芋艿 + jason:是不是搞个合并网关;这里微信讨论下,有点奇怪;
422   - // @芋艿 isFork 为 false 就是合并网关。由前端传入。这个前端暂时还未实现
423   - if (isFork) {
424   - Assert.notEmpty(node.getConditionNodes(), "条件节点不能为空");
425   - // 寻找默认的序列流
426   - BpmSimpleModelNodeVO defaultSeqFlow = CollUtil.findOne(
427   - node.getConditionNodes(), item -> BooleanUtil.isTrue(item.getDefaultFlow()));
428   - if (defaultSeqFlow != null) {
429   - inclusiveGateway.setDefaultFlow(defaultSeqFlow.getId());
430   - }
  329 + @Override
  330 + public EndEvent convert(BpmSimpleModelNodeVO node) {
  331 + EndEvent endEvent = new EndEvent();
  332 + endEvent.setId(node.getId());
  333 + endEvent.setName(node.getName());
  334 + // TODO @芋艿 + jason:要不要加一个终止定义?
  335 + return endEvent;
431 336 }
432   - return inclusiveGateway;
433   - }
434 337  
435   - private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node) {
436   - UserTask userTask = new UserTask();
437   - userTask.setId(node.getId());
438   - userTask.setName(node.getName());
  338 + @Override
  339 + public BpmSimpleModelNodeType getType() {
  340 + return BpmSimpleModelNodeType.END_NODE;
  341 + }
  342 +
  343 + }
439 344  
440   - // 如果不是审批人节点,则直接返回
441   - addExtensionElement(userTask, USER_TASK_APPROVE_TYPE, StrUtil.toStringOrNull(node.getApproveType()));
442   - if (ObjectUtil.notEqual(node.getApproveType(), USER.getType())) {
  345 + private static class StartUserNodeConvert implements NodeConvert {
  346 +
  347 + @Override
  348 + public UserTask convert(BpmSimpleModelNodeVO node) {
  349 + UserTask userTask = new UserTask();
  350 + userTask.setId(node.getId());
  351 + userTask.setName(node.getName());
  352 +
  353 + // 人工审批
  354 + addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_TYPE, BpmUserTaskApproveTypeEnum.USER.getType());
  355 + // 候选人策略为发起人自己
  356 + addCandidateElements(BpmTaskCandidateStrategyEnum.START_USER.getStrategy(), null, userTask);
  357 + // 添加表单字段权限属性元素
  358 + addFormFieldsPermission(node.getFieldsPermission(), userTask);
  359 + // 添加操作按钮配置属性元素
  360 + addButtonsSetting(node.getButtonsSetting(), userTask);
  361 + // 使用自动通过策略
  362 + // TODO @芋艿 复用了SKIP, 是否需要新加一个策略;TODO @芋艿:【回复】是不是应该类似飞书,搞个草稿状态。待定;还有一种策略,不标记自动通过,而是首次发起后,第一个节点,自动通过;
  363 + addAssignStartUserHandlerType(BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType(), userTask);
443 364 return userTask;
444 365 }
445 366  
446   - // 添加候选人元素
447   - addCandidateElements(node.getCandidateStrategy(), node.getCandidateParam(), userTask);
448   - // 添加表单字段权限属性元素
449   - addFormFieldsPermission(node.getFieldsPermission(), userTask);
450   - // 添加操作按钮配置属性元素
451   - addButtonsSetting(node.getButtonsSetting(), userTask);
452   - // 处理多实例(审批方式)
453   - processMultiInstanceLoopCharacteristics(node.getApproveMethod(), node.getApproveRatio(), userTask);
454   - // 添加任务被拒绝的处理元素
455   - addTaskRejectElements(node.getRejectHandler(), userTask);
456   - // 添加用户任务的审批人与发起人相同时的处理元素
457   - addAssignStartUserHandlerType(node.getAssignStartUserHandlerType(), userTask);
458   - // 添加用户任务的空处理元素
459   - addAssignEmptyHandlerType(node.getAssignEmptyHandler(), userTask);
460   - // 设置审批任务的截止时间
461   - if (node.getTimeoutHandler() != null && node.getTimeoutHandler().getEnable()) {
462   - userTask.setDueDate(node.getTimeoutHandler().getTimeDuration());
  367 + @Override
  368 + public BpmSimpleModelNodeType getType() {
  369 + return BpmSimpleModelNodeType.START_USER_NODE;
463 370 }
464   - return userTask;
  371 +
465 372 }
466 373  
467   - private static void addTaskRejectElements(RejectHandler rejectHandler, UserTask userTask) {
468   - if (rejectHandler == null) {
469   - return;
  374 + private static class ApproveNodeConvert implements NodeConvert {
  375 +
  376 + @Override
  377 + public List<FlowElement> convertList(BpmSimpleModelNodeVO node) {
  378 + List<FlowElement> flowElements = new ArrayList<>(2);
  379 + // 1. 构建用户任务
  380 + UserTask userTask = buildBpmnUserTask(node);
  381 + flowElements.add(userTask);
  382 +
  383 + // 2. 添加用户任务的 Timer Boundary Event, 用于任务的审批超时处理
  384 + if (node.getTimeoutHandler() != null && node.getTimeoutHandler().getEnable()) {
  385 + BoundaryEvent boundaryEvent = buildUserTaskTimeoutBoundaryEvent(userTask, node.getTimeoutHandler());
  386 + flowElements.add(boundaryEvent);
  387 + }
  388 + return flowElements;
470 389 }
471   - addExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE, StrUtil.toStringOrNull(rejectHandler.getType()));
472   - addExtensionElement(userTask, USER_TASK_REJECT_RETURN_TASK_ID, rejectHandler.getReturnNodeId());
473   - }
474 390  
475   - private static void addAssignStartUserHandlerType(Integer assignStartUserHandlerType, UserTask userTask) {
476   - if (assignStartUserHandlerType == null) {
477   - return;
  391 + @Override
  392 + public BpmSimpleModelNodeType getType() {
  393 + return BpmSimpleModelNodeType.APPROVE_NODE;
478 394 }
479   - addExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE, assignStartUserHandlerType.toString());
480   - }
481 395  
482   - private static void addAssignEmptyHandlerType(BpmSimpleModelNodeVO.AssignEmptyHandler emptyHandler, UserTask userTask) {
483   - if (emptyHandler == null) {
484   - return;
  396 + /**
  397 + * 添加 UserTask 用户的审批超时 BoundaryEvent 事件
  398 + *
  399 + * @param userTask 审批任务
  400 + * @param timeoutHandler 超时处理器
  401 + * @return BoundaryEvent 超时事件
  402 + */
  403 + private BoundaryEvent buildUserTaskTimeoutBoundaryEvent(UserTask userTask, TimeoutHandler timeoutHandler) {
  404 + // 1.1 定时器边界事件
  405 + BoundaryEvent boundaryEvent = new BoundaryEvent();
  406 + boundaryEvent.setId("Event-" + IdUtil.fastUUID());
  407 + boundaryEvent.setCancelActivity(false); // 设置关联的任务为不会被中断
  408 + boundaryEvent.setAttachedToRef(userTask);
  409 + // 1.2 定义超时时间、最大提醒次数
  410 + TimerEventDefinition eventDefinition = new TimerEventDefinition();
  411 + eventDefinition.setTimeDuration(timeoutHandler.getTimeDuration());
  412 + if (Objects.equals(REMINDER.getType(), timeoutHandler.getType()) &&
  413 + timeoutHandler.getMaxRemindCount() != null && timeoutHandler.getMaxRemindCount() > 1) {
  414 + eventDefinition.setTimeCycle(String.format("R%d/%s",
  415 + timeoutHandler.getMaxRemindCount(), timeoutHandler.getTimeDuration()));
  416 + }
  417 + boundaryEvent.addEventDefinition(eventDefinition);
  418 +
  419 + // 2.1 添加定时器边界事件类型
  420 + addExtensionElement(boundaryEvent, BOUNDARY_EVENT_TYPE, BpmBoundaryEventType.USER_TASK_TIMEOUT.getType().toString());
  421 + // 2.2 添加超时执行动作元素
  422 + addExtensionElement(boundaryEvent, USER_TASK_TIMEOUT_HANDLER_TYPE, StrUtil.toStringOrNull(timeoutHandler.getType()));
  423 + return boundaryEvent;
485 424 }
486   - addExtensionElement(userTask, USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE, StrUtil.toStringOrNull(emptyHandler.getType()));
487   - addExtensionElement(userTask, USER_TASK_ASSIGN_USER_IDS, StrUtil.join(",", emptyHandler.getUserIds()));
488   - }
489 425  
490   - private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
491   - BpmUserTaskApproveMethodEnum approveMethodEnum = BpmUserTaskApproveMethodEnum.valueOf(approveMethod);
492   - Assert.notNull(approveMethodEnum, "审批方式({})不能为空", approveMethodEnum);
493   - // 添加审批方式的扩展属性
494   - addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_METHOD, approveMethod.toString());
495   - if (approveMethodEnum == RANDOM) {
496   - // 随机审批,不需要设置多实例属性
497   - return;
  426 + private UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node) {
  427 + UserTask userTask = new UserTask();
  428 + userTask.setId(node.getId());
  429 + userTask.setName(node.getName());
  430 +
  431 + // 如果不是审批人节点,则直接返回
  432 + addExtensionElement(userTask, USER_TASK_APPROVE_TYPE, StrUtil.toStringOrNull(node.getApproveType()));
  433 + if (ObjectUtil.notEqual(node.getApproveType(), USER.getType())) {
  434 + return userTask;
  435 + }
  436 +
  437 + // 添加候选人元素
  438 + addCandidateElements(node.getCandidateStrategy(), node.getCandidateParam(), userTask);
  439 + // 添加表单字段权限属性元素
  440 + addFormFieldsPermission(node.getFieldsPermission(), userTask);
  441 + // 添加操作按钮配置属性元素
  442 + addButtonsSetting(node.getButtonsSetting(), userTask);
  443 + // 处理多实例(审批方式)
  444 + processMultiInstanceLoopCharacteristics(node.getApproveMethod(), node.getApproveRatio(), userTask);
  445 + // 添加任务被拒绝的处理元素
  446 + addTaskRejectElements(node.getRejectHandler(), userTask);
  447 + // 添加用户任务的审批人与发起人相同时的处理元素
  448 + addAssignStartUserHandlerType(node.getAssignStartUserHandlerType(), userTask);
  449 + // 添加用户任务的空处理元素
  450 + addAssignEmptyHandlerType(node.getAssignEmptyHandler(), userTask);
  451 + // 设置审批任务的截止时间
  452 + if (node.getTimeoutHandler() != null && node.getTimeoutHandler().getEnable()) {
  453 + userTask.setDueDate(node.getTimeoutHandler().getTimeDuration());
  454 + }
  455 + return userTask;
498 456 }
499 457  
500   - // 处理多实例审批方式
501   - MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics();
502   - // 设置 collectionVariable。本系统用不到,仅仅为了 Flowable 校验不报错
503   - multiInstanceCharacteristics.setInputDataItem("${coll_userList}");
504   - if (approveMethodEnum == BpmUserTaskApproveMethodEnum.ANY) {
505   - multiInstanceCharacteristics.setCompletionCondition(approveMethodEnum.getCompletionCondition());
506   - multiInstanceCharacteristics.setSequential(false);
507   - } else if (approveMethodEnum == SEQUENTIAL) {
508   - multiInstanceCharacteristics.setCompletionCondition(approveMethodEnum.getCompletionCondition());
509   - multiInstanceCharacteristics.setSequential(true);
510   - multiInstanceCharacteristics.setLoopCardinality("1");
511   - } else if (approveMethodEnum == RATIO) {
512   - Assert.notNull(approveRatio, "通过比例不能为空");
513   - multiInstanceCharacteristics.setCompletionCondition(
514   - String.format(approveMethodEnum.getCompletionCondition(), String.format("%.2f", approveRatio / 100D)));
515   - multiInstanceCharacteristics.setSequential(false);
  458 + private void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
  459 + BpmUserTaskApproveMethodEnum approveMethodEnum = BpmUserTaskApproveMethodEnum.valueOf(approveMethod);
  460 + Assert.notNull(approveMethodEnum, "审批方式({})不能为空", approveMethodEnum);
  461 + // 添加审批方式的扩展属性
  462 + addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_METHOD, approveMethod.toString());
  463 + if (approveMethodEnum == BpmUserTaskApproveMethodEnum.RANDOM) {
  464 + // 随机审批,不需要设置多实例属性
  465 + return;
  466 + }
  467 +
  468 + // 处理多实例审批方式
  469 + MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics();
  470 + // 设置 collectionVariable。本系统用不到,仅仅为了 Flowable 校验不报错
  471 + multiInstanceCharacteristics.setInputDataItem("${coll_userList}");
  472 + if (approveMethodEnum == BpmUserTaskApproveMethodEnum.ANY) {
  473 + multiInstanceCharacteristics.setCompletionCondition(approveMethodEnum.getCompletionCondition());
  474 + multiInstanceCharacteristics.setSequential(false);
  475 + } else if (approveMethodEnum == BpmUserTaskApproveMethodEnum.SEQUENTIAL) {
  476 + multiInstanceCharacteristics.setCompletionCondition(approveMethodEnum.getCompletionCondition());
  477 + multiInstanceCharacteristics.setSequential(true);
  478 + multiInstanceCharacteristics.setLoopCardinality("1");
  479 + } else if (approveMethodEnum == BpmUserTaskApproveMethodEnum.RATIO) {
  480 + Assert.notNull(approveRatio, "通过比例不能为空");
  481 + multiInstanceCharacteristics.setCompletionCondition(
  482 + String.format(approveMethodEnum.getCompletionCondition(), String.format("%.2f", approveRatio / 100D)));
  483 + multiInstanceCharacteristics.setSequential(false);
  484 + }
  485 + userTask.setLoopCharacteristics(multiInstanceCharacteristics);
516 486 }
517   - userTask.setLoopCharacteristics(multiInstanceCharacteristics);
  487 +
518 488 }
519 489  
520   - /**
521   - * 给节点添加操作按钮设置元素
522   - */
523   - private static void addButtonsSetting(List<OperationButtonSetting> buttonsSetting, UserTask userTask) {
524   - if (CollUtil.isNotEmpty(buttonsSetting)) {
525   - List<Map<String, String>> list = CollectionUtils.convertList(buttonsSetting, item -> {
526   - Map<String, String> settingMap = MapUtil.newHashMap(16);
527   - settingMap.put(BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE, String.valueOf(item.getId()));
528   - settingMap.put(BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE, item.getDisplayName());
529   - settingMap.put(BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE, String.valueOf(item.getEnable()));
530   - return settingMap;
531   - });
532   - list.forEach(item -> addExtensionElement(userTask, BUTTON_SETTING_ELEMENT, item));
  490 + private static class CopyNodeConvert implements NodeConvert {
  491 +
  492 + @Override
  493 + public ServiceTask convert(BpmSimpleModelNodeVO node) {
  494 + ServiceTask serviceTask = new ServiceTask();
  495 + serviceTask.setId(node.getId());
  496 + serviceTask.setName(node.getName());
  497 + serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
  498 + serviceTask.setImplementation("${" + BpmCopyTaskDelegate.BEAN_NAME + "}");
  499 +
  500 + // 添加抄送候选人元素
  501 + addCandidateElements(node.getCandidateStrategy(), node.getCandidateParam(), serviceTask);
  502 + // 添加表单字段权限属性元素
  503 + addFormFieldsPermission(node.getFieldsPermission(), serviceTask);
  504 + return serviceTask;
533 505 }
534   - }
535 506  
536   - /**
537   - * 给节点添加表单字段权限元素
538   - */
539   - private static void addFormFieldsPermission(List<Map<String, String>> fieldsPermissions, FlowElement flowElement) {
540   - if (CollUtil.isNotEmpty(fieldsPermissions)) {
541   - fieldsPermissions.forEach(item -> addExtensionElement(flowElement, FORM_FIELD_PERMISSION_ELEMENT, item));
  507 + @Override
  508 + public BpmSimpleModelNodeType getType() {
  509 + return BpmSimpleModelNodeType.COPY_NODE;
542 510 }
  511 +
543 512 }
544 513  
545   - private static void addExtensionElement(FlowElement element, String name, Map<String, String> attributes) {
546   - if (attributes == null) {
547   - return;
  514 + private static class ConditionBranchNodeConvert implements NodeConvert {
  515 +
  516 + @Override
  517 + public ExclusiveGateway convert(BpmSimpleModelNodeVO node) {
  518 + ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
  519 + exclusiveGateway.setId(node.getId());
  520 + // TODO @jason:setName
  521 +
  522 + // 设置默认的序列流(条件)
  523 + BpmSimpleModelNodeVO defaultSeqFlow = CollUtil.findOne(node.getConditionNodes(),
  524 + item -> BooleanUtil.isTrue(item.getDefaultFlow()));
  525 + Assert.notNull(defaultSeqFlow, "条件分支节点({})的默认序列流不能为空", node.getId());
  526 + exclusiveGateway.setDefaultFlow(defaultSeqFlow.getId());
  527 + return exclusiveGateway;
548 528 }
549   - ExtensionElement extensionElement = new ExtensionElement();
550   - extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
551   - extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
552   - extensionElement.setName(name);
553   - attributes.forEach((key, value) -> {
554   - ExtensionAttribute extensionAttribute = new ExtensionAttribute(key, value);
555   - extensionAttribute.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
556   - extensionElement.addAttribute(extensionAttribute);
557   - });
558   - element.addExtensionElement(extensionElement);
559   - }
560 529  
561   - private static void addExtensionElement(FlowElement element, String name, String value) {
562   - if (value == null) {
563   - return;
  530 + @Override
  531 + public BpmSimpleModelNodeType getType() {
  532 + return BpmSimpleModelNodeType.CONDITION_BRANCH_NODE;
564 533 }
565   - ExtensionElement extensionElement = new ExtensionElement();
566   - extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
567   - extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
568   - extensionElement.setElementText(value);
569   - extensionElement.setName(name);
570   - element.addExtensionElement(extensionElement);
  534 +
571 535 }
572 536  
573   - // ========== 各种 build 节点的方法 ==========
  537 + private static class ParallelBranchNodeConvert implements NodeConvert {
574 538  
575   - private static StartEvent convertStartNode(BpmSimpleModelNodeVO node) {
576   - StartEvent startEvent = new StartEvent();
577   - startEvent.setId(node.getId());
578   - startEvent.setName(node.getName());
579   - return startEvent;
580   - }
  539 + @Override
  540 + public List<ParallelGateway> convertList(BpmSimpleModelNodeVO node) {
  541 + ParallelGateway parallelGateway = new ParallelGateway();
  542 + parallelGateway.setId(node.getId());
  543 + // TODO @jason:setName
581 544  
582   - private static UserTask buildBpmnStartUserTask(BpmSimpleModelNodeVO node) {
583   - UserTask userTask = new UserTask();
584   - userTask.setId(node.getId());
585   - userTask.setName(node.getName());
586   - // 人工审批
587   - addExtensionElement(userTask, USER_TASK_APPROVE_TYPE, USER.getType().toString());
588   - // 候选人策略为发起人自己
589   - addCandidateElements(START_USER.getStrategy(), null, userTask);
590   - // 添加表单字段权限属性元素
591   - addFormFieldsPermission(node.getFieldsPermission(), userTask);
592   - // 添加操作按钮配置属性元素
593   - addButtonsSetting(node.getButtonsSetting(), userTask);
594   - // 使用自动通过策略 TODO @芋艿 复用了SKIP, 是否需要新加一个策略;TODO @芋艿:【回复】是不是应该类似飞书,搞个草稿状态。待定;还有一种策略,不标记自动通过,而是首次发起后,第一个节点,自动通过;
595   - addAssignStartUserHandlerType(SKIP.getType(), userTask);
596   - return userTask;
597   - }
  545 + // 并行聚合网关由程序创建,前端不需要传入
  546 + ParallelGateway joinParallelGateway = new ParallelGateway();
  547 + joinParallelGateway.setId(node.getId() + JOIN_GATE_WAY_NODE_ID_SUFFIX);
  548 + return CollUtil.newArrayList(parallelGateway, joinParallelGateway);
  549 + }
598 550  
599   - private static EndEvent convertEndNode(BpmSimpleModelNodeVO node) {
600   - EndEvent endEvent = new EndEvent();
601   - endEvent.setId(node.getId());
602   - endEvent.setName(node.getName());
  551 + @Override
  552 + public BpmSimpleModelNodeType getType() {
  553 + return BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE;
  554 + }
603 555  
604   - // TODO @芋艿 + jason:要不要加一个终止定义?
605   - return endEvent;
606 556 }
607 557  
608 558 }
... ...