Commit d6775a5619226611da610eb9785007c90250e5ea

Authored by jason
1 parent 073d860a

工作流 Flowable 发起流程, 用户任务相关实现

Showing 12 changed files with 362 additions and 8 deletions
yudao-module-bpm/yudao-module-bpm-impl-activiti/src/main/java/cn/iocoder/yudao/module/bpm/framework/activiti/core/behavior/BpmActivityBehaviorFactory.java
... ... @@ -44,7 +44,7 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
44 44  
45 45 @Override
46 46 public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
47   - BpmUserTaskActivitiBehavior userTaskActivityBehavior = new BpmUserTaskActivitiBehavior(userTask);
  47 + BpmUserTaskActivityBehavior userTaskActivityBehavior = new BpmUserTaskActivityBehavior(userTask);
48 48 userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
49 49 userTaskActivityBehavior.setPermissionApi(permissionApi);
50 50 userTaskActivityBehavior.setDeptApi(deptApi);
... ...
yudao-module-bpm/yudao-module-bpm-impl-activiti/src/main/java/cn/iocoder/yudao/module/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehavior.java renamed to yudao-module-bpm/yudao-module-bpm-impl-activiti/src/main/java/cn/iocoder/yudao/module/bpm/framework/activiti/core/behavior/BpmUserTaskActivityBehavior.java
... ... @@ -44,7 +44,7 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_F
44 44 * @author 芋道源码
45 45 */
46 46 @Slf4j
47   -public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior {
  47 +public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
48 48  
49 49 @Setter
50 50 private BpmTaskAssignRuleService bpmTaskRuleService;
... ... @@ -64,7 +64,7 @@ public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior {
64 64 */
65 65 private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
66 66  
67   - public BpmUserTaskActivitiBehavior(UserTask userTask) {
  67 + public BpmUserTaskActivityBehavior(UserTask userTask) {
68 68 super(userTask);
69 69 }
70 70  
... ...
yudao-module-bpm/yudao-module-bpm-impl-activiti/src/test/java/cn/iocoder/yudao/module/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehaviorTest.java renamed to yudao-module-bpm/yudao-module-bpm-impl-activiti/src/test/java/cn/iocoder/yudao/module/bpm/framework/activiti/core/behavior/BpmUserTaskActivityBehaviorTest.java
... ... @@ -33,10 +33,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
33 33 import static org.mockito.ArgumentMatchers.eq;
34 34 import static org.mockito.Mockito.when;
35 35  
36   -public class BpmUserTaskActivitiBehaviorTest extends BaseMockitoUnitTest {
  36 +public class BpmUserTaskActivityBehaviorTest extends BaseMockitoUnitTest {
37 37  
38 38 @InjectMocks
39   - private BpmUserTaskActivitiBehavior behavior;
  39 + private BpmUserTaskActivityBehavior behavior;
40 40 @Mock
41 41 private BpmTaskAssignRuleService bpmTaskRuleService;
42 42 @Mock
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
... ... @@ -2,10 +2,12 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
5 6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
6 7 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
7 8 import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
8 9 import io.swagger.annotations.Api;
  10 +import io.swagger.annotations.ApiImplicitParam;
9 11 import io.swagger.annotations.ApiOperation;
10 12 import org.flowable.bpmn.model.BpmnModel;
11 13 import org.flowable.engine.TaskService;
... ... @@ -13,11 +15,14 @@ import org.springframework.security.access.prepost.PreAuthorize;
13 15 import org.springframework.validation.annotation.Validated;
14 16 import org.springframework.web.bind.annotation.GetMapping;
15 17 import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RequestParam;
16 19 import org.springframework.web.bind.annotation.RestController;
17 20  
18 21 import javax.annotation.Resource;
19 22 import javax.validation.Valid;
20 23  
  24 +import java.util.List;
  25 +
21 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 27 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
23 28  
... ... @@ -36,4 +41,13 @@ public class BpmTaskController {
36 41 public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) {
37 42 return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
38 43 }
  44 +
  45 + @GetMapping("/list-by-process-instance-id")
  46 + @ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的")
  47 + @ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class)
  48 + @PreAuthorize("@ss.hasPermission('bpm:task:query')")
  49 + public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId(
  50 + @RequestParam("processInstanceId") String processInstanceId) {
  51 + return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
  52 + }
39 53 }
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
... ... @@ -37,6 +37,9 @@ public interface BpmProcessInstanceConvert {
37 37  
38 38 List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list);
39 39  
  40 + @Mapping(source = "processInstanceId", target = "id")
  41 + BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean);
  42 +
40 43 List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks);
41 44  
42 45 default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt,
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
... ... @@ -62,6 +62,45 @@ public interface BpmTaskConvert {
62 62 })
63 63 BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
64 64  
  65 + default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
  66 + HistoricProcessInstance processInstance, Map<Long, AdminUserRespDTO> userMap,
  67 + Map<Long, DeptRespDTO> deptMap) {
  68 + return CollectionUtils.convertList(tasks, task -> {
  69 + BpmTaskRespVO respVO = convert3(task);
  70 + BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
  71 + copyTo(taskExtDO, respVO);
  72 + if (processInstance != null) {
  73 + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
  74 + respVO.setProcessInstance(convert(processInstance, startUser));
  75 + }
  76 + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee()));
  77 + if (assignUser != null) {
  78 + respVO.setAssigneeUser(convert3(assignUser));
  79 + DeptRespDTO dept = deptMap.get(assignUser.getDeptId());
  80 + if (dept != null) {
  81 + respVO.getAssigneeUser().setDeptName(dept.getName());
  82 + }
  83 + }
  84 + return respVO;
  85 + });
  86 + }
  87 +
  88 + @Mapping(source = "taskDefinitionKey", target = "definitionKey")
  89 + BpmTaskRespVO convert3(HistoricTaskInstance bean);
  90 +
  91 + BpmTaskRespVO.User convert3(AdminUserRespDTO bean);
  92 +
  93 + void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to);
  94 +
  95 + @Mappings({
  96 + @Mapping(source = "processInstance.id", target = "id"),
  97 + @Mapping(source = "processInstance.name", target = "name"),
  98 + @Mapping(source = "processInstance.startUserId", target = "startUserId"),
  99 + @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
  100 + @Mapping(source = "startUser.nickname", target = "startUserNickname")
  101 + })
  102 + BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, AdminUserRespDTO startUser);
  103 +
