Commit 39e89bd378e7c9747e3906d8614ea9ea5d450aa7

Authored by YunaiV
1 parent 4657dcf9

重构 bpmn 任务的处理人的逻辑,收拢到 BpmTaskAssignRuleService

Showing 13 changed files with 508 additions and 339 deletions
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java
... ... @@ -29,7 +29,7 @@ public class BpmTaskExtDO extends BaseDO {
29 29 private Long id;
30 30  
31 31 /**
32   - * 流程任务key
  32 + * 流程任务key TODO 芋艿,看看这个字段的作用
33 33 */
34 34 private String taskDefKey;
35 35 /**
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/domain/enums/definition/BpmTaskAssignRuleTypeEnum.java
... ... @@ -17,8 +17,6 @@ public enum BpmTaskAssignRuleTypeEnum {
17 17 DEPT_LEADER(21, "部门的负责人"),
18 18 POST(22, "岗位"),
19 19 USER(30, "用户"),
20   - USER_SIGN(31, "用户---会签"),
21   - USER_OR_SIGN(32, "用户---或签"),
22 20 USER_GROUP(40, "用户组"),
23 21 SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导
24 22 ;
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java
... ... @@ -2,12 +2,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.config;
2 2  
3 3 import cn.hutool.core.collection.ListUtil;
4 4 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory;
5   -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
6 5 import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
7   -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
8   -import cn.iocoder.yudao.module.system.api.dept.DeptApi;
9   -import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
10   -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
11 6 import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
12 7 import org.flowable.spring.SpringProcessEngineConfiguration;
13 8 import org.flowable.spring.boot.EngineConfigurationConfigurer;
... ... @@ -15,8 +10,6 @@ import org.springframework.beans.factory.ObjectProvider;
15 10 import org.springframework.context.annotation.Bean;
16 11 import org.springframework.context.annotation.Configuration;
17 12  
18   -import java.util.List;
19   -
20 13 /**
21 14 * BPM 模块的 Flowable 配置类
22 15 *
... ... @@ -44,19 +37,10 @@ public class BpmFlowableConfiguration {
44 37 }
45 38  
46 39 @Bean
47   - public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService,
48   - BpmUserGroupService userGroupService,
49   - PermissionApi permissionApi,
50   - DeptApi deptApi,
51   - AdminUserApi adminUserApi,
52   - List<BpmTaskAssignScript> scripts) {
  40 + public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService) {
53 41 BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory();
54 42 bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService);
55   - bpmActivityBehaviorFactory.setUserGroupService(userGroupService);
56   - bpmActivityBehaviorFactory.setAdminUserApi(adminUserApi);
57   - bpmActivityBehaviorFactory.setPermissionApi(permissionApi);
58   - bpmActivityBehaviorFactory.setDeptApi(deptApi);
59   - bpmActivityBehaviorFactory.setScripts(scripts);
60 43 return bpmActivityBehaviorFactory;
61 44 }
  45 +
62 46 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
2 2  
3   -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
4 3 import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
5   -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
6   -import cn.iocoder.yudao.module.system.api.dept.DeptApi;
7   -import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
8   -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
9 4 import lombok.Data;
10 5 import lombok.EqualsAndHashCode;
11 6 import lombok.Setter;
... ... @@ -17,8 +12,6 @@ import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
17 12 import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
18 13 import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;
19 14  
20   -import java.util.List;
21   -
22 15 /**
23 16 * 自定义的 ActivityBehaviorFactory 实现类,目的如下:
24 17 * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配
... ... @@ -32,41 +25,18 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
32 25  
33 26 @Setter
34 27 private BpmTaskAssignRuleService bpmTaskRuleService;
35   - @Setter
36   - private BpmUserGroupService userGroupService;
37   -
38   - @Setter
39   - private PermissionApi permissionApi;
40   - @Setter
41   - private DeptApi deptApi;
42   - @Setter
43   - private AdminUserApi adminUserApi;
44   - @Setter
45   - private List<BpmTaskAssignScript> scripts;
46 28  
47 29 @Override
48 30 public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
49   - BpmUserTaskActivityBehavior userTaskActivityBehavior = new BpmUserTaskActivityBehavior(userTask);
50   - userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
51   - userTaskActivityBehavior.setPermissionApi(permissionApi);
52   - userTaskActivityBehavior.setDeptApi(deptApi);
53   - userTaskActivityBehavior.setUserGroupService(userGroupService);
54   - userTaskActivityBehavior.setAdminUserApi(adminUserApi);
55   - userTaskActivityBehavior.setScripts(scripts);
56   - return userTaskActivityBehavior;
  31 + return new BpmUserTaskActivityBehavior(userTask)
  32 + .setBpmTaskRuleService(bpmTaskRuleService);
57 33 }
58 34  
59 35 @Override
60 36 public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity,
61   - AbstractBpmnActivityBehavior innerActivityBehavior) {
62   - BpmParallelMultiInstanceActivityBehavior bpmParallelMultiInstanceActivityBehavior =
63   - new BpmParallelMultiInstanceActivityBehavior(activity, innerActivityBehavior);
64   - bpmParallelMultiInstanceActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
65   - bpmParallelMultiInstanceActivityBehavior.setPermissionApi(permissionApi);
66   - bpmParallelMultiInstanceActivityBehavior.setDeptApi(deptApi);
67   - bpmParallelMultiInstanceActivityBehavior.setUserGroupService(userGroupService);
68   - bpmParallelMultiInstanceActivityBehavior.setAdminUserApi(adminUserApi);
69   - bpmParallelMultiInstanceActivityBehavior.setScripts(scripts);
70   - return bpmParallelMultiInstanceActivityBehavior;
  37 + AbstractBpmnActivityBehavior innerActivityBehavior) {
  38 + return new BpmParallelMultiInstanceBehavior(activity, innerActivityBehavior)
  39 + .setBpmTaskRuleService(bpmTaskRuleService);
71 40 }
  41 +
72 42 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceActivityBehavior.java renamed to 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 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.util.StrUtil;
5   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
6 5 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
7   -import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum;
8   -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
9 6 import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
10   -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
11   -import cn.iocoder.yudao.module.system.api.dept.DeptApi;
12   -import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
13   -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
14   -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
15   -import com.google.common.annotations.VisibleForTesting;
16 7 import lombok.Setter;
17 8 import lombok.extern.slf4j.Slf4j;
18 9 import org.flowable.bpmn.model.Activity;
19   -import org.flowable.common.engine.api.FlowableException;
20 10 import org.flowable.engine.delegate.DelegateExecution;
21 11 import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
22 12 import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
23 13 import org.flowable.engine.impl.util.CommandContextUtil;
24 14  
25   -import java.util.*;
  15 +import java.util.Set;
26 16  
27 17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
28   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
29 18 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
30 19 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
31 20  
... ... @@ -34,37 +23,21 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_F
34 23 * @create 2022-04-21 16:57
35 24 */
36 25 @Slf4j
37   -public class BpmParallelMultiInstanceActivityBehavior extends ParallelMultiInstanceBehavior {
  26 +public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior {
38 27  
39   - @Setter
40   - private BpmTaskAssignRuleService bpmTaskRuleService;
41   - @Setter
42   - private BpmUserGroupService userGroupService;
43   - @Setter
44   - private DeptApi deptApi;
45   - @Setter
46   - private AdminUserApi adminUserApi;
47   - @Setter
48   - private PermissionApi permissionApi;
49 28 /**
50 29 * EL表达式集合模板
51 30 */
52 31 private final static String EXPRESSION_TEXT_TEMPLATE = "${coll_userList}";
53 32  
54   - /**
55   - * 任务分配脚本
56   - */
57   - private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
  33 + @Setter
  34 + private BpmTaskAssignRuleService bpmTaskRuleService;
58 35  
59   - public BpmParallelMultiInstanceActivityBehavior(Activity activity,
60   - AbstractBpmnActivityBehavior innerActivityBehavior) {
  36 + public BpmParallelMultiInstanceBehavior(Activity activity,
  37 + AbstractBpmnActivityBehavior innerActivityBehavior) {
61 38 super(activity, innerActivityBehavior);
62 39 }
63 40  
64   - public void setScripts(List<BpmTaskAssignScript> scripts) {
65   - this.scriptMap = convertMap(scripts, script -> script.getEnum().getId());
66   - }
67   -
68 41 /**
69 42 * 创建并行任务
70 43 *
... ... @@ -75,7 +48,8 @@ public class BpmParallelMultiInstanceActivityBehavior extends ParallelMultiInsta
75 48 @Override
76 49 protected int createInstances(DelegateExecution multiInstanceRootExecution) {
77 50 // 查找任务信息
78   - BpmTaskAssignRuleDO taskRule = getTaskRule(multiInstanceRootExecution);
  51 +// BpmTaskAssignRuleDO taskRule = getTaskRule(multiInstanceRootExecution);
  52 + BpmTaskAssignRuleDO taskRule = null;
79 53 // 获取任务用户
80 54 Set<Long> assigneeUserIds = calculateTaskCandidateUsers(multiInstanceRootExecution, taskRule);
81 55 // 设置任务集合变量
... ... @@ -86,13 +60,13 @@ public class BpmParallelMultiInstanceActivityBehavior extends ParallelMultiInsta
86 60 this.collectionExpression = CommandContextUtil.getProcessEngineConfiguration().getExpressionManager()
87 61 .createExpression(String.format("${%s}", expressionText));
88 62 // 根据会签,或签类型,设置会签,或签条件
89   - if (BpmTaskAssignRuleTypeEnum.USER_SIGN.getType().equals(taskRule.getType())) {
90   - // 会签
91   - this.completionCondition = "${ nrOfInstances == nrOfCompletedInstances }";
92   - } else {
93   - // 或签
94   - this.completionCondition = "${ nrOfCompletedInstances == 1 }";
95   - }
  63 +// if (BpmTaskAssignRuleTypeEnum.USER_SIGN.getType().equals(taskRule.getType())) {
  64 +// // 会签
  65 +// this.completionCondition = "${ nrOfInstances == nrOfCompletedInstances }";
  66 +// } else {
  67 +// // 或签
  68 +// this.completionCondition = "${ nrOfCompletedInstances == 1 }";
  69 +// }
96 70 // 设置取出集合变量
97 71 this.collectionElementVariable = "user";
98 72 return super.createInstances(multiInstanceRootExecution);
... ... @@ -103,7 +77,8 @@ public class BpmParallelMultiInstanceActivityBehavior extends ParallelMultiInsta
103 77 Object collection = null;
104 78 if (EXPRESSION_TEXT_TEMPLATE.equals(this.collectionExpression.getExpressionText())) {
105 79 // 查找任务信息
106   - BpmTaskAssignRuleDO taskRule = getTaskRule(execution);
  80 +// BpmTaskAssignRuleDO taskRule = getTaskRule(execution);
  81 + BpmTaskAssignRuleDO taskRule = null;
107 82 // 设置任务集合变量
108 83 String expressionText = String.format("%s_userList", execution.getCurrentActivityId());
109 84 // 获取任务用户
... ... @@ -125,47 +100,10 @@ public class BpmParallelMultiInstanceActivityBehavior extends ParallelMultiInsta
125 100 return collection;
126 101 }
127 102  
128   - private BpmTaskAssignRuleDO getTaskRule(DelegateExecution task) {
129   - List<BpmTaskAssignRuleDO> taskRules =
130   - bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(),
131   - task.getCurrentActivityId());
132   - if (CollUtil.isEmpty(taskRules)) {
133   - throw new FlowableException(
134   - StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则", task.getId(), task.getProcessDefinitionId(),
135   - task.getCurrentActivityId()));
136   - }
137   - if (taskRules.size() > 1) {
138   - throw new FlowableException(
139   - StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})", task.getId(), task.getProcessDefinitionId(),
140   - task.getCurrentActivityId(), taskRules.size()));
141   - }
142   - return taskRules.get(0);
143   - }
144   -
145 103 Set<Long> calculateTaskCandidateUsers(DelegateExecution task, BpmTaskAssignRuleDO rule) {
146   - Set<Long> assigneeUserIds = null;
147   - // if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
148   - // assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule);
149   - // } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
150   - // assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule);
151   - // } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
152   - // assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule);
153   - // } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
154   - // assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule);
155   - // } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
156   - // assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
157   - // } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
158   - // assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule);
159   - // } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
160   - // assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule);
161   - if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType(), rule.getType())) {
162   - assigneeUserIds = calculateTaskCandidateUsersSignByUser(task, rule);
163   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType(), rule.getType())) {
164   - assigneeUserIds = calculateTaskCandidateUsersSignByUser(task, rule);
165   - }
  104 + Set<Long> assigneeUserIds = SetUtils.asSet(1L, 104L);
166 105  
167 106 // 移除被禁用的用户
168   - removeDisableUsers(assigneeUserIds);
169 107 // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人
170 108 if (CollUtil.isEmpty(assigneeUserIds)) {
171 109 log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", task.getId(),
... ... @@ -175,20 +113,4 @@ public class BpmParallelMultiInstanceActivityBehavior extends ParallelMultiInsta
175 113 return assigneeUserIds;
176 114 }
177 115  
178   - private Set<Long> calculateTaskCandidateUsersSignByUser(DelegateExecution task, BpmTaskAssignRuleDO rule) {
179   - return rule.getOptions();
180   - }
181   -
182   - @VisibleForTesting
183   - void removeDisableUsers(Set<Long> assigneeUserIds) {
184   - if (CollUtil.isEmpty(assigneeUserIds)) {
185   - return;
186   - }
187   - //TODO 芋艿 这里有数据权限的问题。默认会加上数据权限 dept_id IN (deptId). 导致查询不到数据
188   - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
189   - assigneeUserIds.removeIf(id -> {
190   - AdminUserRespDTO user = userMap.get(id);
191   - return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
192   - });
193   - }
194 116 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java
... ... @@ -2,25 +2,11 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.RandomUtil;
5   -import cn.hutool.core.util.StrUtil;
6   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 5 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
8   -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
9   -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
10   -import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum;
11   -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
12 6 import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
13   -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
14   -import cn.iocoder.yudao.module.system.api.dept.DeptApi;
15   -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
16   -import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
17   -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
18   -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
19   -import com.google.common.annotations.VisibleForTesting;
20 7 import lombok.Setter;
21 8 import lombok.extern.slf4j.Slf4j;
22 9 import org.flowable.bpmn.model.UserTask;
23   -import org.flowable.common.engine.api.FlowableException;
24 10 import org.flowable.common.engine.impl.el.ExpressionManager;
25 11 import org.flowable.engine.delegate.DelegateExecution;
26 12 import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
... ... @@ -29,14 +15,9 @@ import org.flowable.engine.impl.util.TaskHelper;
29 15 import org.flowable.task.service.TaskService;
30 16 import org.flowable.task.service.impl.persistence.entity.TaskEntity;
31 17  
32   -import java.util.*;
33   -
34   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
35   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
36   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
37   -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
38   -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS;
39   -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
  18 +import java.util.List;
  19 +import java.util.Map;
  20 +import java.util.Set;
40 21  
41 22 /**
42 23 * 自定义的流程任务的 assignee 负责人的分配
... ... @@ -51,153 +32,24 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
51 32  
52 33 @Setter
53 34 private BpmTaskAssignRuleService bpmTaskRuleService;
54   - @Setter
55   - private BpmUserGroupService userGroupService;
56   - @Setter
57   - private DeptApi deptApi;
58   - @Setter
59   - private AdminUserApi adminUserApi;
60   - @Setter
61   - private PermissionApi permissionApi;
62   -
63   - /**
64   - * 任务分配脚本
65   - */
66   - private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
67 35  
68 36 public BpmUserTaskActivityBehavior(UserTask userTask) {
69 37 super(userTask);
70 38 }
71 39  
72   - public void setScripts(List<BpmTaskAssignScript> scripts) {
73   - this.scriptMap = convertMap(scripts, script -> script.getEnum().getId());
74   - }
75   -
76 40 @Override
77 41 @DataPermission(enable = false) // 不需要处理数据权限, 不然会有问题,查询不到数据
78 42 protected void handleAssignments(TaskService taskService, String assignee, String owner,
79 43 List<String> candidateUsers, List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager,
80 44 DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
81   - /*boolean isMultiInstance = hasMultiInstanceCharacteristics();
82   - if (isMultiInstance) {
83   - //多实例 会签/或签,执行多次每个人 待办人都在execution里面获取
84   - Integer assigneeUserId = execution.getVariableLocal("user", Integer.class);
85   - TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
86   - } else {
87   - // 第一步,获得任务的规则
88   - BpmTaskAssignRuleDO rule = getTaskRule(task);
89   - // 第二步,获得任务的候选用户们
90   - Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule);
91   - // 第三步,设置一个作为负责人
92   - Long assigneeUserId = chooseTaskAssignee(execution, candidateUserIds);
93   - TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
94   - }
95   - */
96   - // 第一步,获得任务的规则
97   - BpmTaskAssignRuleDO rule = getTaskRule(task);
98   - // 第二步,获得任务的候选用户们
99   - Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule);
100   - // 第三步,设置一个作为负责人
  45 + // 第一步,获得任务的候选用户们
  46 + Set<Long> candidateUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(task);
  47 + // 第二步,选择一个作为候选人
101 48 Long assigneeUserId = chooseTaskAssignee(execution, candidateUserIds);
  49 + // 第三步,设置作为负责人
102 50 TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
103 51 }
104 52  
105   - private BpmTaskAssignRuleDO getTaskRule(TaskEntity task) {
106   - List<BpmTaskAssignRuleDO> taskRules =
107   - bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(),
108   - task.getTaskDefinitionKey());
109   - if (CollUtil.isEmpty(taskRules)) {
110   - throw new FlowableException(
111   - StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则", task.getId(), task.getProcessDefinitionId(),
112   - task.getTaskDefinitionKey()));
113   - }
114   - if (taskRules.size() > 1) {
115   - throw new FlowableException(
116   - StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})", task.getId(), task.getProcessDefinitionId(),
117   - task.getTaskDefinitionKey(), taskRules.size()));
118   - }
119   - return taskRules.get(0);
120   - }
121   -
122   - Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) {
123   - Set<Long> assigneeUserIds = null;
124   - if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
125   - assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule);
126   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
127   - assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule);
128   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
129   - assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule);
130   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
131   - assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule);
132   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
133   - assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
134   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
135   - assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule);
136   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
137   - assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule);
138   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType(), rule.getType())) {
139   - assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
140   - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType(), rule.getType())) {
141   - assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
142   - }
143   -
144   - // 移除被禁用的用户
145   - removeDisableUsers(assigneeUserIds);
146   - // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人
147   - if (CollUtil.isEmpty(assigneeUserIds)) {
148   - log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", task.getId(),
149   - task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule));
150   - throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
151   - }
152   - return assigneeUserIds;
153   - }
154   -
155   - private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) {
156   - return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions());
157   - }
158   -
159   - private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) {
160   - List<AdminUserRespDTO> users = adminUserApi.getUsersByDeptIds(rule.getOptions());
161   - return convertSet(users, AdminUserRespDTO::getId);
162   - }
163   -
164   - private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) {
165   - List<DeptRespDTO> depts = deptApi.getDepts(rule.getOptions());
166   - return convertSet(depts, DeptRespDTO::getLeaderUserId);
167   - }
168   -
169   - private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) {
170   - List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions());
171   - return convertSet(users, AdminUserRespDTO::getId);
172   - }
173   -
174   - private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) {
175   - return rule.getOptions();
176   - }
177   -
178   - private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) {
179   - List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
180   - Set<Long> userIds = new HashSet<>();
181   - userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds()));
182   - return userIds;
183   - }
184   -
185   - private Set<Long> calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskAssignRuleDO rule) {
186   - // 获得对应的脚本
187   - List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size());
188   - rule.getOptions().forEach(id -> {
189   - BpmTaskAssignScript script = scriptMap.get(id);
190   - if (script == null) {
191   - throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id);
192   - }
193   - scripts.add(script);
194   - });
195   - // 逐个计算任务
196   - Set<Long> userIds = new HashSet<>();
197   - scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(task)));
198   - return userIds;
199   - }
200   -
201 53 private Long chooseTaskAssignee(DelegateExecution execution, Set<Long> candidateUserIds) {
202 54 // 获取任务变量
203 55 Map<String, Object> variables = execution.getVariables();
... ... @@ -214,16 +66,4 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
214 66 return CollUtil.get(candidateUserIds, index);
215 67 }
216 68  
217   - @VisibleForTesting
218   - void removeDisableUsers(Set<Long> assigneeUserIds) {
219   - if (CollUtil.isEmpty(assigneeUserIds)) {
220   - return;
221   - }
222   - //TODO 芋艿 这里有数据权限的问题。默认会加上数据权限 dept_id IN (deptId). 导致查询不到数据
223   - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
224   - assigneeUserIds.removeIf(id -> {
225   - AdminUserRespDTO user = userMap.get(id);
226   - return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
227   - });
228   - }
229 69 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java
... ... @@ -4,10 +4,12 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAs
4 4 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
5 5 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
6 6 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
  7 +import org.flowable.task.service.impl.persistence.entity.TaskEntity;
