Commit 8c681a77f5170ddb39f6fe6f4605ecceb06e3de0

Authored by jason
2 parents 3f8221ba 254b5577

Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm

# Conflicts:
#	yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
Showing 14 changed files with 386 additions and 31 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserEmptyTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.enums.definition;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  5 +import lombok.AllArgsConstructor;
  6 +import lombok.Getter;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * BPM 当子流程发起人为空时类型枚举
  12 + *
  13 + * @author Lesan
  14 + */
  15 +@Getter
  16 +@AllArgsConstructor
  17 +public enum BpmChildProcessStartUserEmptyTypeEnum implements ArrayValuable<Integer> {
  18 +
  19 + MAIN_PROCESS_START_USER(1, "同主流程发起人"),
  20 + CHILD_PROCESS_ADMIN(2, "子流程管理员"),
  21 + MAIN_PROCESS_ADMIN(3, "主流程管理员");
  22 +
  23 + private final Integer type;
  24 + private final String name;
  25 +
  26 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(BpmChildProcessStartUserEmptyTypeEnum::getType).toArray(Integer[]::new);
  27 +
  28 + public static BpmChildProcessStartUserEmptyTypeEnum typeOf(Integer type) {
  29 + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
  30 + }
  31 +
  32 + @Override
  33 + public Integer[] array() {
  34 + return ARRAYS;
  35 + }
  36 +}
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessStartUserTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.enums.definition;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  5 +import lombok.AllArgsConstructor;
  6 +import lombok.Getter;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * BPM 子流程发起人类型枚举
  12 + *
  13 + * @author Lesan
  14 + */
  15 +@Getter
  16 +@AllArgsConstructor
  17 +public enum BpmChildProcessStartUserTypeEnum implements ArrayValuable<Integer> {
  18 +
  19 + MAIN_PROCESS_START_USER(1, "同主流程发起人"),
  20 + FROM_FORM(2, "表单");
  21 +
  22 + private final Integer type;
  23 + private final String name;
  24 +
  25 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(BpmChildProcessStartUserTypeEnum::getType).toArray(Integer[]::new);
  26 +
  27 + public static BpmChildProcessStartUserTypeEnum typeOf(Integer type) {
  28 + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
  29 + }
  30 +
  31 + @Override
  32 + public Integer[] array() {
  33 + return ARRAYS;
  34 + }
  35 +}
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java
@@ -30,6 +30,9 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable&lt;Integer&gt; { @@ -30,6 +30,9 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable&lt;Integer&gt; {
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"), // TODO @lesan:CHILD_PROCESS、ASYNC_CHILD_PROCESS 可以合并为一个么?
  34 + ASYNC_CHILD_PROCESS(21, "异步子流程", "callActivity"),
  35 +
33 // 50 ~ 条件分支 36 // 50 ~ 条件分支
34 CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式 37 CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式
35 CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), 38 CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"),
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
@@ -26,6 +26,7 @@ public enum BpmReasonEnum { @@ -26,6 +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_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"), 30 ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"),
30 ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"), 31 ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"),
31 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
@@ -11,6 +11,7 @@ import jakarta.validation.Valid; @@ -11,6 +11,7 @@ import jakarta.validation.Valid;
11 import jakarta.validation.constraints.NotEmpty; 11 import jakarta.validation.constraints.NotEmpty;
12 import jakarta.validation.constraints.NotNull; 12 import jakarta.validation.constraints.NotNull;
13 import lombok.Data; 13 import lombok.Data;
  14 +import org.flowable.bpmn.model.IOParameter;