65 104  
66 105 }
67 106  
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.config;
2 2  
  3 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory;
3 4 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmProcessInstanceEventListener;
  5 +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
  6 +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
  7 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  8 +import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
  9 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
4 10 import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
5 11 import org.flowable.engine.runtime.ProcessInstance;
6 12 import org.flowable.spring.SpringProcessEngineConfiguration;
... ... @@ -19,15 +25,35 @@ import java.util.List;
19 25 public class BpmFlowableConfiguration {
20 26  
21 27 /**
22   - *将自定义 listener 加入全局listener
  28 + * 将自定义 listener 加入全局listener
23 29 * @param processInstanceListener 自定义监听 {@link ProcessInstance}
24 30 */
25 31 @Bean
26   - public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (BpmProcessInstanceEventListener processInstanceListener) {
  32 + public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (BpmProcessInstanceEventListener processInstanceListener,
  33 + BpmActivityBehaviorFactory bpmActivityBehaviorFactory) {
27 34 return engineConfiguration -> {
28 35 List<FlowableEventListener> eventListeners = new ArrayList<>();
29 36 eventListeners.add(processInstanceListener);
30 37 engineConfiguration.setEventListeners(eventListeners);
  38 + engineConfiguration.setActivityBehaviorFactory(bpmActivityBehaviorFactory);
31 39 };
32 40 }
  41 +
  42 +
  43 +
  44 + @Bean
  45 + public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService,
  46 + BpmUserGroupService userGroupService,
  47 + PermissionApi permissionApi,
  48 + DeptApi deptApi,
  49 + AdminUserApi adminUserApi) {
  50 + BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory();
  51 + bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService);
  52 + bpmActivityBehaviorFactory.setUserGroupService(userGroupService);
  53 + bpmActivityBehaviorFactory.setAdminUserApi(adminUserApi);
  54 + bpmActivityBehaviorFactory.setPermissionApi(permissionApi);
  55 + bpmActivityBehaviorFactory.setDeptApi(deptApi);
  56 +// bpmActivityBehaviorFactory.setScripts(scripts);
  57 + return bpmActivityBehaviorFactory;
  58 + }
