Commit 254b55778f839de4639c4831ca0110f89bbbaf36

Authored by YunaiV
1 parent 10bbe741

【代码评审】BPM:子流程

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java
@@ -30,7 +30,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> { @@ -30,7 +30,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> {
30 DELAY_TIMER_NODE(14, "延迟器", "receiveTask"), 30 DELAY_TIMER_NODE(14, "延迟器", "receiveTask"),
31 TRIGGER_NODE(15, "触发器", "serviceTask"), 31 TRIGGER_NODE(15, "触发器", "serviceTask"),
32 32
33 - CHILD_PROCESS(20, "子流程", "callActivity"), 33 + CHILD_PROCESS(20, "子流程", "callActivity"), // TODO @lesan:CHILD_PROCESS、ASYNC_CHILD_PROCESS 可以合并为一个么?
34 ASYNC_CHILD_PROCESS(21, "异步子流程", "callActivity"), 34 ASYNC_CHILD_PROCESS(21, "异步子流程", "callActivity"),
35 35
36 // 50 ~ 条件分支 36 // 50 ~ 条件分支
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
@@ -26,7 +26,7 @@ public enum BpmReasonEnum { @@ -26,7 +26,7 @@ public enum BpmReasonEnum {
26 TIMEOUT_REJECT("审批超时,系统自动不通过"), 26 TIMEOUT_REJECT("审批超时,系统自动不通过"),
27 ASSIGN_START_USER_APPROVE("审批人与提交人为同一人时,自动通过"), 27 ASSIGN_START_USER_APPROVE("审批人与提交人为同一人时,自动通过"),
28 ASSIGN_START_USER_APPROVE_WHEN_SKIP("审批人与提交人为同一人时,自动通过"), 28 ASSIGN_START_USER_APPROVE_WHEN_SKIP("审批人与提交人为同一人时,自动通过"),
29 - ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE("发起人节点首次自动通过"), 29 + ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE("发起人节点首次自动通过"), // 目前仅“子流程”使用
30 ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"), 30 ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"),
31 ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"), 31 ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"),
32 ASSIGN_EMPTY_APPROVE("审批人为空,自动通过"), 32 ASSIGN_EMPTY_APPROVE("审批人为空,自动通过"),
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
@@ -124,6 +124,9 @@ public class BpmSimpleModelNodeVO { @@ -124,6 +124,9 @@ public class BpmSimpleModelNodeVO {
124 */ 124 */
125 private TriggerSetting triggerSetting; 125 private TriggerSetting triggerSetting;
126 126
  127 + /**
  128 + * 子流程设置
  129 + */
127 private ChildProcessSetting childProcessSetting; 130 private ChildProcessSetting childProcessSetting;
128 131
129 @Schema(description = "任务监听器") 132 @Schema(description = "任务监听器")
@@ -410,21 +413,24 @@ public class BpmSimpleModelNodeVO { @@ -410,21 +413,24 @@ public class BpmSimpleModelNodeVO {
410 @Valid 413 @Valid
411 public static class ChildProcessSetting { 414 public static class ChildProcessSetting {
412 415
413 - @Schema(description = "被调用流程", example = "xxx") 416 + // TODO @lesan:calledElement => calledProcessDefinitionKey ? 这样更容易理解?不过如果一个流程多次发起,key 变了,好像会有问题?
  417 + @Schema(description = "被调用流程", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx")
414 @NotEmpty(message = "被调用流程不能为空") 418 @NotEmpty(message = "被调用流程不能为空")
415 private String calledElement; 419 private String calledElement;
416 420
417 - @Schema(description = "被调用流程名称", example = "xxx") 421 + @Schema(description = "被调用流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx")
418 @NotEmpty(message = "被调用流程名称不能为空") 422 @NotEmpty(message = "被调用流程名称不能为空")
419 private String calledElementName; 423 private String calledElementName;
420 424
421 - @Schema(description = "是否异步", example = "false") 425 + @Schema(description = "是否异步", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
422 @NotNull(message = "是否异步不能为空") 426 @NotNull(message = "是否异步不能为空")
423 private Boolean async; 427 private Boolean async;
424 428
425 - @Schema(description = "输入参数(主->子)", example = "[]") 429 + // TODO @lesan:inVariables
  430 + @Schema(description = "输入参数(主->子)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[]")
426 private List<IOParameter> inVariable; 431 private List<IOParameter> inVariable;
427 432
  433 + // TODO @lesan:outVariables
428 @Schema(description = "输出参数(子->主)", example = "[]") 434 @Schema(description = "输出参数(子->主)", example = "[]")
429 private List<IOParameter> outVariable; 435 private List<IOParameter> outVariable;
430 436
@@ -432,7 +438,8 @@ public class BpmSimpleModelNodeVO { @@ -432,7 +438,8 @@ public class BpmSimpleModelNodeVO {
432 @NotNull(message = "是否自动跳过子流程发起节点不能为空") 438 @NotNull(message = "是否自动跳过子流程发起节点不能为空")
433 private Boolean skipStartUserNode; 439 private Boolean skipStartUserNode;
434 440
435 - @Schema(description = "子流程发起人配置", example = "{}") 441 + @Schema(description = "子流程发起人配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  442 + // TODO @lesan:这个应该也必须填写?
436 private StartUserSetting startUserSetting; 443 private StartUserSetting startUserSetting;
437 444
438 @Schema(description = "子流程发起人配置") 445 @Schema(description = "子流程发起人配置")
@@ -448,7 +455,9 @@ public class BpmSimpleModelNodeVO { @@ -448,7 +455,9 @@ public class BpmSimpleModelNodeVO {
448 @Schema(description = "表单", example = "xxx") 455 @Schema(description = "表单", example = "xxx")
449 private String formField; 456 private String formField;
450 457
  458 + // TODO @lesan:emptyHandleType => emptyType,和 type 对上?
451 @Schema(description = "当子流程发起人为空时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 459 @Schema(description = "当子流程发起人为空时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  460 + @NotNull(message = "当子流程发起人为空时类型不能为空")
452 @InEnum(BpmChildProcessStartUserEmptyTypeEnum.class) 461 @InEnum(BpmChildProcessStartUserEmptyTypeEnum.class)
453 private Integer emptyHandleType; 462 private Integer emptyHandleType;
454 463
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
@@ -25,7 +25,10 @@ import org.flowable.engine.impl.util.CommandContextUtil; @@ -25,7 +25,10 @@ import org.flowable.engine.impl.util.CommandContextUtil;
25 import org.flowable.engine.runtime.ProcessInstance; 25 import org.flowable.engine.runtime.ProcessInstance;
26 import org.flowable.task.api.TaskInfo; 26 import org.flowable.task.api.TaskInfo;
27 27
28 -import java.util.*; 28 +import java.util.HashMap;
  29 +import java.util.List;
  30 +import java.util.Map;
  31 +import java.util.Objects;
29 import java.util.concurrent.Callable; 32 import java.util.concurrent.Callable;
30 import java.util.stream.Collectors; 33 import java.util.stream.Collectors;
31 34
@@ -241,6 +244,7 @@ public class FlowableUtils { @@ -241,6 +244,7 @@ public class FlowableUtils {
241 return formFieldsMap.entrySet().stream() 244 return formFieldsMap.entrySet().stream()
242 .limit(3) 245 .limit(3)
243 .map(entry -> new KeyValue<>(entry.getValue().getTitle(), 246 .map(entry -> new KeyValue<>(entry.getValue().getTitle(),
  247 + // TODO @lesan: MapUtil.getStr 可以更简单?
244 StrUtil.toStringOrEmpty(processVariables.getOrDefault(entry.getValue().getField(), "")))) 248 StrUtil.toStringOrEmpty(processVariables.getOrDefault(entry.getValue().getField(), ""))))
245 .collect(Collectors.toList()); 249 .collect(Collectors.toList());
246 } 250 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -11,8 +11,11 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.B @@ -11,8 +11,11 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.B
11 import cn.iocoder.yudao.module.bpm.enums.definition.*; 11 import cn.iocoder.yudao.module.bpm.enums.definition.*;
12 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; 12 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
13 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 cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
14 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate; 15 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate;
15 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmTriggerTaskDelegate; 16 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmTriggerTaskDelegate;
  17 +import cn.iocoder.yudao.module.bpm.service.task.listener.BpmCallActivityListener;
  18 +import cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener;
16 import org.flowable.bpmn.BpmnAutoLayout; 19 import org.flowable.bpmn.BpmnAutoLayout;
17 import org.flowable.bpmn.constants.BpmnXMLConstants; 20 import org.flowable.bpmn.constants.BpmnXMLConstants;
18 import org.flowable.bpmn.model.Process; 21 import org.flowable.bpmn.model.Process;
@@ -24,10 +27,7 @@ import org.springframework.util.MultiValueMap; @@ -24,10 +27,7 @@ import org.springframework.util.MultiValueMap;
24 import java.util.*; 27 import java.util.*;
25 28
26 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; 29 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
27 -import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE;  
28 -import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS;  
29 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; 30 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
30 -import static cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener.DELEGATE_EXPRESSION;  
31 import static java.util.Arrays.asList; 31 import static java.util.Arrays.asList;
32 32
33 /** 33 /**
@@ -462,7 +462,7 @@ public class SimpleModelUtils { @@ -462,7 +462,7 @@ public class SimpleModelUtils {
462 FlowableListener flowableListener = new FlowableListener(); 462 FlowableListener flowableListener = new FlowableListener();
463 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE); 463 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
464 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 464 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
465 - flowableListener.setImplementation(DELEGATE_EXPRESSION); 465 + flowableListener.setImplementation(BpmUserTaskListener.DELEGATE_EXPRESSION);
466 addListenerConfig(flowableListener, node.getTaskCreateListener()); 466 addListenerConfig(flowableListener, node.getTaskCreateListener());
467 flowableListeners.add(flowableListener); 467 flowableListeners.add(flowableListener);
468 } 468 }
@@ -471,7 +471,7 @@ public class SimpleModelUtils { @@ -471,7 +471,7 @@ public class SimpleModelUtils {
471 FlowableListener flowableListener = new FlowableListener(); 471 FlowableListener flowableListener = new FlowableListener();
472 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT); 472 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
473 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 473 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
474 - flowableListener.setImplementation(DELEGATE_EXPRESSION); 474 + flowableListener.setImplementation(BpmUserTaskListener.DELEGATE_EXPRESSION);
475 addListenerConfig(flowableListener, node.getTaskAssignListener()); 475 addListenerConfig(flowableListener, node.getTaskAssignListener());
476 flowableListeners.add(flowableListener); 476 flowableListeners.add(flowableListener);
477 } 477 }
@@ -480,7 +480,7 @@ public class SimpleModelUtils { @@ -480,7 +480,7 @@ public class SimpleModelUtils {
480 FlowableListener flowableListener = new FlowableListener(); 480 FlowableListener flowableListener = new FlowableListener();
481 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE); 481 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
482 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 482 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
483 - flowableListener.setImplementation(DELEGATE_EXPRESSION); 483 + flowableListener.setImplementation(BpmUserTaskListener.DELEGATE_EXPRESSION);
484 addListenerConfig(flowableListener, node.getTaskCompleteListener()); 484 addListenerConfig(flowableListener, node.getTaskCompleteListener());
485 flowableListeners.add(flowableListener); 485 flowableListeners.add(flowableListener);
486 } 486 }
@@ -788,48 +788,56 @@ public class SimpleModelUtils { @@ -788,48 +788,56 @@ public class SimpleModelUtils {
788 CallActivity callActivity = new CallActivity(); 788 CallActivity callActivity = new CallActivity();
789 callActivity.setId(node.getId()); 789 callActivity.setId(node.getId());
790 callActivity.setName(node.getName()); 790 callActivity.setName(node.getName());
791 - callActivity.setCalledElementType("key"); 791 + callActivity.setCalledElementType("key"); // TODO @lesan:这里为啥是 key 哈?
792 // 1. 是否异步 792 // 1. 是否异步
793 callActivity.setAsynchronous(node.getChildProcessSetting().getAsync()); 793 callActivity.setAsynchronous(node.getChildProcessSetting().getAsync());
  794 +
794 // 2. 调用的子流程 795 // 2. 调用的子流程
795 callActivity.setCalledElement(childProcessSetting.getCalledElement()); 796 callActivity.setCalledElement(childProcessSetting.getCalledElement());
796 callActivity.setProcessInstanceName(childProcessSetting.getCalledElementName()); 797 callActivity.setProcessInstanceName(childProcessSetting.getCalledElementName());
  798 +
797 // 3. 是否自动跳过子流程发起节点 799 // 3. 是否自动跳过子流程发起节点
  800 + // TODO @lesan:貌似只有 SourceExpression 的区别,直接通过 valueOf childProcessSetting.getSkipStartUserNode()???
798 if (Boolean.TRUE.equals(childProcessSetting.getSkipStartUserNode())) { 801 if (Boolean.TRUE.equals(childProcessSetting.getSkipStartUserNode())) {
799 IOParameter ioParameter = new IOParameter(); 802 IOParameter ioParameter = new IOParameter();
800 ioParameter.setSourceExpression("true"); 803 ioParameter.setSourceExpression("true");
801 - ioParameter.setTarget(PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE); 804 + ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE);
802 inVariable.add(ioParameter); 805 inVariable.add(ioParameter);
803 } else { 806 } else {
804 IOParameter ioParameter = new IOParameter(); 807 IOParameter ioParameter = new IOParameter();
805 ioParameter.setSourceExpression("false"); 808 ioParameter.setSourceExpression("false");
806 - ioParameter.setTarget(PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE); 809 + ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE);
807 inVariable.add(ioParameter); 810 inVariable.add(ioParameter);
808 } 811 }
  812 +
809 // 4. 主→子变量传递 813 // 4. 主→子变量传递
810 - // 默认需要传递的一些变量  
811 - // 4.1 流程状态 814 + // 4.1 【默认需要传递的一些变量】流程状态
  815 + // TODO @lesan:4.1 这个要不,单独一个序号,类似 3. 这个。然后下面,就是把 主→子变量传递、子→主变量传递;这样逻辑连贯点哈
812 IOParameter ioParameter = new IOParameter(); 816 IOParameter ioParameter = new IOParameter();
813 - ioParameter.setSource(PROCESS_INSTANCE_VARIABLE_STATUS);  
814 - ioParameter.setTarget(PROCESS_INSTANCE_VARIABLE_STATUS); 817 + ioParameter.setSource(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
  818 + ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
815 inVariable.add(ioParameter); 819 inVariable.add(ioParameter);
816 callActivity.setInParameters(inVariable); 820 callActivity.setInParameters(inVariable);
  821 +
817 // 5. 子→主变量传递 822 // 5. 子→主变量传递
  823 + // TODO @lesan:通过 isNotEmpty 这种哈
818 if (childProcessSetting.getOutVariable() != null && !childProcessSetting.getOutVariable().isEmpty()) { 824 if (childProcessSetting.getOutVariable() != null && !childProcessSetting.getOutVariable().isEmpty()) {
819 callActivity.setOutParameters(childProcessSetting.getOutVariable()); 825 callActivity.setOutParameters(childProcessSetting.getOutVariable());
820 } 826 }
  827 +
821 // 6. 子流程发起人配置 828 // 6. 子流程发起人配置
822 List<FlowableListener> executionListeners = new ArrayList<>(); 829 List<FlowableListener> executionListeners = new ArrayList<>();
823 FlowableListener flowableListener = new FlowableListener(); 830 FlowableListener flowableListener = new FlowableListener();
824 flowableListener.setEvent(ExecutionListener.EVENTNAME_START); 831 flowableListener.setEvent(ExecutionListener.EVENTNAME_START);
825 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 832 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
826 - flowableListener.setImplementation("${bpmCallActivityListener}"); 833 + flowableListener.setImplementation(BpmCallActivityListener.DELEGATE_EXPRESSION);
827 FieldExtension fieldExtension = new FieldExtension(); 834 FieldExtension fieldExtension = new FieldExtension();
828 fieldExtension.setFieldName("listenerConfig"); 835 fieldExtension.setFieldName("listenerConfig");
829 fieldExtension.setStringValue(JsonUtils.toJsonString(childProcessSetting.getStartUserSetting())); 836 fieldExtension.setStringValue(JsonUtils.toJsonString(childProcessSetting.getStartUserSetting()));
830 flowableListener.getFieldExtensions().add(fieldExtension); 837 flowableListener.getFieldExtensions().add(fieldExtension);
831 executionListeners.add(flowableListener); 838 executionListeners.add(flowableListener);
832 callActivity.setExecutionListeners(executionListeners); 839 callActivity.setExecutionListeners(executionListeners);
  840 +
833 // 添加节点类型 841 // 添加节点类型
834 addNodeType(node.getType(), callActivity); 842 addNodeType(node.getType(), callActivity);
835 return callActivity; 843 return callActivity;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
@@ -320,7 +320,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -320,7 +320,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
320 // 遍历 tasks 列表,只处理已结束的 UserTask 320 // 遍历 tasks 列表,只处理已结束的 UserTask
321 // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 321 // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities
322 // 的话,它无法成为一个节点 322 // 的话,它无法成为一个节点
323 - // TODO @芋艿:子流程只有activity,这里获取不到已结束的子流程 323 + // TODO @芋艿:子流程只有activity,这里获取不到已结束的子流程;TODO @lesan:这个会有啥影响?微信聊?
324 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null); 324 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null);
325 List<ActivityNode> approvalNodes = convertList(endTasks, task -> { 325 List<ActivityNode> approvalNodes = convertList(endTasks, task -> {
326 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); 326 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
@@ -389,7 +389,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -389,7 +389,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
389 Map<String, Object> processVariables, 389 Map<String, Object> processVariables,
390 List<HistoricActivityInstance> activities, 390 List<HistoricActivityInstance> activities,
391 List<HistoricTaskInstance> tasks) { 391 List<HistoricTaskInstance> tasks) {
392 - // 构建运行中的任务,基于 activityId 分组 392 + // 构建运行中的任务、子流程,基于 activityId 分组
393 List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null 393 List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null
394 && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER, ELEMENT_CALL_ACTIVITY))); 394 && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER, ELEMENT_CALL_ACTIVITY)));
395 Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities, 395 Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities,
@@ -414,6 +414,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -414,6 +414,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
414 // 处理每个任务的 tasks 属性 414 // 处理每个任务的 tasks 属性
415 for (HistoricActivityInstance activity : taskActivities) { 415 for (HistoricActivityInstance activity : taskActivities) {
416 HistoricTaskInstance task = taskMap.get(activity.getTaskId()); 416 HistoricTaskInstance task = taskMap.get(activity.getTaskId());
  417 + // TODO @lesan:这里为啥 continue 哈?
417 if (task == null) { 418 if (task == null) {
418 continue; 419 continue;
419 } 420 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -1214,7 +1214,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -1214,7 +1214,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
1214 } 1214 }
1215 } 1215 }
1216 1216
1217 - // 发起人节点 1217 + // 获取发起人节点
1218 BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId()); 1218 BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());
1219 if (bpmnModel == null) { 1219 if (bpmnModel == null) {
1220 log.error("[processTaskAssigned][taskId({}) 没有找到流程模型]", task.getId()); 1220 log.error("[processTaskAssigned][taskId({}) 没有找到流程模型]", task.getId());
@@ -1227,16 +1227,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -1227,16 +1227,17 @@ public class BpmTaskServiceImpl implements BpmTaskService {
1227 String.format(PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class); 1227 String.format(PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class);
1228 Boolean skipStartUserNodeFlag = Convert.toBool(runtimeService.getVariable(processInstance.getProcessInstanceId(), 1228 Boolean skipStartUserNodeFlag = Convert.toBool(runtimeService.getVariable(processInstance.getProcessInstanceId(),
1229 PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class)); 1229 PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class));
1230 - if (userTaskElement.getId().equals(START_USER_NODE_ID) &&  
1231 - (skipStartUserNodeFlag == null || Boolean.TRUE.equals(skipStartUserNodeFlag)) &&  
1232 - !Boolean.TRUE.equals(returnTaskFlag)) { 1230 + if (userTaskElement.getId().equals(START_USER_NODE_ID)
  1231 + && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核
  1232 + || Boolean.TRUE.equals(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核
  1233 + && !Boolean.TRUE.equals(returnTaskFlag)) { // TODO @lesan:ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE) 改成这个有问题么?尽量不用 ! 取反
1233 getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) 1234 getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
1234 .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); 1235 .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason()));
1235 return; 1236 return;
1236 } 1237 }
1237 // 当不为发起人节点时,审批人与提交人为同一人时,根据 BpmUserTaskAssignStartUserHandlerTypeEnum 策略进行处理 1238 // 当不为发起人节点时,审批人与提交人为同一人时,根据 BpmUserTaskAssignStartUserHandlerTypeEnum 策略进行处理
1238 - if (!userTaskElement.getId().equals(START_USER_NODE_ID) &&  
1239 - StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) { 1239 + if (ObjectUtil.notEqual(userTaskElement.getId(), START_USER_NODE_ID)
  1240 + && StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) {
1240 if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { 1241 if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) {
1241 Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement); 1242 Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement);
1242 1243
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java
1 package cn.iocoder.yudao.module.bpm.service.task.listener; 1 package cn.iocoder.yudao.module.bpm.service.task.listener;
2 2
3 -import cn.hutool.core.convert.Convert;  
4 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -22,7 +21,7 @@ import org.springframework.stereotype.Component; @@ -22,7 +21,7 @@ import org.springframework.stereotype.Component;
22 import java.util.List; 21 import java.util.List;
23 22
24 /** 23 /**
25 - * BPM 子流程监听器 24 + * BPM 子流程监听器:设置流程的发起人
26 * 25 *
27 * @author Lesan 26 * @author Lesan
28 */ 27 */
@@ -42,47 +41,51 @@ public class BpmCallActivityListener implements ExecutionListener { @@ -42,47 +41,51 @@ public class BpmCallActivityListener implements ExecutionListener {
42 public void notify(DelegateExecution execution) { 41 public void notify(DelegateExecution execution) {
43 String expressionText = listenerConfig.getExpressionText(); 42 String expressionText = listenerConfig.getExpressionText();
44 Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText); 43 Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText);
45 - BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting startUserSetting = JsonUtils.parseObject(expressionText, BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting.class);  
46 - // 1. 当发起人来源为表单时  
47 - if (startUserSetting != null &&  
48 - startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.FROM_FORM.getType())) { 44 + BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting startUserSetting = JsonUtils.parseObject(
  45 + expressionText, BpmSimpleModelNodeVO.ChildProcessSetting.StartUserSetting.class);
  46 +
  47 + // 1. 当发起人来源为主流程发起人时,并兜底 startUserSetting 为空时
  48 + if (startUserSetting == null
  49 + || startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER.getType())) {
  50 + ExecutionEntity parent = (ExecutionEntity) execution.getParent();
  51 + FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
  52 + return;
  53 + }
  54 +
  55 + // 2. 当发起人来源为表单时
  56 + if (startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.FROM_FORM.getType())) {
49 ExecutionEntity parent = (ExecutionEntity) execution.getParent(); 57 ExecutionEntity parent = (ExecutionEntity) execution.getParent();
50 - String formField = parent.getVariable(startUserSetting.getFormField(), String.class);  
51 - // 1.1 当表单值为空时  
52 - if (StrUtil.isEmpty(formField)) {  
53 - // 1.1.1 来自主流程发起人  
54 - if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())){ 58 + String formFieldValue = parent.getVariable(startUserSetting.getFormField(), String.class);
  59 + // 2.1 当表单值为空时
  60 + if (StrUtil.isEmpty(formFieldValue)) {
  61 + // 2.1.1 来自主流程发起人
  62 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())) {
55 FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); 63 FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
56 return; 64 return;
57 } 65 }
58 - // 1.1.2 来自子流程管理员  
59 - if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN.getType())){ 66 + // 2.1.2 来自子流程管理员
  67 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN.getType())) {
60 BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId()); 68 BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId());
61 List<Long> managerUserIds = processDefinition.getManagerUserIds(); 69 List<Long> managerUserIds = processDefinition.getManagerUserIds();
62 - FlowableUtils.setAuthenticatedUserId(Convert.toLong(managerUserIds.get(0))); 70 + FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0));
63 return; 71 return;
64 } 72 }
65 - // 1.1.3 来自主流程管理员  
66 - if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())){ 73 + // 2.1.3 来自主流程管理员
  74 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())) {
67 BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId()); 75 BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId());
68 List<Long> managerUserIds = processDefinition.getManagerUserIds(); 76 List<Long> managerUserIds = processDefinition.getManagerUserIds();
69 - FlowableUtils.setAuthenticatedUserId(Convert.toLong(managerUserIds.get(0))); 77 + FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0));
70 return; 78 return;
71 } 79 }
72 } 80 }
73 - // 1.2 使用表单值,并兜底字符串转Long失败时使用主流程发起人 81 + // 2.2 使用表单值,并兜底字符串转 Long 失败时使用主流程发起人
74 try { 82 try {
75 - FlowableUtils.setAuthenticatedUserId(Long.parseLong(formField)); 83 + FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue));
76 } catch (Exception e) { 84 } catch (Exception e) {
  85 + // todo @lesan:打个日志,方便排查
77 FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); 86 FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
78 } 87 }
79 } 88 }
80 - // 2. 当发起人来源为主流程发起人时,并兜底startUserSetting为空时  
81 - if (startUserSetting == null ||  
82 - startUserSetting.getType().equals(BpmChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER.getType())) {  
83 - ExecutionEntity parent = (ExecutionEntity) execution.getParent();  
84 - FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));  
85 - }  
86 } 89 }
87 90
88 } 91 }
89 \ No newline at end of file 92 \ No newline at end of file