14 import org.hibernate.validator.constraints.URL; 15 import org.hibernate.validator.constraints.URL;
15 16
16 import java.util.List; 17 import java.util.List;
@@ -131,6 +132,11 @@ public class BpmSimpleModelNodeVO { @@ -131,6 +132,11 @@ public class BpmSimpleModelNodeVO {
131 private String attachNodeId; // 目前用于异步触发器节点。需要 UserTask 和 ReceiveTask(附加节点) 来完成 132 private String attachNodeId; // 目前用于异步触发器节点。需要 UserTask 和 ReceiveTask(附加节点) 来完成
132 133
133 134
  135 + /**
  136 + * 子流程设置
  137 + */
  138 + private ChildProcessSetting childProcessSetting;
  139 +
134 @Schema(description = "任务监听器") 140 @Schema(description = "任务监听器")
135 @Valid 141 @Valid
136 @Data 142 @Data
@@ -413,4 +419,61 @@ public class BpmSimpleModelNodeVO { @@ -413,4 +419,61 @@ public class BpmSimpleModelNodeVO {
413 private Set<String> deleteFields; 419 private Set<String> deleteFields;
414 } 420 }
415 } 421 }
  422 +
  423 + @Schema(description = "子流程节点配置")
  424 + @Data
  425 + @Valid
  426 + public static class ChildProcessSetting {
  427 +
  428 + // TODO @lesan:calledElement => calledProcessDefinitionKey ? 这样更容易理解?不过如果一个流程多次发起,key 变了,好像会有问题?
  429 + @Schema(description = "被调用流程", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx")
  430 + @NotEmpty(message = "被调用流程不能为空")
  431 + private String calledElement;
  432 +
  433 + @Schema(description = "被调用流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx")
  434 + @NotEmpty(message = "被调用流程名称不能为空")
  435 + private String calledElementName;
  436 +
  437 + @Schema(description = "是否异步", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
  438 + @NotNull(message = "是否异步不能为空")
  439 + private Boolean async;
  440 +
  441 + // TODO @lesan:inVariables
  442 + @Schema(description = "输入参数(主->子)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[]")
  443 + private List<IOParameter> inVariable;
  444 +
  445 + // TODO @lesan:outVariables
  446 + @Schema(description = "输出参数(子->主)", example = "[]")
  447 + private List<IOParameter> outVariable;
  448 +
  449 + @Schema(description = "是否自动跳过子流程发起节点", example = "false")
  450 + @NotNull(message = "是否自动跳过子流程发起节点不能为空")
  451 + private Boolean skipStartUserNode;
  452 +
  453 + @Schema(description = "子流程发起人配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
  454 + // TODO @lesan:这个应该也必须填写?
  455 + private StartUserSetting startUserSetting;
  456 +
  457 + @Schema(description = "子流程发起人配置")
  458 + @Data
  459 + @Valid
  460 + public static class StartUserSetting {
  461 +
  462 + @Schema(description = "子流程发起人类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  463 + @NotNull(message = "子流程发起人类型")
  464 + @InEnum(BpmChildProcessStartUserTypeEnum.class)
  465 + private Integer type;
  466 +
  467 + @Schema(description = "表单", example = "xxx")
  468 + private String formField;
  469 +
  470 + // TODO @lesan:emptyHandleType => emptyType,和 type 对上?
  471 + @Schema(description = "当子流程发起人为空时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  472 + @NotNull(message = "当子流程发起人为空时类型不能为空")
  473 + @InEnum(BpmChildProcessStartUserEmptyTypeEnum.class)
  474 + private Integer emptyHandleType;
  475 +
  476 + }
  477 +
  478 + }
416 } 479 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java
@@ -52,6 +52,13 @@ public class BpmnVariableConstants { @@ -52,6 +52,13 @@ public class BpmnVariableConstants {
52 public static final String PROCESS_INSTANCE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED"; 52 public static final String PROCESS_INSTANCE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED";
53 53
54 /** 54 /**
  55 + * 流程实例的变量 - 用于判断流程是否需要跳过发起人节点
  56 + *
  57 + * @see ProcessInstance#getProcessVariables()
  58 + */
  59 + public static final String PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE = "PROCESS_SKIP_START_USER_NODE";
  60 +
  61 + /**
55 * 流程实例的变量 - 流程开始时间 62 * 流程实例的变量 - 流程开始时间
56 * 63 *
57 * 【非存储变量】用于部分需要 format 的场景,例如说:流程实例的自定义标题 64 * 【非存储变量】用于部分需要 format 的场景,例如说:流程实例的自定义标题
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.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.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
  4 +import cn.hutool.core.util.StrUtil;
4 import cn.hutool.extra.spring.SpringUtil; 5 import cn.hutool.extra.spring.SpringUtil;
5 import cn.iocoder.yudao.framework.common.core.KeyValue; 6 import cn.iocoder.yudao.framework.common.core.KeyValue;
6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 7 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -24,7 +25,10 @@ import org.flowable.engine.impl.util.CommandContextUtil; @@ -24,7 +25,10 @@ import org.flowable.engine.impl.util.CommandContextUtil;
24 import org.flowable.engine.runtime.ProcessInstance; 25 import org.flowable.engine.runtime.ProcessInstance;
25 import org.flowable.task.api.TaskInfo; 26 import org.flowable.task.api.TaskInfo;
26 27
27 -import java.util.*; 28 +import java.util.HashMap;
  29 +import java.util.List;
  30 +import java.util.Map;
  31 +import java.util.Objects;
28 import java.util.concurrent.Callable; 32 import java.util.concurrent.Callable;
29 import java.util.stream.Collectors; 33 import java.util.stream.Collectors;
30 34
@@ -240,7 +244,8 @@ public class FlowableUtils { @@ -240,7 +244,8 @@ public class FlowableUtils {
240 return formFieldsMap.entrySet().stream() 244 return formFieldsMap.entrySet().stream()
241 .limit(3) 245 .limit(3)
242 .map(entry -> new KeyValue<>(entry.getValue().getTitle(), 246 .map(entry -> new KeyValue<>(entry.getValue().getTitle(),
243 - processVariables.getOrDefault(entry.getValue().getField(), "").toString())) 247 + // TODO @lesan: MapUtil.getStr 可以更简单?
  248 + StrUtil.toStringOrEmpty(processVariables.getOrDefault(entry.getValue().getField(), ""))))
244 .collect(Collectors.toList()); 249 .collect(Collectors.toList());
245 } 250 }
246 251
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -5,17 +5,22 @@ import cn.hutool.core.lang.Assert; @@ -5,17 +5,22 @@ import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.map.MapUtil; 5 import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.*; 6 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.framework.common.util.json.JsonUtils;
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;
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.ConditionGroups;
10 import cn.iocoder.yudao.module.bpm.enums.definition.*; 11 import cn.iocoder.yudao.module.bpm.enums.definition.*;
11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; 12 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
12 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;
13 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate; 15 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate;
14 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;
15 import org.flowable.bpmn.BpmnAutoLayout; 19 import org.flowable.bpmn.BpmnAutoLayout;
16 import org.flowable.bpmn.constants.BpmnXMLConstants; 20 import org.flowable.bpmn.constants.BpmnXMLConstants;
17 import org.flowable.bpmn.model.Process; 21 import org.flowable.bpmn.model.Process;
18 import org.flowable.bpmn.model.*; 22 import org.flowable.bpmn.model.*;
  23 +import org.flowable.engine.delegate.ExecutionListener;
19 import org.flowable.engine.delegate.TaskListener; 24 import org.flowable.engine.delegate.TaskListener;
20 import org.springframework.util.MultiValueMap; 25 import org.springframework.util.MultiValueMap;
21 26
@@ -24,7 +29,6 @@ import java.util.*; @@ -24,7 +29,6 @@ import java.util.*;
24 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum.ASYNC_HTTP_REQUEST; 29 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum.ASYNC_HTTP_REQUEST;
25 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; 30 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
26 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; 31 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
27 -import static cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener.DELEGATE_EXPRESSION;  
28 import static java.util.Arrays.asList; 32 import static java.util.Arrays.asList;
29 33
30 /** 34 /**
@@ -43,7 +47,8 @@ public class SimpleModelUtils { @@ -43,7 +47,8 @@ public class SimpleModelUtils {
43 List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(), 47 List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(),
44 new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), new TransactorNodeConvert(), 48 new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), new TransactorNodeConvert(),
45 new DelayTimerNodeConvert(), new TriggerNodeConvert(), 49 new DelayTimerNodeConvert(), new TriggerNodeConvert(),
46 - new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), new RouteBranchNodeConvert()); 50 + new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), new RouteBranchNodeConvert(),
  51 + new ChildProcessConvert(), new AsyncChildProcessConvert());
47 converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); 52 converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert));
48 } 53 }
49 54
@@ -478,7 +483,7 @@ public class SimpleModelUtils { @@ -478,7 +483,7 @@ public class SimpleModelUtils {
478 FlowableListener flowableListener = new FlowableListener(); 483 FlowableListener flowableListener = new FlowableListener();
479 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE); 484 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
480 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 485 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
481 - flowableListener.setImplementation(DELEGATE_EXPRESSION); 486 + flowableListener.setImplementation(BpmUserTaskListener.DELEGATE_EXPRESSION);
482 addListenerConfig(flowableListener, node.getTaskCreateListener()); 487 addListenerConfig(flowableListener, node.getTaskCreateListener());
483 flowableListeners.add(flowableListener); 488 flowableListeners.add(flowableListener);
484 } 489 }
@@ -487,7 +492,7 @@ public class SimpleModelUtils { @@ -487,7 +492,7 @@ public class SimpleModelUtils {
487 FlowableListener flowableListener = new FlowableListener(); 492 FlowableListener flowableListener = new FlowableListener();
488 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT); 493 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
489 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 494 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
490 - flowableListener.setImplementation(DELEGATE_EXPRESSION); 495 + flowableListener.setImplementation(BpmUserTaskListener.DELEGATE_EXPRESSION);
491 addListenerConfig(flowableListener, node.getTaskAssignListener()); 496 addListenerConfig(flowableListener, node.getTaskAssignListener());
492 flowableListeners.add(flowableListener); 497 flowableListeners.add(flowableListener);
493 } 498 }
@@ -496,7 +501,7 @@ public class SimpleModelUtils { @@ -496,7 +501,7 @@ public class SimpleModelUtils {
496 FlowableListener flowableListener = new FlowableListener(); 501 FlowableListener flowableListener = new FlowableListener();
497 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE); 502 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
498 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 503 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
499 - flowableListener.setImplementation(DELEGATE_EXPRESSION); 504 + flowableListener.setImplementation(BpmUserTaskListener.DELEGATE_EXPRESSION);
500 addListenerConfig(flowableListener, node.getTaskCompleteListener()); 505 addListenerConfig(flowableListener, node.getTaskCompleteListener());
501 flowableListeners.add(flowableListener); 506 flowableListeners.add(flowableListener);
502 } 507 }
@@ -809,6 +814,88 @@ public class SimpleModelUtils { @@ -809,6 +814,88 @@ public class SimpleModelUtils {
809 814
810 } 815 }
811 816
  817 + private static class ChildProcessConvert implements NodeConvert {
  818 +
  819 + @Override
  820 + public CallActivity convert(BpmSimpleModelNodeVO node) {
  821 + BpmSimpleModelNodeVO.ChildProcessSetting childProcessSetting = node.getChildProcessSetting();
  822 + List<IOParameter> inVariable = childProcessSetting.getInVariable() == null ?
  823 + new ArrayList<>() : new ArrayList<>(childProcessSetting.getInVariable());
  824 + CallActivity callActivity = new CallActivity();
  825 + callActivity.setId(node.getId());
  826 + callActivity.setName(node.getName());
  827 + callActivity.setCalledElementType("key"); // TODO @lesan:这里为啥是 key 哈?
  828 + // 1. 是否异步
  829 + callActivity.setAsynchronous(node.getChildProcessSetting().getAsync());
  830 +
  831 + // 2. 调用的子流程
  832 + callActivity.setCalledElement(childProcessSetting.getCalledElement());
  833 + callActivity.setProcessInstanceName(childProcessSetting.getCalledElementName());
  834 +
  835 + // 3. 是否自动跳过子流程发起节点
  836 + // TODO @lesan:貌似只有 SourceExpression 的区别,直接通过 valueOf childProcessSetting.getSkipStartUserNode()???
  837 + if (Boolean.TRUE.equals(childProcessSetting.getSkipStartUserNode())) {
  838 + IOParameter ioParameter = new IOParameter();
  839 + ioParameter.setSourceExpression("true");
  840 + ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE);
  841 + inVariable.add(ioParameter);
  842 + } else {
  843 + IOParameter ioParameter = new IOParameter();
  844 + ioParameter.setSourceExpression("false");
  845 + ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE);
  846 + inVariable.add(ioParameter);
  847 + }
  848 +
  849 + // 4. 主→子变量传递
  850 + // 4.1 【默认需要传递的一些变量】流程状态
  851 + // TODO @lesan:4.1 这个要不,单独一个序号,类似 3. 这个。然后下面,就是把 主→子变量传递、子→主变量传递;这样逻辑连贯点哈
  852 + IOParameter ioParameter = new IOParameter();
  853 + ioParameter.setSource(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
  854 + ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
  855 + inVariable.add(ioParameter);
  856 + callActivity.setInParameters(inVariable);
  857 +
  858 + // 5. 子→主变量传递
  859 + // TODO @lesan:通过 isNotEmpty 这种哈
  860 + if (childProcessSetting.getOutVariable() != null && !childProcessSetting.getOutVariable().isEmpty()) {
  861 + callActivity.setOutParameters(childProcessSetting.getOutVariable());
  862 + }
  863 +
  864 + // 6. 子流程发起人配置
  865 + List<FlowableListener> executionListeners = new ArrayList<>();
  866 + FlowableListener flowableListener = new FlowableListener();
  867 + flowableListener.setEvent(ExecutionListener.EVENTNAME_START);
  868 + flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
  869 + flowableListener.setImplementation(BpmCallActivityListener.DELEGATE_EXPRESSION);
  870 + FieldExtension fieldExtension = new FieldExtension();
  871 + fieldExtension.setFieldName("listenerConfig");
  872 + fieldExtension.setStringValue(JsonUtils.toJsonString(childProcessSetting.getStartUserSetting()));
  873 + flowableListener.getFieldExtensions().add(fieldExtension);
  874 + executionListeners.add(flowableListener);
  875 + callActivity.setExecutionListeners(executionListeners);
  876 +
  877 + // 添加节点类型
  878 + addNodeType(node.getType(), callActivity);
  879 + return callActivity;
  880 + }
  881 +
  882 + @Override
  883 + public BpmSimpleModelNodeTypeEnum getType() {
  884 + return BpmSimpleModelNodeTypeEnum.CHILD_PROCESS;
  885 + }
  886 +
  887 + }
  888 +
  889 + private static class AsyncChildProcessConvert extends ChildProcessConvert {
  890 +
  891 + @Override
  892 + public BpmSimpleModelNodeTypeEnum getType() {
  893 + return BpmSimpleModelNodeTypeEnum.ASYNC_CHILD_PROCESS;
  894 + }
  895 +
  896 + }
  897 +
  898 +
812 private static String buildGatewayJoinId(String id) { 899 private static String buildGatewayJoinId(String id) {
813 return id + "_join"; 900 return id + "_join";
814 } 901 }
@@ -838,6 +925,8 @@ public class SimpleModelUtils { @@ -838,6 +925,8 @@ public class SimpleModelUtils {
838 || nodeType == BpmSimpleModelNodeTypeEnum.APPROVE_NODE 925 || nodeType == BpmSimpleModelNodeTypeEnum.APPROVE_NODE
839 || nodeType == BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE 926 || nodeType == BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE
840 || nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE 927 || nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE
  928 + || nodeType == BpmSimpleModelNodeTypeEnum.CHILD_PROCESS
  929 + || nodeType == BpmSimpleModelNodeTypeEnum.ASYNC_CHILD_PROCESS
841 || nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) { 930 || nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) {
842 // 添加元素 931 // 添加元素
843 resultNodes.add(currentNode); 932 resultNodes.add(currentNode);
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java
@@ -160,10 +160,10 @@ public interface BpmProcessInstanceService { @@ -160,10 +160,10 @@ public interface BpmProcessInstanceService {
160 /** 160 /**
161 * 删除 ProcessInstance 的变量 161 * 删除 ProcessInstance 的变量
162 * 162 *
163 - * @param processInstanceId 流程编号 163 + * @param id 流程编号
164 * @param variableNames 流程变量名 164 * @param variableNames 流程变量名
165 */ 165 */
166 - void removeProcessInstanceVariables(String processInstanceId, Collection<String> variableNames); 166 + void removeProcessInstanceVariables(String id, Collection<String> variableNames);
167 167
168 // ========== Event 事件相关方法 ========== 168 // ========== Event 事件相关方法 ==========
169 169
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
@@ -320,6 +320,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -320,6 +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,这里获取不到已结束的子流程;TODO @lesan:这个会有啥影响?微信聊?
323 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null); 324 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null);
324 List<ActivityNode> approvalNodes = convertList(endTasks, task -> { 325 List<ActivityNode> approvalNodes = convertList(endTasks, task -> {
325 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); 326 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
@@ -388,9 +389,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -388,9 +389,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
388 Map<String, Object> processVariables, 389 Map<String, Object> processVariables,
389 List<HistoricActivityInstance> activities, 390 List<HistoricActivityInstance> activities,
390 List<HistoricTaskInstance> tasks) { 391 List<HistoricTaskInstance> tasks) {
391 - // 构建运行中的任务,基于 activityId 分组 392 + // 构建运行中的任务、子流程,基于 activityId 分组
392 List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null 393 List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null
393 - && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER))); 394 + && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER, ELEMENT_CALL_ACTIVITY)));
394 Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities, 395 Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities,
395 HistoricActivityInstance::getActivityId); 396 HistoricActivityInstance::getActivityId);
396 397
@@ -404,7 +405,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -404,7 +405,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
404 HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同 405 HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同
405 ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId()) 406 ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId())
406 .setName(firstActivity.getActivityName()) 407 .setName(firstActivity.getActivityName())
407 - .setNodeType(ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的:解决“办理节点”的识别 408 + .setNodeType(ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的:解决“办理节点”和"子流程"的识别
408 BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())) 409 BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()))
409 .setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) 410 .setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
410 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) 411 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
@@ -413,6 +414,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -413,6 +414,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
413 // 处理每个任务的 tasks 属性 414 // 处理每个任务的 tasks 属性
414 for (HistoricActivityInstance activity : taskActivities) { 415 for (HistoricActivityInstance activity : taskActivities) {
415 HistoricTaskInstance task = taskMap.get(activity.getTaskId()); 416 HistoricTaskInstance task = taskMap.get(activity.getTaskId());
  417 + // TODO @lesan:这里为啥 continue 哈?
  418 + if (task == null) {
  419 + continue;
  420 + }
416 activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task)); 421 activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task));
417 // 加签子任务,需要过滤掉已经完成的加签子任务 422 // 加签子任务,需要过滤掉已经完成的加签子任务
418 List<HistoricTaskInstance> childrenTasks = filterList( 423 List<HistoricTaskInstance> childrenTasks = filterList(
@@ -503,6 +508,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -503,6 +508,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
503 activityNode.setCandidateUserIds(candidateUserIds); 508 activityNode.setCandidateUserIds(candidateUserIds);
504 return activityNode; 509 return activityNode;
505 } 510 }
  511 +
  512 + // 4. 子流程节点
  513 + if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(node.getType()) ||
  514 + BpmSimpleModelNodeTypeEnum.ASYNC_CHILD_PROCESS.getType().equals(node.getType())) {
  515 + return activityNode;
  516 + }
