Commit 9456d461f9337c6cc590d0201c31501ca9a4074b

Authored by jason
1 parent 1e97ca28

仿钉钉流程设计- code review 修改。扩展属性保存在 extensionElement 尝试

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
@@ -18,20 +18,17 @@ import java.util.Objects; @@ -18,20 +18,17 @@ import java.util.Objects;
18 public enum BpmSimpleModelNodeType implements IntArrayValuable { 18 public enum BpmSimpleModelNodeType implements IntArrayValuable {
19 19
20 // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批; 20 // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批;
21 - // TODO @jason:_NODE 都删除掉哈;  
22 - START_EVENT_NODE(0, "开始节点"),  
23 - END_EVENT_NODE(-2, "结束节点"), // TODO @jaosn:挪到 START_EVENT_NODE 后;  
24 -  
25 - APPROVE_USER_NODE(1, "审批人节点"), // TODO @jaosn:是不是这里从 10 开始好点;相当于说,0-9 给开始和结束;10-19 给各种节点;20-29 给各种条件;TODO @jason:改成 USER_TASK 是不是好点呀  
26 - // 抄送人节点、对应 BPMN 的 ScriptTask. 使用ScriptTask 原因。好像 ServiceTask 自定义属性不能写入 XML;  
27 - // TODO @jason:ServiceTask 自定义 xml,有没啥报错信息;  
28 - SCRIPT_TASK_NODE(2, "抄送人节点"), // TODO @jason:是不是改成 COPY_TASK 好一点哈;  
29 -  
30 - EXCLUSIVE_GATEWAY_NODE(4, "排他网关"), // TODO @jason:是不是改成叫 条件分支?  
31 - PARALLEL_GATEWAY_FORK_NODE(5, "并行网关分叉节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦?  
32 - PARALLEL_GATEWAY_JOIN_NODE(6, "并行网关聚合节点"),  
33 - INCLUSIVE_GATEWAY_FORK_NODE(7, "包容网关分叉节点"),  
34 - INCLUSIVE_GATEWAY_JOIN_NODE(8, "包容网关聚合节点"), 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, "包容网关聚合节点"),
35 ; 32 ;
36 33
37 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); 34 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray();
@@ -39,9 +36,13 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { @@ -39,9 +36,13 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
39 private final Integer type; 36 private final Integer type;
40 private final String name; 37 private final String name;
41 38
42 - public static boolean isGatewayNode(Integer type) {  
43 - return Objects.equals(EXCLUSIVE_GATEWAY_NODE.getType(), type) || Objects.equals(PARALLEL_GATEWAY_FORK_NODE.getType(), type)  
44 - || Objects.equals(INCLUSIVE_GATEWAY_FORK_NODE.getType(), type) ; 39 + /**
  40 + * 判断是否为分支节点
  41 + * @param type 节点类型
  42 + */
  43 + public static boolean isBranchNode(Integer type) {
  44 + return Objects.equals(EXCLUSIVE_GATEWAY.getType(), type) || Objects.equals(PARALLEL_GATEWAY_FORK.getType(), type)
  45 + || Objects.equals(INCLUSIVE_GATEWAY_FORK.getType(), type) ;
45 } 46 }
46 47
47 public static BpmSimpleModelNodeType valueOf(Integer type) { 48 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/BpmnModelUtils.java
1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.hutool.core.lang.Assert;  
5 -import cn.hutool.core.map.MapUtil;  
6 import cn.hutool.core.util.ArrayUtil; 4 import cn.hutool.core.util.ArrayUtil;
7 -import cn.hutool.core.util.StrUtil;  
8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 5 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
9 -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO;  
10 -import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;  
11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; 6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
12 -import org.flowable.bpmn.BpmnAutoLayout;  
13 import org.flowable.bpmn.converter.BpmnXMLConverter; 7 import org.flowable.bpmn.converter.BpmnXMLConverter;
14 import org.flowable.bpmn.model.Process; 8 import org.flowable.bpmn.model.Process;
15 import org.flowable.bpmn.model.*; 9 import org.flowable.bpmn.model.*;
16 -import org.flowable.common.engine.impl.scripting.ScriptingEngines;  
17 import org.flowable.common.engine.impl.util.io.BytesStreamSource; 10 import org.flowable.common.engine.impl.util.io.BytesStreamSource;
18 11
19 -import java.util.ArrayList;  
20 -import java.util.HashSet;  
21 -import java.util.List;  
22 -import java.util.Set;  
23 -  
24 -import static org.flowable.bpmn.constants.BpmnXMLConstants.*; 12 +import java.util.*;
25 13
26 /** 14 /**
27 * 流程模型转操作工具类 15 * 流程模型转操作工具类
28 */ 16 */
29 public class BpmnModelUtils { 17 public class BpmnModelUtils {
30 18
31 - public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}";  
32 -  
33 public static Integer parseCandidateStrategy(FlowElement userTask) { 19 public static Integer parseCandidateStrategy(FlowElement userTask) {
34 - return NumberUtils.parseInt(userTask.getAttributeValue( 20 + Integer candidateStrategy = NumberUtils.parseInt(userTask.getAttributeValue(
35 BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); 21 BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY));
  22 + // @芋艿 尝试从 ExtensionElement 取. 后续相关扩展是否都可以 存 extensionElement。 如表单权限。 按钮权限
  23 + if (candidateStrategy == null) {
  24 + ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY));
  25 + candidateStrategy = NumberUtils.parseInt(Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null));
  26 +
  27 + }
  28 + return candidateStrategy;
36 } 29 }
37 30
38 public static String parseCandidateParam(FlowElement userTask) { 31 public static String parseCandidateParam(FlowElement userTask) {
39 - return userTask.getAttributeValue( 32 + String candidateParam = userTask.getAttributeValue(
40 BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); 33 BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM);
  34 + if (candidateParam == null) {
  35 + ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM));
  36 + candidateParam = Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null);
  37 + }
  38 + return candidateParam;
41 } 39 }
42 40
43 /** 41 /**
@@ -339,231 +337,4 @@ public class BpmnModelUtils { @@ -339,231 +337,4 @@ public class BpmnModelUtils {
339 } 337 }
340 return userTaskList; 338 return userTaskList;
341 } 339 }
342 -  
343 - // ========== TODO @jason:单独出一个 SimpleModelUtils;定位上,它是 BPMN 的精简模式 ==========  
344 -  
345 - /**  
346 - * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善)  
347 - *  
348 - * @param processId 流程标识  
349 - * @param processName 流程名称  
350 - * @param simpleModelNode 仿钉钉流程设计模型数据结构  
351 - * @return Bpmn Model  
352 - */  
353 - public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) {  
354 - BpmnModel bpmnModel = new BpmnModel();  
355 - Process mainProcess = new Process();  
356 - mainProcess.setId(processId);  
357 - mainProcess.setName(processName);  
358 - mainProcess.setExecutable(Boolean.TRUE);  
359 - bpmnModel.addProcess(mainProcess);  
360 - // 前端模型数据结构。 有 start event 节点. 没有 end event 节点。  
361 - // 添加 FlowNode  
362 - addBpmnFlowNode(mainProcess, simpleModelNode);  
363 - // 单独添加 end event 节点  
364 - addBpmnEndEventNode(mainProcess);  
365 - // 添加节点之间的连线 Sequence Flow  
366 - addBpmnSequenceFlow(mainProcess, simpleModelNode, BpmnModelConstants.END_EVENT_ID);  
367 - // 自动布局  
368 - new BpmnAutoLayout(bpmnModel).execute();  
369 - return bpmnModel;  
370 - }  
371 -  
372 - private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String endId) {  
373 - // 节点为 null 退出  
374 - if (node == null || node.getId() == null) {  
375 - return;  
376 - }  
377 - BpmSimpleModelNodeVO childNode = node.getChildNode();  
378 - // 如果不是网关节点、且后续节点为 null. 添加与结束节点的连线  
379 - if (!BpmSimpleModelNodeType.isGatewayNode(node.getType()) && (childNode == null || childNode.getId() == null)) {  
380 - addBpmnSequenceFlowElement(mainProcess, node.getId(), endId, null, null);  
381 - return;  
382 - }  
383 - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());  
384 - Assert.notNull(nodeType, "模型节点类型不支持");  
385 - // TODO @jason:建议是,addXXX 都改成 buildXXX,构建出一个什么;然后返回之后,让这个方法添加到自己的结果里;  
386 - switch (nodeType) {  
387 - case START_EVENT_NODE:  
388 - case APPROVE_USER_NODE:  
389 - case SCRIPT_TASK_NODE:  
390 - case PARALLEL_GATEWAY_JOIN_NODE:  
391 - case INCLUSIVE_GATEWAY_JOIN_NODE:{  
392 - addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null, null);  
393 - // 递归调用后续节点  
394 - addBpmnSequenceFlow(mainProcess, childNode, endId);  
395 - break;  
396 - }  
397 - case PARALLEL_GATEWAY_FORK_NODE:  
398 - case EXCLUSIVE_GATEWAY_NODE:  
399 - case INCLUSIVE_GATEWAY_FORK_NODE:{  
400 - String gateWayEndId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId();  
401 - List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();  
402 - Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空");  
403 - for (int i = 0; i < conditionNodes.size(); i++) {  
404 - BpmSimpleModelNodeVO item = conditionNodes.get(i);  
405 - BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode();  
406 - if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) {  
407 - addBpmnSequenceFlowElement(mainProcess, node.getId(), nextNodeOnCondition.getId(),  
408 - String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null);  
409 - addBpmnSequenceFlow(mainProcess, nextNodeOnCondition, gateWayEndId);  
410 - } else {  
411 - addBpmnSequenceFlowElement(mainProcess, node.getId(), gateWayEndId,  
412 - String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null);  
413 - }  
414 - }  
415 - // 递归调用后续节点  
416 - addBpmnSequenceFlow(mainProcess, childNode, endId);  
417 - break;  
418 - }  
419 - default: {  
420 - // TODO 其它节点类型的实现  
421 - }  
422 - }  
423 -  
424 - }  
425 -  
426 - private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String seqFlowId, String conditionExpression) {  
427 - SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId);  
428 - if (StrUtil.isNotEmpty(conditionExpression)) {  
429 - sequenceFlow.setConditionExpression(conditionExpression);  
430 - }  
431 - if (StrUtil.isNotEmpty(seqFlowId)) {  
432 - sequenceFlow.setId(seqFlowId);  
433 - }  
434 - mainProcess.addFlowElement(sequenceFlow);  
435 - }  
436 -  
437 - private static void addBpmnFlowNode(Process mainProcess, BpmSimpleModelNodeVO simpleModelNode) {  
438 - // 节点为 null 退出  
439 - if (simpleModelNode == null || simpleModelNode.getId() == null) {  
440 - return;  
441 - }  
442 - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType());  
443 - Assert.notNull(nodeType, "模型节点类型不支持");  
444 - switch (nodeType) {  
445 - case START_EVENT_NODE:  
446 - addBpmnStartEventNode(mainProcess, simpleModelNode);  
447 - break;  
448 - case APPROVE_USER_NODE:  
449 - addBpmnUserTaskNode(mainProcess, simpleModelNode);  
450 - break;  
451 - case SCRIPT_TASK_NODE:  
452 - addBpmnScriptTaSskNode(mainProcess, simpleModelNode);  
453 - break;  
454 - case EXCLUSIVE_GATEWAY_NODE:  
455 - addBpmnExclusiveGatewayNode(mainProcess, simpleModelNode);  
456 - break;  
457 - case PARALLEL_GATEWAY_FORK_NODE:  
458 - case PARALLEL_GATEWAY_JOIN_NODE:  
459 - addBpmnParallelGatewayNode(mainProcess, simpleModelNode);  
460 - break;  
461 - case INCLUSIVE_GATEWAY_FORK_NODE:  
462 - addBpmnInclusiveGatewayNode(mainProcess, simpleModelNode, Boolean.TRUE);  
463 - break;  
464 - case INCLUSIVE_GATEWAY_JOIN_NODE:  
465 - addBpmnInclusiveGatewayNode(mainProcess, simpleModelNode, Boolean.FALSE);  
466 - break;  
467 - default: {  
468 - // TODO 其它节点类型的实现  
469 - }  
470 - }  
471 -  
472 - // 如果不是网关类型的接口, 并且chileNode为空退出  
473 - if (!BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) {  
474 - return;  
475 - }  
476 -  
477 - // 如果是网关类型接口. 递归添加条件节点  
478 - if (BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) {  
479 - for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) {  
480 - addBpmnFlowNode(mainProcess, node.getChildNode());  
481 - }  
482 - }  
483 -  
484 - // chileNode不为空,递归添加子节点  
485 - if (simpleModelNode.getChildNode() != null) {  
486 - addBpmnFlowNode(mainProcess, simpleModelNode.getChildNode());  
487 - }  
488 - }  
489 -  
490 - private static void addBpmnParallelGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) {  
491 - ParallelGateway parallelGateway = new ParallelGateway();  
492 - parallelGateway.setId(node.getId());  
493 - mainProcess.addFlowElement(parallelGateway);  
494 - }  
495 -  
496 - private static void addBpmnScriptTaSskNode(Process mainProcess, BpmSimpleModelNodeVO node) {  
497 - ScriptTask scriptTask = new ScriptTask();  
498 - scriptTask.setId(node.getId());  
499 - scriptTask.setName(node.getName());  
500 - // TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现;  
501 - scriptTask.setScriptFormat(ScriptingEngines.DEFAULT_SCRIPTING_LANGUAGE);  
502 - scriptTask.setScript(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT);  
503 - // 添加自定义属性  
504 - // TODO @jason:可以使用 ServiceTask 搞 ExtensionAttribute 么?  
505 - addExtensionAttributes(node, scriptTask);  
506 - mainProcess.addFlowElement(scriptTask);  
507 - }  
508 -  
509 - private static void addExtensionAttributes(BpmSimpleModelNodeVO node, FlowElement flowElement) {  
510 - Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY);  
511 - addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,  
512 - candidateStrategy == null ? null : String.valueOf(candidateStrategy));  
513 - addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM,  
514 - MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM));  
515 - }  
516 -  
517 - private static void addBpmnExclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) {  
518 - Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");  
519 - ExclusiveGateway exclusiveGateway = new ExclusiveGateway();  
520 - exclusiveGateway.setId(node.getId());  
521 - // 网关的最后一个条件为 网关的 default sequence flow  
522 - exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size()));  
523 - mainProcess.addFlowElement(exclusiveGateway);  
524 - }  
525 -  
526 - private static void addBpmnInclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node, Boolean isFork) {  
527 - InclusiveGateway inclusiveGateway = new InclusiveGateway();  
528 - inclusiveGateway.setId(node.getId());  
529 - if (isFork) {  
530 - Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");  
531 - // 网关的最后一个条件为 网关的 default sequence flow  
532 - inclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size()));  
533 - }  
534 - mainProcess.addFlowElement(inclusiveGateway);  
535 - }  
536 -  
537 - private static void addBpmnEndEventNode(Process mainProcess) {  
538 - EndEvent endEvent = new EndEvent();  
539 - endEvent.setId(BpmnModelConstants.END_EVENT_ID);  
540 - endEvent.setName("结束");  
541 - mainProcess.addFlowElement(endEvent);  
542 - }  
543 -  
544 - private static void addBpmnUserTaskNode(Process mainProcess, BpmSimpleModelNodeVO node) {  
545 - UserTask userTask = new UserTask();  
546 - userTask.setId(node.getId());  
547 - userTask.setName(node.getName());  
548 - addExtensionAttributes(node, userTask);  
549 - mainProcess.addFlowElement(userTask);  
550 - }  
551 -  
552 - private static void addExtensionAttributes(FlowElement element, String namespace, String name, String value) {  
553 - if (value == null) {  
554 - return;  
555 - }  
556 - ExtensionAttribute extensionAttribute = new ExtensionAttribute(name, value);  
557 - extensionAttribute.setNamespace(namespace);  
558 - extensionAttribute.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);  
559 - element.addAttribute(extensionAttribute);  
560 - }  
561 -  
562 - private static void addBpmnStartEventNode(Process mainProcess, BpmSimpleModelNodeVO node) {  
563 - StartEvent startEvent = new StartEvent();  
564 - startEvent.setId(node.getId());  
565 - startEvent.setName(node.getName());  
566 - mainProcess.addFlowElement(startEvent);  
567 - }  
568 -  
569 } 340 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.ArrayUtil;
  6 +import cn.hutool.core.util.StrUtil;
  7 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO;
  8 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
  9 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
  10 +import org.flowable.bpmn.BpmnAutoLayout;
  11 +import org.flowable.bpmn.model.*;
  12 +import org.flowable.bpmn.model.Process;
  13 +
  14 +import java.util.List;
  15 +
  16 +import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;
  17 +import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX;
  18 +
  19 +/**
  20 + * 仿钉钉快搭模型相关的工具方法
  21 + *
  22 + * @author jason
  23 + */
  24 +public class SimpleModelUtils {
  25 +
  26 + public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}";
  27 +
  28 + /**
  29 + * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善)
  30 + *
  31 + * @param processId 流程标识
  32 + * @param processName 流程名称
  33 + * @param simpleModelNode 仿钉钉流程设计模型数据结构
  34 + * @return Bpmn Model
  35 + */
  36 + public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) {
  37 + BpmnModel bpmnModel = new BpmnModel();
  38 + Process mainProcess = new Process();
  39 + mainProcess.setId(processId);
  40 + mainProcess.setName(processName);
  41 + mainProcess.setExecutable(Boolean.TRUE);
  42 + bpmnModel.addProcess(mainProcess);
  43 + // 前端模型数据结构。 有 start event 节点. 没有 end event 节点。
  44 + // 从 SimpleModel 构建 FlowNode 并添加到 Main Process
  45 + buildAndAddBpmnFlowNode(simpleModelNode, mainProcess);
  46 + // 单独构建 end event 节点
  47 + buildAndAddBpmnEndEvent(mainProcess);
  48 + // 构建并添加节点之间的连线 Sequence Flow
  49 + buildAndAddBpmnSequenceFlow(mainProcess, simpleModelNode, BpmnModelConstants.END_EVENT_ID);
  50 + // 自动布局
  51 + new BpmnAutoLayout(bpmnModel).execute();
  52 + return bpmnModel;
  53 + }
  54 +
  55 + private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) {
  56 + // 节点为 null 退出
  57 + if (node == null || node.getId() == null) {
  58 + return;
  59 + }
  60 + BpmSimpleModelNodeVO childNode = node.getChildNode();
  61 + // 如果不是网关节点、且后续节点为 null. 添加与结束节点的连线
  62 + if (!BpmSimpleModelNodeType.isBranchNode(node.getType()) && (childNode == null || childNode.getId() == null)) {
  63 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetId, null, null);
  64 + mainProcess.addFlowElement(sequenceFlow);
  65 + return;
  66 + }
  67 + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
  68 + Assert.notNull(nodeType, "模型节点类型不支持");
  69 + switch (nodeType) {
  70 + case START_EVENT:
  71 + case USER_TASK:
  72 + case COPY_TASK:
  73 + case PARALLEL_GATEWAY_JOIN:
  74 + case INCLUSIVE_GATEWAY_JOIN:{
  75 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null);
  76 + mainProcess.addFlowElement(sequenceFlow);
  77 + // 递归调用后续节点
  78 + buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId);
  79 + break;
  80 + }
  81 + case PARALLEL_GATEWAY_FORK:
  82 + case EXCLUSIVE_GATEWAY:
  83 + case INCLUSIVE_GATEWAY_FORK:{
  84 + String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId();
  85 + List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes();
  86 + Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空");
  87 + for (int i = 0; i < conditionNodes.size(); i++) {
  88 + BpmSimpleModelNodeVO item = conditionNodes.get(i);
  89 + BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode();
  90 + if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) {
  91 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(),
  92 + String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null);
  93 + mainProcess.addFlowElement(sequenceFlow);
  94 + // 递归调用后续节点
  95 + buildAndAddBpmnSequenceFlow(mainProcess, nextNodeOnCondition, sequenceFlowTargetId);
  96 + } else {
  97 + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), sequenceFlowTargetId,
  98 + String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null);
  99 + mainProcess.addFlowElement(sequenceFlow);
  100 + }
  101 + }
  102 + // 递归调用后续节点
  103 + buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId);
  104 + break;
  105 + }
  106 + default: {
  107 + // TODO 其它节点类型的实现
  108 + }
  109 + }
  110 +
  111 + }
  112 +
  113 + private static SequenceFlow buildBpmnSequenceFlow(String sourceId, String targetId, String seqFlowId, String conditionExpression) {
  114 + SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId);
  115 + if (StrUtil.isNotEmpty(conditionExpression)) {
  116 + sequenceFlow.setConditionExpression(conditionExpression);
  117 + }
  118 + if (StrUtil.isNotEmpty(seqFlowId)) {
  119 + sequenceFlow.setId(seqFlowId);
  120 + }
  121 + return sequenceFlow;
  122 + }
  123 +
  124 + private static void buildAndAddBpmnFlowNode(BpmSimpleModelNodeVO simpleModelNode, Process mainProcess) {
  125 + // 节点为 null 退出
  126 + if (simpleModelNode == null || simpleModelNode.getId() == null) {
  127 + return;
  128 + }
  129 + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType());
  130 + Assert.notNull(nodeType, "模型节点类型不支持");
  131 + switch (nodeType) {
  132 + case START_EVENT: {
  133 + StartEvent startEvent = buildBpmnStartEvent(simpleModelNode);
  134 + mainProcess.addFlowElement(startEvent);
  135 + break;
  136 + }
  137 + case USER_TASK: {
  138 + UserTask userTask = buildBpmnUserTask(simpleModelNode);
  139 + mainProcess.addFlowElement(userTask);
  140 + break;
  141 + }
  142 + case COPY_TASK: {
  143 + ServiceTask serviceTask = buildBpmnServiceTask(simpleModelNode);
  144 + mainProcess.addFlowElement(serviceTask);
  145 + break;
  146 + }
  147 + case EXCLUSIVE_GATEWAY: {
  148 + ExclusiveGateway exclusiveGateway = buildBpmnExclusiveGateway(simpleModelNode);
  149 + mainProcess.addFlowElement(exclusiveGateway);
  150 + break;
  151 + }
  152 + case PARALLEL_GATEWAY_FORK:
  153 + case PARALLEL_GATEWAY_JOIN: {
  154 + ParallelGateway parallelGateway = buildBpmnParallelGateway(simpleModelNode);
  155 + mainProcess.addFlowElement(parallelGateway);
  156 + break;
  157 + }
  158 + case INCLUSIVE_GATEWAY_FORK: {
  159 + InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.TRUE);
  160 + mainProcess.addFlowElement(inclusiveGateway);
  161 + break;
  162 + }
  163 + case INCLUSIVE_GATEWAY_JOIN: {
  164 + InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.FALSE);
  165 + mainProcess.addFlowElement(inclusiveGateway);
  166 + break;
  167 + }
  168 + default: {
  169 + // TODO 其它节点类型的实现
  170 + }
  171 + }
  172 +
  173 + // 如果不是网关类型的接口, 并且chileNode为空退出
  174 + if (!BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) {
  175 + return;
  176 + }
  177 +
  178 + // 如果是网关类型接口. 递归添加条件节点
  179 + if (BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) {
  180 + for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) {
  181 + buildAndAddBpmnFlowNode(node.getChildNode(), mainProcess);
  182 + }
  183 + }
  184 +
  185 + // chileNode不为空,递归添加子节点
  186 + if (simpleModelNode.getChildNode() != null) {
  187 + buildAndAddBpmnFlowNode(simpleModelNode.getChildNode(), mainProcess);
  188 + }
  189 + }
  190 +
  191 + private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) {
  192 + ParallelGateway parallelGateway = new ParallelGateway();
  193 + parallelGateway.setId(node.getId());
  194 + return parallelGateway;
  195 + }
  196 +
  197 + private static ServiceTask buildBpmnServiceTask(BpmSimpleModelNodeVO node) {
  198 + ServiceTask serviceTask = new ServiceTask();
  199 + serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION);
  200 + serviceTask.setImplementation(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT);
  201 + serviceTask.setId(node.getId());
  202 + serviceTask.setName(node.getName());
  203 + // TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现;
  204 + // @芋艿 ServiceTask 就可以了吧。 不需要 executionListeners
  205 + addExtensionElement(node, serviceTask);
  206 + return serviceTask;
  207 + }
  208 +
  209 + private static void addExtensionElement(BpmSimpleModelNodeVO node, FlowElement flowElement) {
  210 + Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY);
  211 + addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,
  212 + candidateStrategy == null ? null : String.valueOf(candidateStrategy));
  213 + addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM,
  214 + MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM));
  215 + }
  216 +
  217 + private static ExclusiveGateway buildBpmnExclusiveGateway(BpmSimpleModelNodeVO node) {
  218 + Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");
  219 + ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
  220 + exclusiveGateway.setId(node.getId());
  221 + // 网关的最后一个条件为 网关的 default sequence flow
  222 + exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size()));
  223 + return exclusiveGateway;
  224 + }
  225 +
  226 + private static InclusiveGateway buildBpmnInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) {
  227 + InclusiveGateway inclusiveGateway = new InclusiveGateway();
  228 + inclusiveGateway.setId(node.getId());
  229 + if (isFork) {
  230 + Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");
  231 + // 网关的最后一个条件为 网关的 default sequence flow
  232 + inclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size()));
  233 + }
  234 + return inclusiveGateway;
  235 + }
  236 +
  237 + private static void buildAndAddBpmnEndEvent(Process mainProcess) {
  238 + EndEvent endEvent = new EndEvent();
  239 + endEvent.setId(BpmnModelConstants.END_EVENT_ID);
  240 + endEvent.setName("结束");
  241 + mainProcess.addFlowElement(endEvent);
  242 + }
  243 +
  244 + private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node) {
  245 + UserTask userTask = new UserTask();
  246 + userTask.setId(node.getId());
  247 + userTask.setName(node.getName());
  248 + addExtensionElement(node, userTask);
  249 + return userTask;
  250 + }
  251 +
  252 + private static void addExtensionElement(FlowElement element, String namespace, String name, String value) {
  253 + if (value == null) {
  254 + return;
  255 + }
  256 + ExtensionElement extensionElement = new ExtensionElement();
  257 + extensionElement.setNamespace(namespace);
  258 + extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
  259 + extensionElement.setElementText(value);
  260 + extensionElement.setName(name);
  261 + element.addExtensionElement(extensionElement);
  262 + }
  263 +
  264 + private static StartEvent buildBpmnStartEvent(BpmSimpleModelNodeVO node) {
  265 + StartEvent startEvent = new StartEvent();
  266 + startEvent.setId(node.getId());
  267 + startEvent.setName(node.getName());
  268 + return startEvent;
  269 + }
  270 +}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java
