Commit d6775a5619226611da610eb9785007c90250e5ea
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,7 +44,7 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { | ||
| 44 | 44 | ||
| 45 | @Override | 45 | @Override |
| 46 | public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { | 46 | public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { |
| 47 | - BpmUserTaskActivitiBehavior userTaskActivityBehavior = new BpmUserTaskActivitiBehavior(userTask); | 47 | + BpmUserTaskActivityBehavior userTaskActivityBehavior = new BpmUserTaskActivityBehavior(userTask); |
| 48 | userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService); | 48 | userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService); |
| 49 | userTaskActivityBehavior.setPermissionApi(permissionApi); | 49 | userTaskActivityBehavior.setPermissionApi(permissionApi); |
| 50 | userTaskActivityBehavior.setDeptApi(deptApi); | 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,7 +44,7 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_F | ||
| 44 | * @author 芋道源码 | 44 | * @author 芋道源码 |
| 45 | */ | 45 | */ |
| 46 | @Slf4j | 46 | @Slf4j |
| 47 | -public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior { | 47 | +public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { |
| 48 | 48 | ||
| 49 | @Setter | 49 | @Setter |
| 50 | private BpmTaskAssignRuleService bpmTaskRuleService; | 50 | private BpmTaskAssignRuleService bpmTaskRuleService; |
| @@ -64,7 +64,7 @@ public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior { | @@ -64,7 +64,7 @@ public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior { | ||
| 64 | */ | 64 | */ |
| 65 | private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap(); | 65 | private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap(); |
| 66 | 66 | ||
| 67 | - public BpmUserTaskActivitiBehavior(UserTask userTask) { | 67 | + public BpmUserTaskActivityBehavior(UserTask userTask) { |
| 68 | super(userTask); | 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,10 +33,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 33 | import static org.mockito.ArgumentMatchers.eq; | 33 | import static org.mockito.ArgumentMatchers.eq; |
| 34 | import static org.mockito.Mockito.when; | 34 | import static org.mockito.Mockito.when; |
| 35 | 35 | ||
| 36 | -public class BpmUserTaskActivitiBehaviorTest extends BaseMockitoUnitTest { | 36 | +public class BpmUserTaskActivityBehaviorTest extends BaseMockitoUnitTest { |
| 37 | 37 | ||
| 38 | @InjectMocks | 38 | @InjectMocks |
| 39 | - private BpmUserTaskActivitiBehavior behavior; | 39 | + private BpmUserTaskActivityBehavior behavior; |
| 40 | @Mock | 40 | @Mock |
| 41 | private BpmTaskAssignRuleService bpmTaskRuleService; | 41 | private BpmTaskAssignRuleService bpmTaskRuleService; |
| 42 | @Mock | 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,10 +2,12 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | ||
| 5 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; | 6 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; |
| 6 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; | 7 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; |
| 7 | import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; | 8 | import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; |
| 8 | import io.swagger.annotations.Api; | 9 | import io.swagger.annotations.Api; |
| 10 | +import io.swagger.annotations.ApiImplicitParam; | ||
| 9 | import io.swagger.annotations.ApiOperation; | 11 | import io.swagger.annotations.ApiOperation; |
| 10 | import org.flowable.bpmn.model.BpmnModel; | 12 | import org.flowable.bpmn.model.BpmnModel; |
| 11 | import org.flowable.engine.TaskService; | 13 | import org.flowable.engine.TaskService; |
| @@ -13,11 +15,14 @@ import org.springframework.security.access.prepost.PreAuthorize; | @@ -13,11 +15,14 @@ import org.springframework.security.access.prepost.PreAuthorize; | ||
| 13 | import org.springframework.validation.annotation.Validated; | 15 | import org.springframework.validation.annotation.Validated; |
| 14 | import org.springframework.web.bind.annotation.GetMapping; | 16 | import org.springframework.web.bind.annotation.GetMapping; |
| 15 | import org.springframework.web.bind.annotation.RequestMapping; | 17 | import org.springframework.web.bind.annotation.RequestMapping; |
| 18 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 16 | import org.springframework.web.bind.annotation.RestController; | 19 | import org.springframework.web.bind.annotation.RestController; |
| 17 | 20 | ||
| 18 | import javax.annotation.Resource; | 21 | import javax.annotation.Resource; |
| 19 | import javax.validation.Valid; | 22 | import javax.validation.Valid; |
| 20 | 23 | ||
| 24 | +import java.util.List; | ||
| 25 | + | ||
| 21 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 26 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 22 | import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; | 27 | import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; |
| 23 | 28 | ||
| @@ -36,4 +41,13 @@ public class BpmTaskController { | @@ -36,4 +41,13 @@ public class BpmTaskController { | ||
| 36 | public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) { | 41 | public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) { |
| 37 | return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO)); | 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,6 +37,9 @@ public interface BpmProcessInstanceConvert { | ||
| 37 | 37 | ||
| 38 | List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list); | 38 | List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list); |
| 39 | 39 | ||
| 40 | + @Mapping(source = "processInstanceId", target = "id") | ||
| 41 | + BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean); | ||
| 42 | + | ||
| 40 | List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks); | 43 | List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks); |
| 41 | 44 | ||
| 42 | default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt, | 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,6 +62,45 @@ public interface BpmTaskConvert { | ||
| 62 | }) | 62 | }) |
| 63 | BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); | 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 | package cn.iocoder.yudao.module.bpm.framework.flowable.config; | 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 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmProcessInstanceEventListener; | 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 | import org.flowable.common.engine.api.delegate.event.FlowableEventListener; | 10 | import org.flowable.common.engine.api.delegate.event.FlowableEventListener; |
| 5 | import org.flowable.engine.runtime.ProcessInstance; | 11 | import org.flowable.engine.runtime.ProcessInstance; |
| 6 | import org.flowable.spring.SpringProcessEngineConfiguration; | 12 | import org.flowable.spring.SpringProcessEngineConfiguration; |
| @@ -19,15 +25,35 @@ import java.util.List; | @@ -19,15 +25,35 @@ import java.util.List; | ||
| 19 | public class BpmFlowableConfiguration { | 25 | public class BpmFlowableConfiguration { |
| 20 | 26 | ||
| 21 | /** | 27 | /** |
| 22 | - *将自定义 listener 加入全局listener | 28 | + * 将自定义 listener 加入全局listener |
| 23 | * @param processInstanceListener 自定义监听 {@link ProcessInstance} | 29 | * @param processInstanceListener 自定义监听 {@link ProcessInstance} |
| 24 | */ | 30 | */ |
| 25 | @Bean | 31 | @Bean |
| 26 | - public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (BpmProcessInstanceEventListener processInstanceListener) { | 32 | + public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (BpmProcessInstanceEventListener processInstanceListener, |
| 33 | + BpmActivityBehaviorFactory bpmActivityBehaviorFactory) { | ||
| 27 | return engineConfiguration -> { | 34 | return engineConfiguration -> { |
| 28 | List<FlowableEventListener> eventListeners = new ArrayList<>(); | 35 | List<FlowableEventListener> eventListeners = new ArrayList<>(); |
| 29 | eventListeners.add(processInstanceListener); | 36 | eventListeners.add(processInstanceListener); |
| 30 | engineConfiguration.setEventListeners(eventListeners); | 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,6 +47,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService{ | ||
| 47 | @Lazy // 解决循环依赖 | 47 | @Lazy // 解决循环依赖 |
| 48 | private BpmModelService modelService; | 48 | private BpmModelService modelService; |
| 49 | @Resource | 49 | @Resource |
| 50 | + @Lazy // 解决循环依赖 | ||
| 50 | private BpmProcessDefinitionService processDefinitionService; | 51 | private BpmProcessDefinitionService processDefinitionService; |
| 51 | @Resource | 52 | @Resource |
| 52 | private BpmUserGroupService userGroupService; | 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,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 5 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | ||
| 5 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; | 6 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; |
| 6 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; | 7 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; |
| 7 | import org.flowable.task.api.Task; | 8 | import org.flowable.task.api.Task; |
| @@ -44,4 +45,12 @@ public interface BpmTaskService { | @@ -44,4 +45,12 @@ public interface BpmTaskService { | ||
| 44 | * @return 流程任务列表 | 45 | * @return 流程任务列表 |
| 45 | */ | 46 | */ |
| 46 | List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds); | 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,24 +3,35 @@ package cn.iocoder.yudao.module.bpm.service.task; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; |
| 8 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | ||
| 7 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; | 9 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; |
| 8 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; | 10 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; |
| 9 | import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; | 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 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | 16 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 11 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 17 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 12 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
| 19 | +import org.flowable.engine.HistoryService; | ||
| 13 | import org.flowable.engine.TaskService; | 20 | import org.flowable.engine.TaskService; |
| 21 | +import org.flowable.engine.history.HistoricProcessInstance; | ||
| 14 | import org.flowable.engine.runtime.ProcessInstance; | 22 | import org.flowable.engine.runtime.ProcessInstance; |
| 15 | import org.flowable.task.api.Task; | 23 | import org.flowable.task.api.Task; |
| 16 | import org.flowable.task.api.TaskQuery; | 24 | import org.flowable.task.api.TaskQuery; |
| 25 | +import org.flowable.task.api.history.HistoricTaskInstance; | ||
| 17 | import org.springframework.stereotype.Service; | 26 | import org.springframework.stereotype.Service; |
| 18 | 27 | ||
| 19 | import javax.annotation.Resource; | 28 | import javax.annotation.Resource; |
| 20 | import java.util.Collections; | 29 | import java.util.Collections; |
| 21 | import java.util.List; | 30 | import java.util.List; |
| 22 | import java.util.Map; | 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 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 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,9 +47,16 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | ||
| 36 | @Resource | 47 | @Resource |
| 37 | private TaskService taskService; | 48 | private TaskService taskService; |
| 38 | @Resource | 49 | @Resource |
| 39 | - private AdminUserApi adminUserApi; | 50 | + private HistoryService historyService; |
| 51 | + | ||
| 40 | @Resource | 52 | @Resource |
| 41 | private BpmProcessInstanceService processInstanceService; | 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 | @Override | 61 | @Override |
| 44 | public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { | 62 | public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { |
| @@ -79,4 +97,31 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | @@ -79,4 +97,31 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | ||
| 79 | } | 97 | } |
| 80 | return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list(); | 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 | } |