7 8 import org.springframework.lang.Nullable;
8 9  
9 10 import javax.validation.Valid;
10 11 import java.util.List;
  12 +import java.util.Set;
11 13  
12 14 /**
13 15 * BPM 任务分配规则 Service 接口
... ... @@ -84,4 +86,6 @@ public interface BpmTaskAssignRuleService {
84 86 */
85 87 void checkTaskAssignRuleAllConfig(String id);
86 88  
  89 + Set<Long> calculateTaskCandidateUsers(TaskEntity task);
  90 +
87 91 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
... ... @@ -3,25 +3,35 @@ package cn.iocoder.yudao.module.bpm.service.definition;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
5 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 8 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  9 +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
8 10 import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils;
9 11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
10 12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
11 13 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
12 14 import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert;
13 15 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
  16 +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
14 17 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
15   -import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
16 18 import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum;
  19 +import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
  20 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
17 21 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
18 22 import cn.iocoder.yudao.module.system.api.dept.PostApi;
  23 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
19 24 import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
  25 +import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
20 26 import cn.iocoder.yudao.module.system.api.permission.RoleApi;
21 27 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  28 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  29 +import com.google.common.annotations.VisibleForTesting;
22 30 import lombok.extern.slf4j.Slf4j;
23 31 import org.flowable.bpmn.model.BpmnModel;
24 32 import org.flowable.bpmn.model.UserTask;
  33 +import org.flowable.common.engine.api.FlowableException;
  34 +import org.flowable.task.service.impl.persistence.entity.TaskEntity;
25 35 import org.springframework.context.annotation.Lazy;
26 36 import org.springframework.stereotype.Service;
27 37 import org.springframework.validation.annotation.Validated;
... ... @@ -31,6 +41,9 @@ import javax.validation.Valid;
31 41 import java.util.*;
32 42  
33 43 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  44 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  45 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  46 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
34 47 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
35 48  
36 49 /**
... ... @@ -61,6 +74,17 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
61 74 private AdminUserApi adminUserApi;
62 75 @Resource
63 76 private DictDataApi dictDataApi;
  77 + @Resource
  78 + private PermissionApi permissionApi;
  79 + /**
  80 + * 任务分配脚本
  81 + */
  82 + private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
  83 +
  84 + @Resource
  85 + public void setScripts(List<BpmTaskAssignScript> scripts) {
  86 + this.scriptMap = convertMap(scripts, script -> script.getEnum().getId());
  87 + }
64 88  
65 89 @Override
66 90 public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
... ... @@ -198,10 +222,6 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
198 222 adminUserApi.validUsers(options);
199 223 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) {
200 224 userGroupService.validUserGroups(options);
201   - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_SIGN.getType())) {
202   - adminUserApi.validUsers(options);
203   - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType())) {
204   - adminUserApi.validUsers(options);
205 225 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) {
206 226 dictDataApi.validDictDatas(DictTypeConstants.TASK_ASSIGN_SCRIPT,
207 227 CollectionUtils.convertSet(options, String::valueOf));
... ... @@ -209,4 +229,117 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
209 229 throw new IllegalArgumentException(StrUtil.format("未知的规则类型({})", type));
210 230 }
211 231 }
  232 +
  233 + @Override
  234 + @DataPermission(enable = false) // 忽略数据权限,不然分配会存在问题
  235 + public Set<Long> calculateTaskCandidateUsers(TaskEntity task) {
  236 + BpmTaskAssignRuleDO rule = getTaskRule(task);
  237 + return calculateTaskCandidateUsers(task, rule);
  238 + }
  239 +
  240 + @VisibleForTesting
  241 + BpmTaskAssignRuleDO getTaskRule(TaskEntity task) {
  242 + List<BpmTaskAssignRuleDO> taskRules = getTaskAssignRuleListByProcessDefinitionId(
  243 + task.getProcessDefinitionId(), task.getTaskDefinitionKey());
  244 + if (CollUtil.isEmpty(taskRules)) {
  245 + throw new FlowableException(
  246 + StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则", task.getId(), task.getProcessDefinitionId(),
  247 + task.getTaskDefinitionKey()));
  248 + }
  249 + if (taskRules.size() > 1) {
  250 + throw new FlowableException(
  251 + StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})", task.getId(), task.getProcessDefinitionId(),
  252 + task.getTaskDefinitionKey(), taskRules.size()));
  253 + }
  254 + return taskRules.get(0);
  255 + }
  256 +
  257 + @VisibleForTesting
  258 + Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) {
  259 + Set<Long> assigneeUserIds = null;
  260 + if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
  261 + assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule);
  262 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
  263 + assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule);
  264 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
  265 + assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule);
  266 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
  267 + assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule);
  268 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
  269 + assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
  270 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
  271 + assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule);
  272 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
  273 + assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule);
  274 + }
  275 +
  276 + // 移除被禁用的用户
  277 + removeDisableUsers(assigneeUserIds);
  278 + // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人
  279 + if (CollUtil.isEmpty(assigneeUserIds)) {
  280 + log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", task.getId(),
  281 + task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule));
  282 + throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
  283 + }
  284 + return assigneeUserIds;
  285 + }
  286 +
  287 + private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) {
  288 + return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions());
  289 + }
  290 +
  291 + private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) {
  292 + List<AdminUserRespDTO> users = adminUserApi.getUsersByDeptIds(rule.getOptions());
  293 + return convertSet(users, AdminUserRespDTO::getId);
  294 + }
  295 +
  296 + private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) {
  297 + List<DeptRespDTO> depts = deptApi.getDepts(rule.getOptions());
  298 + return convertSet(depts, DeptRespDTO::getLeaderUserId);
  299 + }
  300 +
  301 + private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) {
  302 + List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions());
  303 + return convertSet(users, AdminUserRespDTO::getId);
  304 + }
  305 +
  306 + private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) {
  307 + return rule.getOptions();
  308 + }
  309 +
  310 + private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) {
  311 + List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
  312 + Set<Long> userIds = new HashSet<>();
  313 + userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds()));
  314 + return userIds;
  315 + }
  316 +
  317 + private Set<Long> calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskAssignRuleDO rule) {
  318 + // 获得对应的脚本
  319 + List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size());
  320 + rule.getOptions().forEach(id -> {
  321 + BpmTaskAssignScript script = scriptMap.get(id);
  322 + if (script == null) {
  323 + throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id);
  324 + }
  325 + scripts.add(script);
  326 + });
  327 + // 逐个计算任务
  328 + Set<Long> userIds = new HashSet<>();
  329 + scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(task)));
  330 + return userIds;
  331 + }
  332 +
  333 + @VisibleForTesting
  334 + void removeDisableUsers(Set<Long> assigneeUserIds) {
  335 + if (CollUtil.isEmpty(assigneeUserIds)) {
  336 + return;
  337 + }
  338 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
  339 + assigneeUserIds.removeIf(id -> {
  340 + AdminUserRespDTO user = userMap.get(id);
  341 + return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
  342 + });
  343 + }
  344 +
