Commit 4bd399cd3261597192963141cd9a885287efad29
1 parent
8f31e745
仿钉钉流程设计- code review 修改
Showing
2 changed files
with
79 additions
and
70 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
| ... | ... | @@ -18,17 +18,18 @@ import java.util.Objects; |
| 18 | 18 | public enum BpmSimpleModelNodeType implements IntArrayValuable { |
| 19 | 19 | |
| 20 | 20 | // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批; |
| 21 | - START_EVENT(0, "开始节点"), | |
| 22 | - END_EVENT(-2, "结束节点"), // TODO @jaosn:挪到 START_EVENT_NODE 后; | |
| 23 | - | |
| 24 | - USER_TASK(1, "审批人节点"), // TODO @jaosn:是不是这里从 10 开始好点;相当于说,0-9 给开始和结束;10-19 给各种节点;20-29 给各种条件; TODO 后面改改 | |
| 25 | - COPY_TASK(2, "抄送人节点"), | |
| 26 | - | |
| 27 | - EXCLUSIVE_GATEWAY(4, "排他网关"), // TODO @jason:是不是改成叫 条件分支? | |
| 28 | - PARALLEL_GATEWAY_FORK(5, "并行网关分叉节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦? 后面是否去掉并行网关。只用包容网关 | |
| 29 | - PARALLEL_GATEWAY_JOIN(6, "并行网关聚合节点"), | |
| 30 | - INCLUSIVE_GATEWAY_FORK(7, "包容网关分叉节点"), | |
| 31 | - INCLUSIVE_GATEWAY_JOIN(8, "包容网关聚合节点"), | |
| 21 | + // @芋艿 感觉还是用 START_NODE . END_NODE 比较好. | |
| 22 | + START_NODE(0, "开始节点"), | |
| 23 | + END_NODE(-2, "结束节点"), // TODO @jaosn:挪到 START_EVENT_NODE 后; | |
| 24 | + | |
| 25 | + APPROVE_NODE(1, "审批人节点"), // TODO @jaosn:是不是这里从 10 开始好点;相当于说,0-9 给开始和结束;10-19 给各种节点;20-29 给各种条件; TODO 后面改改 | |
| 26 | + COPY_NODE(2, "抄送人节点"), | |
| 27 | + | |
| 28 | + CONDITION_BRANCH_NODE(4, "条件分支节点"), // TODO @jason:是不是改成叫 条件分支? | |
| 29 | + PARALLEL_BRANCH_FORK_NODE(5, "并行分支分叉节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦? 后面是否去掉并行网关。只用包容网关 | |
| 30 | + PARALLEL_BRANCH_JOIN_NODE(6, "并行分支聚合节点"), | |
| 31 | + INCLUSIVE_BRANCH_FORK_NODE(7, "包容网关分叉节点"), | |
| 32 | + INCLUSIVE_BRANCH_JOIN_NODE(8, "包容网关聚合节点"), | |
| 32 | 33 | ; |
| 33 | 34 | |
| 34 | 35 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); |
| ... | ... | @@ -42,8 +43,8 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { |
| 42 | 43 | * @param type 节点类型 |
| 43 | 44 | */ |
| 44 | 45 | public static boolean isBranchNode(Integer type) { |
| 45 | - return Objects.equals(EXCLUSIVE_GATEWAY.getType(), type) || Objects.equals(PARALLEL_GATEWAY_FORK.getType(), type) | |
| 46 | - || Objects.equals(INCLUSIVE_GATEWAY_FORK.getType(), type) ; | |
| 46 | + return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) || Objects.equals(PARALLEL_BRANCH_FORK_NODE.getType(), type) | |
| 47 | + || Objects.equals(INCLUSIVE_BRANCH_FORK_NODE.getType(), type) ; | |
| 47 | 48 | } |
| 48 | 49 | |
| 49 | 50 | public static BpmSimpleModelNodeType valueOf(Integer type) { | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| ... | ... | @@ -25,7 +25,7 @@ import java.util.Map; |
| 25 | 25 | import java.util.Objects; |
| 26 | 26 | |
| 27 | 27 | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT; |
| 28 | -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT; | |
| 28 | +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_NODE; | |
| 29 | 29 | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER; |
| 30 | 30 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; |
| 31 | 31 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*; |
| ... | ... | @@ -63,10 +63,10 @@ public class SimpleModelUtils { |
| 63 | 63 | */ |
| 64 | 64 | public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { |
| 65 | 65 | BpmnModel bpmnModel = new BpmnModel(); |
| 66 | + // 不加这个 解析 Message 会报 NPE 异常 . | |
| 66 | 67 | bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason:待定:是不是搞个自定义的 namespace; |
| 67 | 68 | // TODO 芋艿:后续在 review |
| 68 | 69 | // @芋艿 这个 Message 可以去掉 暂时用不上 |
| 69 | - // 不加这个 解析 Message 会报 NPE 异常 . | |
| 70 | 70 | Message rejectPostProcessMsg = new Message(); |
| 71 | 71 | rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME); |
| 72 | 72 | bpmnModel.addMessage(rejectPostProcessMsg); |
| ... | ... | @@ -92,7 +92,7 @@ public class SimpleModelUtils { |
| 92 | 92 | |
| 93 | 93 | private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) { |
| 94 | 94 | // 节点为 null 或者 为END_EVENT 退出 |
| 95 | - if (node == null || node.getId() == null || END_EVENT.getType().equals(node.getType())) { | |
| 95 | + if (node == null || node.getId() == null || END_NODE.getType().equals(node.getType())) { | |
| 96 | 96 | return; |
| 97 | 97 | } |
| 98 | 98 | BpmSimpleModelNodeVO childNode = node.getChildNode(); |
| ... | ... | @@ -105,20 +105,20 @@ public class SimpleModelUtils { |
| 105 | 105 | BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); |
| 106 | 106 | Assert.notNull(nodeType, "模型节点类型不支持"); |
| 107 | 107 | switch (nodeType) { |
| 108 | - case START_EVENT: | |
| 109 | - case USER_TASK: | |
| 110 | - case COPY_TASK: | |
| 111 | - case PARALLEL_GATEWAY_JOIN: | |
| 112 | - case INCLUSIVE_GATEWAY_JOIN: { | |
| 108 | + case START_NODE: | |
| 109 | + case APPROVE_NODE: | |
| 110 | + case COPY_NODE: | |
| 111 | + case PARALLEL_BRANCH_JOIN_NODE: | |
| 112 | + case INCLUSIVE_BRANCH_JOIN_NODE: { | |
| 113 | 113 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null); |
| 114 | 114 | mainProcess.addFlowElement(sequenceFlow); |
| 115 | 115 | // 递归调用后续节点 |
| 116 | 116 | buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId); |
| 117 | 117 | break; |
| 118 | 118 | } |
| 119 | - case PARALLEL_GATEWAY_FORK: | |
| 120 | - case EXCLUSIVE_GATEWAY: | |
| 121 | - case INCLUSIVE_GATEWAY_FORK: { | |
| 119 | + case PARALLEL_BRANCH_FORK_NODE: | |
| 120 | + case CONDITION_BRANCH_NODE: | |
| 121 | + case INCLUSIVE_BRANCH_FORK_NODE: { | |
| 122 | 122 | String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? targetId : childNode.getId(); |
| 123 | 123 | List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); |
| 124 | 124 | Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); |
| ... | ... | @@ -238,55 +238,50 @@ public class SimpleModelUtils { |
| 238 | 238 | private static List<FlowElement> buildFlowNode(BpmSimpleModelNodeVO node, BpmSimpleModelNodeType nodeType) { |
| 239 | 239 | List<FlowElement> list = new ArrayList<>(); |
| 240 | 240 | switch (nodeType) { |
| 241 | - case START_EVENT: { | |
| 241 | + case START_NODE: { | |
| 242 | 242 | // TODO-DONE @jason:每个 nodeType,buildXXX 方法要不更明确,并且去掉 Bpmn; |
| 243 | - StartEvent startEvent = buildStartEvent(node); | |
| 243 | + // @芋艿 改成 convert 是不是好理解一点 | |
| 244 | + StartEvent startEvent = convertStartNode(node); | |
| 244 | 245 | list.add(startEvent); |
| 245 | 246 | break; |
| 246 | 247 | } |
| 247 | - case USER_TASK: { | |
| 248 | - // TODO @jason:这个,搞成一个 buildUserTask,然后把下面这 2 种节点,搞在一起实现类;这样 buildNode 里面可以更简洁; | |
| 249 | - // TODO @jason:这里还有个想法,是不是可以所有的都叫 buildXXXNode,然后里面有一些是 bpmn 相关的构建,叫做 buildBpmnUserTask,用于区分; | |
| 250 | - // 获取用户任务的配置 | |
| 251 | - SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(node.getAttributes(), SimpleModelUserTaskConfig.class); | |
| 252 | - UserTask userTask = buildBpmnUserTask(node, userTaskConfig); | |
| 253 | - list.add(userTask); | |
| 254 | - if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) { | |
| 255 | - // 添加用户任务的 Timer Boundary Event, 用于任务的超时处理 | |
| 256 | - BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler()); | |
| 257 | - //process.addFlowElement(boundaryEvent); | |
| 258 | - list.add(boundaryEvent); | |
| 259 | - } | |
| 248 | + case APPROVE_NODE: { | |
| 249 | + // TODO-DONE @jason:这个,搞成一个 buildUserTask,然后把下面这 2 种节点,搞在一起实现类;这样 buildNode 里面可以更简洁; | |
| 250 | + // TODO-DONE @jason:这里还有个想法,是不是可以所有的都叫 buildXXXNode,然后里面有一些是 bpmn 相关的构建,叫做 buildBpmnUserTask,用于区分; | |
| 251 | + // @芋艿 改成 convertXXXNode, , 方面里面使用 buildBpmnXXXNode. 是否更好理解 | |
| 252 | + // 转换审批节点 | |
| 253 | + List<FlowElement> flowElements = convertApproveNode(node); | |
| 254 | + list.addAll(flowElements); | |
| 260 | 255 | break; |
| 261 | 256 | } |
| 262 | - case COPY_TASK: { | |
| 263 | - ServiceTask serviceTask = buildServiceTask(node); | |
| 257 | + case COPY_NODE: { | |
| 258 | + ServiceTask serviceTask = convertCopyNode(node); | |
| 264 | 259 | list.add(serviceTask); |
| 265 | 260 | break; |
| 266 | 261 | } |
| 267 | - case EXCLUSIVE_GATEWAY: { | |
| 268 | - ExclusiveGateway exclusiveGateway = buildExclusiveGateway(node); | |
| 262 | + case CONDITION_BRANCH_NODE: { | |
| 263 | + ExclusiveGateway exclusiveGateway = convertConditionBranchNode(node); | |
| 269 | 264 | list.add(exclusiveGateway); |
| 270 | 265 | break; |
| 271 | 266 | } |
| 272 | - case PARALLEL_GATEWAY_FORK: | |
| 273 | - case PARALLEL_GATEWAY_JOIN: { | |
| 274 | - ParallelGateway parallelGateway = buildParallelGateway(node); | |
| 267 | + case PARALLEL_BRANCH_FORK_NODE: | |
| 268 | + case PARALLEL_BRANCH_JOIN_NODE: { | |
| 269 | + ParallelGateway parallelGateway = convertParallelBranchNode(node); | |
| 275 | 270 | list.add(parallelGateway); |
| 276 | 271 | break; |
| 277 | 272 | } |
| 278 | - case INCLUSIVE_GATEWAY_FORK: { | |
| 279 | - InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.TRUE); | |
| 273 | + case INCLUSIVE_BRANCH_FORK_NODE: { | |
| 274 | + InclusiveGateway inclusiveGateway = convertInclusiveBranchNode(node, Boolean.TRUE); | |
| 280 | 275 | list.add(inclusiveGateway); |
| 281 | 276 | break; |
| 282 | 277 | } |
| 283 | - case INCLUSIVE_GATEWAY_JOIN: { | |
| 284 | - InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.FALSE); | |
| 278 | + case INCLUSIVE_BRANCH_JOIN_NODE: { | |
| 279 | + InclusiveGateway inclusiveGateway = convertInclusiveBranchNode(node, Boolean.FALSE); | |
| 285 | 280 | list.add(inclusiveGateway); |
| 286 | 281 | break; |
| 287 | 282 | } |
| 288 | - case END_EVENT: { | |
| 289 | - EndEvent endEvent = buildEndEvent(node); | |
| 283 | + case END_NODE: { | |
| 284 | + EndEvent endEvent = convertEndNode(node); | |
| 290 | 285 | list.add(endEvent); |
| 291 | 286 | break; |
| 292 | 287 | } |
| ... | ... | @@ -297,6 +292,19 @@ public class SimpleModelUtils { |
| 297 | 292 | return list; |
| 298 | 293 | } |
| 299 | 294 | |
| 295 | + private static List<FlowElement> convertApproveNode(BpmSimpleModelNodeVO node) { | |
| 296 | + List<FlowElement> flowElements = new ArrayList<>(); | |
| 297 | + SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(node.getAttributes(), SimpleModelUserTaskConfig.class); | |
| 298 | + UserTask userTask = buildBpmnUserTask(node, userTaskConfig); | |
| 299 | + flowElements.add(userTask); | |
| 300 | + if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) { | |
| 301 | + // 添加用户任务的 Timer Boundary Event, 用于任务的超时处理 | |
| 302 | + BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler()); | |
| 303 | + flowElements.add(boundaryEvent); | |
| 304 | + } | |
| 305 | + return flowElements; | |
| 306 | + } | |
| 307 | + | |
| 300 | 308 | private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) { |
| 301 | 309 | // 定时器边界事件 |
| 302 | 310 | BoundaryEvent boundaryEvent = new BoundaryEvent(); |
| ... | ... | @@ -319,16 +327,17 @@ public class SimpleModelUtils { |
| 319 | 327 | return boundaryEvent; |
| 320 | 328 | } |
| 321 | 329 | |
| 322 | - private static ParallelGateway buildParallelGateway(BpmSimpleModelNodeVO node) { | |
| 330 | + private static ParallelGateway convertParallelBranchNode(BpmSimpleModelNodeVO node) { | |
| 323 | 331 | ParallelGateway parallelGateway = new ParallelGateway(); |
| 324 | 332 | parallelGateway.setId(node.getId()); |
| 325 | 333 | // TODO @jason:setName |
| 326 | 334 | |
| 327 | 335 | // TODO @芋艿 + jason:合并网关;是不是要有条件啥的。微信讨论 |
| 336 | + // @芋艿 貌似并行网关没有条件的 | |
| 328 | 337 | return parallelGateway; |
| 329 | 338 | } |
| 330 | 339 | |
| 331 | - private static ServiceTask buildServiceTask(BpmSimpleModelNodeVO node) { | |
| 340 | + private static ServiceTask convertCopyNode(BpmSimpleModelNodeVO node) { | |
| 332 | 341 | ServiceTask serviceTask = new ServiceTask(); |
| 333 | 342 | serviceTask.setId(node.getId()); |
| 334 | 343 | serviceTask.setName(node.getName()); |
| ... | ... | @@ -359,8 +368,8 @@ public class SimpleModelUtils { |
| 359 | 368 | addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam); |
| 360 | 369 | } |
| 361 | 370 | |
| 362 | - private static ExclusiveGateway buildExclusiveGateway(BpmSimpleModelNodeVO node) { | |
| 363 | - Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); | |
| 371 | + private static ExclusiveGateway convertConditionBranchNode(BpmSimpleModelNodeVO node) { | |
| 372 | + Assert.notEmpty(node.getConditionNodes(), "条件分支节点不能为空"); | |
| 364 | 373 | ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); |
| 365 | 374 | exclusiveGateway.setId(node.getId()); |
| 366 | 375 | // 寻找默认的序列流 |
| ... | ... | @@ -372,28 +381,25 @@ public class SimpleModelUtils { |
| 372 | 381 | return exclusiveGateway; |
| 373 | 382 | } |
| 374 | 383 | |
| 375 | - private static InclusiveGateway buildInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) { | |
| 384 | + private static InclusiveGateway convertInclusiveBranchNode(BpmSimpleModelNodeVO node, Boolean isFork) { | |
| 376 | 385 | InclusiveGateway inclusiveGateway = new InclusiveGateway(); |
| 377 | 386 | inclusiveGateway.setId(node.getId()); |
| 378 | 387 | // TODO @jason:这里是不是 setName 哈; |
| 379 | 388 | |
| 380 | 389 | // TODO @芋艿 + jason:是不是搞个合并网关;这里微信讨论下,有点奇怪; |
| 390 | + // @芋艿 isFork 为 false 就是合并网关。由前端传入。这个前端暂时还未实现 | |
| 381 | 391 | if (isFork) { |
| 382 | - Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); | |
| 383 | - // 网关的最后一个条件为 网关的 default sequence flow | |
| 384 | - inclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); | |
| 392 | + Assert.notEmpty(node.getConditionNodes(), "条件节点不能为空"); | |
| 393 | + // 寻找默认的序列流 | |
| 394 | + BpmSimpleModelNodeVO defaultSeqFlow = CollUtil.findOne(node.getConditionNodes(), | |
| 395 | + item -> BooleanUtil.isTrue(MapUtil.getBool(item.getAttributes(), DEFAULT_FLOW_ATTRIBUTE))); | |
| 396 | + if (defaultSeqFlow != null) { | |
| 397 | + inclusiveGateway.setDefaultFlow(defaultSeqFlow.getId()); | |
| 398 | + } | |
| 385 | 399 | } |
| 386 | 400 | return inclusiveGateway; |
| 387 | 401 | } |
| 388 | 402 | |
| 389 | - private static EndEvent buildAndAddBpmnEndEvent(Process mainProcess) { | |
| 390 | - EndEvent endEvent = new EndEvent(); | |
| 391 | - endEvent.setId(BpmnModelConstants.END_EVENT_ID); | |
| 392 | - endEvent.setName("结束"); | |
| 393 | - mainProcess.addFlowElement(endEvent); | |
| 394 | - return endEvent; | |
| 395 | - } | |
| 396 | - | |
| 397 | 403 | private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node, SimpleModelUserTaskConfig userTaskConfig) { |
| 398 | 404 | UserTask userTask = new UserTask(); |
| 399 | 405 | userTask.setId(node.getId()); |
| ... | ... | @@ -488,16 +494,18 @@ public class SimpleModelUtils { |
| 488 | 494 | |
| 489 | 495 | // ========== 各种 build 节点的方法 ========== |
| 490 | 496 | |
| 491 | - private static StartEvent buildStartEvent(BpmSimpleModelNodeVO node) { | |
| 497 | + private static StartEvent convertStartNode(BpmSimpleModelNodeVO node) { | |
| 492 | 498 | StartEvent startEvent = new StartEvent(); |
| 493 | 499 | startEvent.setId(node.getId()); |
| 494 | 500 | startEvent.setName(node.getName()); |
| 495 | 501 | |
| 496 | 502 | // TODO 芋艿 + jason:要不要在开启节点后面,加一个“发起人”任务节点,然后自动审批通过 |
| 503 | + // @芋艿 这个是不是由前端来实现。 默认开始节点后面跟一个 “发起人”的审批节点(审批人是发起人自己)。 | |
| 504 | + // 我看有些平台这个审批节点允许删除,有些不允许。由用户决定 | |
| 497 | 505 | return startEvent; |
| 498 | 506 | } |
| 499 | 507 | |
| 500 | - private static EndEvent buildEndEvent(BpmSimpleModelNodeVO node) { | |
| 508 | + private static EndEvent convertEndNode(BpmSimpleModelNodeVO node) { | |
| 501 | 509 | EndEvent endEvent = new EndEvent(); |
| 502 | 510 | endEvent.setId(node.getId()); |
| 503 | 511 | endEvent.setName(node.getName()); | ... | ... |