¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |