Commit 0d738fa3976c61fdd840f695af5f51f3991a7832

Authored by YunaiV
1 parent d4306846

【功能新增】工作流:支持审批人为空时,根据配置进行自动通过、自动拒绝、指定人审批的效果

Showing 13 changed files with 197 additions and 22 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskAssignEmptyHandlerTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.enums.definition;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +/**
  8 + * BPM 用户任务的审批人为空时,处理类型枚举
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@RequiredArgsConstructor
  13 +@Getter
  14 +public enum BpmUserTaskAssignEmptyHandlerTypeEnum implements IntArrayValuable {
  15 +
  16 + APPROVE(1), // 自动通过
  17 + REJECT(2), // 自动拒绝
  18 + ASSIGN_USER(3), // 指定人员审批
  19 + ASSIGN_ADMIN(4), // 转交给流程管理员
  20 + ;
  21 +
  22 + private final Integer type;
  23 +
  24 + @Override
  25 + public int[] array() {
  26 + return new int[0];
  27 + }
  28 +
  29 +}
... ...
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
... ... @@ -28,6 +28,8 @@ public enum BpmReasonEnum {
28 28 ASSIGN_START_USER_APPROVE_WHEN_SKIP("审批人与提交人为同一人时,自动通过"),
29 29 ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"),
30 30 ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"),
  31 + ASSIGN_EMPTY_APPROVE("审批人为空,自动通过"),
  32 + ASSIGN_EMPTY_REJECT("审批人为空,自动不通过"),
31 33 ;
32 34  
33 35 private final String reason;
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
... ... @@ -86,6 +86,11 @@ public class BpmSimpleModelNodeVO {
86 86 @InEnum(BpmUserTaskAssignStartUserHandlerTypeEnum.class)
87 87 private Integer assignStartUserHandlerType;
88 88  
  89 + /**
  90 + * 空处理策略
  91 + */
  92 + private AssignEmptyHandler assignEmptyHandler;
  93 +
