【代码优化】工作流:优化 todo 任务的获取

This commit is contained in:
YunaiV 2024-10-28 21:54:19 +08:00
parent 7cd9638ff6
commit 0c7fd9e1db
7 changed files with 106 additions and 106 deletions

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -33,10 +34,17 @@ public class BpmTaskRespVO {
@Schema(description = "审批理由", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @Schema(description = "审批理由", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private String reason; private String reason;
@Schema(description = "任务负责人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048")
@JsonIgnore // 不返回只是方便后续读取赋值给 ownerUser
private Long owner;
/** /**
* 负责人的用户信息 * 负责人的用户信息
*/ */
private UserSimpleBaseVO ownerUser; private UserSimpleBaseVO ownerUser;
@Schema(description = "任务分配人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048")
@JsonIgnore // 不返回只是方便后续读取赋值给 assigneeUser
private Long assignee;
/** /**
* 审核的用户信息 * 审核的用户信息
*/ */

View File

@ -189,7 +189,8 @@ public interface BpmProcessInstanceConvert {
} }
default Set<Long> parseUserIds(HistoricProcessInstance processInstance, default Set<Long> parseUserIds(HistoricProcessInstance processInstance,
List<BpmApprovalDetailRespVO.ActivityNode> activityNodes) { List<BpmApprovalDetailRespVO.ActivityNode> activityNodes,
BpmTaskRespVO todoTask) {
Set<Long> userIds = new HashSet<>(); Set<Long> userIds = new HashSet<>();
if (processInstance != null) { if (processInstance != null) {
userIds.add(NumberUtils.parseLong(processInstance.getStartUserId())); userIds.add(NumberUtils.parseLong(processInstance.getStartUserId()));
@ -199,6 +200,14 @@ public interface BpmProcessInstanceConvert {
CollUtil.addAll(userIds, convertSet(activityNode.getTasks(), BpmApprovalDetailRespVO.ActivityNodeTask::getOwner)); CollUtil.addAll(userIds, convertSet(activityNode.getTasks(), BpmApprovalDetailRespVO.ActivityNodeTask::getOwner));
CollUtil.addAll(userIds, activityNode.getCandidateUserIds()); CollUtil.addAll(userIds, activityNode.getCandidateUserIds());
} }
if (todoTask != null) {
CollUtil.addIfAbsent(userIds, todoTask.getAssignee());
CollUtil.addIfAbsent(userIds, todoTask.getOwner());
if (CollUtil.isNotEmpty(todoTask.getChildren())) {
CollUtil.addAll(userIds, convertSet(todoTask.getChildren(), BpmTaskRespVO::getAssignee));
CollUtil.addAll(userIds, convertSet(todoTask.getChildren(), BpmTaskRespVO::getOwner));
}
}
return userIds; return userIds;
} }
@ -222,7 +231,7 @@ public interface BpmProcessInstanceConvert {
Map<String, String> formFieldsPermission, Map<String, String> formFieldsPermission,
Map<Long, AdminUserRespDTO> userMap, Map<Long, AdminUserRespDTO> userMap,
Map<Long, DeptRespDTO> deptMap) { Map<Long, DeptRespDTO> deptMap) {
// 1. 流程实例 // 1.1 流程实例
BpmProcessInstanceRespVO processInstanceResp = null; BpmProcessInstanceRespVO processInstanceResp = null;
if (processInstance != null) { if (processInstance != null) {
AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
@ -230,12 +239,12 @@ public interface BpmProcessInstanceConvert {
processInstanceResp = buildProcessInstance(processInstance, null, null, startUser, dept); processInstanceResp = buildProcessInstance(processInstance, null, null, startUser, dept);
} }
// 2. 流程定义 // 1.2 流程定义
List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel);
BpmProcessDefinitionRespVO definitionResp = BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition( BpmProcessDefinitionRespVO definitionResp = BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition(
processDefinition, null, processDefinitionInfo, null, null, bpmnModel, userTaskList); processDefinition, null, processDefinitionInfo, null, null, bpmnModel, userTaskList);
// 3. 流程节点 // 1.3 流程节点
activityNodes.forEach(approveNode -> { activityNodes.forEach(approveNode -> {
if (approveNode.getTasks() != null) { if (approveNode.getTasks() != null) {
approveNode.getTasks().forEach(task -> { approveNode.getTasks().forEach(task -> {
@ -246,7 +255,19 @@ public interface BpmProcessInstanceConvert {
approveNode.setCandidateUsers(convertList(approveNode.getCandidateUserIds(), userId -> buildUser(userId, userMap, deptMap))); approveNode.setCandidateUsers(convertList(approveNode.getCandidateUserIds(), userId -> buildUser(userId, userMap, deptMap)));
}); });
// 4. 拼接起来 // 1.4 待办任务
if (todoTask != null) {
todoTask.setAssigneeUser(buildUser(todoTask.getAssignee(), userMap, deptMap));
todoTask.setOwnerUser(buildUser(todoTask.getOwner(), userMap, deptMap));
if (CollUtil.isNotEmpty(todoTask.getChildren())) {
todoTask.getChildren().forEach(childTask -> {
childTask.setAssigneeUser(buildUser(childTask.getAssignee(), userMap, deptMap));
childTask.setOwnerUser(buildUser(childTask.getOwner(), userMap, deptMap));
});
}
}
// 2. 拼接起来
return new BpmApprovalDetailRespVO().setStatus(processInstanceStatus) return new BpmApprovalDetailRespVO().setStatus(processInstanceStatus)
.setProcessDefinition(definitionResp) .setProcessDefinition(definitionResp)
.setProcessInstance(processInstanceResp) .setProcessInstance(processInstanceResp)

View File

@ -9,12 +9,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.history.HistoricProcessInstance; 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;
@ -29,7 +27,6 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils.isAddSignUserTask;
/** /**
* Bpm 任务 Convert * Bpm 任务 Convert
@ -126,29 +123,13 @@ public interface BpmTaskConvert {
})); }));
} }
default List<BpmTaskRespVO> buildTodoTaskListByUserId(Long userId, List<Task> todoTaskList, default BpmTaskRespVO buildTodoTask(Task todoTask, List<Task> childrenTasks,
Map<String, List<Task>> childrenTaskMap, Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting) {
BpmnModel bpmnModel, return BeanUtils.toBean(todoTask, BpmTaskRespVO.class)
Map<Long, AdminUserRespDTO> userMap, .setStatus(FlowableUtils.getTaskStatus(todoTask)).setReason(FlowableUtils.getTaskReason(todoTask))
Map<Long, DeptRespDTO> deptMap) { .setButtonsSetting(buttonsSetting)
return convertList(todoTaskList, task -> { .setChildren(convertList(childrenTasks, childTask -> BeanUtils.toBean(childTask, BpmTaskRespVO.class)
// 找到分配给当前用户或者当前用户加签的任务为了减签 .setStatus(FlowableUtils.getTaskStatus(childTask))));
if (!FlowableUtils.isAssignUserTask(userId, task)
&& !FlowableUtils.isAddSignUserTask(userId, task, childrenTaskMap)) {
return null;
}
BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class);
taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task));
taskVO.setButtonsSetting(BpmnModelUtils.parseButtonsSetting(bpmnModel, task.getTaskDefinitionKey()));
buildTaskOwner(taskVO, task.getOwner(), userMap, deptMap);
buildTaskAssignee(taskVO, task.getAssignee(), userMap, deptMap);
// 如果是被加签的任务. 找到它的子任务 (为了减签)
// TODO @jason如果是向后加签这个判断有问题哈因为向后加签后当前任务assignee 还是没变可以简单点直接拿子任务哈另外需要考虑子任务的子任务
if (isAddSignUserTask(userId, task, childrenTaskMap)) {
buildTaskChildren(taskVO, childrenTaskMap, userMap, deptMap);
}
return taskVO;
});
} }
default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser,

View File

@ -1,7 +1,5 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
@ -16,7 +14,6 @@ import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo; import org.flowable.task.api.TaskInfo;
import java.util.HashMap; import java.util.HashMap;
@ -203,43 +200,6 @@ public class FlowableUtils {
return taskLocalVariables; return taskLocalVariables;
} }
/**
* 判断指定用户是否是当前任务的分配人
*
* @param userId 用户编号
* @param task 任务
* @return 是否
*/
public static boolean isAssignUserTask(Long userId, Task task) {
Long assignee = NumberUtil.parseLong(task.getAssignee(), null);
return ObjectUtil.equal(userId, assignee);
}
/**
* 判断指定用户是否是当前任务的拥有人
*
* @param userId 用户编号
* @param task 任务
* @return 是否
*/
public static boolean isOwnerUserTask(Long userId, Task task) {
Long assignee = NumberUtil.parseLong(task.getAssignee(), null);
return ObjectUtil.equal(userId, assignee);
}
/**
* 判断指定用户是否是当前任务的加签人
*
* @param userId 用户 Id
* @param task 任务
* @param childrenTaskMap 子任务集合
* @return 是否
*/
public static boolean isAddSignUserTask(Long userId, Task task, Map<String, List<Task>> childrenTaskMap) {
return (isAssignUserTask(userId, task) || isOwnerUserTask(userId, task))
&& CollUtil.isNotEmpty(childrenTaskMap.get(task.getId()));
}
// ========== Expression 相关的工具方法 ========== // ========== Expression 相关的工具方法 ==========
public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) { public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) {

View File

@ -8,6 +8,7 @@ import jakarta.validation.Valid;
import org.flowable.bpmn.model.UserTask; import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstance;
import java.util.Collection; import java.util.Collection;
@ -138,7 +139,7 @@ public interface BpmTaskService {
* @param tasks 任务列表 * @param tasks 任务列表
* @return 子任务列表 * @return 子任务列表
*/ */
List<HistoricTaskInstance> getAllChildrenTaskListByParentTaskId(String parentTaskId, List<HistoricTaskInstance> tasks); <T extends TaskInfo> List<T> getAllChildrenTaskListByParentTaskId(String parentTaskId, List<T> tasks);
/** /**
* 获取指定任务的子任务列表 * 获取指定任务的子任务列表

View File

@ -40,10 +40,10 @@ import org.flowable.engine.ManagementService;
import org.flowable.engine.RuntimeService; import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService; import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.DelegationState; import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.TaskQuery; import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.api.history.HistoricTaskInstanceQuery;
@ -121,46 +121,39 @@ public class BpmTaskServiceImpl implements BpmTaskService {
return new PageResult<>(tasks, count); return new PageResult<>(tasks, count);
} }
// TODO @芋艿可以进一步简化
@Override @Override
public BpmTaskRespVO getFirstTodoTask(Long userId, String processInstanceId) { public BpmTaskRespVO getFirstTodoTask(Long userId, String processInstanceId) {
if (processInstanceId == null) { if (processInstanceId == null) {
return null; return null;
} }
// 1.1 查询任务 // 1. 查询所有任务
TaskQuery taskQuery = taskService.createTaskQuery() List<Task> tasks = taskService.createTaskQuery()
.active() .active()
.processInstanceId(processInstanceId) .processInstanceId(processInstanceId)
.includeTaskLocalVariables() .includeTaskLocalVariables()
.includeProcessVariables() .includeProcessVariables()
.orderByTaskCreateTime().asc(); // 按创建时间升序 .orderByTaskCreateTime().asc() // 按创建时间升序
List<Task> todoList = taskQuery.list(); .list();
if (CollUtil.isEmpty(todoList)) { if (CollUtil.isEmpty(tasks)) {
return null; return null;
} }
// 1.2 构建子任务 Map用于减签keyparentTaskId
Map<String, List<Task>> childrenTaskMap = convertMultiMap(
filterList(todoList, r -> StrUtil.isNotEmpty(r.getParentTaskId())),
Task::getParentTaskId);
// 2.1 获取用户信息 // 2.1 查询我的首个任务
Set<Long> userIds = CollUtil.newHashSet(); Task todoTask = CollUtil.findOne(tasks, task -> {
todoList.forEach(task -> { return isAssignUserTask(userId, task) // 当前用户为审批人
CollUtil.addIfAbsent(userIds, NumberUtils.parseLong((task.getAssignee()))); || isAddSignUserTask(userId, task); // 当前用户为价钱人为了减签
CollUtil.addIfAbsent(userIds, NumberUtils.parseLong((task.getOwner())));
}); });
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); if (todoTask == null) {
Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( return null;
convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); }
// 2.2 查询该任务的子任务
List<Task> childrenTasks = getAllChildrenTaskListByParentTaskId(todoTask.getId(), tasks);
// 2.2 构建用户待办 Task 列表 // 3. 转换返回
HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(todoTask.getProcessDefinitionId());
BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId()); Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting = BpmnModelUtils.parseButtonsSetting(
List<BpmTaskRespVO> todoTasks = BpmTaskConvert.INSTANCE.buildTodoTaskListByUserId(userId, todoList, childrenTaskMap, bpmnModel, todoTask.getTaskDefinitionKey());
bpmnModel, userMap, deptMap); return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting);
// 2.3 找到首个任务
return findFirst(todoTasks, Objects::nonNull);
} }
@Override @Override
@ -307,17 +300,17 @@ public class BpmTaskServiceImpl implements BpmTaskService {
} }
@Override @Override
public List<HistoricTaskInstance> getAllChildrenTaskListByParentTaskId(String parentTaskId, List<HistoricTaskInstance> tasks) { public <T extends TaskInfo> List<T> getAllChildrenTaskListByParentTaskId(String parentTaskId, List<T> tasks) {
if (CollUtil.isEmpty(tasks)) { if (CollUtil.isEmpty(tasks)) {
return Collections.emptyList(); return Collections.emptyList();
} }
Map<String, List<HistoricTaskInstance>> parentTaskMap = convertMultiMap( Map<String, List<T>> parentTaskMap = convertMultiMap(
filterList(tasks, task -> StrUtil.isNotEmpty(task.getParentTaskId())), HistoricTaskInstance::getParentTaskId); filterList(tasks, task -> StrUtil.isNotEmpty(task.getParentTaskId())), TaskInfo::getParentTaskId);
if (CollUtil.isEmpty(parentTaskMap)) { if (CollUtil.isEmpty(parentTaskMap)) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<HistoricTaskInstance> result = new ArrayList<>(); List<T> result = new ArrayList<>();
// 1. 递归获取子级 // 1. 递归获取子级
Stack<String> stack = new Stack<>(); Stack<String> stack = new Stack<>();
stack.push(parentTaskId); stack.push(parentTaskId);
@ -328,10 +321,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
} }
// 2.1 获取子任务们 // 2.1 获取子任务们
String taskId = stack.pop(); String taskId = stack.pop();
List<HistoricTaskInstance> childTaskList = filterList(tasks, task -> StrUtil.equals(task.getParentTaskId(), taskId)); List<T> childTaskList = filterList(tasks, task -> StrUtil.equals(task.getParentTaskId(), taskId));
// 2.2 如果非空则添加到 stack 进一步递归 // 2.2 如果非空则添加到 stack 进一步递归
if (CollUtil.isNotEmpty(childTaskList)) { if (CollUtil.isNotEmpty(childTaskList)) {
stack.addAll(convertList(childTaskList, HistoricTaskInstance::getId)); stack.addAll(convertList(childTaskList, TaskInfo::getId));
result.addAll(childTaskList); result.addAll(childTaskList);
} }
} }
@ -420,6 +413,42 @@ public class BpmTaskServiceImpl implements BpmTaskService {
return historyService.createHistoricActivityInstanceQuery().executionId(executionId).list(); return historyService.createHistoricActivityInstanceQuery().executionId(executionId).list();
} }
/**
* 判断指定用户是否是当前任务的审批人
*
* @param userId 用户编号
* @param task 任务
* @return 是否
*/
private boolean isAssignUserTask(Long userId, Task task) {
Long assignee = NumberUtil.parseLong(task.getAssignee(), null);
return ObjectUtil.equals(userId, assignee);
}
/**
* 判断指定用户是否是当前任务的拥有人
*
* @param userId 用户编号
* @param task 任务
* @return 是否
*/
private boolean isOwnerUserTask(Long userId, Task task) {
Long assignee = NumberUtil.parseLong(task.getOwner(), null);
return ObjectUtil.equal(userId, assignee);
}
/**
* 判断指定用户是否是当前任务的加签人
*
* @param userId 用户 Id
* @param task 任务
* @return 是否
*/
private boolean isAddSignUserTask(Long userId, Task task) {
return (isAssignUserTask(userId, task) || isOwnerUserTask(userId, task))
&& BpmTaskSignTypeEnum.of(task.getScopeType()) != null;
}
// ========== Update 写入相关方法 ========== // ========== Update 写入相关方法 ==========
@Override @Override