Commit 2c2512e40550f0950202f5332b0b309f4375e999
1 parent
8469b2b8
【代码优化】工作流:将元素相关的操作,挪到 BpmnModelUtils 中
【代码优化】工作流:新增 NodeConvert 接口以及其实现,将 SimpleModelUtils 统一收敛
Showing
3 changed files
with
396 additions
and
329 deletions
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,6 +10,8 @@ import lombok.Data; | ||
| 10 | @Data | 10 | @Data |
| 11 | public class BpmApprovalDetailReqVO { | 11 | public class BpmApprovalDetailReqVO { |
| 12 | 12 | ||
| 13 | + // TODO @jason:这里要不注释说明下,什么情况下,使用 processDefinitionId、processInstanceId、activityId、taskId。 | ||
| 14 | + | ||
| 13 | @Schema(description = "流程定义的编号", example = "1024") | 15 | @Schema(description = "流程定义的编号", example = "1024") |
| 14 | private String processDefinitionId; // 发起流程的时候传流程定义 Id | 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,11 +4,14 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.map.MapUtil; | 4 | import cn.hutool.core.map.MapUtil; |
| 5 | import cn.hutool.core.util.ArrayUtil; | 5 | import cn.hutool.core.util.ArrayUtil; |
| 6 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 8 | import cn.iocoder.yudao.framework.common.util.string.StrUtils; | 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 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | 11 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; |
| 10 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType; | 12 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType; |
| 11 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | 13 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; |
| 14 | +import com.google.common.collect.Maps; | ||
| 12 | import org.flowable.bpmn.converter.BpmnXMLConverter; | 15 | import org.flowable.bpmn.converter.BpmnXMLConverter; |
| 13 | import org.flowable.bpmn.model.Process; | 16 | import org.flowable.bpmn.model.Process; |
| 14 | import org.flowable.bpmn.model.*; | 17 | import org.flowable.bpmn.model.*; |
| @@ -18,12 +21,67 @@ import java.util.*; | @@ -18,12 +21,67 @@ import java.util.*; | ||
| 18 | 21 | ||
| 19 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; | 22 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; |
| 20 | import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE; | 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 | public class BpmnModelUtils { | 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 | public static Integer parseCandidateStrategy(FlowElement userTask) { | 85 | public static Integer parseCandidateStrategy(FlowElement userTask) { |
| 28 | Integer candidateStrategy = NumberUtils.parseInt(userTask.getAttributeValue( | 86 | Integer candidateStrategy = NumberUtils.parseInt(userTask.getAttributeValue( |
| 29 | BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); | 87 | BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); |
| @@ -49,6 +107,14 @@ public class BpmnModelUtils { | @@ -49,6 +107,14 @@ public class BpmnModelUtils { | ||
| 49 | return NumberUtils.parseInt(parseExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_TYPE)); | 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 | public static BpmUserTaskRejectHandlerType parseRejectHandlerType(FlowElement userTask) { | 118 | public static BpmUserTaskRejectHandlerType parseRejectHandlerType(FlowElement userTask) { |
| 53 | Integer rejectHandlerType = NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE)); | 119 | Integer rejectHandlerType = NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE)); |
| 54 | return BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType); | 120 | return BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType); |
| @@ -58,6 +124,21 @@ public class BpmnModelUtils { | @@ -58,6 +124,21 @@ public class BpmnModelUtils { | ||
| 58 | return parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID); | 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 | public static Integer parseAssignStartUserHandlerType(FlowElement userTask) { | 142 | public static Integer parseAssignStartUserHandlerType(FlowElement userTask) { |
| 62 | return NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE)); | 143 | return NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE)); |
| 63 | } | 144 | } |
| @@ -78,6 +159,25 @@ public class BpmnModelUtils { | @@ -78,6 +159,25 @@ public class BpmnModelUtils { | ||
| 78 | return element != null ? element.getElementText() : null; | 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 | public static Map<String, String> parseFormFieldsPermission(BpmnModel bpmnModel, String flowElementId) { | 181 | public static Map<String, String> parseFormFieldsPermission(BpmnModel bpmnModel, String flowElementId) { |
| 82 | if (bpmnModel == null || StrUtil.isEmpty(flowElementId)) { | 182 | if (bpmnModel == null || StrUtil.isEmpty(flowElementId)) { |
| 83 | return null; | 183 | return null; |
| @@ -101,6 +201,22 @@ public class BpmnModelUtils { | @@ -101,6 +201,22 @@ public class BpmnModelUtils { | ||
| 101 | return fieldsPermission; | 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 | public static Map<Integer, BpmTaskRespVO.OperationButtonSetting> parseButtonsSetting(BpmnModel bpmnModel, String flowElementId) { | 220 | public static Map<Integer, BpmTaskRespVO.OperationButtonSetting> parseButtonsSetting(BpmnModel bpmnModel, String flowElementId) { |
| 105 | FlowElement flowElement = getFlowElementById(bpmnModel, flowElementId); | 221 | FlowElement flowElement = getFlowElementById(bpmnModel, flowElementId); |
| 106 | if (flowElement == null) { | 222 | if (flowElement == null) { |
| @@ -193,7 +309,7 @@ public class BpmnModelUtils { | @@ -193,7 +309,7 @@ public class BpmnModelUtils { | ||
| 193 | 309 | ||
| 194 | public static EndEvent getEndEvent(BpmnModel model) { | 310 | public static EndEvent getEndEvent(BpmnModel model) { |
| 195 | Process process = model.getMainProcess(); | 311 | Process process = model.getMainProcess(); |
| 196 | - // 从 flowElementList 找 endEvent. TODO 多个 EndEvent 会有问题 | 312 | + // 从 flowElementList 找 endEvent |
| 197 | return (EndEvent) CollUtil.findOne(process.getFlowElements(), flowElement -> flowElement instanceof EndEvent); | 313 | return (EndEvent) CollUtil.findOne(process.getFlowElements(), flowElement -> flowElement instanceof EndEvent); |
| 198 | } | 314 | } |
| 199 | 315 | ||
| @@ -316,7 +432,6 @@ public class BpmnModelUtils { | @@ -316,7 +432,6 @@ public class BpmnModelUtils { | ||
| 316 | return userTaskList; | 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,32 +7,24 @@ import cn.hutool.core.util.*; | ||
| 7 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 7 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 8 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; | 8 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; | 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 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | 12 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; |
| 16 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate; | 13 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate; |
| 17 | import org.flowable.bpmn.BpmnAutoLayout; | 14 | import org.flowable.bpmn.BpmnAutoLayout; |
| 15 | +import org.flowable.bpmn.constants.BpmnXMLConstants; | ||
| 18 | import org.flowable.bpmn.model.Process; | 16 | import org.flowable.bpmn.model.Process; |
| 19 | import org.flowable.bpmn.model.*; | 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 | import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler; | 21 | import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler; |
| 28 | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*; | 22 | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*; |
| 29 | -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveMethodEnum.*; | ||
| 30 | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveTypeEnum.USER; | 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 | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutHandlerTypeEnum.REMINDER; | 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 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; | 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,8 +38,17 @@ public class SimpleModelUtils { | ||
| 46 | */ | 38 | */ |
| 47 | public static final String JOIN_GATE_WAY_NODE_ID_SUFFIX = "_join"; | 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 | * @param processId 流程标识 | 53 | * @param processId 流程标识 |
| 53 | * @param processName 流程名称 | 54 | * @param processName 流程名称 |
| @@ -57,7 +58,7 @@ public class SimpleModelUtils { | @@ -57,7 +58,7 @@ public class SimpleModelUtils { | ||
| 57 | public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { | 58 | public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { |
| 58 | // 1. 创建 BpmnModel | 59 | // 1. 创建 BpmnModel |
| 59 | BpmnModel bpmnModel = new BpmnModel(); | 60 | BpmnModel bpmnModel = new BpmnModel(); |
| 60 | - bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // 设置命名空间。不加这个,解析 Message 会报 NPE 异常 | 61 | + bpmnModel.setTargetNamespace(BpmnXMLConstants.BPMN2_NAMESPACE); // 设置命名空间。不加这个,解析 Message 会报 NPE 异常 |
| 61 | // 创建 Process 对象 | 62 | // 创建 Process 对象 |
| 62 | Process process = new Process(); | 63 | Process process = new Process(); |
| 63 | process.setId(processId); | 64 | process.setId(processId); |
| @@ -69,14 +70,14 @@ public class SimpleModelUtils { | @@ -69,14 +70,14 @@ public class SimpleModelUtils { | ||
| 69 | // 原因是:目前前端的第一个节点是“发起人节点”,所以这里构建一个 StartNode,用于创建 Bpmn 的 StartEvent 节点 | 70 | // 原因是:目前前端的第一个节点是“发起人节点”,所以这里构建一个 StartNode,用于创建 Bpmn 的 StartEvent 节点 |
| 70 | BpmSimpleModelNodeVO startNode = buildStartNode(); | 71 | BpmSimpleModelNodeVO startNode = buildStartNode(); |
| 71 | startNode.setChildNode(simpleModelNode); | 72 | startNode.setChildNode(simpleModelNode); |
| 72 | - // 从 前端模型数据结构 SimpleModel 构建 FlowNode 并添加到 Main Process | 73 | + // 2.2 将前端传递的 simpleModelNode 数据结构(json),转换成从 BPMN FlowNode 元素,并添加到 Main Process 中 |
| 73 | traverseNodeToBuildFlowNode(startNode, process); | 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 | traverseNodeToBuildSequenceFlow(process, startNode, endEvent.getId()); | 78 | traverseNodeToBuildSequenceFlow(process, startNode, endEvent.getId()); |
| 79 | - // 自动布局 | 79 | + |
| 80 | + // 3. 自动布局 | ||
| 80 | new BpmnAutoLayout(bpmnModel).execute(); | 81 | new BpmnAutoLayout(bpmnModel).execute(); |
| 81 | return bpmnModel; | 82 | return bpmnModel; |
| 82 | } | 83 | } |
| @@ -85,6 +86,31 @@ public class SimpleModelUtils { | @@ -85,6 +86,31 @@ public class SimpleModelUtils { | ||
| 85 | return new BpmSimpleModelNodeVO().setId(START_EVENT_NODE_ID).setName(START_EVENT_NODE_NAME).setType(START_NODE.getType()); | 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 | // TODO @芋艿:在优化下这个注释 | 114 | // TODO @芋艿:在优化下这个注释 |
| 89 | private static void traverseNodeToBuildSequenceFlow(Process process, BpmSimpleModelNodeVO node, String targetNodeId) { | 115 | private static void traverseNodeToBuildSequenceFlow(Process process, BpmSimpleModelNodeVO node, String targetNodeId) { |
| 90 | // 1.1 无效节点返回 | 116 | // 1.1 无效节点返回 |
| @@ -94,7 +120,7 @@ public class SimpleModelUtils { | @@ -94,7 +120,7 @@ public class SimpleModelUtils { | ||
| 94 | // 1.2 END_NODE 直接返回 | 120 | // 1.2 END_NODE 直接返回 |
| 95 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); | 121 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); |
| 96 | Assert.notNull(nodeType, "模型节点类型不支持"); | 122 | Assert.notNull(nodeType, "模型节点类型不支持"); |
| 97 | - if (nodeType == END_NODE) { | 123 | + if (nodeType == BpmSimpleModelNodeType.END_NODE) { |
| 98 | return; | 124 | return; |
| 99 | } | 125 | } |
| 100 | // 2.1 情况一:普通节点 | 126 | // 2.1 情况一:普通节点 |
| @@ -238,371 +264,295 @@ public class SimpleModelUtils { | @@ -238,371 +264,295 @@ public class SimpleModelUtils { | ||
| 238 | return sequenceFlow; | 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 | public static boolean isValidNode(BpmSimpleModelNodeVO node) { | 267 | public static boolean isValidNode(BpmSimpleModelNodeVO node) { |
| 265 | return node != null && node.getId() != null; | 268 | return node != null && node.getId() != null; |
| 266 | } | 269 | } |
| 267 | 270 | ||
| 268 | public static boolean isSequentialApproveNode(BpmSimpleModelNodeVO node) { | 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 | return userTask; | 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 | } |