89 94 @Data
90 95 @Schema(description = "审批节点拒绝处理策略")
91 96 public static class RejectHandler {
... ... @@ -122,6 +127,21 @@ public class BpmSimpleModelNodeVO {
122 127 }
123 128  
124 129 @Data
  130 + @Schema(description = "空处理策略")
  131 + @Valid
  132 + public static class AssignEmptyHandler {
  133 +
  134 + @Schema(description = "空处理类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  135 + @NotNull(message = "空处理类型不能为空")
  136 + @InEnum(BpmUserTaskAssignEmptyHandlerTypeEnum.class)
  137 + private Integer type;
  138 +
  139 + @Schema(description = "指定人员审批的用户编号数组", example = "1")
  140 + private List<Long> userIds;
  141 +
  142 + }
  143 +
  144 + @Data
125 145 @Schema(description = "操作按钮设置")
126 146 public static class OperationButtonSetting {
127 147  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
3 5 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
4 6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
5 7 import lombok.Setter;
... ... @@ -49,6 +51,10 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav
49 51  
50 52 // 第二步,获取任务的所有处理人
51 53 Set<Long> assigneeUserIds = taskCandidateInvoker.calculateUsers(execution);
  54 + if (CollUtil.isEmpty(assigneeUserIds)) {
  55 + // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务,避免自动通过!
  56 + assigneeUserIds = SetUtils.asSet((Long) null);
  57 + }
52 58 execution.setVariable(super.collectionVariable, assigneeUserIds);
53 59 return assigneeUserIds.size();
54 60 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
3 5 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
4 6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
5 7 import lombok.Setter;
... ... @@ -43,6 +45,10 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB
43 45  
44 46 // 第二步,获取任务的所有处理人
45 47 Set<Long> assigneeUserIds = new LinkedHashSet<>(taskCandidateInvoker.calculateUsers(execution)); // 保证有序!!!
  48 + if (CollUtil.isEmpty(assigneeUserIds)) {
  49 + // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务,避免自动通过!
  50 + assigneeUserIds = SetUtils.asSet((Long) null);
  51 + }
46 52 execution.setVariable(super.collectionVariable, assigneeUserIds);
47 53 return assigneeUserIds.size();
48 54 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.ObjectUtil;
5 5 import cn.hutool.core.util.RandomUtil;
  6 +import cn.hutool.extra.spring.SpringUtil;
  7 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO;
  8 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRejectReqVO;
  9 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
  10 +import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
6 11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
  12 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  13 +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
7 14 import lombok.Setter;
8 15 import lombok.extern.slf4j.Slf4j;
9 16 import org.flowable.bpmn.model.UserTask;
... ... @@ -14,6 +21,8 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
14 21 import org.flowable.engine.impl.util.TaskHelper;
15 22 import org.flowable.task.service.TaskService;
16 23 import org.flowable.task.service.impl.persistence.entity.TaskEntity;
  24 +import org.springframework.transaction.support.TransactionSynchronization;
  25 +import org.springframework.transaction.support.TransactionSynchronizationManager;
17 26  
18 27 import java.util.List;
19 28 import java.util.Set;
... ... @@ -41,9 +50,29 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
41 50 DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
42 51 // 第一步,获得任务的候选用户
43 52 Long assigneeUserId = calculateTaskCandidateUsers(execution);
44   - Assert.notNull(assigneeUserId, "任务处理人不能为空");
45 53 // 第二步,设置作为负责人
46   - TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
  54 + if (assigneeUserId != null) {
  55 + TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
  56 + return;
  57 + }
  58 +
  59 + // 特殊:审批人为空,根据配置是否要自动通过、自动拒绝
  60 + Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(userTask);
  61 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  62 +
  63 + @Override
  64 + public void afterCommit() {
  65 + if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.APPROVE.getType())) {
  66 + SpringUtil.getBean(BpmTaskService.class).approveTask(null, new BpmTaskApproveReqVO()
  67 + .setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_APPROVE.getReason()));
  68 + } else if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.REJECT.getType())) {
  69 + SpringUtil.getBean(BpmTaskService.class).rejectTask(null, new BpmTaskRejectReqVO()
  70 + .setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_REJECT.getReason()));
  71 + }
  72 +
  73 + }
  74 +
  75 + });
