diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 8dde5b208d..9111176fd4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -149,7 +149,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } private Map getFormFieldsPermission(BpmnModel bpmnModel, - String activityId, String taskId) { + String activityId, String taskId) { // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) { activityId = Optional.ofNullable(taskService.getHistoricTask(taskId)) @@ -232,57 +232,62 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @Override public List getNextFlowNodes(Long loginUserId, BpmApprovalDetailReqVO reqVO) { - // 1 校验任务存在 + // 1.1 校验任务存在 Task task = taskService.getTask(reqVO.getTaskId()); if (task == null) { throw exception(TASK_NOT_EXISTS); } - // 2 校验任务是否由当前用户审批 + // 1.2 校验任务是否由当前用户审批 if (StrUtil.isNotBlank(task.getAssignee()) && ObjectUtil.notEqual(loginUserId, NumberUtils.parseLong(task.getAssignee()))) { throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF); } - // 3 校验流程实例存在 + // 1.3 校验流程实例存在 ProcessInstance instance = getProcessInstance(task.getProcessInstanceId()); if (instance == null) { throw exception(PROCESS_INSTANCE_NOT_EXISTS); } - // 4 获取 BpmnModel + // 1.4 校验BpmnModel BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(task.getProcessDefinitionId()); if (bpmnModel == null) { return null; } + //1.5 流程实例是否存在 HistoricProcessInstance historicProcessInstance = getHistoricProcessInstance(task.getProcessInstanceId()); if (historicProcessInstance == null) { throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); } + + // 2 设置流程变量 Map processVariables = new HashMap<>(); - // 获取历史中流程变量 + // 2.1 获取历史中流程变量 Map historicVariables = historicProcessInstance.getProcessVariables(); if (CollUtil.isNotEmpty(historicVariables)) { processVariables.putAll(historicVariables); } - // 合并前端传递的流程变量,以前端为准 - if (CollUtil.isNotEmpty(reqVO.getProcessVariables())){ + // 2.2 合并前端传递的流程变量,以前端为准 + if (CollUtil.isNotEmpty(reqVO.getProcessVariables())) { processVariables.putAll(reqVO.getProcessVariables()); } - // 获取流程定义信息 - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService - .getProcessDefinitionInfo(task.getProcessDefinitionId()); - // 获取当前任务节点的信息 + // 3 获取当前任务节点的信息 FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); - // 获取下一个将要执行的节点集合 + // 3.1 获取下一个将要执行的节点集合 List nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables); return convertList(nextFlowNodes, node -> { List candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), - loginUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables); - //存在一个节点多人审批的情况 - List candidateUsers = new ArrayList<>(); - for (Long candidateUserId : candidateUserIds) { - Map userMap = adminUserApi.getUserMap(candidateUserIds); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - candidateUsers.add(BpmProcessInstanceConvert.INSTANCE.buildUser(candidateUserId, userMap, deptMap)); + loginUserId, historicProcessInstance.getProcessDefinitionId(), processVariables); + // 3.2 获取节点的审批人信息 + Map userMap = adminUserApi.getUserMap(candidateUserIds); + if (CollUtil.isEmpty(userMap)) { + return null; } + // 3.3 获取节点的审批人部门信息 + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 3.4 存在一个节点多人审批的情况,组装审批人信息 + List candidateUsers = new ArrayList<>(); + userMap.forEach((key, value) -> { + candidateUsers.add(BpmProcessInstanceConvert.INSTANCE.buildUser(key, userMap, deptMap)); + }); return new ActivityNode().setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) .setId(node.getId()) .setName(node.getName()) @@ -356,15 +361,15 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService * 主要是,拼接审批人的用户信息、部门信息 */ private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO, - BpmnModel bpmnModel, - ProcessDefinition processDefinition, - BpmProcessDefinitionInfoDO processDefinitionInfo, - HistoricProcessInstance processInstance, - Integer processInstanceStatus, - List endApprovalNodeInfos, - List runningApprovalNodeInfos, - List simulateApprovalNodeInfos, - BpmTaskRespVO todoTask) { + BpmnModel bpmnModel, + ProcessDefinition processDefinition, + BpmProcessDefinitionInfoDO processDefinitionInfo, + HistoricProcessInstance processInstance, + Integer processInstanceStatus, + List endApprovalNodeInfos, + List runningApprovalNodeInfos, + List simulateApprovalNodeInfos, + BpmTaskRespVO todoTask) { // 1. 获取所有需要读取用户信息的 userIds List approveNodes = newArrayList( asList(endApprovalNodeInfos, runningApprovalNodeInfos, simulateApprovalNodeInfos)); @@ -386,9 +391,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService * 获得【已结束】的活动节点们 */ private List getEndActivityNodeList(Long startUserId, BpmnModel bpmnModel, - BpmProcessDefinitionInfoDO processDefinitionInfo, - HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus, - List activities, List tasks) { + BpmProcessDefinitionInfoDO processDefinitionInfo, + HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus, + List activities, List tasks) { // 遍历 tasks 列表,只处理已结束的 UserTask // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities // 的话,它无法成为一个节点 @@ -400,7 +405,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey()) ? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType() : ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的:解决“办理节点”的识别 - BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())) + BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())) .setStatus(FlowableUtils.getTaskStatus(task)) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) @@ -456,11 +461,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService * 获得【进行中】的活动节点们 */ private List getRunApproveNodeList(Long startUserId, - BpmnModel bpmnModel, - ProcessDefinition processDefinition, - Map processVariables, - List activities, - List tasks) { + BpmnModel bpmnModel, + ProcessDefinition processDefinition, + Map processVariables, + List activities, + List tasks) { // 构建运行中的任务、子流程,基于 activityId 分组 List runActivities = filterList(activities, activity -> activity.getEndTime() == null && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER, ELEMENT_CALL_ACTIVITY))); @@ -521,9 +526,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService * 获得【预测(未来)】的活动节点们 */ private List getSimulateApproveNodeList(Long startUserId, BpmnModel bpmnModel, - BpmProcessDefinitionInfoDO processDefinitionInfo, - Map processVariables, - List activities) { + BpmProcessDefinitionInfoDO processDefinitionInfo, + Map processVariables, + List activities) { // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance // 包括了历史的操作,不是只有 startEvent 到当前节点的记录 Set runActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId); @@ -545,8 +550,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } private ActivityNode buildNotRunApproveNodeForSimple(Long startUserId, BpmnModel bpmnModel, - BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, - BpmSimpleModelNodeVO node, Set runActivityIds) { + BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, + BpmSimpleModelNodeVO node, Set runActivityIds) { // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance // 包括了历史的操作,不是只有 startEvent 到当前节点的记录 if (runActivityIds.contains(node.getId())) { @@ -590,8 +595,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel, - BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, - FlowElement node, Set runActivityIds) { + BpmProcessDefinitionInfoDO processDefinitionInfo, Map processVariables, + FlowElement node, Set runActivityIds) { if (runActivityIds.contains(node.getId())) { return null; } @@ -622,7 +627,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } private List getTaskCandidateUserList(BpmnModel bpmnModel, String activityId, - Long startUserId, String processDefinitionId, Map processVariables) { + Long startUserId, String processDefinitionId, Map processVariables) { Set userIds = taskCandidateInvoker.calculateUsersByActivity(bpmnModel, activityId, startUserId, processDefinitionId, processVariables); return new ArrayList<>(userIds); @@ -658,11 +663,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService Set finishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.notEqual(activityInstance.getActivityType(), - BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); + BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); Set finishedSequenceFlowActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.equals(activityInstance.getActivityType(), - BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); + BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉 finishedTaskActivityIds.removeAll(unfinishedTaskActivityIds); // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。 @@ -714,8 +719,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } private String createProcessInstance0(Long userId, ProcessDefinition definition, - Map variables, String businessKey, - Map> startUserSelectAssignees) { + Map variables, String businessKey, + Map> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); @@ -744,8 +749,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); variables.put(BpmnVariableConstants.PROCESS_INSTANCE_SKIP_EXPRESSION_ENABLED, true); // 跳过表达式需要添加此变量为 - // true,不影响没配置 - // skipExpression 的节点 + // true,不影响没配置 + // skipExpression 的节点 if (CollUtil.isNotEmpty(startUserSelectAssignees)) { // 设置流程变量,发起人自选审批人 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, @@ -784,20 +789,20 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService private void validateStartUserSelectAssignees(Long userId, ProcessDefinition definition, Map> startUserSelectAssignees, - Map variables) { + Map variables) { // 1. 获取预测的节点信息 BpmApprovalDetailRespVO detailRespVO = getApprovalDetail(userId, new BpmApprovalDetailReqVO() .setProcessDefinitionId(definition.getId()) .setProcessVariables(variables)); List activityNodes = detailRespVO.getActivityNodes(); - if (CollUtil.isEmpty(activityNodes)){ + if (CollUtil.isEmpty(activityNodes)) { return; } // 2.1 移除掉不是发起人或者审批人自选审批人节点 activityNodes.removeIf(task -> ObjectUtil.notEqual(BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy(), task.getCandidateStrategy()) - && ObjectUtil.notEqual(BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy(), task.getCandidateStrategy())); + && ObjectUtil.notEqual(BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy(), task.getCandidateStrategy())); // 2.2 流程发起时要先获取当前流程的预测走向节点,发起时只校验预测的节点发起人自选审批人的审批人和抄送人是否都配置了 activityNodes.forEach(task -> { List assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(task.getId()) : null;