From 69e3afc7707d467b758858b52d3784947f7a502b Mon Sep 17 00:00:00 2001 From: 疯狂的狮子Li <15040126243@163.com> Date: 星期一, 20 五月 2024 10:25:23 +0800 Subject: [PATCH] !538 ♥️发布 5.2.0-BETA 公测版本 Merge pull request !538 from 疯狂的狮子Li/dev --- ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java | 343 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 343 insertions(+), 0 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 new file mode 100644 index 0000000..f475f19 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java @@ -0,0 +1,343 @@ +package org.dromara.workflow.utils; + +import cn.hutool.core.bean.BeanUtil; +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 lombok.AccessLevel; +import lombok.NoArgsConstructor; +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.core.utils.reflect.ReflectUtils; +import org.dromara.common.mail.utils.MailUtils; +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.workflow.common.enums.BusinessStatusEnum; +import org.dromara.workflow.common.enums.MessageTypeEnum; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.ActHiProcinst; +import org.dromara.workflow.domain.ActHiTaskinst; +import org.dromara.workflow.domain.vo.MultiInstanceVo; +import org.dromara.workflow.domain.vo.ParticipantVo; +import org.dromara.workflow.domain.vo.ProcessInstanceVo; +import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd; +import org.dromara.workflow.mapper.ActHiTaskinstMapper; +import org.dromara.workflow.service.IActHiProcinstService; +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.history.HistoricTaskInstance; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; + +import java.util.*; + +import static org.dromara.workflow.common.constant.FlowConstant.PROCESS_INSTANCE_VO; + +/** + * 宸ヤ綔娴佸伐鍏� + * + * @author may + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class WorkflowUtils { + + private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); + private static final UserService USER_SERVICE = SpringUtils.getBean(UserService.class); + private static final IActHiProcinstService ACT_HI_PROCINST_SERVICE = SpringUtils.getBean(IActHiProcinstService.class); + private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class); + + /** + * 鍒涘缓涓�涓柊浠诲姟 + * + * @param currentTask 鍙傛暟 + */ + 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; + } + + /** + * 鎶勯�佷换鍔� + * + * @param parentTaskList 鐖剁骇浠诲姟 + * @param userIds 浜哄憳id + */ + 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); + } + } + 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) { + 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 = USER_SERVICE.selectUserIdsByRoleIds(groupIds); + if (CollUtil.isNotEmpty(userIds)) { + participantVo.setGroupIds(groupIds); + List<UserDTO> userList = USER_SERVICE.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 = USER_SERVICE.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 processInstanceId 娴佺▼瀹炰緥id + */ + public static String getBusinessStatus(String processInstanceId) { + HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult(); + return historicProcessInstance.getBusinessStatus(); + } + + /** + * 璁剧疆娴佺▼瀹炰緥瀵硅薄 + * + * @param obj 涓氬姟瀵硅薄 + * @param businessKey 涓氬姟id + */ + public static void setProcessInstanceVo(Object obj, String businessKey) { + if (StringUtils.isBlank(businessKey) || obj == null) { + return; + } + ActHiProcinst actHiProcinst = ACT_HI_PROCINST_SERVICE.selectByBusinessKey(businessKey); + if (actHiProcinst == null) { + ProcessInstanceVo processInstanceVo = new ProcessInstanceVo(); + processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus()); + ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo); + return; + } + ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo); + } + + /** + * 璁剧疆娴佺▼瀹炰緥瀵硅薄 + * + * @param obj 涓氬姟瀵硅薄 + * @param idList 涓氬姟id + * @param fieldName 涓婚敭灞炴�у悕绉� + */ + public static void setProcessInstanceListVo(Object obj, List<String> idList, String fieldName) { + if (CollUtil.isEmpty(idList) || obj == null) { + return; + } + List<ActHiProcinst> actHiProcinstList = ACT_HI_PROCINST_SERVICE.selectByBusinessKeyIn(idList); + if (obj instanceof Collection<?> collection) { + for (Object o : collection) { + String fieldValue = ReflectUtils.invokeGetter(o, fieldName).toString(); + if (CollUtil.isEmpty(actHiProcinstList)) { + ProcessInstanceVo processInstanceVo = new ProcessInstanceVo(); + processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus()); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo); + } else { + ActHiProcinst actHiProcinst = actHiProcinstList.stream().filter(e -> e.getBusinessKey().equals(fieldValue)).findFirst().orElse(null); + if (ObjectUtil.isNotEmpty(actHiProcinst)) { + ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo); + } else { + ProcessInstanceVo processInstanceVo = new ProcessInstanceVo(); + processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus()); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo); + } + } + } + } + } + + /** + * 鍙戦�佹秷鎭� + * + * @param list 浠诲姟 + * @param name 娴佺▼鍚嶇О + * @param messageType 娑堟伅绫诲瀷 + * @param message 娑堟伅鍐呭锛屼负绌哄垯鍙戦�侀粯璁ら厤缃殑娑堟伅鍐呭 + */ + public static void sendMessage(List<Task> list, String name, List<String> messageType, String message) { + Set<Long> userIds = new HashSet<>(); + if (StringUtils.isBlank(message)) { + message = "鏈夋柊鐨勩��" + name + "銆戝崟鎹凡缁忔彁浜よ嚦鎮ㄧ殑寰呭姙锛岃鎮ㄥ強鏃跺鐞嗐��"; + } + for (Task t : list) { + ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId()); + if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) { + List<Long> userIdList = USER_SERVICE.selectUserIdsByRoleIds(taskParticipant.getGroupIds()); + if (CollUtil.isNotEmpty(userIdList)) { + userIds.addAll(userIdList); + } + } + List<Long> candidate = taskParticipant.getCandidate(); + if (CollUtil.isNotEmpty(candidate)) { + userIds.addAll(candidate); + } + } + if (CollUtil.isNotEmpty(userIds)) { + List<UserDTO> userList = USER_SERVICE.selectListByIds(new ArrayList<>(userIds)); + 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)); + dto.setMessage(message); + WebSocketUtils.publishMessage(dto); + break; + case EMAIL_MESSAGE: + MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), "鍗曟嵁瀹℃壒鎻愰啋", message); + break; + case SMS_MESSAGE: + //todo 鐭俊鍙戦�� + break; + } + } + } + } + } +} -- Gitblit v1.9.3