506 return null; 517 return null;
507 } 518 }
508 519
@@ -790,8 +801,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -790,8 +801,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
790 } 801 }
791 802
792 @Override 803 @Override
793 - public void removeProcessInstanceVariables(String processInstanceId, Collection<String> variableNames) {  
794 - runtimeService.removeVariables(processInstanceId, variableNames); 804 + public void removeProcessInstanceVariables(String id, Collection<String> variableNames) {
  805 + runtimeService.removeVariables(id, variableNames);
795 } 806 }
796 807
797 // ========== Event 事件相关方法 ========== 808 // ========== Event 事件相关方法 ==========
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
1 package cn.iocoder.yudao.module.bpm.service.task; 1 package cn.iocoder.yudao.module.bpm.service.task;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.convert.Convert;
4 import cn.hutool.core.lang.Assert; 5 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.util.*; 6 import cn.hutool.core.util.*;
6 import cn.hutool.extra.spring.SpringUtil; 7 import cn.hutool.extra.spring.SpringUtil;
@@ -63,6 +64,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -63,6 +64,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
63 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; 64 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
64 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; 65 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
65 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG; 66 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG;
  67 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE;
66 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; 68 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
67 69
68 /** 70 /**
@@ -1212,19 +1214,31 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -1212,19 +1214,31 @@ public class BpmTaskServiceImpl implements BpmTaskService {
1212 } 1214 }
1213 } 1215 }
1214 1216
1215 - // 审批人与提交人为同一人时,根据 BpmUserTaskAssignStartUserHandlerTypeEnum 策略进行处理  
1216 - if (StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) {  
1217 - // 判断是否为退回或者驳回:如果是退回或者驳回不走这个策略  
1218 - // TODO 芋艿:【优化】未来有没更好的判断方式?!另外,还要考虑清理机制。就是说,下次处理了之后,就移除这个标识  
1219 - Boolean returnTaskFlag = runtimeService.getVariable(processInstance.getProcessInstanceId(),  
1220 - String.format(PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class); 1217 + // 获取发起人节点
  1218 + BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());
  1219 + if (bpmnModel == null) {
  1220 + log.error("[processTaskAssigned][taskId({}) 没有找到流程模型]", task.getId());
  1221 + return;
  1222 + }
  1223 + FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
  1224 + // 判断是否为退回或者驳回:如果是退回或者驳回不走这个策略
  1225 + // TODO 芋艿:【优化】未来有没更好的判断方式?!另外,还要考虑清理机制。就是说,下次处理了之后,就移除这个标识
  1226 + Boolean returnTaskFlag = runtimeService.getVariable(processInstance.getProcessInstanceId(),
  1227 + String.format(PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class);
  1228 + Boolean skipStartUserNodeFlag = Convert.toBool(runtimeService.getVariable(processInstance.getProcessInstanceId(),
  1229 + PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class));
  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) 改成这个有问题么?尽量不用 ! 取反
  1234 + getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
  1235 + .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason()));
  1236 + return;
  1237 + }
  1238 + // 当不为发起人节点时,审批人与提交人为同一人时,根据 BpmUserTaskAssignStartUserHandlerTypeEnum 策略进行处理
  1239 + if (ObjectUtil.notEqual(userTaskElement.getId(), START_USER_NODE_ID)
  1240 + && StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) {
1221 if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { 1241 if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) {
1222 - BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());  
1223 - if (bpmnModel == null) {  
1224 - log.error("[processTaskAssigned][taskId({}) 没有找到流程模型]", task.getId());  
1225 - return;  
1226 - }  
1227 - FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());  
1228 Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement); 1242 Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement);
1229 1243
1230 // 情况一:自动跳过 1244 // 情况一:自动跳过
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.task.listener;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  6 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
  7 +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
  8 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessStartUserEmptyTypeEnum;
  9 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmChildProcessStartUserTypeEnum;
  10 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
  11 +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
  12 +import jakarta.annotation.Resource;
  13 +import lombok.Setter;
  14 +import lombok.extern.slf4j.Slf4j;
  15 +import org.flowable.engine.delegate.DelegateExecution;
  16 +import org.flowable.engine.delegate.ExecutionListener;
  17 +import org.flowable.engine.impl.el.FixedValue;
  18 +import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
  19 +import org.springframework.stereotype.Component;
  20 +
  21 +import java.util.List;
  22 +
  23 +/**
  24 + * BPM 子流程监听器:设置流程的发起人
  25 + *
  26 + * @author Lesan
  27 + */
  28 +@Component
  29 +@Slf4j
  30 +public class BpmCallActivityListener implements ExecutionListener {
  31 +
  32 + public static final String DELEGATE_EXPRESSION = "${bpmCallActivityListener}";
  33 +
  34 + @Setter
  35 + private FixedValue listenerConfig;
  36 +
  37 + @Resource
  38 + private BpmProcessDefinitionService processDefinitionService;
  39 +
  40 + @Override
  41 + public void notify(DelegateExecution execution) {
  42 + String expressionText = listenerConfig.getExpressionText();
  43 + Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText);
  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())) {
  57 + ExecutionEntity parent = (ExecutionEntity) execution.getParent();
  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())) {
  63 + FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
  64 + return;
  65 + }
  66 + // 2.1.2 来自子流程管理员
  67 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN.getType())) {
  68 + BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId());
  69 + List<Long> managerUserIds = processDefinition.getManagerUserIds();
  70 + FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0));
  71 + return;
  72 + }
  73 + // 2.1.3 来自主流程管理员
  74 + if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())) {
  75 + BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId());
  76 + List<Long> managerUserIds = processDefinition.getManagerUserIds();
  77 + FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0));
  78 + return;
  79 + }
  80 + }
  81 + // 2.2 使用表单值,并兜底字符串转 Long 失败时使用主流程发起人
  82 + try {
  83 + FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue));
  84 + } catch (Exception e) {
  85 + // todo @lesan:打个日志,方便排查
  86 + FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId()));
  87 + }
  88 + }
  89 + }
  90 +
  91 +}