33 59 }
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
  2 +
  3 +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
  4 +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
  5 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  6 +import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
  7 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.Setter;
  11 +import lombok.ToString;
  12 +import org.flowable.bpmn.model.UserTask;
  13 +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
  14 +import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;
  15 +
  16 +/**
  17 + * 自定义的 ActivityBehaviorFactory 实现类,目的如下:
  18 + * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@Data
  23 +@EqualsAndHashCode(callSuper = true)
  24 +@ToString(callSuper = true)
  25 +public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
  26 +
  27 + @Setter
  28 + private BpmTaskAssignRuleService bpmTaskRuleService;
  29 + @Setter
  30 + private BpmUserGroupService userGroupService;
  31 +
  32 + @Setter
  33 + private PermissionApi permissionApi;
  34 + @Setter
  35 + private DeptApi deptApi;
  36 + @Setter
  37 + private AdminUserApi adminUserApi;
  38 +
  39 + @Override
  40 + public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
  41 + BpmUserTaskActivityBehavior userTaskActivityBehavior = new BpmUserTaskActivityBehavior(userTask);
  42 + userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
  43 + userTaskActivityBehavior.setPermissionApi(permissionApi);
  44 + userTaskActivityBehavior.setDeptApi(deptApi);
  45 + userTaskActivityBehavior.setUserGroupService(userGroupService);
  46 + userTaskActivityBehavior.setAdminUserApi(adminUserApi);
  47 + //TODO
  48 + //userTaskActivityBehavior.setScripts(scripts);
  49 + return userTaskActivityBehavior;
  50 + }
  51 +}
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.RandomUtil;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  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.enums.definition.BpmTaskAssignRuleTypeEnum;
  10 +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
  11 +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
  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 com.google.common.annotations.VisibleForTesting;
  18 +import lombok.Setter;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.flowable.bpmn.model.UserTask;
  21 +import org.flowable.common.engine.api.FlowableException;
  22 +import org.flowable.common.engine.impl.el.ExpressionManager;
  23 +import org.flowable.engine.delegate.DelegateExecution;
  24 +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
  25 +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
  26 +import org.flowable.engine.impl.util.TaskHelper;
  27 +import org.flowable.task.service.TaskService;
  28 +import org.flowable.task.service.impl.persistence.entity.TaskEntity;
  29 +
  30 +import java.util.*;
  31 +
  32 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  33 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  34 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  35 +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
  36 +
  37 +/**
  38 + * 自定义的流程任务的 assignee 负责人的分配
  39 + * 第一步,获得对应的分配规则;
  40 + * 第二步,根据分配规则,计算出分配任务的候选人。如果找不到,则直接报业务异常,不继续执行后续的流程;
  41 + * 第三步,随机选择一个候选人,则选择作为 assignee 负责人。
  42 + *
  43 + * @author 芋道源码
  44 + */
  45 +@Slf4j
  46 +public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
  47 +
  48 + @Setter
  49 + private BpmTaskAssignRuleService bpmTaskRuleService;
  50 + @Setter
  51 + private BpmUserGroupService userGroupService;
  52 + @Setter
  53 + private DeptApi deptApi;
  54 + @Setter
  55 + private AdminUserApi adminUserApi;
  56 + @Setter
  57 + private PermissionApi permissionApi;
  58 +
  59 + public BpmUserTaskActivityBehavior(UserTask userTask) {
  60 + super(userTask);
  61 + }
  62 +
  63 + @Override
  64 + protected void handleAssignments(TaskService taskService, String assignee, String owner, List<String> candidateUsers, List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
  65 + // 第一步,获得任务的规则
  66 + BpmTaskAssignRuleDO rule = getTaskRule(task);
  67 + // 第二步,获得任务的候选用户们
  68 + Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule);
  69 + // 第三步,设置一个作为负责人
  70 + Long assigneeUserId = chooseTaskAssignee(candidateUserIds);
  71 + TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
  72 + }
  73 +
  74 + private BpmTaskAssignRuleDO getTaskRule(TaskEntity task) {
  75 + List<BpmTaskAssignRuleDO> taskRules = bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(),
  76 + task.getTaskDefinitionKey());
  77 + if (CollUtil.isEmpty(taskRules)) {
  78 + throw new FlowableException(StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则",
  79 + task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey()));
  80 + }
  81 + if (taskRules.size() > 1) {
  82 + throw new FlowableException(StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})",
  83 + task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), taskRules.size()));
  84 + }
  85 + return taskRules.get(0);
  86 + }
  87 +
  88 + @VisibleForTesting
  89 + Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) {
  90 + Set<Long> assigneeUserIds = null;
  91 + if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
  92 + assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule);
  93 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
  94 + assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule);
  95 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
  96 + assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule);
  97 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
  98 + assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule);
  99 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
  100 + assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
  101 + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
  102 + assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule);
  103 + }
  104 +// else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
  105 +// assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule);
  106 +// }
  107 +
  108 + // 移除被禁用的用户
  109 + removeDisableUsers(assigneeUserIds);
  110 + // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人
  111 + if (CollUtil.isEmpty(assigneeUserIds)) {
  112 + log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]",
  113 + task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule));
  114 + throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
  115 + }
  116 + return assigneeUserIds;
  117 + }
  118 +
  119 + private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) {
  120 + return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions());
  121 + }
  122 +
  123 + private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) {
  124 + List<AdminUserRespDTO> users = adminUserApi.getUsersByDeptIds(rule.getOptions());
  125 + return convertSet(users, AdminUserRespDTO::getId);
  126 + }
  127 +
  128 + private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) {
  129 + List<DeptRespDTO> depts = deptApi.getDepts(rule.getOptions());
  130 + return convertSet(depts, DeptRespDTO::getLeaderUserId);
  131 + }
  132 +
  133 + private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) {
  134 + List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions());
  135 + return convertSet(users, AdminUserRespDTO::getId);
  136 + }
  137 +
  138 + private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) {
  139 + return rule.getOptions();
  140 + }
  141 +
  142 + private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) {
  143 + List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
  144 + Set<Long> userIds = new HashSet<>();
  145 + userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds()));
  146 + return userIds;
  147 + }
  148 +
  149 + private Long chooseTaskAssignee(Set<Long> candidateUserIds) {
  150 + // TODO 芋艿:未来可以优化下,改成轮询的策略
  151 + int index = RandomUtil.randomInt(candidateUserIds.size());
  152 + return CollUtil.get(candidateUserIds, index);
  153 + }
  154 +
  155 + @VisibleForTesting
  156 + void removeDisableUsers(Set<Long> assigneeUserIds) {
  157 + if (CollUtil.isEmpty(assigneeUserIds)) {
  158 + return;
  159 + }
  160 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
  161 + assigneeUserIds.removeIf(id -> {
  162 + AdminUserRespDTO user = userMap.get(id);
  163 + return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
  164 + });
  165 + }
  166 +}
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
... ... @@ -47,6 +47,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService{
47 47 @Lazy // 解决循环依赖
48 48 private BpmModelService modelService;
49 49 @Resource
  50 + @Lazy // 解决循环依赖
50 51 private BpmProcessDefinitionService processDefinitionService;
51 52 @Resource
52 53 private BpmUserGroupService userGroupService;
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
5 6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
6 7 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
7 8 import org.flowable.task.api.Task;
... ... @@ -44,4 +45,12 @@ public interface BpmTaskService {
44 45 * @return 流程任务列表
45 46 */
46 47 List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
  48 +
  49 + /**
  50 + * 获得指令流程实例的流程任务列表,包括所有状态的
  51 + *
  52 + * @param processInstanceId 流程实例的编号
  53 + * @return 流程任务列表
  54 + */
  55 + List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId);
47 56 }
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -3,24 +3,35 @@ package cn.iocoder.yudao.module.bpm.service.task;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
6 7 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
  8 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
