From f1208474f771a1c233d7425c8ed13fbaa0d521ac Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期三, 12 三月 2025 09:35:13 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/5.X' into 5.X --- ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java | 363 +++++++++++++++++++-------------------------------- 1 files changed, 137 insertions(+), 226 deletions(-) diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java index d7c4472..e48ffc8 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java @@ -2,43 +2,42 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.dto.UserDTO; -import org.dromara.common.core.service.UserService; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mail.utils.MailUtils; -import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.common.websocket.dto.WebSocketMessageDto; -import org.dromara.common.websocket.utils.WebSocketUtils; -import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.warm.flow.core.constant.ExceptionCons; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.entity.User; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.service.NodeService; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.core.service.UserService; +import org.dromara.warm.flow.core.utils.AssertUtil; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.entity.FlowUser; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; import org.dromara.workflow.common.enums.MessageTypeEnum; -import org.dromara.workflow.common.enums.TaskStatusEnum; -import org.dromara.workflow.domain.ActHiTaskinst; -import org.dromara.workflow.domain.vo.MultiInstanceVo; -import org.dromara.workflow.domain.vo.ParticipantVo; -import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd; -import org.dromara.workflow.mapper.ActHiTaskinstMapper; -import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.FlowNode; -import org.flowable.common.engine.api.delegate.Expression; -import org.flowable.engine.ProcessEngine; -import org.flowable.engine.history.HistoricProcessInstance; -import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; -import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; -import org.flowable.identitylink.api.history.HistoricIdentityLink; -import org.flowable.task.api.Task; -import org.flowable.task.api.TaskQuery; -import org.flowable.task.api.history.HistoricTaskInstance; -import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.dromara.workflow.service.IFlwTaskService; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + /** * 宸ヤ綔娴佸伐鍏� @@ -48,220 +47,84 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class WorkflowUtils { - private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); - private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class); + private static final IFlwTaskAssigneeService TASK_ASSIGNEE_SERVICE = SpringUtils.getBean(IFlwTaskAssigneeService.class); + private static final IFlwTaskService FLW_TASK_SERVICE = SpringUtils.getBean(IFlwTaskService.class); + private static final FlowNodeMapper FLOW_NODE_MAPPER = SpringUtils.getBean(FlowNodeMapper.class); + private static final FlowTaskMapper FLOW_TASK_MAPPER = SpringUtils.getBean(FlowTaskMapper.class); + private static final UserService USER_SERVICE = SpringUtils.getBean(UserService.class); + private static final TaskService TASK_SERVICE = SpringUtils.getBean(TaskService.class); + private static final NodeService NODE_SERVICE = SpringUtils.getBean(NodeService.class); /** - * 鍒涘缓涓�涓柊浠诲姟 - * - * @param currentTask 鍙傛暟 + * 鑾峰彇宸ヤ綔娴佺敤鎴穝ervice */ - public static TaskEntity createNewTask(Task currentTask) { - TaskEntity task = null; - if (ObjectUtil.isNotEmpty(currentTask)) { - task = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask(); - task.setCategory(currentTask.getCategory()); - task.setDescription(currentTask.getDescription()); - task.setAssignee(currentTask.getAssignee()); - task.setName(currentTask.getName()); - task.setProcessDefinitionId(currentTask.getProcessDefinitionId()); - task.setProcessInstanceId(currentTask.getProcessInstanceId()); - task.setTaskDefinitionKey(currentTask.getTaskDefinitionKey()); - task.setPriority(currentTask.getPriority()); - task.setCreateTime(new Date()); - task.setTenantId(TenantHelper.getTenantId()); - PROCESS_ENGINE.getTaskService().saveTask(task); - } - if (ObjectUtil.isNotNull(task)) { - UpdateHiTaskInstCmd updateHiTaskInstCmd = new UpdateHiTaskInstCmd(Collections.singletonList(task.getId()), task.getProcessDefinitionId(), task.getProcessInstanceId()); - PROCESS_ENGINE.getManagementService().executeCommand(updateHiTaskInstCmd); - } - return task; + public static UserService getFlowUserService() { + return USER_SERVICE; } /** - * 鎶勯�佷换鍔� + * 鏋勫缓宸ヤ綔娴佺敤鎴� * - * @param parentTaskList 鐖剁骇浠诲姟 - * @param userIds 浜哄憳id + * @param userList 鍔炵悊鐢ㄦ埛 + * @param taskId 浠诲姟ID + * @return 鐢ㄦ埛 */ - public static void createCopyTask(List<Task> parentTaskList, List<Long> userIds) { - List<Task> list = new ArrayList<>(); - String tenantId = TenantHelper.getTenantId(); - for (Task parentTask : parentTaskList) { - for (Long userId : userIds) { - TaskEntity newTask = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask(); - newTask.setParentTaskId(parentTask.getId()); - newTask.setAssignee(userId.toString()); - newTask.setName("銆愭妱閫併��-" + parentTask.getName()); - newTask.setProcessDefinitionId(parentTask.getProcessDefinitionId()); - newTask.setProcessInstanceId(parentTask.getProcessInstanceId()); - newTask.setTaskDefinitionKey(parentTask.getTaskDefinitionKey()); - newTask.setTenantId(tenantId); - list.add(newTask); + public static Set<User> buildUser(List<User> userList, Long taskId) { + if (CollUtil.isEmpty(userList)) { + return Set.of(); + } + Set<User> list = new HashSet<>(); + Set<String> processedBySet = new HashSet<>(); + for (User user : userList) { + // 鏍规嵁 processedBy 鍓嶇紑鍒ゆ柇澶勭悊浜虹被鍨嬶紝鍒嗗埆鑾峰彇鐢ㄦ埛鍒楄〃 + List<UserDTO> users = TASK_ASSIGNEE_SERVICE.fetchUsersByStorageId(user.getProcessedBy()); + // 杞崲涓� FlowUser 骞舵坊鍔犲埌缁撴灉闆嗗悎 + if (CollUtil.isNotEmpty(users)) { + users.forEach(dto -> { + String processedBy = String.valueOf(dto.getUserId()); + if (!processedBySet.contains(processedBy)) { + FlowUser flowUser = new FlowUser(); + flowUser.setType(user.getType()); + flowUser.setProcessedBy(processedBy); + flowUser.setAssociated(taskId); + list.add(flowUser); + processedBySet.add(processedBy); + } + }); } } - PROCESS_ENGINE.getTaskService().bulkSaveTasks(list); - if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(parentTaskList)) { - String processInstanceId = parentTaskList.get(0).getProcessInstanceId(); - String processDefinitionId = parentTaskList.get(0).getProcessDefinitionId(); - List<String> taskIds = StreamUtils.toList(list, Task::getId); - ActHiTaskinst actHiTaskinst = new ActHiTaskinst(); - actHiTaskinst.setProcDefId(processDefinitionId); - actHiTaskinst.setProcInstId(processInstanceId); - actHiTaskinst.setScopeType(TaskStatusEnum.COPY.getStatus()); - actHiTaskinst.setTenantId(tenantId); - LambdaUpdateWrapper<ActHiTaskinst> updateWrapper = new LambdaUpdateWrapper<>(); - updateWrapper.in(ActHiTaskinst::getId, taskIds); - ACT_HI_TASKINST_MAPPER.update(actHiTaskinst, updateWrapper); - for (Task task : list) { - PROCESS_ENGINE.getTaskService().addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), StrUtil.EMPTY); - } - } - } - - /** - * 鑾峰彇褰撳墠浠诲姟鍙備笌鑰� - * - * @param taskId 浠诲姟id - */ - public static ParticipantVo getCurrentTaskParticipant(String taskId, UserService userService) { - ParticipantVo participantVo = new ParticipantVo(); - List<HistoricIdentityLink> linksForTask = PROCESS_ENGINE.getHistoryService().getHistoricIdentityLinksForTask(taskId); - Task task = QueryUtils.taskQuery().taskId(taskId).singleResult(); - if (task != null && CollUtil.isNotEmpty(linksForTask)) { - List<HistoricIdentityLink> groupList = StreamUtils.filter(linksForTask, e -> StringUtils.isNotBlank(e.getGroupId())); - if (CollUtil.isNotEmpty(groupList)) { - List<Long> groupIds = StreamUtils.toList(groupList, e -> Long.valueOf(e.getGroupId())); - List<Long> userIds = userService.selectUserIdsByRoleIds(groupIds); - if (CollUtil.isNotEmpty(userIds)) { - participantVo.setGroupIds(groupIds); - List<UserDTO> userList = userService.selectListByIds(userIds); - if (CollUtil.isNotEmpty(userList)) { - List<Long> userIdList = StreamUtils.toList(userList, UserDTO::getUserId); - List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName); - participantVo.setCandidate(userIdList); - participantVo.setCandidateName(nickNames); - participantVo.setClaim(!StringUtils.isBlank(task.getAssignee())); - } - } - } else { - List<HistoricIdentityLink> candidateList = StreamUtils.filter(linksForTask, e -> FlowConstant.CANDIDATE.equals(e.getType())); - List<Long> userIdList = new ArrayList<>(); - for (HistoricIdentityLink historicIdentityLink : linksForTask) { - try { - userIdList.add(Long.valueOf(historicIdentityLink.getUserId())); - } catch (NumberFormatException ignored) { - - } - } - List<UserDTO> userList = userService.selectListByIds(userIdList); - if (CollUtil.isNotEmpty(userList)) { - List<Long> userIds = StreamUtils.toList(userList, UserDTO::getUserId); - List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName); - participantVo.setCandidate(userIds); - participantVo.setCandidateName(nickNames); - // 鍒ゆ柇褰撳墠浠诲姟鏄惁鍏锋湁澶氫釜鍔炵悊浜� - if (CollUtil.isNotEmpty(candidateList) && candidateList.size() > 1) { - // 濡傛灉 assignee 瀛樺湪锛屽垯璁剧疆褰撳墠浠诲姟宸茬粡琚棰� - participantVo.setClaim(StringUtils.isNotBlank(task.getAssignee())); - } - } - } - } - return participantVo; - } - - /** - * 鍒ゆ柇褰撳墠鑺傜偣鏄惁涓轰細绛捐妭鐐� - * - * @param processDefinitionId 娴佺▼瀹氫箟id - * @param taskDefinitionKey 娴佺▼瀹氫箟id - */ - public static MultiInstanceVo isMultiInstance(String processDefinitionId, String taskDefinitionKey) { - BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); - FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); - MultiInstanceVo multiInstanceVo = new MultiInstanceVo(); - //鍒ゆ柇鏄惁涓哄苟琛屼細绛捐妭鐐� - if (flowNode.getBehavior() instanceof ParallelMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) { - Expression collectionExpression = behavior.getCollectionExpression(); - String assigneeList = collectionExpression.getExpressionText(); - String assignee = behavior.getCollectionElementVariable(); - multiInstanceVo.setType(behavior); - multiInstanceVo.setAssignee(assignee); - multiInstanceVo.setAssigneeList(assigneeList); - return multiInstanceVo; - //鍒ゆ柇鏄惁涓轰覆琛屼細绛捐妭鐐� - } else if (flowNode.getBehavior() instanceof SequentialMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) { - Expression collectionExpression = behavior.getCollectionExpression(); - String assigneeList = collectionExpression.getExpressionText(); - String assignee = behavior.getCollectionElementVariable(); - multiInstanceVo.setType(behavior); - multiInstanceVo.setAssignee(assignee); - multiInstanceVo.setAssigneeList(assigneeList); - return multiInstanceVo; - } - return null; - } - - /** - * 鑾峰彇褰撳墠娴佺▼鐘舵�� - * - * @param taskId 浠诲姟id - */ - public static String getBusinessStatusByTaskId(String taskId) { - HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().taskId(taskId).singleResult(); - HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(historicTaskInstance.getProcessInstanceId()).singleResult(); - return historicProcessInstance.getBusinessStatus(); - } - - /** - * 鑾峰彇褰撳墠娴佺▼鐘舵�� - * - * @param businessKey 涓氬姟id - */ - public static String getBusinessStatus(String businessKey) { - HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult(); - return historicProcessInstance.getBusinessStatus(); + return list; } /** * 鍙戦�佹秷鎭� * - * @param list 浠诲姟 - * @param name 娴佺▼鍚嶇О + * @param flowName 娴佺▼瀹氫箟鍚嶇О * @param messageType 娑堟伅绫诲瀷 * @param message 娑堟伅鍐呭锛屼负绌哄垯鍙戦�侀粯璁ら厤缃殑娑堟伅鍐呭 */ - public static void sendMessage(List<Task> list, String name, List<String> messageType, String message, UserService userService) { - Set<Long> userIds = new HashSet<>(); + public static void sendMessage(String flowName, Long instId, List<String> messageType, String message) { + List<UserDTO> userList = new ArrayList<>(); + List<FlowTask> list = FLW_TASK_SERVICE.selectByInstId(instId); if (StringUtils.isBlank(message)) { - message = "鏈夋柊鐨勩��" + name + "銆戝崟鎹凡缁忔彁浜よ嚦鎮ㄧ殑寰呭姙锛岃鎮ㄥ強鏃跺鐞嗐��"; + message = "鏈夋柊鐨勩��" + flowName + "銆戝崟鎹凡缁忔彁浜よ嚦鎮紝璇锋偍鍙婃椂澶勭悊銆�"; } - for (Task t : list) { - ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId(), userService); - if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) { - List<Long> userIdList = userService.selectUserIdsByRoleIds(taskParticipant.getGroupIds()); - if (CollUtil.isNotEmpty(userIdList)) { - userIds.addAll(userIdList); - } - } - List<Long> candidate = taskParticipant.getCandidate(); - if (CollUtil.isNotEmpty(candidate)) { - userIds.addAll(candidate); + for (Task task : list) { + List<UserDTO> users = FLW_TASK_SERVICE.currentTaskAllUser(task.getId()); + if (CollUtil.isNotEmpty(users)) { + userList.addAll(users); } } - if (CollUtil.isNotEmpty(userIds)) { - List<UserDTO> userList = userService.selectListByIds(new ArrayList<>(userIds)); + if (CollUtil.isNotEmpty(userList)) { for (String code : messageType) { MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code); if (ObjectUtil.isNotEmpty(messageTypeEnum)) { switch (messageTypeEnum) { case SYSTEM_MESSAGE: - WebSocketMessageDto dto = new WebSocketMessageDto(); - dto.setSessionKeys(new ArrayList<>(userIds)); + SseMessageDto dto = new SseMessageDto(); + dto.setUserIds(StreamUtils.toList(userList, UserDTO::getUserId).stream().distinct().collect(Collectors.toList())); dto.setMessage(message); - WebSocketUtils.publishMessage(dto); + SseMessageUtils.publishMessage(dto); break; case EMAIL_MESSAGE: MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), "鍗曟嵁瀹℃壒鎻愰啋", message); @@ -269,6 +132,8 @@ case SMS_MESSAGE: //todo 鐭俊鍙戦�� break; + default: + throw new IllegalStateException("Unexpected value: " + messageTypeEnum); } } } @@ -276,20 +141,66 @@ } /** - * 鏍规嵁浠诲姟id鏌ヨ 褰撳墠鐢ㄦ埛鐨勪换鍔★紝妫�鏌� 褰撳墠浜哄憳 鏄惁鏄 taskId 鐨勫姙鐞嗕汉 + * 椹冲洖 * - * @param taskId 浠诲姟id - * @return 缁撴灉 + * @param message 瀹℃壒鎰忚 + * @param instanceId 娴佺▼瀹炰緥id + * @param targetNodeCode 鐩爣鑺傜偣 + * @param flowStatus 娴佺▼鐘舵�� + * @param flowHisStatus 鑺傜偣鎿嶄綔鐘舵�� */ - public static Task getTaskByCurrentUser(String taskId) { - TaskQuery taskQuery = QueryUtils.taskQuery(); - taskQuery.taskId(taskId).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())); - - List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles(); - if (CollUtil.isNotEmpty(roles)) { - List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId())); - taskQuery.taskCandidateGroupIn(groupIds); + public static void backTask(String message, Long instanceId, String targetNodeCode, String flowStatus, String flowHisStatus) { + List<FlowTask> list = FLW_TASK_SERVICE.selectByInstId(instanceId); + if (CollUtil.isNotEmpty(list)) { + List<FlowTask> tasks = StreamUtils.filter(list, e -> e.getNodeCode().equals(targetNodeCode)); + if (list.size() == tasks.size()) { + return; + } } - return taskQuery.singleResult(); + for (FlowTask task : list) { + List<UserDTO> userList = FLW_TASK_SERVICE.currentTaskAllUser(task.getId()); + FlowParams flowParams = FlowParams.build(); + flowParams.nodeCode(targetNodeCode); + flowParams.message(message); + flowParams.skipType(SkipType.PASS.getKey()); + flowParams.flowStatus(flowStatus).hisStatus(flowHisStatus); + flowParams.ignore(true); + //瑙e喅浼氱娌℃潈闄愰棶棰� + if (CollUtil.isNotEmpty(userList)) { + flowParams.handler(userList.get(0).getUserId().toString()); + } + TASK_SERVICE.skip(task.getId(), flowParams); + } + //瑙e喅浼氱澶氫汉瀹℃壒闂 + backTask(message, instanceId, targetNodeCode, flowStatus, flowHisStatus); + } + + /** + * 鐢宠浜鸿妭鐐圭紪鐮� + * + * @param definitionId 娴佺▼瀹氫箟id + * @return 鐢宠浜鸿妭鐐圭紪鐮� + */ + public static String applyNodeCode(Long definitionId) { + //鑾峰彇宸插彂甯冪殑娴佺▼鑺傜偣 + List<FlowNode> flowNodes = FLOW_NODE_MAPPER.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, definitionId)); + AssertUtil.isTrue(CollUtil.isEmpty(flowNodes), ExceptionCons.NOT_PUBLISH_NODE); + Node startNode = flowNodes.stream().filter(t -> NodeType.isStart(t.getNodeType())).findFirst().orElse(null); + AssertUtil.isNull(startNode, ExceptionCons.LOST_START_NODE); + Node nextNode = NODE_SERVICE.getNextNode(definitionId, startNode.getNodeCode(), null, SkipType.PASS.getKey()); + return nextNode.getNodeCode(); + } + + /** + * 鍒犻櫎杩愯涓殑浠诲姟 + * + * @param taskIds 浠诲姟id + */ + public static void deleteRunTask(List<Long> taskIds) { + if (CollUtil.isEmpty(taskIds)) { + return; + } + USER_SERVICE.deleteByTaskIds(taskIds); + FLOW_TASK_MAPPER.deleteByIds(taskIds); } } -- Gitblit v1.9.3