212 345 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
15 15 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
16 16 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper;
17 17 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
18   -import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum;
19 18 import cn.iocoder.yudao.module.bpm.domain.enums.task.BpmProcessInstanceResultEnum;
20 19 import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
21 20 import cn.iocoder.yudao.module.business.hi.task.inst.service.HiTaskInstService;
... ... @@ -214,11 +213,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
214 213 taskAssignRuleMapper.selectListByProcessDefinitionId(task.getProcessDefinitionId(),
215 214 task.getTaskDefinitionKey());
216 215 if (CollUtil.isNotEmpty(bpmTaskAssignRuleList) && bpmTaskAssignRuleList.size() > 0) {
217   - if (BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType().equals(bpmTaskAssignRuleList.get(0).getType())) {
218   - taskExtMapper.delTaskByProcInstIdAndTaskIdAndTaskDefKey(
219   - new BpmTaskExtDO().setTaskId(task.getId()).setTaskDefKey(task.getTaskDefinitionKey())
220   - .setProcessInstanceId(task.getProcessInstanceId()));
221   - }
  216 + // edit by 芋艿
  217 +// if (BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType().equals(bpmTaskAssignRuleList.get(0).getType())) {
  218 +// taskExtMapper.delTaskByProcInstIdAndTaskIdAndTaskDefKey(
  219 +// new BpmTaskExtDO().setTaskId(task.getId()).setTaskDefKey(task.getTaskDefinitionKey())
  220 +// .setProcessInstanceId(task.getProcessInstanceId()));
  221 +// }
222 222 }
223 223 }
224 224  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/service/HiTaskInstService.java
... ... @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPage
9 9 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
10 10 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
11 11 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
12   -import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum;
13 12 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
14 13 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
15 14 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
... ... @@ -21,14 +20,18 @@ import org.flowable.common.engine.impl.de.odysseus.el.ExpressionFactoryImpl;
21 20 import org.flowable.common.engine.impl.de.odysseus.el.util.SimpleContext;
22 21 import org.flowable.common.engine.impl.javax.el.ExpressionFactory;
23 22 import org.flowable.common.engine.impl.javax.el.ValueExpression;
24   -import org.flowable.engine.*;
  23 +import org.flowable.engine.HistoryService;
  24 +import org.flowable.engine.RepositoryService;