0 \ No newline at end of file 92 \ No newline at end of file
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/BpmFormDeleteTrigger.java
@@ -43,10 +43,10 @@ public class BpmFormDeleteTrigger implements BpmTrigger { @@ -43,10 +43,10 @@ public class BpmFormDeleteTrigger implements BpmTrigger {
43 return; 43 return;
44 } 44 }
45 45
46 - // 2.获取流程变量 46 + // 2. 获取流程变量
47 Map<String, Object> processVariables = processInstanceService.getProcessInstance(processInstanceId).getProcessVariables(); 47 Map<String, Object> processVariables = processInstanceService.getProcessInstance(processInstanceId).getProcessVariables();
48 48
49 - // 3.获取需要删除的表单字段 49 + // 3.1 获取需要删除的表单字段
50 Set<String> deleteFields = new HashSet<>(); 50 Set<String> deleteFields = new HashSet<>();
51 settings.forEach(setting -> { 51 settings.forEach(setting -> {
52 if (CollUtil.isEmpty(setting.getDeleteFields())) { 52 if (CollUtil.isEmpty(setting.getDeleteFields())) {
@@ -64,7 +64,7 @@ public class BpmFormDeleteTrigger implements BpmTrigger { @@ -64,7 +64,7 @@ public class BpmFormDeleteTrigger implements BpmTrigger {
64 } 64 }
65 }); 65 });
66 66
67 - // 4. 删除流程变量 67 + // 3.2 删除流程变量
68 if (CollUtil.isNotEmpty(deleteFields)) { 68 if (CollUtil.isNotEmpty(deleteFields)) {
69 processInstanceService.removeProcessInstanceVariables(processInstanceId, deleteFields); 69 processInstanceService.removeProcessInstanceVariables(processInstanceId, deleteFields);
70 } 70 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/BpmFormUpdateTrigger.java
@@ -41,10 +41,10 @@ public class BpmFormUpdateTrigger implements BpmTrigger { @@ -41,10 +41,10 @@ public class BpmFormUpdateTrigger implements BpmTrigger {
41 return; 41 return;
42 } 42 }
43 43
44 - // 2.获取流程变量 44 + // 2. 获取流程变量
45 Map<String, Object> processVariables = processInstanceService.getProcessInstance(processInstanceId).getProcessVariables(); 45 Map<String, Object> processVariables = processInstanceService.getProcessInstance(processInstanceId).getProcessVariables();
46 46
47 - // 3.更新流程变量 47 + // 3. 更新流程变量
48 for (FormTriggerSetting setting : settings) { 48 for (FormTriggerSetting setting : settings) {
49 if (CollUtil.isEmpty(setting.getUpdateFormFields())) { 49 if (CollUtil.isEmpty(setting.getUpdateFormFields())) {
50 continue; 50 continue;