@@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimp @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimp
10 import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; 10 import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; 11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
12 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; 12 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  13 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils;
13 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
14 import org.flowable.bpmn.model.*; 15 import org.flowable.bpmn.model.*;
15 import org.flowable.engine.repository.Model; 16 import org.flowable.engine.repository.Model;
@@ -22,7 +23,7 @@ import java.util.Map; @@ -22,7 +23,7 @@ import java.util.Map;
22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
23 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT; 24 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT;
24 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; 25 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS;
25 -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT_NODE; 26 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT;
26 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM; 27 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM;
27 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY; 28 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY;
28 29
@@ -56,7 +57,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { @@ -56,7 +57,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService {
56 // return Boolean.FALSE; 57 // return Boolean.FALSE;
57 // } 58 // }
58 // 1. JSON 转换成 bpmnModel 59 // 1. JSON 转换成 bpmnModel
59 - BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); 60 + BpmnModel bpmnModel = SimpleModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody());
60 // 2.1 保存 Bpmn XML 61 // 2.1 保存 Bpmn XML
61 bpmModelService.saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel))); 62 bpmModelService.saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel)));
62 // 2.2 保存 JSON 数据 63 // 2.2 保存 JSON 数据
@@ -93,7 +94,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { @@ -93,7 +94,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService {
93 return null; 94 return null;
94 } 95 }
95 BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO(); 96 BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO();
96 - rootNode.setType(START_EVENT_NODE.getType()); 97 + rootNode.setType(START_EVENT.getType());
97 rootNode.setId(startEvent.getId()); 98 rootNode.setId(startEvent.getId());
98 rootNode.setName(startEvent.getName()); 99 rootNode.setName(startEvent.getName());
99 recursiveBuildSimpleModelNode(startEvent, rootNode); 100 recursiveBuildSimpleModelNode(startEvent, rootNode);
@@ -105,10 +106,10 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { @@ -105,10 +106,10 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService {
105 Assert.notNull(nodeType, "节点类型不支持"); 106 Assert.notNull(nodeType, "节点类型不支持");
106 // 校验节点是否支持转仿钉钉的流程模型 107 // 校验节点是否支持转仿钉钉的流程模型
107 List<SequenceFlow> outgoingFlows = validateCanConvertSimpleNode(nodeType, currentFlowNode); 108 List<SequenceFlow> outgoingFlows = validateCanConvertSimpleNode(nodeType, currentFlowNode);
108 - if (CollUtil.isEmpty(outgoingFlows) || outgoingFlows.get(0).getTargetFlowElement() == null) { 109 + if (CollUtil.isEmpty(outgoingFlows) || CollUtil.getFirst(outgoingFlows).getTargetFlowElement() == null) {
109 return; 110 return;
110 } 111 }
111 - FlowElement targetElement = outgoingFlows.get(0).getTargetFlowElement(); 112 + FlowElement targetElement = CollUtil.getFirst(outgoingFlows).getTargetFlowElement();
112 // 如果是 EndEvent 直接退出 113 // 如果是 EndEvent 直接退出
113 if (targetElement instanceof EndEvent) { 114 if (targetElement instanceof EndEvent) {
114 return; 115 return;
@@ -123,7 +124,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { @@ -123,7 +124,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService {
123 124
124 private BpmSimpleModelNodeVO convertUserTaskToSimpleModelNode(UserTask userTask) { 125 private BpmSimpleModelNodeVO convertUserTaskToSimpleModelNode(UserTask userTask) {
125 BpmSimpleModelNodeVO simpleModelNodeVO = new BpmSimpleModelNodeVO(); 126 BpmSimpleModelNodeVO simpleModelNodeVO = new BpmSimpleModelNodeVO();
126 - simpleModelNodeVO.setType(BpmSimpleModelNodeType.APPROVE_USER_NODE.getType()); 127 + simpleModelNodeVO.setType(BpmSimpleModelNodeType.USER_TASK.getType());
127 simpleModelNodeVO.setName(userTask.getName()); 128 simpleModelNodeVO.setName(userTask.getName());
128 simpleModelNodeVO.setId(userTask.getId()); 129 simpleModelNodeVO.setId(userTask.getId());
129 Map<String, Object> attributes = MapUtil.newHashMap(); 130 Map<String, Object> attributes = MapUtil.newHashMap();
@@ -137,13 +138,13 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { @@ -137,13 +138,13 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService {
137 138
138 private List<SequenceFlow> validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) { 139 private List<SequenceFlow> validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) {
139 switch (nodeType) { 140 switch (nodeType) {
140 - case START_EVENT_NODE:  
141 - case APPROVE_USER_NODE: { 141 + case START_EVENT:
  142 + case USER_TASK: {
142 List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows(); 143 List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows();
143 if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) { 144 if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) {
144 throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); 145 throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT);
145 } 146 }
146 - validIsSupportFlowNode(outgoingFlows.get(0).getTargetFlowElement()); 147 + validIsSupportFlowNode(CollUtil.getFirst(outgoingFlows).getTargetFlowElement());
147 return outgoingFlows; 148 return outgoingFlows;
148 } 149 }
149 default: { 150 default: {
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java
@@ -47,7 +47,7 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy @@ -47,7 +47,7 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy
47 // TODO @芋艿:这里多加了一个 name; 47 // TODO @芋艿:这里多加了一个 name;
48 @Override 48 @Override
49 public void createProcessInstanceCopy(Collection<Long> userIds, String processInstanceId, String taskId, String taskName) { 49 public void createProcessInstanceCopy(Collection<Long> userIds, String processInstanceId, String taskId, String taskName) {
50 - // 1.1 校验任务存在 暂时去掉这个校验. 因为任务可能仿钉钉快搭的抄送节点(ScriptTask) TODO jason:抄送节点,会没有来源的 taskId 么? 50 + // 1.1 校验任务存在 暂时去掉这个校验. 因为任务可能仿钉钉快搭的抄送节点(ScriptTask) TODO jason:抄送节点,会没有来源的 taskId 么? @芋艿 是否校验一下 传递进来的 id 不为空就行
51 // Task task = taskService.getTask(taskId); 51 // Task task = taskService.getTask(taskId);
52 // if (ObjectUtil.isNull(task)) { 52 // if (ObjectUtil.isNull(task)) {
53 // throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); 53 // throw exception(ErrorCodeConstants.TASK_NOT_EXISTS);
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java
@@ -9,7 +9,8 @@ import org.springframework.stereotype.Service; @@ -9,7 +9,8 @@ import org.springframework.stereotype.Service;
9 import java.util.Set; 9 import java.util.Set;
10 10
11 /** 11 /**
12 - * 仿钉钉快搭各个节点 Service TODO @jason:注释要有空行哈; 12 + * 仿钉钉快搭各个节点 Service
  13 + *
13 * @author jason 14 * @author jason
14 */ 15 */
15 @Service 16 @Service
@@ -21,7 +22,8 @@ public class BpmSimpleNodeService { @@ -21,7 +22,8 @@ public class BpmSimpleNodeService {
21 private BpmProcessInstanceCopyService processInstanceCopyService; 22 private BpmProcessInstanceCopyService processInstanceCopyService;
22 23
23 /** 24 /**
24 - * 仿钉钉快搭抄送 TODO @jason:注释要有空行哈; 25 + * 仿钉钉快搭抄送
  26 + *
25 * @param execution 执行的任务(ScriptTask) 27 * @param execution 执行的任务(ScriptTask)
26 */ 28 */
27 public Boolean copy(DelegateExecution execution) { 29 public Boolean copy(DelegateExecution execution) {