25 25 import org.flowable.engine.history.HistoricProcessInstance;
26 26 import org.flowable.task.api.history.HistoricTaskInstance;
27 27 import org.flowable.variable.api.history.HistoricVariableInstance;
28 28 import org.springframework.stereotype.Service;
29 29  
30 30 import javax.annotation.Resource;
31   -import java.util.*;
  31 +import java.util.HashMap;
  32 +import java.util.LinkedList;
  33 +import java.util.List;
  34 +import java.util.Map;
32 35 import java.util.function.Function;
33 36 import java.util.stream.Collectors;
34 37  
... ... @@ -259,10 +262,11 @@ public class HiTaskInstService {
259 262 DeptDO deptDO = deptMap.get(adminUserDO.getDeptId());
260 263 bpmTaskRespVO.setAssigneeUser(setUser(adminUserDO));
261 264 bpmTaskRespVO.getAssigneeUser().setDeptName(deptDO.getName());
262   - if (!bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType())
263   - && !bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType())) {
264   - break;
265   - }
  265 + // edit by 芋艿
  266 +// if (!bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType())
  267 +// && !bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType())) {
  268 +// break;
  269 +// }
266 270 }
267 271 }
268 272 getFlow(bpmnModel, nextTaskDefKey, tmpBpmTaskAssignRuleDOList, bpmTaskRespVOList, userDoMap, deptMap,
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/BpmActivityMapper.xml
... ... @@ -21,6 +21,7 @@
21 21 SELECT *
22 22 FROM act_hi_taskinst;
23 23 </select>
  24 +
24 25 <select id="listAllByProcInstIdAndDelete"
25 26 resultType="cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO">
26 27 SELECT id_ AS `id`,
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  4 +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
  5 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  6 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  7 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  8 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  9 +import org.flowable.task.service.impl.persistence.entity.TaskEntity;
  10 +import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
  11 +import org.junit.jupiter.api.Test;
  12 +import org.mockito.InjectMocks;
  13 +import org.mockito.Mock;
  14 +
  15 +import java.util.Set;
  16 +
  17 +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
  18 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  19 +import static org.junit.jupiter.api.Assertions.assertEquals;
  20 +import static org.mockito.ArgumentMatchers.eq;
  21 +import static org.mockito.Mockito.when;
  22 +
  23 +public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
  24 +
  25 + @InjectMocks
  26 + private BpmTaskAssignLeaderX2Script script;
  27 +
  28 + @Mock
  29 + private AdminUserApi adminUserApi;
  30 + @Mock
  31 + private DeptApi deptApi;
  32 + @Mock
  33 + private BpmProcessInstanceService bpmProcessInstanceService;
  34 +
  35 + @Test
  36 + public void testCalculateTaskCandidateUsers_noDept() {
  37 + // 准备参数
  38 + TaskEntity task = buildTaskEntity(1L);
  39 + // mock 方法(startUser)
  40 + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
  41 + when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
  42 +
  43 + // 调用
  44 + Set<Long> result = script.calculateTaskCandidateUsers(task);
  45 + // 断言
  46 + assertEquals(0, result.size());
  47 + }
  48 +
  49 + @Test
  50 + public void testCalculateTaskCandidateUsers_noParentDept() {
  51 + // 准备参数
  52 + TaskEntity task = buildTaskEntity(1L);
  53 + // mock 方法(startUser)
  54 + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
  55 + when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
  56 + DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
  57 + .setLeaderUserId(20L));
  58 + when(deptApi.getDept(eq(10L))).thenReturn(startUserDept);
  59 +
  60 + // 调用
  61 + Set<Long> result = script.calculateTaskCandidateUsers(task);
  62 + // 断言
  63 + assertEquals(asSet(20L), result);
  64 + }
  65 +
  66 + @Test
  67 + public void testCalculateTaskCandidateUsers_existParentDept() {
  68 + // 准备参数
  69 + TaskEntity task = buildTaskEntity(1L);
  70 + // mock 方法(startUser)
  71 + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
  72 + when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
  73 + DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
  74 + .setLeaderUserId(20L));
  75 + when(deptApi.getDept(eq(10L))).thenReturn(startUserDept);
  76 + // mock 方法(父 dept)
  77 + DeptRespDTO parentDept = randomPojo(DeptRespDTO.class, o -> o.setId(100L).setParentId(1000L)
  78 + .setLeaderUserId(200L));
  79 + when(deptApi.getDept(eq(100L))).thenReturn(parentDept);
  80 +
  81 + // 调用
  82 + Set<Long> result = script.calculateTaskCandidateUsers(task);
  83 + // 断言
  84 + assertEquals(asSet(200L), result);
  85 + }
  86 +
  87 + @SuppressWarnings("SameParameterValue")
  88 + private TaskEntity buildTaskEntity(Long startUserId) {
  89 + TaskEntityImpl task = new TaskEntityImpl();
  90 +// task.setProcessInstance(new ExecutionEntityImpl());
  91 +// task.getProcessInstance().setStartUserId(String.valueOf(startUserId));
  92 + // TODO
  93 + return task;
  94 + }
  95 +
  96 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.definition;
  2 +
  3 +import cn.hutool.core.map.MapUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  7 +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
  8 +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
  9 +import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum;
  10 +import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskRuleScriptEnum;
  11 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
  12 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  13 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  14 +import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
  15 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  16 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  17 +import org.flowable.task.service.impl.persistence.entity.TaskEntity;
  18 +import org.junit.jupiter.api.Test;
  19 +import org.springframework.boot.test.mock.mockito.MockBean;
  20 +import org.springframework.context.annotation.Import;
  21 +
  22 +import javax.annotation.Resource;
  23 +import java.util.Arrays;
  24 +import java.util.List;
  25 +import java.util.Map;
  26 +import java.util.Set;
  27 +
  28 +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
  29 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  30 +import static java.util.Collections.singleton;
  31 +import static org.junit.jupiter.api.Assertions.assertEquals;
  32 +import static org.mockito.ArgumentMatchers.eq;
  33 +import static org.mockito.Mockito.when;
  34 +
  35 +/**
  36 + * {@link BpmTaskAssignRuleService} 的单元测试
  37 + *
  38 + * @author 芋道源码
  39 + */
  40 +@Import(BpmTaskAssignRuleServiceImpl.class)
  41 +public class BpmTaskAssignRuleServiceImplTest extends BaseDbUnitTest {
  42 +
  43 + @Resource
  44 + private BpmTaskAssignRuleServiceImpl bpmTaskRuleService;
  45 +
  46 + @MockBean
  47 + private BpmUserGroupService userGroupService;
  48 + @MockBean
  49 + private DeptApi deptApi;
  50 + @MockBean
  51 + private AdminUserApi adminUserApi;
  52 + @MockBean
  53 + private PermissionApi permissionApi;
  54 +
  55 + @Test
  56 + public void testCalculateTaskCandidateUsers_Role() {
  57 + // 准备参数
  58 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L))
  59 + .setType(BpmTaskAssignRuleTypeEnum.ROLE.getType());
  60 + // mock 方法
  61 + when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions())))
  62 + .thenReturn(asSet(11L, 22L));
  63 + mockGetUserMap(asSet(11L, 22L));
  64 +
  65 + // 调用
  66 + Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule);
  67 + // 断言
  68 + assertEquals(asSet(11L, 22L), results);
  69 + }
  70 +
  71 + @Test
  72 + public void testCalculateTaskCandidateUsers_DeptMember() {
  73 + // 准备参数
  74 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L))
  75 + .setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType());
  76 + // mock 方法
  77 + List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L),
  78 + id -> new AdminUserRespDTO().setId(id));
  79 + when(adminUserApi.getUsersByDeptIds(eq(rule.getOptions()))).thenReturn(users);
  80 + mockGetUserMap(asSet(11L, 22L));
  81 +
  82 + // 调用
  83 + Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule);
  84 + // 断言
  85 + assertEquals(asSet(11L, 22L), results);
  86 + }
  87 +
  88 + @Test
  89 + public void testCalculateTaskCandidateUsers_DeptLeader() {
  90 + // 准备参数
  91 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L))
  92 + .setType(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType());
  93 + // mock 方法
  94 + DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L));
  95 + DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L));
  96 + when(deptApi.getDepts(eq(rule.getOptions()))).thenReturn(Arrays.asList(dept1, dept2));
  97 + mockGetUserMap(asSet(11L, 22L));
  98 +
  99 + // 调用
  100 + Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule);
  101 + // 断言
  102 + assertEquals(asSet(11L, 22L), results);
  103 + }
  104 +
  105 + @Test
  106 + public void testCalculateTaskCandidateUsers_Post() {
  107 + // 准备参数
  108 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L))
  109 + .setType(BpmTaskAssignRuleTypeEnum.POST.getType());
  110 + // mock 方法
  111 + List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L),
  112 + id -> new AdminUserRespDTO().setId(id));
  113 + when(adminUserApi.getUsersByPostIds(eq(rule.getOptions()))).thenReturn(users);
  114 + mockGetUserMap(asSet(11L, 22L));
  115 +
  116 + // 调用
  117 + Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule);
  118 + // 断言
  119 + assertEquals(asSet(11L, 22L), results);
  120 + }
  121 +
  122 + @Test
  123 + public void testCalculateTaskCandidateUsers_User() {
  124 + // 准备参数
  125 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L))
  126 + .setType(BpmTaskAssignRuleTypeEnum.USER.getType());
  127 + // mock 方法
  128 + mockGetUserMap(asSet(1L, 2L));
  129 +
  130 + // 调用
  131 + Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule);
  132 + // 断言
  133 + assertEquals(asSet(1L, 2L), results);
  134 + }
  135 +
  136 + @Test
  137 + public void testCalculateTaskCandidateUsers_UserGroup() {
  138 + // 准备参数
  139 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L))
  140 + .setType(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType());
  141 + // mock 方法
  142 + BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L)));
  143 + BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L)));
  144 + when(userGroupService.getUserGroupList(eq(rule.getOptions()))).thenReturn(Arrays.asList(userGroup1, userGroup2));
  145 + mockGetUserMap(asSet(11L, 12L, 21L, 22L));
  146 +
  147 + // 调用
  148 + Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule);
  149 + // 断言
  150 + assertEquals(asSet(11L, 12L, 21L, 22L), results);
  151 + }
  152 +
  153 + @Test
  154 + public void testCalculateTaskCandidateUsers_Script() {
  155 + // 准备参数
  156 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(20L, 21L))
  157 + .setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType());
  158 + // mock 方法
  159 + BpmTaskAssignScript script1 = new BpmTaskAssignScript() {
  160 +
  161 + @Override
  162 + public Set<Long> calculateTaskCandidateUsers(TaskEntity task) {
  163 + return singleton(11L);
  164 + }
  165 +
  166 + @Override
  167 + public BpmTaskRuleScriptEnum getEnum() {
  168 + return BpmTaskRuleScriptEnum.LEADER_X1;
  169 + }
  170 + };
  171 + BpmTaskAssignScript script2 = new BpmTaskAssignScript() {
  172 +
  173 + @Override
  174 + public Set<Long> calculateTaskCandidateUsers(TaskEntity task) {
  175 + return singleton(22L);
  176 + }
  177 +
  178 + @Override
  179 + public BpmTaskRuleScriptEnum getEnum() {
  180 + return BpmTaskRuleScriptEnum.LEADER_X2;
  181 + }
  182 + };
  183 + bpmTaskRuleService.setScripts(Arrays.asList(script1, script2));
  184 + mockGetUserMap(asSet(11L, 22L));
  185 +
  186 + // 调用
  187 + Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule);
  188 + // 断言
  189 + assertEquals(asSet(11L, 22L), results);
  190 + }
  191 +
  192 + @Test
  193 + public void testRemoveDisableUsers() {
  194 + // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到
  195 + Set<Long> assigneeUserIds = asSet(1L, 2L, 3L);
  196 + // mock 方法
  197 + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L)
  198 + .setStatus(CommonStatusEnum.ENABLE.getStatus()));
  199 + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L)
  200 + .setStatus(CommonStatusEnum.DISABLE.getStatus()));
  201 + Map<Long, AdminUserRespDTO> userMap = MapUtil.builder(user1.getId(), user1)
  202 + .put(user2.getId(), user2).build();
  203 + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap);
  204 +
  205 + // 调用
  206 + bpmTaskRuleService.removeDisableUsers(assigneeUserIds);
  207 + // 断言
  208 + assertEquals(asSet(1L), assigneeUserIds);
  209 + }
  210 +
  211 + private void mockGetUserMap(Set<Long> assigneeUserIds) {
  212 + Map<Long, AdminUserRespDTO> userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id,
  213 + id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  214 + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap);
  215 + }
  216 +
  217 +}
... ...