7 9 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
8 10 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
9 11 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
  12 +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
  13 +import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
  14 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  15 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
10 16 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
11 17 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
12 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.flowable.engine.HistoryService;
13 20 import org.flowable.engine.TaskService;
  21 +import org.flowable.engine.history.HistoricProcessInstance;
14 22 import org.flowable.engine.runtime.ProcessInstance;
15 23 import org.flowable.task.api.Task;
16 24 import org.flowable.task.api.TaskQuery;
  25 +import org.flowable.task.api.history.HistoricTaskInstance;
17 26 import org.springframework.stereotype.Service;
18 27  
19 28 import javax.annotation.Resource;
20 29 import java.util.Collections;
21 30 import java.util.List;
22 31 import java.util.Map;
  32 +import java.util.Set;
23 33  
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
24 35 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
25 36  
26 37 /**
... ... @@ -36,9 +47,16 @@ public class BpmTaskServiceImpl implements BpmTaskService{
36 47 @Resource
37 48 private TaskService taskService;
38 49 @Resource
39   - private AdminUserApi adminUserApi;
  50 + private HistoryService historyService;
  51 +
40 52 @Resource
41 53 private BpmProcessInstanceService processInstanceService;
  54 + @Resource
  55 + private AdminUserApi adminUserApi;
  56 + @Resource
  57 + private DeptApi deptApi;
  58 + @Resource
  59 + private BpmTaskExtMapper taskExtMapper;
42 60  
43 61 @Override
44 62 public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
... ... @@ -79,4 +97,31 @@ public class BpmTaskServiceImpl implements BpmTaskService{
79 97 }
80 98 return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
81 99 }
  100 +
  101 + @Override
  102 + public List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId) {
  103 + // 获得任务列表
  104 + List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
  105 + .processInstanceId(processInstanceId)
  106 + .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序
  107 + .list();
  108 + if (CollUtil.isEmpty(tasks)) {
  109 + return Collections.emptyList();
  110 + }
  111 +
  112 + // 获得 TaskExtDO Map
  113 + List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
  114 + Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
  115 + // 获得 ProcessInstance Map
  116 + HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
  117 + // 获得 User Map
  118 + Set<Long> userIds = convertSet(tasks, task -> NumberUtils.parseLong(task.getAssignee()));
  119 + userIds.add(NumberUtils.parseLong(processInstance.getStartUserId()));
  120 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
  121 + // 获得 Dept Map
  122 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  123 +
  124 + // 拼接数据
  125 + return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap);
  126 + }
82 127 }
... ...