47 76 }
48 77  
49 78 private Long calculateTaskCandidateUsers(DelegateExecution execution) {
... ... @@ -56,6 +85,9 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
56 85 // 情况二,如果非多实例的任务,则计算任务处理人
57 86 // 第一步,先计算可处理该任务的处理人们
58 87 Set<Long> candidateUserIds = taskCandidateInvoker.calculateUsers(execution);
  88 + if (CollUtil.isEmpty(candidateUserIds)) {
  89 + return null;
  90 + }
59 91 // 第二步,后随机选择一个任务的处理人
60 92 // 疑问:为什么一定要选择一个任务处理人?
61 93 // 解答:项目对 bpm 的任务是责任到人,所以每个任务有且仅有一个处理人。
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java
... ... @@ -27,7 +27,6 @@ import java.util.Set;
27 27  
28 28 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
29 29 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG;
30   -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
31 30  
32 31 /**
33 32 * {@link BpmTaskCandidateStrategy} 的调用者,用于调用对应的策略,实现任务的候选人的计算
... ... @@ -89,17 +88,16 @@ public class BpmTaskCandidateInvoker {
89 88 String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
90 89 // 1.1 计算任务的候选人
91 90 Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
92   - // 1.2 移除被禁用的用户
93   - removeDisableUsers(userIds);
  91 + // 1.2 候选人为空时,根据“审批人为空”的配置补充
  92 + if (CollUtil.isEmpty(userIds)) {
  93 + userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
  94 + .calculateUsers(execution, param);
  95 + }
94 96 // 1.3 移除发起人的用户
95 97 removeStartUserIfSkip(execution, userIds);
96 98  
97   - // 2. 校验是否有候选人
98   - if (CollUtil.isEmpty(userIds)) {
99   - log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(),
100   - execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param);
101   - throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
102   - }
  99 + // 2. 移除被禁用的用户
  100 + removeDisableUsers(userIds);
103 101 return userIds;
104 102 }
105 103  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateAssignEmptyStrategy.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
  2 +
  3 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
  4 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
  5 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
  6 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  7 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  8 +import jakarta.annotation.Resource;
  9 +import org.flowable.engine.delegate.DelegateExecution;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +import java.util.HashSet;
  13 +import java.util.Objects;
  14 +import java.util.Set;
  15 +
  16 +/**
  17 + * 审批人为空 {@link BpmTaskCandidateStrategy} 实现类
  18 + *
  19 + * @author kyle
  20 + */
  21 +@Component
  22 +public class BpmTaskCandidateAssignEmptyStrategy implements BpmTaskCandidateStrategy {
  23 +
  24 + @Resource
  25 + private AdminUserApi adminUserApi;
  26 +
  27 + @Override
  28 + public BpmTaskCandidateStrategyEnum getStrategy() {
  29 + return BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY;
  30 + }
  31 +
  32 + @Override
  33 + public void validateParam(String param) {
  34 + }
  35 +
  36 + @Override
  37 + public Set<Long> calculateUsers(DelegateExecution execution, String param) {
  38 + // 情况一:指定人员审批
  39 + Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(execution.getCurrentFlowElement());
  40 + if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_USER.getType())) {
  41 + return new HashSet<>(BpmnModelUtils.parseAssignEmptyHandlerUserIds(execution.getCurrentFlowElement()));
  42 + }
  43 +
  44 + // 情况二:流程管理员
  45 + if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_ADMIN.getType())) {
  46 + // TODO 芋艿:需要等待流程实例的管理员支持
  47 + throw new UnsupportedOperationException("暂时实现!!!");
  48 + }
  49 +
  50 + // 都不满足,还是返回空
  51 + return new HashSet<>();
  52 + }
  53 +
  54 +}
0 55 \ No newline at end of file
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java
... ... @@ -30,6 +30,7 @@ public enum BpmTaskCandidateStrategyEnum implements IntArrayValuable {
30 30 START_USER_MULTI_LEVEL_DEPT_LEADER(38, "发起人连续多级部门的负责人"),
31 31 USER_GROUP(40, "用户组"),
32 32 EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager
  33 + ASSIGN_EMPTY(1, "审批人为空"),
33 34 ;
34 35  
35 36 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmTaskCandidateStrategyEnum::getStrategy).toArray();
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
... ... @@ -39,6 +39,15 @@ public interface BpmnModelConstants {
39 39 String USER_TASK_ASSIGN_START_USER_HANDLER_TYPE = "assignStartUserHandlerType";
40 40  
41 41 /**
  42 + * BPMN ExtensionElement 的扩展属性,用于标记用户任务的空处理类型
  43 + */
  44 + String USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE = "assignEmptyHandlerType";
  45 + /**
  46 + * BPMN ExtensionElement 的扩展属性,用于标记用户任务的空处理的指定用户编号数组
  47 + */
  48 + String USER_TASK_ASSIGN_USER_IDS = "assignEmptyUserIds";
  49 +
  50 + /**
42 51 * BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型
43 52 */
44 53 String USER_TASK_REJECT_HANDLER_TYPE = "rejectHandlerType";
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
5 5 import cn.hutool.core.util.ArrayUtil;
6 6 import cn.hutool.core.util.StrUtil;
7 7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
  8 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
8 9 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
9 10 import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
10 11 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
... ... @@ -45,16 +46,24 @@ public class BpmnModelUtils {
45 46 }
46 47  
47 48 public static BpmUserTaskRejectHandlerType parseRejectHandlerType(FlowElement userTask) {
48   - Integer rejectHandlerType = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE));
  49 + Integer rejectHandlerType = NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE));
49 50 return BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
50 51 }
51 52  
52 53 public static String parseReturnTaskId(FlowElement flowElement) {
53   - return BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID);
  54 + return parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID);
