mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-23 07:41:53 +08:00
工作流 Flowable 发起流程, 用户任务相关实现
This commit is contained in:
parent
073d860a78
commit
d6775a5619
@ -44,7 +44,7 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
|
public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
|
||||||
BpmUserTaskActivitiBehavior userTaskActivityBehavior = new BpmUserTaskActivitiBehavior(userTask);
|
BpmUserTaskActivityBehavior userTaskActivityBehavior = new BpmUserTaskActivityBehavior(userTask);
|
||||||
userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
|
userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
|
||||||
userTaskActivityBehavior.setPermissionApi(permissionApi);
|
userTaskActivityBehavior.setPermissionApi(permissionApi);
|
||||||
userTaskActivityBehavior.setDeptApi(deptApi);
|
userTaskActivityBehavior.setDeptApi(deptApi);
|
||||||
|
@ -44,7 +44,7 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_F
|
|||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior {
|
public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private BpmTaskAssignRuleService bpmTaskRuleService;
|
private BpmTaskAssignRuleService bpmTaskRuleService;
|
||||||
@ -64,7 +64,7 @@ public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior {
|
|||||||
*/
|
*/
|
||||||
private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
|
private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
|
||||||
|
|
||||||
public BpmUserTaskActivitiBehavior(UserTask userTask) {
|
public BpmUserTaskActivityBehavior(UserTask userTask) {
|
||||||
super(userTask);
|
super(userTask);
|
||||||
}
|
}
|
||||||
|
|
@ -33,10 +33,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class BpmUserTaskActivitiBehaviorTest extends BaseMockitoUnitTest {
|
public class BpmUserTaskActivityBehaviorTest extends BaseMockitoUnitTest {
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private BpmUserTaskActivitiBehavior behavior;
|
private BpmUserTaskActivityBehavior behavior;
|
||||||
@Mock
|
@Mock
|
||||||
private BpmTaskAssignRuleService bpmTaskRuleService;
|
private BpmTaskAssignRuleService bpmTaskRuleService;
|
||||||
@Mock
|
@Mock
|
@ -2,10 +2,12 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
|
||||||
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
|
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.flowable.bpmn.model.BpmnModel;
|
import org.flowable.bpmn.model.BpmnModel;
|
||||||
import org.flowable.engine.TaskService;
|
import org.flowable.engine.TaskService;
|
||||||
@ -13,11 +15,14 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
|
||||||
|
|
||||||
@ -36,4 +41,13 @@ public class BpmTaskController {
|
|||||||
public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) {
|
public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) {
|
||||||
return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
|
return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list-by-process-instance-id")
|
||||||
|
@ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的")
|
||||||
|
@ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class)
|
||||||
|
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
|
||||||
|
public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId(
|
||||||
|
@RequestParam("processInstanceId") String processInstanceId) {
|
||||||
|
return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,9 @@ public interface BpmProcessInstanceConvert {
|
|||||||
|
|
||||||
List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list);
|
List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list);
|
||||||
|
|
||||||
|
@Mapping(source = "processInstanceId", target = "id")
|
||||||
|
BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean);
|
||||||
|
|
||||||
List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks);
|
List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks);
|
||||||
|
|
||||||
default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt,
|
default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt,
|
||||||
|
@ -62,6 +62,45 @@ public interface BpmTaskConvert {
|
|||||||
})
|
})
|
||||||
BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
|
BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
|
||||||
|
|
||||||
|
default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
|
||||||
|
HistoricProcessInstance processInstance, Map<Long, AdminUserRespDTO> userMap,
|
||||||
|
Map<Long, DeptRespDTO> deptMap) {
|
||||||
|
return CollectionUtils.convertList(tasks, task -> {
|
||||||
|
BpmTaskRespVO respVO = convert3(task);
|
||||||
|
BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
|
||||||
|
copyTo(taskExtDO, respVO);
|
||||||
|
if (processInstance != null) {
|
||||||
|
AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
|
||||||
|
respVO.setProcessInstance(convert(processInstance, startUser));
|
||||||
|
}
|
||||||
|
AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee()));
|
||||||
|
if (assignUser != null) {
|
||||||
|
respVO.setAssigneeUser(convert3(assignUser));
|
||||||
|
DeptRespDTO dept = deptMap.get(assignUser.getDeptId());
|
||||||
|
if (dept != null) {
|
||||||
|
respVO.getAssigneeUser().setDeptName(dept.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return respVO;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mapping(source = "taskDefinitionKey", target = "definitionKey")
|
||||||
|
BpmTaskRespVO convert3(HistoricTaskInstance bean);
|
||||||
|
|
||||||
|
BpmTaskRespVO.User convert3(AdminUserRespDTO bean);
|
||||||
|
|
||||||
|
void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to);
|
||||||
|
|
||||||
|
@Mappings({
|
||||||
|
@Mapping(source = "processInstance.id", target = "id"),
|
||||||
|
@Mapping(source = "processInstance.name", target = "name"),
|
||||||
|
@Mapping(source = "processInstance.startUserId", target = "startUserId"),
|
||||||
|
@Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
|
||||||
|
@Mapping(source = "startUser.nickname", target = "startUserNickname")
|
||||||
|
})
|
||||||
|
BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, AdminUserRespDTO startUser);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.config;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.config;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmProcessInstanceEventListener;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmProcessInstanceEventListener;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
||||||
import org.flowable.engine.runtime.ProcessInstance;
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||||
@ -19,15 +25,35 @@ import java.util.List;
|
|||||||
public class BpmFlowableConfiguration {
|
public class BpmFlowableConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*将自定义 listener 加入全局listener
|
* 将自定义 listener 加入全局listener
|
||||||
* @param processInstanceListener 自定义监听 {@link ProcessInstance}
|
* @param processInstanceListener 自定义监听 {@link ProcessInstance}
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (BpmProcessInstanceEventListener processInstanceListener) {
|
public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (BpmProcessInstanceEventListener processInstanceListener,
|
||||||
|
BpmActivityBehaviorFactory bpmActivityBehaviorFactory) {
|
||||||
return engineConfiguration -> {
|
return engineConfiguration -> {
|
||||||
List<FlowableEventListener> eventListeners = new ArrayList<>();
|
List<FlowableEventListener> eventListeners = new ArrayList<>();
|
||||||
eventListeners.add(processInstanceListener);
|
eventListeners.add(processInstanceListener);
|
||||||
engineConfiguration.setEventListeners(eventListeners);
|
engineConfiguration.setEventListeners(eventListeners);
|
||||||
|
engineConfiguration.setActivityBehaviorFactory(bpmActivityBehaviorFactory);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService,
|
||||||
|
BpmUserGroupService userGroupService,
|
||||||
|
PermissionApi permissionApi,
|
||||||
|
DeptApi deptApi,
|
||||||
|
AdminUserApi adminUserApi) {
|
||||||
|
BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory();
|
||||||
|
bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService);
|
||||||
|
bpmActivityBehaviorFactory.setUserGroupService(userGroupService);
|
||||||
|
bpmActivityBehaviorFactory.setAdminUserApi(adminUserApi);
|
||||||
|
bpmActivityBehaviorFactory.setPermissionApi(permissionApi);
|
||||||
|
bpmActivityBehaviorFactory.setDeptApi(deptApi);
|
||||||
|
// bpmActivityBehaviorFactory.setScripts(scripts);
|
||||||
|
return bpmActivityBehaviorFactory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.flowable.bpmn.model.UserTask;
|
||||||
|
import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
|
||||||
|
import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义的 ActivityBehaviorFactory 实现类,目的如下:
|
||||||
|
* 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private BpmTaskAssignRuleService bpmTaskRuleService;
|
||||||
|
@Setter
|
||||||
|
private BpmUserGroupService userGroupService;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private PermissionApi permissionApi;
|
||||||
|
@Setter
|
||||||
|
private DeptApi deptApi;
|
||||||
|
@Setter
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
|
||||||
|
BpmUserTaskActivityBehavior userTaskActivityBehavior = new BpmUserTaskActivityBehavior(userTask);
|
||||||
|
userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
|
||||||
|
userTaskActivityBehavior.setPermissionApi(permissionApi);
|
||||||
|
userTaskActivityBehavior.setDeptApi(deptApi);
|
||||||
|
userTaskActivityBehavior.setUserGroupService(userGroupService);
|
||||||
|
userTaskActivityBehavior.setAdminUserApi(adminUserApi);
|
||||||
|
//TODO
|
||||||
|
//userTaskActivityBehavior.setScripts(scripts);
|
||||||
|
return userTaskActivityBehavior;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.flowable.bpmn.model.UserTask;
|
||||||
|
import org.flowable.common.engine.api.FlowableException;
|
||||||
|
import org.flowable.common.engine.impl.el.ExpressionManager;
|
||||||
|
import org.flowable.engine.delegate.DelegateExecution;
|
||||||
|
import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
|
||||||
|
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||||
|
import org.flowable.engine.impl.util.TaskHelper;
|
||||||
|
import org.flowable.task.service.TaskService;
|
||||||
|
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
|
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义的流程任务的 assignee 负责人的分配
|
||||||
|
* 第一步,获得对应的分配规则;
|
||||||
|
* 第二步,根据分配规则,计算出分配任务的候选人。如果找不到,则直接报业务异常,不继续执行后续的流程;
|
||||||
|
* 第三步,随机选择一个候选人,则选择作为 assignee 负责人。
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private BpmTaskAssignRuleService bpmTaskRuleService;
|
||||||
|
@Setter
|
||||||
|
private BpmUserGroupService userGroupService;
|
||||||
|
@Setter
|
||||||
|
private DeptApi deptApi;
|
||||||
|
@Setter
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
@Setter
|
||||||
|
private PermissionApi permissionApi;
|
||||||
|
|
||||||
|
public BpmUserTaskActivityBehavior(UserTask userTask) {
|
||||||
|
super(userTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleAssignments(TaskService taskService, String assignee, String owner, List<String> candidateUsers, List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
|
||||||
|
// 第一步,获得任务的规则
|
||||||
|
BpmTaskAssignRuleDO rule = getTaskRule(task);
|
||||||
|
// 第二步,获得任务的候选用户们
|
||||||
|
Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule);
|
||||||
|
// 第三步,设置一个作为负责人
|
||||||
|
Long assigneeUserId = chooseTaskAssignee(candidateUserIds);
|
||||||
|
TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private BpmTaskAssignRuleDO getTaskRule(TaskEntity task) {
|
||||||
|
List<BpmTaskAssignRuleDO> taskRules = bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(),
|
||||||
|
task.getTaskDefinitionKey());
|
||||||
|
if (CollUtil.isEmpty(taskRules)) {
|
||||||
|
throw new FlowableException(StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则",
|
||||||
|
task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey()));
|
||||||
|
}
|
||||||
|
if (taskRules.size() > 1) {
|
||||||
|
throw new FlowableException(StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})",
|
||||||
|
task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), taskRules.size()));
|
||||||
|
}
|
||||||
|
return taskRules.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) {
|
||||||
|
Set<Long> assigneeUserIds = null;
|
||||||
|
if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
|
||||||
|
assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule);
|
||||||
|
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
|
||||||
|
assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule);
|
||||||
|
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
|
||||||
|
assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule);
|
||||||
|
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
|
||||||
|
assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule);
|
||||||
|
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
|
||||||
|
assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
|
||||||
|
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
|
||||||
|
assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule);
|
||||||
|
}
|
||||||
|
// else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
|
||||||
|
// assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 移除被禁用的用户
|
||||||
|
removeDisableUsers(assigneeUserIds);
|
||||||
|
// 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人
|
||||||
|
if (CollUtil.isEmpty(assigneeUserIds)) {
|
||||||
|
log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]",
|
||||||
|
task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule));
|
||||||
|
throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
|
||||||
|
}
|
||||||
|
return assigneeUserIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) {
|
||||||
|
return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) {
|
||||||
|
List<AdminUserRespDTO> users = adminUserApi.getUsersByDeptIds(rule.getOptions());
|
||||||
|
return convertSet(users, AdminUserRespDTO::getId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) {
|
||||||
|
List<DeptRespDTO> depts = deptApi.getDepts(rule.getOptions());
|
||||||
|
return convertSet(depts, DeptRespDTO::getLeaderUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) {
|
||||||
|
List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions());
|
||||||
|
return convertSet(users, AdminUserRespDTO::getId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) {
|
||||||
|
return rule.getOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) {
|
||||||
|
List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
|
||||||
|
Set<Long> userIds = new HashSet<>();
|
||||||
|
userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds()));
|
||||||
|
return userIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long chooseTaskAssignee(Set<Long> candidateUserIds) {
|
||||||
|
// TODO 芋艿:未来可以优化下,改成轮询的策略
|
||||||
|
int index = RandomUtil.randomInt(candidateUserIds.size());
|
||||||
|
return CollUtil.get(candidateUserIds, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void removeDisableUsers(Set<Long> assigneeUserIds) {
|
||||||
|
if (CollUtil.isEmpty(assigneeUserIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
|
||||||
|
assigneeUserIds.removeIf(id -> {
|
||||||
|
AdminUserRespDTO user = userMap.get(id);
|
||||||
|
return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -47,6 +47,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService{
|
|||||||
@Lazy // 解决循环依赖
|
@Lazy // 解决循环依赖
|
||||||
private BpmModelService modelService;
|
private BpmModelService modelService;
|
||||||
@Resource
|
@Resource
|
||||||
|
@Lazy // 解决循环依赖
|
||||||
private BpmProcessDefinitionService processDefinitionService;
|
private BpmProcessDefinitionService processDefinitionService;
|
||||||
@Resource
|
@Resource
|
||||||
private BpmUserGroupService userGroupService;
|
private BpmUserGroupService userGroupService;
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
|
||||||
import org.flowable.task.api.Task;
|
import org.flowable.task.api.Task;
|
||||||
@ -44,4 +45,12 @@ public interface BpmTaskService {
|
|||||||
* @return 流程任务列表
|
* @return 流程任务列表
|
||||||
*/
|
*/
|
||||||
List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
|
List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得指令流程实例的流程任务列表,包括所有状态的
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例的编号
|
||||||
|
* @return 流程任务列表
|
||||||
|
*/
|
||||||
|
List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId);
|
||||||
}
|
}
|
||||||
|
@ -3,24 +3,35 @@ package cn.iocoder.yudao.module.bpm.service.task;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
|
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
|
||||||
import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
|
import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.flowable.engine.HistoryService;
|
||||||
import org.flowable.engine.TaskService;
|
import org.flowable.engine.TaskService;
|
||||||
|
import org.flowable.engine.history.HistoricProcessInstance;
|
||||||
import org.flowable.engine.runtime.ProcessInstance;
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
import org.flowable.task.api.Task;
|
import org.flowable.task.api.Task;
|
||||||
import org.flowable.task.api.TaskQuery;
|
import org.flowable.task.api.TaskQuery;
|
||||||
|
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,9 +47,16 @@ public class BpmTaskServiceImpl implements BpmTaskService{
|
|||||||
@Resource
|
@Resource
|
||||||
private TaskService taskService;
|
private TaskService taskService;
|
||||||
@Resource
|
@Resource
|
||||||
private AdminUserApi adminUserApi;
|
private HistoryService historyService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private BpmProcessInstanceService processInstanceService;
|
private BpmProcessInstanceService processInstanceService;
|
||||||
|
@Resource
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
@Resource
|
||||||
|
private DeptApi deptApi;
|
||||||
|
@Resource
|
||||||
|
private BpmTaskExtMapper taskExtMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
|
public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
|
||||||
@ -79,4 +97,31 @@ public class BpmTaskServiceImpl implements BpmTaskService{
|
|||||||
}
|
}
|
||||||
return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
|
return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId) {
|
||||||
|
// 获得任务列表
|
||||||
|
List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
|
||||||
|
.processInstanceId(processInstanceId)
|
||||||
|
.orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序
|
||||||
|
.list();
|
||||||
|
if (CollUtil.isEmpty(tasks)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得 TaskExtDO Map
|
||||||
|
List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
|
||||||
|
Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
|
||||||
|
// 获得 ProcessInstance Map
|
||||||
|
HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
|
||||||
|
// 获得 User Map
|
||||||
|
Set<Long> userIds = convertSet(tasks, task -> NumberUtils.parseLong(task.getAssignee()));
|
||||||
|
userIds.add(NumberUtils.parseLong(processInstance.getStartUserId()));
|
||||||
|
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
||||||
|
// 获得 Dept Map
|
||||||
|
Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
|
||||||
|
|
||||||
|
// 拼接数据
|
||||||
|
return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user