54 55 }
55 56  
56 57 public static Integer parseAssignStartUserHandlerType(FlowElement userTask) {
57   - return NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE));
  58 + return NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE));
  59 + }
  60 +
  61 + public static Integer parseAssignEmptyHandlerType(FlowElement userTask) {
  62 + return NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE));
  63 + }
  64 +
  65 + public static List<Long> parseAssignEmptyHandlerUserIds(FlowElement userTask) {
  66 + return StrUtils.splitToLong(parseExtensionElement(userTask, USER_TASK_ASSIGN_USER_IDS), ",");
58 67 }
59 68  
60 69 public static String parseExtensionElement(FlowElement flowElement, String elementName) {
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
... ... @@ -19,10 +19,7 @@ import org.flowable.bpmn.BpmnAutoLayout;
19 19 import org.flowable.bpmn.model.Process;
20 20 import org.flowable.bpmn.model.*;
21 21  
22   -import java.util.ArrayList;
23   -import java.util.List;
24   -import java.util.Map;
25   -import java.util.Objects;
  22 +import java.util.*;
26 23  
27 24 import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.OperationButtonSetting;
28 25 import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler;
... ... @@ -456,7 +453,6 @@ public class SimpleModelUtils {
456 453 userTask.setDueDate(node.getTimeoutHandler().getTimeDuration());
457 454 }
458 455  
459   - // TODO @jason:addCandidateElements、processMultiInstanceLoopCharacteristics 建议一起搞哈?
460 456 // 添加候选人元素
461 457 addCandidateElements(node.getCandidateStrategy(), node.getCandidateParam(), userTask);
462 458 // 添加表单字段权限属性元素
... ... @@ -469,6 +465,8 @@ public class SimpleModelUtils {
469 465 addTaskRejectElements(node.getRejectHandler(), userTask);
470 466 // 添加用户任务的审批人与发起人相同时的处理元素
471 467 addAssignStartUserHandlerType(node.getAssignStartUserHandlerType(), userTask);
  468 + // 添加用户任务的空处理元素
  469 + addAssignEmptyHandlerType(node.getAssignEmptyHandler(), userTask);
472 470 return userTask;
473 471 }
474 472  
... ... @@ -487,6 +485,14 @@ public class SimpleModelUtils {
487 485 addExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE, assignStartUserHandlerType.toString());
488 486 }
489 487  
  488 + private static void addAssignEmptyHandlerType(BpmSimpleModelNodeVO.AssignEmptyHandler emptyHandler, UserTask userTask) {
  489 + if (emptyHandler == null) {
  490 + return;
  491 + }
  492 + addExtensionElement(userTask, USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE, StrUtil.toStringOrNull(emptyHandler.getType()));
  493 + addExtensionElement(userTask, USER_TASK_ASSIGN_USER_IDS, StrUtil.join(",", emptyHandler.getUserIds()));
  494 + }
  495 +
490 496 private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
491 497 BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod);
492 498 if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.RANDOM) {
... ... @@ -496,7 +502,7 @@ public class SimpleModelUtils {
496 502 addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_METHOD,
497 503 approveMethod == null ? null : approveMethod.toString());
498 504 MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics();
499   - // 设置 collectionVariable。本系统用不到。会在 仅仅为了校验。
  505 + // 设置 collectionVariable。本系统用不到。仅仅为了 Flowable 校验不报错。
500 506 multiInstanceCharacteristics.setInputDataItem("${coll_userList}");
501 507 if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY) {
502 508 multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION);
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -191,7 +191,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
191 191 */
192 192 private Task validateTask(Long userId, String taskId) {
193 193 Task task = validateTaskExist(taskId);
194   - if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
  194 + // 为什么判断 assignee 非空的情况下?
  195 + // 例如说:在审批人为空时,我们会有“自动审批通过”的策略,此时 userId 为 null,允许通过
  196 + if (StrUtil.isNotBlank(task.getAssignee())
  197 + && ObjectUtil.notEqual(userId, NumberUtils.parseLong(task.getAssignee()))) {
195 198 throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF);
196 199 }
197 200 return task;
... ...