package com.ycl.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.TypeReference; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ycl.common.base.Result; import com.ycl.common.constant.ProcessConstants; import com.ycl.common.core.domain.AjaxResult; import com.ycl.common.core.domain.entity.SysDept; import com.ycl.common.core.domain.entity.SysDictData; import com.ycl.common.core.domain.entity.SysRole; import com.ycl.common.core.domain.entity.SysUser; import com.ycl.common.enums.FlowComment; import com.ycl.common.enums.business.ProcessLogEventTypeEnum; import com.ycl.common.enums.business.TaskStatusEnum; import com.ycl.common.exception.CustomException; import com.ycl.common.utils.SecurityUtils; import com.ycl.domain.dto.FlowCommentDto; import com.ycl.domain.dto.FlowNextDto; import com.ycl.domain.dto.FlowTaskDto; import com.ycl.domain.dto.FlowViewerDto; import com.ycl.domain.entity.ProcessCoding; import com.ycl.domain.entity.ProcessLog; import com.ycl.domain.entity.ProjectProcess; import com.ycl.domain.entity.SysForm; import com.ycl.domain.form.EditFinishedTaskForm; import com.ycl.domain.json.RejectData; import com.ycl.domain.query.ProcessLogQuery; import com.ycl.domain.vo.*; import com.ycl.event.event.TaskLogEvent; import com.ycl.factory.FlowServiceFactory; import com.ycl.flow.CustomProcessDiagramGenerator; import com.ycl.flow.FindNextNodeUtil; import com.ycl.flow.FlowableUtils; import com.ycl.mapper.ProcessCodingMapper; import com.ycl.mapper.ProjectProcessMapper; import com.ycl.service.*; import com.ycl.service.common.TaskCommonService; import com.ycl.system.service.ISysDeptService; import com.ycl.system.service.ISysDictTypeService; import com.ycl.system.service.ISysRoleService; import com.ycl.system.service.ISysUserService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.FlowableObjectNotFoundException; import org.flowable.common.engine.impl.persistence.StrongUuidGenerator; import org.flowable.engine.ProcessEngineConfiguration; import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.impl.cmd.AddMultiInstanceExecutionCmd; import org.flowable.engine.impl.cmd.DeleteMultiInstanceExecutionCmd; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.task.Comment; import org.flowable.identitylink.api.history.HistoricIdentityLink; import org.flowable.image.ProcessDiagramGenerator; import org.flowable.task.api.DelegationState; import org.flowable.task.api.Task; import org.flowable.task.api.TaskQuery; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.springframework.beans.BeanUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.*; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import static com.ycl.common.constant.ProcessOverTimeConstants.RED; import static com.ycl.common.constant.ProcessOverTimeConstants.YELLOW; /** * @author Tony * @date 2021-04-03 **/ @Service @RequiredArgsConstructor @Slf4j public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTaskService { private final ISysUserService sysUserService; private final ISysRoleService sysRoleService; private final ISysDeptService sysDeptService; private final ISysDictTypeService sysDictDService; private final ISysDeployFormService sysInstanceFormService; private final ISysFormService sysFormService; private final TaskCommonService taskCommonService; private final ProcessCodingMapper processCodingMapper; private final ProcessLogService processLogService; private final ApplicationEventPublisher publisher; private final ProjectProcessMapper projectProcessMapper; /** * 完成审核任务 * * @param taskVo 请求实体参数 */ @Transactional(rollbackFor = Exception.class) @Override public AjaxResult complete(FlowTaskVo taskVo) { Task task = taskService.createTaskQuery().taskId(taskVo.getTaskId()).singleResult(); if (Objects.isNull(task)) { return AjaxResult.error("任务不存在"); } if (DelegationState.PENDING.equals(task.getDelegationState())) { taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.DELEGATE.getType(), taskVo.getComment()); taskService.resolveTask(taskVo.getTaskId(), taskVo.getVariables()); } else { taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.NORMAL.getType(), taskVo.getComment()); Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); taskService.setAssignee(taskVo.getTaskId(), userId.toString()); taskService.complete(taskVo.getTaskId(), taskVo.getVariables()); } return AjaxResult.success(); } /** * 完成表单提交任务/普通任务 * * @param taskId 任务id * @param variables 表单数据 * @param addLog * @return */ @Override @Transactional(rollbackFor = Exception.class) public AjaxResult completeSubmitForm(String taskId, Map variables, Boolean addLog) { Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if (Objects.isNull(task)) { return AjaxResult.error("任务不存在"); } ProjectProcess projectProcess = new LambdaQueryChainWrapper<>(projectProcessMapper) .eq(ProjectProcess::getProcessInsId, task.getProcessInstanceId()) .eq(ProjectProcess::getProcessDefId, task.getProcessDefinitionId()) .one(); if (Objects.isNull(projectProcess)) { return AjaxResult.error("项目流程未绑定"); } // 查出字典中需要注入的字段信息 List dictList = sysDictDService.selectDictDataByType("flow_variables").stream().map(SysDictData::getDictValue).collect(Collectors.toList()); Map newV = new HashMap<>(2); if (!org.springframework.util.CollectionUtils.isEmpty(variables)) { for (String key : variables.keySet()) { newV.put(task.getTaskDefinitionKey() + "&" + key, variables.get(key)); // 字典里有就不做处理 if (!CollectionUtils.isEmpty(dictList) && dictList.contains(key)) { newV.put(key,variables.get(key)); } } } taskService.addComment(taskId, task.getProcessInstanceId(), FlowComment.SUBMIT.getType(), "完成提交"); if (DelegationState.PENDING.equals(task.getDelegationState())) { taskService.resolveTask(taskId, newV); } else { // 先让当前用户认领这个任务 taskService.claim(taskId, SecurityUtils.getUserId() + ""); taskService.complete(taskId, newV); } // 保存日志 if (addLog) { publisher.publishEvent(new TaskLogEvent(this, null, SecurityUtils.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), taskId, task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.FINISHED, null)); } return AjaxResult.success("提交成功"); } /** * 容缺补交 * * @param taskId 任务id * @param variables 表单数据 * @param addLog * @return */ @Override @Transactional(rollbackFor = Exception.class) public AjaxResult waitCompleteSubmitForm(String taskId, Map variables, Boolean addLog) throws IOException { List hisTasks = historyService.createHistoricTaskInstanceQuery().taskId(taskId).orderByHistoricTaskInstanceStartTime().desc().list(); if (CollectionUtils.isEmpty(hisTasks) || Objects.isNull(hisTasks.get(0))) { return AjaxResult.error("任务不存在"); } HistoricTaskInstance task = hisTasks.get(0); ProjectProcess projectProcess = new LambdaQueryChainWrapper<>(projectProcessMapper) .eq(ProjectProcess::getProcessInsId, task.getProcessInstanceId()) .eq(ProjectProcess::getProcessDefId, task.getProcessDefinitionId()) .one(); if (Objects.isNull(projectProcess)) { return AjaxResult.error("项目流程未绑定"); } // 查出字典中需要注入的字段信息 List dictList = sysDictDService.selectDictDataByType("flow_variables").stream().map(SysDictData::getDictValue).collect(Collectors.toList()); Map newV = new HashMap<>(2); if (!org.springframework.util.CollectionUtils.isEmpty(variables)) { for (String key : variables.keySet()) { newV.put(task.getTaskDefinitionKey() + "&" + key, variables.get(key)); // 字典里有就不做处理 if (!CollectionUtils.isEmpty(dictList) && dictList.contains(key)) { newV.put(key,variables.get(key)); } } } ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); Date now = new Date(); for (String key : newV.keySet()) { FlowableVarVO var = null; if (Objects.isNull(processInstance)) { // 查询历史流程变量 var = projectProcessMapper.getHisByteId(projectProcess.getProcessInsId(), key); } else { // 查询运行时流程变量 var = projectProcessMapper.getRuByteId(projectProcess.getProcessInsId(), key); } if (Objects.isNull(var)) { // 没有这个变量新增即可 FlowableVarVO run = new FlowableVarVO(); FlowableVarVO v = new FlowableVarVO(); v.setNAME_(key); v.setPROC_INST_ID_(task.getProcessInstanceId()); v.setEXECUTION_ID_(task.getProcessInstanceId()); v.setCREATE_TIME_(now); v.setLAST_UPDATED_TIME_(now); v.setID_(new StrongUuidGenerator().getNextId()); BeanUtils.copyProperties(v, run); run.setID_(new StrongUuidGenerator().getNextId()); if (newV.get(key) instanceof String) { v.setVAR_TYPE_("string"); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("string"); run.setTEXT_((String) newV.get(key)); } else if (newV.get(key) instanceof Integer) { v.setVAR_TYPE_("integer"); v.setLONG_((Long) newV.get(key)); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("integer"); run.setLONG_((Long) newV.get(key)); run.setTEXT_((String) newV.get(key)); } else if (newV.get(key) instanceof Long) { v.setVAR_TYPE_("long"); v.setLONG_((Long) newV.get(key)); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("long"); run.setLONG_((Long) newV.get(key)); run.setTEXT_((String) newV.get(key)); } else if (newV.get(key) instanceof Boolean) { v.setVAR_TYPE_("boolean"); v.setLONG_((Long) newV.get(key)); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("boolean"); run.setLONG_((Long) newV.get(key)); run.setTEXT_((String) newV.get(key)); } else { // 其它类型的表单数据:如图片、文件单独存表的。历史、运行中的流程需各存一份 v.setVAR_TYPE_("serializable"); v.setBYTEARRAY_ID_(new StrongUuidGenerator().getNextId()); projectProcessMapper.insertByteArray(v.getBYTEARRAY_ID_(), 1, "hist.var-" + key, newV.get(key)); run.setVAR_TYPE_("serializable"); run.setBYTEARRAY_ID_(new StrongUuidGenerator().getNextId()); projectProcessMapper.insertByteArray(run.getBYTEARRAY_ID_(), 1, "var-" + key, newV.get(key)); } projectProcessMapper.insertHisFlowableVar(v); projectProcessMapper.insertRunFlowableVar(run); } } // 保存日志 publisher.publishEvent(new TaskLogEvent(this, null, SecurityUtils.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), taskId, task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.FINISHED, null)); return AjaxResult.success("提交成功"); } // 将对象转换为 byte[] public static byte[] objectToBytes(Object obj) throws IOException { if (Objects.isNull(obj)) { return null; } try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) { oos.writeObject(obj); // 序列化对象 oos.flush(); return bos.toByteArray(); // 返回字节数组 } } /** * 驳回任务 * * @param flowTaskVo */ @Override @Transactional(rollbackFor = Exception.class) public void taskReject(FlowTaskVo flowTaskVo) { if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) { throw new CustomException("任务处于挂起状态!"); } // 当前任务 task Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); ProjectProcess projectProcess = new LambdaQueryChainWrapper<>(projectProcessMapper) .eq(ProjectProcess::getProcessInsId, task.getProcessInstanceId()) .eq(ProjectProcess::getProcessDefId, task.getProcessDefinitionId()) .one(); if (Objects.isNull(projectProcess)) { throw new CustomException("项目流程未绑定"); } // 获取流程定义信息 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); // 获取所有节点信息 Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); // 获取全部节点列表,包含子节点 Collection allElements = FlowableUtils.getAllElements(process.getFlowElements(), null); // 获取当前任务节点元素 FlowElement source = null; if (allElements != null) { for (FlowElement flowElement : allElements) { // 类型为用户节点 if (flowElement.getId().equals(task.getTaskDefinitionKey())) { // 获取节点信息 source = flowElement; } } } // 目的获取所有跳转到的节点 targetIds // 获取当前节点的所有父级用户任务节点 // 深度优先算法思想:延边迭代深入 List parentUserTaskList = FlowableUtils.iteratorFindParentUserTasks(source, null, null); if (parentUserTaskList == null || parentUserTaskList.size() == 0) { throw new CustomException("当前节点为初始任务节点,不能驳回"); } // 获取活动 ID 即节点 Key List parentUserTaskKeyList = new ArrayList<>(); parentUserTaskList.forEach(item -> parentUserTaskKeyList.add(item.getId())); // 获取全部历史节点活动实例,即已经走过的节点历史,数据采用开始时间升序 List historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceStartTime().asc().list(); // 数据清洗,将回滚导致的脏数据清洗掉 List lastHistoricTaskInstanceList = FlowableUtils.historicTaskInstanceClean(allElements, historicTaskInstanceList); // 此时历史任务实例为倒序,获取最后走的节点 List targetIds = new ArrayList<>(); // 循环结束标识,遇到当前目标节点的次数 int number = 0; StringBuilder parentHistoricTaskKey = new StringBuilder(); for (String historicTaskInstanceKey : lastHistoricTaskInstanceList) { // 当会签时候会出现特殊的,连续都是同一个节点历史数据的情况,这种时候跳过 if (parentHistoricTaskKey.toString().equals(historicTaskInstanceKey)) { continue; } parentHistoricTaskKey = new StringBuilder(historicTaskInstanceKey); if (historicTaskInstanceKey.equals(task.getTaskDefinitionKey())) { number++; } // 在数据清洗后,历史节点就是唯一一条从起始到当前节点的历史记录,理论上每个点只会出现一次 // 在流程中如果出现循环,那么每次循环中间的点也只会出现一次,再出现就是下次循环 // number == 1,第一次遇到当前节点 // number == 2,第二次遇到,代表最后一次的循环范围 if (number == 2) { break; } // 如果当前历史节点,属于父级的节点,说明最后一次经过了这个点,需要退回这个点 if (parentUserTaskKeyList.contains(historicTaskInstanceKey)) { targetIds.add(historicTaskInstanceKey); } } // 目的获取所有需要被跳转的节点 currentIds // 取其中一个父级任务,因为后续要么存在公共网关,要么就是串行公共线路 UserTask oneUserTask = parentUserTaskList.get(0); // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务 List runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); List runTaskKeyList = new ArrayList<>(); runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey())); // 需驳回任务列表 List currentIds = new ArrayList<>(); // 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务 List currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(oneUserTask, runTaskKeyList, null, null); currentUserTaskList.forEach(item -> currentIds.add(item.getId())); // 规定:并行网关之前节点必须需存在唯一用户任务节点,如果出现多个任务节点,则并行网关节点默认为结束节点,原因为不考虑多对多情况 if (targetIds.size() > 1 && currentIds.size() > 1) { throw new CustomException("任务出现多对多情况,无法撤回"); } // 循环获取那些需要被撤回的节点的ID,用来设置驳回原因 List currentTaskIds = new ArrayList<>(); currentIds.forEach(currentId -> runTaskList.forEach(runTask -> { if (currentId.equals(runTask.getTaskDefinitionKey())) { currentTaskIds.add(runTask.getId()); } })); // 设置驳回意见 currentTaskIds.forEach(item -> taskService.addComment(item, task.getProcessInstanceId(), FlowComment.REJECT.getType(), flowTaskVo.getComment())); try { // 如果父级任务多于 1 个,说明当前节点不是并行节点,原因为不考虑多对多情况 if (targetIds.size() > 1) { // 删除被驳回任务的所有日志 for (String targetId : targetIds) { List rejectHisTaskList = historyService.createHistoricTaskInstanceQuery() .taskDefinitionKey(targetId) .processInstanceId(projectProcess.getProcessInsId()) .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isNotEmpty(rejectHisTaskList)) { new LambdaUpdateChainWrapper<>(processLogService.getBaseMapper()) .eq(ProcessLog::getTaskId, rejectHisTaskList.get(0).getId()) .eq(ProcessLog::getProcessInsId, projectProcess.getProcessInsId()) .remove(); } } // 1 对 多任务跳转,currentIds 当前节点(1),targetIds 跳转到的节点(多) runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()). moveSingleActivityIdToActivityIds(currentIds.get(0), targetIds).changeState(); } // 如果父级任务只有一个,因此当前任务可能为网关中的任务 if (targetIds.size() == 1) { // 删除被驳回任务的所有日志 List rejectHisTaskList = historyService.createHistoricTaskInstanceQuery() .taskDefinitionKey(targetIds.get(0)) .processInstanceId(projectProcess.getProcessInsId()) .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isNotEmpty(rejectHisTaskList)) { new LambdaUpdateChainWrapper<>(processLogService.getBaseMapper()) .eq(ProcessLog::getTaskId, rejectHisTaskList.get(0).getId()) .eq(ProcessLog::getProcessInsId, projectProcess.getProcessInsId()) .remove(); } // 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetIds.get(0) 跳转到的节点(1) runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) .moveActivityIdsToSingleActivityId(currentIds, targetIds.get(0)).changeState(); } historyService.deleteHistoricTaskInstance(flowTaskVo.getTaskId()); } catch (FlowableObjectNotFoundException e) { throw new CustomException("未找到流程实例,流程可能已发生变化"); } catch (FlowableException e) { throw new CustomException("无法取消或开始活动"); } // 保存日志 publisher.publishEvent(new TaskLogEvent(this, null, SecurityUtils.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), flowTaskVo.getTaskId(), task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.REJECT, new RejectData(flowTaskVo.getComment()))); } /** * 退回任务 * * @param flowTaskVo 请求实体参数 */ @Transactional(rollbackFor = Exception.class) @Override public void taskReturn(FlowTaskVo flowTaskVo) { if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) { throw new CustomException("任务处于挂起状态"); } // 当前任务 task Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); // 获取流程定义信息 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); // 获取所有节点信息 Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); // 获取全部节点列表,包含子节点 Collection allElements = FlowableUtils.getAllElements(process.getFlowElements(), null); // 获取当前任务节点元素 FlowElement source = null; // 获取跳转的节点元素 FlowElement target = null; if (allElements != null) { for (FlowElement flowElement : allElements) { // 当前任务节点元素 if (flowElement.getId().equals(task.getTaskDefinitionKey())) { source = flowElement; } // 跳转的节点元素 if (flowElement.getId().equals(flowTaskVo.getTargetKey())) { target = flowElement; } } } // 从当前节点向前扫描 // 如果存在路线上不存在目标节点,说明目标节点是在网关上或非同一路线上,不可跳转 // 否则目标节点相对于当前节点,属于串行 Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, flowTaskVo.getTargetKey(), null, null); if (!isSequential) { throw new CustomException("当前节点相对于目标节点,不属于串行关系,无法回退"); } // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务 List runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); List runTaskKeyList = new ArrayList<>(); runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey())); // 需退回任务列表 List currentIds = new ArrayList<>(); // 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务 List currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null); currentUserTaskList.forEach(item -> currentIds.add(item.getId())); // 循环获取那些需要被撤回的节点的ID,用来设置驳回原因 List currentTaskIds = new ArrayList<>(); currentIds.forEach(currentId -> runTaskList.forEach(runTask -> { if (currentId.equals(runTask.getTaskDefinitionKey())) { currentTaskIds.add(runTask.getId()); } })); // 设置回退意见 currentTaskIds.forEach(currentTaskId -> taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), flowTaskVo.getComment())); try { // 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1) runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) .moveActivityIdsToSingleActivityId(currentIds, flowTaskVo.getTargetKey()).changeState(); } catch (FlowableObjectNotFoundException e) { throw new CustomException("未找到流程实例,流程可能已发生变化"); } catch (FlowableException e) { throw new CustomException("无法取消或开始活动"); } } /** * 获取所有可回退的节点 * * @param flowTaskVo * @return */ @Override public AjaxResult findReturnTaskList(FlowTaskVo flowTaskVo) { // 当前任务 task Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); // 获取流程定义信息 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); // 获取所有节点信息,暂不考虑子流程情况 Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); Collection flowElements = process.getFlowElements(); // 获取当前任务节点元素 UserTask source = null; if (flowElements != null) { for (FlowElement flowElement : flowElements) { // 类型为用户节点 if (flowElement.getId().equals(task.getTaskDefinitionKey())) { source = (UserTask) flowElement; } } } // 获取节点的所有路线 List> roads = FlowableUtils.findRoad(source, null, null, null); // 可回退的节点列表 List userTaskList = new ArrayList<>(); for (List road : roads) { if (userTaskList.size() == 0) { // 还没有可回退节点直接添加 userTaskList = road; } else { // 如果已有回退节点,则比对取交集部分 userTaskList.retainAll(road); } } return AjaxResult.success(userTaskList); } /** * 删除任务 * * @param flowTaskVo 请求实体参数 */ @Override public void deleteTask(FlowTaskVo flowTaskVo) { // todo 待确认删除任务是物理删除任务 还是逻辑删除,让这个任务直接通过? taskService.deleteTask(flowTaskVo.getTaskId(), flowTaskVo.getComment()); } /** * 认领/签收任务 * 认领以后,这个用户就会成为任务的执行人,任务会从其他成员的任务列表中消失 * * @param flowTaskVo 请求实体参数 */ @Override @Transactional(rollbackFor = Exception.class) public void claim(FlowTaskVo flowTaskVo) { taskService.claim(flowTaskVo.getTaskId(), flowTaskVo.getUserId()); } /** * 取消认领/签收任务 * * @param flowTaskVo 请求实体参数 */ @Override @Transactional(rollbackFor = Exception.class) public void unClaim(FlowTaskVo flowTaskVo) { taskService.unclaim(flowTaskVo.getTaskId()); } /** * 委派任务 * 任务委派只是委派人将当前的任务交给被委派人进行审批,处理任务后又重新回到委派人身上。 * * @param flowTaskVo 请求实体参数 */ @Override @Transactional(rollbackFor = Exception.class) public void delegateTask(FlowTaskVo flowTaskVo) { taskService.delegateTask(flowTaskVo.getTaskId(), flowTaskVo.getAssignee()); } /** * 任务归还 * 被委派人完成任务之后,将任务归还委派人 * * @param flowTaskVo 请求实体参数 */ @Override @Transactional(rollbackFor = Exception.class) public void resolveTask(FlowTaskVo flowTaskVo) { taskService.resolveTask(flowTaskVo.getTaskId()); } /** * 转办任务 * 直接将办理人换成别人,这时任务的拥有者不再是转办人 * * @param flowTaskVo 请求实体参数 */ @Override @Transactional(rollbackFor = Exception.class) public void assignTask(FlowTaskVo flowTaskVo) { // 直接转派就可以覆盖掉之前的 taskService.setAssignee(flowTaskVo.getTaskId(), flowTaskVo.getAssignee()); // // 删除指派人重新指派 // taskService.deleteCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee()); // taskService.addCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee()); // // 如果要查询转给他人处理的任务,可以同时将OWNER进行设置: // taskService.setOwner(flowTaskVo.getTaskId(), flowTaskVo.getAssignee()); } /** * 多实例加签 * act_ru_task、act_ru_identitylink各生成一条记录 * * @param flowTaskVo */ @Override public void addMultiInstanceExecution(FlowTaskVo flowTaskVo) { managementService.executeCommand(new AddMultiInstanceExecutionCmd(flowTaskVo.getDefId(), flowTaskVo.getInstanceId(), flowTaskVo.getVariables())); } /** * 多实例减签 * act_ru_task减1、act_ru_identitylink不变 * * @param flowTaskVo */ @Override public void deleteMultiInstanceExecution(FlowTaskVo flowTaskVo) { managementService.executeCommand(new DeleteMultiInstanceExecutionCmd(flowTaskVo.getCurrentChildExecutionId(), flowTaskVo.getFlag())); } /** * 我发起的流程 * * @param queryVo 请求参数 * @return */ @Override public AjaxResult myProcess(FlowQueryVo queryVo) { Page page = new Page<>(); Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery() .startedBy(userId.toString()) .orderByProcessInstanceStartTime() .desc(); List historicProcessInstances = historicProcessInstanceQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize()); page.setTotal(historicProcessInstanceQuery.count()); List flowList = new ArrayList<>(); for (HistoricProcessInstance hisIns : historicProcessInstances) { FlowTaskDto flowTask = new FlowTaskDto(); flowTask.setCreateTime(hisIns.getStartTime()); flowTask.setFinishTime(hisIns.getEndTime()); flowTask.setProcInsId(hisIns.getId()); // 计算耗时 if (Objects.nonNull(hisIns.getEndTime())) { long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime(); flowTask.setDuration(getDate(time)); } else { long time = System.currentTimeMillis() - hisIns.getStartTime().getTime(); flowTask.setDuration(getDate(time)); } // 流程定义信息 ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() .processDefinitionId(hisIns.getProcessDefinitionId()) .singleResult(); flowTask.setDeployId(pd.getDeploymentId()); flowTask.setProcDefName(pd.getName()); flowTask.setProcDefVersion(pd.getVersion()); flowTask.setCategory(pd.getCategory()); flowTask.setProcDefVersion(pd.getVersion()); // 当前所处流程 List taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list(); if (CollectionUtils.isNotEmpty(taskList)) { flowTask.setTaskId(taskList.get(0).getId()); flowTask.setTaskName(taskList.get(0).getName()); if (StringUtils.isNotBlank(taskList.get(0).getAssignee())) { // 当前任务节点办理人信息 SysUser sysUser = sysUserService.selectUserById(Long.parseLong(taskList.get(0).getAssignee())); if (Objects.nonNull(sysUser)) { flowTask.setAssigneeId(sysUser.getUserId()); flowTask.setAssigneeName(sysUser.getNickName()); flowTask.setAssigneeDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); } } } else { List historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list(); flowTask.setTaskId(historicTaskInstance.get(0).getId()); flowTask.setTaskName(historicTaskInstance.get(0).getName()); if (StringUtils.isNotBlank(historicTaskInstance.get(0).getAssignee())) { // 当前任务节点办理人信息 SysUser sysUser = sysUserService.selectUserById(Long.parseLong(historicTaskInstance.get(0).getAssignee())); if (Objects.nonNull(sysUser)) { flowTask.setAssigneeId(sysUser.getUserId()); flowTask.setAssigneeName(sysUser.getNickName()); flowTask.setAssigneeDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); } } } flowList.add(flowTask); } page.setRecords(flowList); return AjaxResult.success(page); } /** * 取消申请 * 目前实现方式: 直接将当前流程变更为已完成 * * @param flowTaskVo * @return */ @Override public AjaxResult stopProcess(FlowTaskVo flowTaskVo) { List task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list(); if (CollectionUtils.isEmpty(task)) { throw new CustomException("流程未启动或已执行完成,取消申请失败"); } // 获取当前流程实例 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId(flowTaskVo.getInstanceId()) .singleResult(); BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()); if (Objects.nonNull(bpmnModel)) { Process process = bpmnModel.getMainProcess(); List endNodes = process.findFlowElementsOfType(EndEvent.class, false); if (CollectionUtils.isNotEmpty(endNodes)) { // TODO 取消流程为什么要设置流程发起人? // SysUser loginUser = SecurityUtils.getLoginUser().getUser(); // Authentication.setAuthenticatedUserId(loginUser.getUserId().toString()); // taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(), // StringUtils.isBlank(flowTaskVo.getComment()) ? "取消申请" : flowTaskVo.getComment()); // 获取当前流程最后一个节点 String endId = endNodes.get(0).getId(); List executions = runtimeService.createExecutionQuery() .parentId(processInstance.getProcessInstanceId()).list(); List executionIds = new ArrayList<>(); executions.forEach(execution -> executionIds.add(execution.getId())); // 变更流程为已结束状态 runtimeService.createChangeActivityStateBuilder() .moveExecutionsToSingleActivityId(executionIds, endId).changeState(); } } return AjaxResult.success(); } /** * 撤回流程 目前存在错误 * * @param flowTaskVo * @return */ @Override public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) { Task task = taskService.createTaskQuery() .processInstanceId(flowTaskVo.getInstanceId()) .singleResult(); if (task == null) { throw new CustomException("流程未启动或已执行完成,无法撤回"); } SysUser loginUser = SecurityUtils.getLoginUser().getUser(); List htiList = historyService.createHistoricTaskInstanceQuery() .processInstanceId(task.getProcessInstanceId()) .orderByTaskCreateTime() .asc() .list(); String myTaskId = null; for (HistoricTaskInstance hti : htiList) { if (loginUser.getUserId().toString().equals(hti.getAssignee())) { myTaskId = hti.getId(); break; } } if (null == myTaskId) { throw new CustomException("该任务非当前用户提交,无法撤回"); } List historicTaskInstanceList = historyService .createHistoricTaskInstanceQuery() .processInstanceId(task.getProcessInstanceId()) .orderByHistoricTaskInstanceStartTime() .asc() .list(); Iterator it = historicTaskInstanceList.iterator(); //循环节点,获取当前节点的上一节点的key String tarKey = ""; while (it.hasNext()) { HistoricTaskInstance his = it.next(); if (!task.getTaskDefinitionKey().equals(his.getTaskDefinitionKey())) { tarKey = his.getTaskDefinitionKey(); } } // 跳转节点 runtimeService.createChangeActivityStateBuilder() .processInstanceId(flowTaskVo.getInstanceId()) .moveActivityIdTo(task.getTaskDefinitionKey(), tarKey) .changeState(); return AjaxResult.success(); } /** * 代办任务列表 * * @param queryVo 请求参数 * @return */ @Override public AjaxResult todoList(FlowQueryVo queryVo) { Page page = new Page<>(); // 只查看自己的数据 SysUser sysUser = SecurityUtils.getLoginUser().getUser(); TaskQuery taskQuery = taskService.createTaskQuery() .active() .includeProcessVariables() .taskCandidateGroupIn(sysUser.getRoles().stream().map(role -> role.getRoleId().toString()).collect(Collectors.toList())) .taskCandidateOrAssigned(sysUser.getUserId().toString()) .orderByTaskCreateTime().desc(); // TODO 传入名称查询不到数据? if (StringUtils.isNotBlank(queryVo.getName())) { taskQuery.processDefinitionNameLike(queryVo.getName()); } page.setTotal(taskQuery.count()); List taskList = taskQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize()); List flowList = new ArrayList<>(); for (Task task : taskList) { FlowTaskDto flowTask = new FlowTaskDto(); // 当前流程信息 flowTask.setTaskId(task.getId()); flowTask.setTaskDefKey(task.getTaskDefinitionKey()); flowTask.setCreateTime(task.getCreateTime()); flowTask.setProcDefId(task.getProcessDefinitionId()); flowTask.setExecutionId(task.getExecutionId()); flowTask.setTaskName(task.getName()); // 流程定义信息 ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() .processDefinitionId(task.getProcessDefinitionId()) .singleResult(); flowTask.setDeployId(pd.getDeploymentId()); flowTask.setProcDefName(pd.getName()); flowTask.setProcDefVersion(pd.getVersion()); flowTask.setProcInsId(task.getProcessInstanceId()); // 流程发起人信息 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(task.getProcessInstanceId()) .singleResult(); SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); flowTask.setStartUserId(startUser.getUserId().toString()); flowTask.setStartUserName(startUser.getNickName()); flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : ""); flowList.add(flowTask); } page.setRecords(flowList); return AjaxResult.success(page); } /** * 已办任务列表 * * @param queryVo 请求参数 * @return */ @Override public AjaxResult finishedList(FlowQueryVo queryVo) { Page page = new Page<>(); Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery() .includeProcessVariables() .finished() .taskAssignee(userId.toString()) .orderByHistoricTaskInstanceEndTime() .desc(); List historicTaskInstanceList = taskInstanceQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize()); List hisTaskList = new ArrayList<>(); for (HistoricTaskInstance histTask : historicTaskInstanceList) { FlowTaskDto flowTask = new FlowTaskDto(); // 当前流程信息 flowTask.setTaskId(histTask.getId()); // 审批人员信息 flowTask.setCreateTime(histTask.getCreateTime()); flowTask.setFinishTime(histTask.getEndTime()); flowTask.setDuration(getDate(histTask.getDurationInMillis())); flowTask.setProcDefId(histTask.getProcessDefinitionId()); flowTask.setTaskDefKey(histTask.getTaskDefinitionKey()); flowTask.setTaskName(histTask.getName()); // 流程定义信息 ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() .processDefinitionId(histTask.getProcessDefinitionId()) .singleResult(); flowTask.setDeployId(pd.getDeploymentId()); flowTask.setProcDefName(pd.getName()); flowTask.setProcDefVersion(pd.getVersion()); flowTask.setProcInsId(histTask.getProcessInstanceId()); flowTask.setHisProcInsId(histTask.getProcessInstanceId()); // 流程发起人信息 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(histTask.getProcessInstanceId()) .singleResult(); SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); flowTask.setStartUserId(startUser.getNickName()); flowTask.setStartUserName(startUser.getNickName()); flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : ""); hisTaskList.add(flowTask); } page.setTotal(taskInstanceQuery.count()); page.setRecords(hisTaskList); return AjaxResult.success(page); } private static Predicate distinctByKey(Function keyExtractor) { Set seen = ConcurrentHashMap.newKeySet(); return t -> seen.add(keyExtractor.apply(t)); } /** * 流程历史流转记录 * * @param procInsId 流程实例Id * @return */ @Override public AjaxResult flowRecord(String procInsId) { Map map = new HashMap(); if (StringUtils.isNotBlank(procInsId)) { List list = historyService .createHistoricTaskInstanceQuery() .processInstanceId(procInsId) .orderByHistoricTaskInstanceStartTime() .desc().list(); //扩展 获取这个流程实例的监控信息 key:TaskId value:实体类 Map processCodingMap = processCodingMapper.selectList(new QueryWrapper().eq("process_ins_id", procInsId)) .stream() .collect(Collectors.toMap(ProcessCoding::getTaskId, Function.identity())); List hisFlowList = new ArrayList<>(); for (HistoricTaskInstance histIns : list) { // 展示开始节点 // if ("startEvent".equals(histIns.getActivityType())) { // FlowTaskDto flowTask = new FlowTaskDto(); // // 流程发起人信息 // HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() // .processInstanceId(histIns.getProcessInstanceId()) // .singleResult(); // SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); // flowTask.setTaskName(startUser.getNickName() + "(" + startUser.getDept().getDeptName() + ")发起申请"); // flowTask.setFinishTime(histIns.getEndTime()); // hisFlowList.add(flowTask); // } else if ("endEvent".equals(histIns.getActivityType())) { // FlowTaskDto flowTask = new FlowTaskDto(); // flowTask.setTaskName(StringUtils.isNotBlank(histIns.getActivityName()) ? histIns.getActivityName() : "结束"); // flowTask.setFinishTime(histIns.getEndTime()); // hisFlowList.add(flowTask); // } else if (StringUtils.isNotBlank(histIns.getId())) { FlowTaskDto flowTask = new FlowTaskDto(); flowTask.setTaskId(histIns.getId()); flowTask.setTaskName(histIns.getName()); flowTask.setCreateTime(histIns.getStartTime()); flowTask.setFinishTime(histIns.getEndTime()); if (StringUtils.isNotBlank(histIns.getAssignee())) { SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee())); flowTask.setAssigneeId(sysUser.getUserId()); flowTask.setAssigneeName(sysUser.getNickName()); flowTask.setDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); } // 展示审批人员 List linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getId()); StringBuilder stringBuilder = new StringBuilder(); for (HistoricIdentityLink identityLink : linksForTask) { // 获选人,候选组/角色(多个) if ("candidate".equals(identityLink.getType())) { if (StringUtils.isNotBlank(identityLink.getUserId())) { SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId())); stringBuilder.append(sysUser.getNickName()).append(","); } if (StringUtils.isNotBlank(identityLink.getGroupId())) { if (identityLink.getGroupId().contains("dept")) { SysDept sysDept = sysDeptService.selectDeptById(Long.parseLong(identityLink.getGroupId().split(":")[1])); stringBuilder.append(sysDept.getDeptName()).append(","); } else { SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); stringBuilder.append(sysRole.getRoleName()).append(","); } } } } if (StringUtils.isNotBlank(stringBuilder)) { flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); } flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis())); //扩展 判断是否超时 ProcessCoding processCoding = processCodingMap.get(histIns.getId()); if (processCoding != null) { //通过耗时判断是否是代办节点 //如果任务是代办节点 if (flowTask.getDuration() == null) { if (RED.equals(processCoding.getStatus()) || YELLOW.equals(processCoding.getStatus())) { flowTask.setOvertime(processCoding.getStatus()); } } else { //如果任务节点属于历史节点 if (RED.equals(processCoding.getStatus())) { flowTask.setOvertime(processCoding.getStatus()); } ; } } // 获取意见评论内容 List commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId()); commentList.forEach(comment -> { if (histIns.getId().equals(comment.getTaskId())) { flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build()); } }); hisFlowList.add(flowTask); } } map.put("flowList", hisFlowList); } // // 第一次申请获取初始化表单 // if (StringUtils.isNotBlank(deployId)) { // SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId); // if (Objects.isNull(sysForm)) { // return AjaxResult.error("请先配置流程表单"); // } // map.put("formData", JSONObject.parseObject(sysForm.getFormContent())); // } return AjaxResult.success(map); } /** * 根据任务ID查询挂载的表单信息 * * @param taskId 任务Id * @return */ @Override public AjaxResult getTaskForm(String taskId) { Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(task.getFormKey())); return AjaxResult.success(sysForm.getFormContent()); } /** * 获取流程过程图 * * @param processId * @return */ @Override public InputStream diagram(String processId) { String processDefinitionId; // 获取当前的流程实例 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); // 如果流程已经结束,则得到结束节点 if (Objects.isNull(processInstance)) { HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult(); processDefinitionId = pi.getProcessDefinitionId(); } else {// 如果流程没有结束,则取当前活动节点 // 根据流程实例ID获得当前处于活动状态的ActivityId合集 ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); processDefinitionId = pi.getProcessDefinitionId(); } // 获得活动的节点 List highLightedFlowList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list(); List highLightedFlows = new ArrayList<>(); List highLightedNodes = new ArrayList<>(); //高亮线 for (HistoricActivityInstance tempActivity : highLightedFlowList) { if ("sequenceFlow".equals(tempActivity.getActivityType())) { //高亮线 highLightedFlows.add(tempActivity.getActivityId()); } else { //高亮节点 highLightedNodes.add(tempActivity.getActivityId()); } } //获取流程图 BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration(); //获取自定义图片生成器 ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator(); InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(), configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true); return in; } /** * 获取流程执行节点 * * @param procInsId 流程实例id * @return */ @Override public AjaxResult getFlowViewer(String procInsId, String executionId) { List flowViewerList = new ArrayList<>(); FlowViewerDto flowViewerDto; // 获取任务开始节点(临时处理方式) List startNodeList = historyService.createHistoricActivityInstanceQuery() .processInstanceId(procInsId) .orderByHistoricActivityInstanceStartTime() .asc().listPage(0, 3); for (HistoricActivityInstance startInstance : startNodeList) { if (!"sequenceFlow".equals(startInstance.getActivityType())) { flowViewerDto = new FlowViewerDto(); if (!"sequenceFlow".equals(startInstance.getActivityType())) { flowViewerDto.setKey(startInstance.getActivityId()); // 根据流程节点处理时间校验改节点是否已完成 flowViewerDto.setCompleted(!Objects.isNull(startInstance.getEndTime())); flowViewerList.add(flowViewerDto); } } } // 历史节点 List hisActIns = historyService.createHistoricActivityInstanceQuery() .executionId(executionId) .orderByHistoricActivityInstanceStartTime() .asc().list(); for (HistoricActivityInstance activityInstance : hisActIns) { if (!"sequenceFlow".equals(activityInstance.getActivityType())) { flowViewerDto = new FlowViewerDto(); flowViewerDto.setKey(activityInstance.getActivityId()); // 根据流程节点处理时间校验改节点是否已完成 flowViewerDto.setCompleted(!Objects.isNull(activityInstance.getEndTime())); flowViewerList.add(flowViewerDto); } } return AjaxResult.success(flowViewerList); } /** * 获取流程变量 * * @param taskId * @return */ @Override public AjaxResult processVariables(String taskId) { // 流程变量 HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().includeProcessVariables().finished().taskId(taskId).singleResult(); if (Objects.nonNull(historicTaskInstance)) { return AjaxResult.success(historicTaskInstance.getProcessVariables()); } else { Map variables = taskService.getVariables(taskId); return AjaxResult.success(variables); } } /** * 审批任务获取下一节点 * * @param flowTaskVo 任务 * @return */ @Override public AjaxResult getNextFlowNode(FlowTaskVo flowTaskVo) { // Step 1. 获取当前节点并找到下一步节点 Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); if (Objects.isNull(task)) { return AjaxResult.error("任务不存在或已被审批!"); } // Step 2. 获取当前流程所有流程变量(网关节点时需要校验表达式) Map variables = taskService.getVariables(task.getId()); List nextUserTask = FindNextNodeUtil.getNextUserTasks(repositoryService, task, variables); if (CollectionUtils.isEmpty(nextUserTask)) { return AjaxResult.success("流程已完结!", null); } return getFlowAttribute(nextUserTask); } /** * 发起流程获取下一节点 * * @param flowTaskVo 任务 * @return */ @Override public AjaxResult getNextFlowNodeByStart(FlowTaskVo flowTaskVo) { // Step 1. 查找流程定义信息 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(flowTaskVo.getDeploymentId()).singleResult(); if (Objects.isNull(processDefinition)) { return AjaxResult.error("流程信息不存在!"); } // Step 2. 获取下一任务节点(网关节点时需要校验表达式) List nextUserTask = FindNextNodeUtil.getNextUserTasksByStart(repositoryService, processDefinition, flowTaskVo.getVariables()); if (CollectionUtils.isEmpty(nextUserTask)) { return AjaxResult.error("暂未查找到下一任务,请检查流程设计是否正确!"); } return getFlowAttribute(nextUserTask); } /** * 获取任务节点属性,包含自定义属性等 * * @param nextUserTask */ private AjaxResult getFlowAttribute(List nextUserTask) { FlowNextDto flowNextDto = new FlowNextDto(); for (UserTask userTask : nextUserTask) { MultiInstanceLoopCharacteristics multiInstance = userTask.getLoopCharacteristics(); // 会签节点 if (Objects.nonNull(multiInstance)) { flowNextDto.setVars(multiInstance.getInputDataItem()); flowNextDto.setType(ProcessConstants.PROCESS_MULTI_INSTANCE); flowNextDto.setDataType(ProcessConstants.DYNAMIC); } else { // 读取自定义节点属性 判断是否是否需要动态指定任务接收人员、组 String dataType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_DATA_TYPE); String userType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_USER_TYPE); flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL); flowNextDto.setType(userType); flowNextDto.setDataType(dataType); } } return AjaxResult.success(flowNextDto); } /** * 流程初始化表单 * * @param deployId * @return */ @Override public AjaxResult flowFormData(String deployId) { // 第一次申请获取初始化表单 if (StringUtils.isNotBlank(deployId)) { SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId); if (Objects.isNull(sysForm)) { return AjaxResult.error("请先配置流程表单!"); } return AjaxResult.success(JSONObject.parseObject(sysForm.getFormContent())); } else { return AjaxResult.error("参数错误!"); } } /** * 流程节点信息 * * @param procInsId * @return */ @Override public AjaxResult flowXmlAndNode(String procInsId, String deployId) { try { List flowViewerList = new ArrayList<>(); // 获取已经完成的节点 List listFinished = historyService.createHistoricActivityInstanceQuery() .processInstanceId(procInsId) .finished() .list(); listFinished = this.distinctHisActivity(listFinished); //扩展 获取这个流程实例的监控信息 key:TaskId value:实体类 Map processCodingMap = new LambdaQueryChainWrapper<>(processCodingMapper) .eq(ProcessCoding::getProcessInsId, procInsId) .list() .stream() .collect(Collectors.toMap(ProcessCoding::getTaskId, Function.identity())); // 保存已经完成的流程节点编号 listFinished.forEach(s -> { FlowViewerDto flowViewerDto = new FlowViewerDto(); flowViewerDto.setKey(s.getActivityId()); flowViewerDto.setCompleted(true); //扩展内容 不反overtime前端默认是绿色 ProcessCoding processCoding = processCodingMap.get(s.getTaskId()); //如果有监控数据, 历史节点只判断红码 if (processCoding != null && RED.equals(processCoding.getStatus())) { flowViewerDto.setOvertime(processCoding.getStatus()); } // 退回节点不进行展示 if (StringUtils.isBlank(s.getDeleteReason())) { flowViewerList.add(flowViewerDto); } flowViewerDto.setHasJump(processLogService.taskIsJump(s.getTaskId(), procInsId)); flowViewerDto.setHasWait(processLogService.taskIsWait(s.getTaskId(), procInsId)); }); // 获取代办节点 List listUnFinished = historyService.createHistoricActivityInstanceQuery() .processInstanceId(procInsId) .unfinished() .list(); // 保存需要代办的节点编号 listUnFinished.forEach(s -> { // 删除已退回节点 flowViewerList.removeIf(task -> task.getKey().equals(s.getActivityId())); FlowViewerDto flowViewerDto = new FlowViewerDto(); flowViewerDto.setKey(s.getActivityId()); flowViewerDto.setCompleted(false); // 扩展内容 代办的通过当前时间作为endTime ProcessCoding processCoding = processCodingMap.get(s.getTaskId()); //如果有监控数据 不反的话前端默认是进行中(蓝色) if (Objects.nonNull(processCoding)) { if (RED.equals(processCoding.getStatus()) || YELLOW.equals(processCoding.getStatus())) { flowViewerDto.setOvertime(processCoding.getStatus()); } } flowViewerList.add(flowViewerDto); }); Map result = new HashMap(); // xmlData 数据 ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName()); String xmlData = IOUtils.toString(inputStream, StandardCharsets.UTF_8); result.put("nodeData", flowViewerList); result.put("xmlData", xmlData); return AjaxResult.success(result); } catch (Exception e) { e.printStackTrace(); return AjaxResult.error("高亮历史任务失败"); } } /** * 根据任务key去重历史任务,相同情况下取最新的一条 * * @param hisTaskList * @return */ private List distinctHisActivity(List hisTaskList) { Map uniqueTasks = new HashMap<>(); for (HistoricActivityInstance task : hisTaskList) { String taskDefinitionKey = task.getActivityId(); HistoricActivityInstance existingTask = uniqueTasks.get(taskDefinitionKey); // 如果任务key重复(可能被驳回过,重新提交导致key重复),取最近的一条 if (existingTask == null || task.getStartTime().after(existingTask.getStartTime())) { uniqueTasks.put(taskDefinitionKey, task); } } // 最终去重后的任务列表 return new ArrayList<>(uniqueTasks.values()); } /** * 查询当前任务的表单数据 * * @param taskId * @return * @throws Exception */ @Override public AjaxResult currentFlowTaskForm(String taskId) { // 流程变量 List hisTaskList = historyService.createHistoricTaskInstanceQuery() .finished() .taskId(taskId) .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isEmpty(hisTaskList) || Objects.isNull(hisTaskList.get(0))) { return AjaxResult.error("未找到该任务信息"); } HistoricTaskInstance historicTaskInstance = hisTaskList.get(0); ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().includeProcessVariables().processInstanceId(historicTaskInstance.getProcessInstanceId()).singleResult(); Map parameters = new HashMap<>(); if (Objects.nonNull(processInstance)) { parameters = processInstance.getProcessVariables(); } else { // 如果为空,表明流程已经结束 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().includeProcessVariables().processInstanceId(historicTaskInstance.getProcessInstanceId()).singleResult(); if (Objects.isNull(historicProcessInstance)) { throw new RuntimeException("流程不存在"); } parameters = historicProcessInstance.getProcessVariables(); } String processInsId = historicTaskInstance.getProcessInstanceId(); List beforeNodes = this.getBeforeNodeForm(parameters, historicTaskInstance.getFormKey(), historicTaskInstance.getName(), historicTaskInstance.getProcessDefinitionId(), historicTaskInstance.getTaskDefinitionKey(), Boolean.TRUE, Boolean.FALSE); String finalProcessInsId = processInsId; List vos = beforeNodes.stream() .filter(FormDetailVO::getCurrent) .map(node -> { // 判断任务是否存在特殊操作(如跳过、转办等),需要在前端展示出来 ProcessLogQuery query = new ProcessLogQuery(); query.setTaskId(taskId); query.setProcessInsId(finalProcessInsId); Result result = processLogService.projectProcessLogList(query); List logList = (List) result.get("data"); DoFormDetailVO vo = new DoFormDetailVO(); BeanUtils.copyProperties(node, vo); if (CollectionUtils.isNotEmpty(logList)) { vo.setEvents(logList); } // 根据日志判断当前任务的状态 if (logList.stream().anyMatch(log -> ProcessLogEventTypeEnum.FINISHED.equals(log.getEventType()))) { vo.setTaskStatus(TaskStatusEnum.FINISHED); } else if (logList.stream().anyMatch(log -> ProcessLogEventTypeEnum.JUMP.equals(log.getEventType()))) { vo.setTaskStatus(TaskStatusEnum.JUMP); } else if (processLogService.taskIsWait(taskId, processInsId)) { vo.setTaskStatus(TaskStatusEnum.WAIT); } else if (processLogService.taskIsHangup(taskId, processInsId)) { vo.setTaskStatus(TaskStatusEnum.HANGUP); } return vo; }).collect(Collectors.toList()); return AjaxResult.success(vos.get(0)); } /** * 流程节点表单 * * @param taskId 流程任务编号 * @return */ @Override public AjaxResult flowTaskForm(String taskId) throws Exception { Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); // 1. 获取到变量信息,因为任务可能是运行中的也可能是历史任务 String processInsId = ""; String processDefId = ""; String formKey = ""; String taskName = ""; String taskDefKey = ""; if (Objects.isNull(task)) { List hisTaskList = historyService.createHistoricTaskInstanceQuery() .finished() .taskId(taskId) .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isEmpty(hisTaskList) || Objects.isNull(hisTaskList.get(0))) { return AjaxResult.error("任务不存在"); } HistoricTaskInstance hisTask = hisTaskList.get(0); processInsId = hisTask.getProcessInstanceId(); processDefId = hisTask.getProcessDefinitionId(); formKey = hisTask.getFormKey(); taskName = hisTask.getName(); taskDefKey = hisTask.getTaskDefinitionKey(); } else { processInsId = task.getProcessInstanceId(); processDefId = task.getProcessDefinitionId(); formKey = task.getFormKey(); taskName = task.getName(); taskDefKey = task.getTaskDefinitionKey(); } // 2. 获取流程变量 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().includeProcessVariables().processInstanceId(processInsId).singleResult(); Map parameters = new HashMap<>(); if (Objects.nonNull(processInstance)) { parameters = processInstance.getProcessVariables(); } else { // 如果为空,表明流程已经结束 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().includeProcessVariables().processInstanceId(processInsId).singleResult(); if (Objects.isNull(historicProcessInstance)) { throw new RuntimeException("流程不存在"); } parameters = historicProcessInstance.getProcessVariables(); } List beforeNodes = new ArrayList<>(); beforeNodes = this.getBeforeNodeForm(parameters, formKey, taskName, processDefId, taskDefKey, Boolean.TRUE, Boolean.FALSE); // 判断前置任务是不是和当前任务为同一个executeId // 判断当前任务是否被挂起中 String finalProcessInsId = processInsId; List dataList = new ArrayList<>(2); Map> map = new HashMap<>(2); beforeNodes.stream().forEach(node -> { if (node.getCurrent()) { node.setTaskId(taskId); dataList.add(node); } else { List beforeTasks = historyService.createHistoricTaskInstanceQuery() .processInstanceId(finalProcessInsId) .finished() .taskDefinitionKey(node.getBeforeNodeDefId()) .orderByTaskCreateTime() .desc() .list(); if (CollectionUtils.isNotEmpty(beforeTasks) && Objects.nonNull(beforeTasks.get(0))) { node.setTaskId(beforeTasks.get(0).getId()); List l = map.get(beforeTasks.get(0)); if (CollectionUtils.isEmpty(l)) { map.put(beforeTasks.get(0).getExecutionId(), Arrays.asList(node)); } else { l.add(node); } } } }); for (String key : map.keySet()) { if (StringUtils.isNotBlank(key)) { // 同一执行器上只取最近的一个 dataList.add(map.get(key).get(0)); } } List vos = dataList.stream().map(node -> { if (node.getCurrent()) { if (processLogService.taskIsHangup(taskId, finalProcessInsId)) { node.setTaskStatus(TaskStatusEnum.HANGUP); } } // 判断任务是否存在特殊操作(如跳过、转办等),需要在前端展示出来 ProcessLogQuery query = new ProcessLogQuery(); query.setTaskId(node.getTaskId()); query.setProcessInsId(finalProcessInsId); Result result = processLogService.projectProcessLogList(query); List logList = (List) result.get("data"); DoFormDetailVO vo = new DoFormDetailVO(); BeanUtils.copyProperties(node, vo); if (CollectionUtils.isNotEmpty(logList)) { vo.setEvents(logList); } return vo; }).collect(Collectors.toList()); return AjaxResult.success(vos); } @Override public AjaxResult detail(String processInsId, String taskId) { ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().includeProcessVariables().processInstanceId(processInsId).singleResult(); // 流程变量 Map parameters = new HashMap<>(); if (Objects.isNull(processInstance)) { // 如果为空,表明流程已经结束 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().includeProcessVariables().processInstanceId(processInsId).singleResult(); if (Objects.isNull(historicProcessInstance)) { throw new RuntimeException("流程不存在"); } List hisTasks = historyService.createHistoricTaskInstanceQuery() .taskId(taskId) .finished() .includeProcessVariables() .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isNotEmpty(hisTasks) && Objects.isNull(hisTasks.get(0))) { throw new RuntimeException("该任务不存在"); } HistoricTaskInstance hisTask = hisTasks.get(0); parameters = historicProcessInstance.getProcessVariables(); List beforeNodes = this.getBeforeNodeForm(parameters, hisTask.getFormKey(), hisTask.getName(), hisTask.getProcessDefinitionId(), hisTask.getTaskDefinitionKey(), Boolean.TRUE, Boolean.TRUE); List dataList = new ArrayList<>(2); Map> map = new HashMap<>(2); beforeNodes.stream().forEach(node -> { if (node.getCurrent()) { node.setTaskId(taskId); dataList.add(node); } else { List beforeTasks = historyService.createHistoricTaskInstanceQuery() .processInstanceId(hisTask.getProcessInstanceId()) .finished() .taskDefinitionKey(node.getBeforeNodeDefId()) .orderByTaskCreateTime() .desc() .list(); if (CollectionUtils.isNotEmpty(beforeTasks) && Objects.nonNull(beforeTasks.get(0))) { node.setTaskId(beforeTasks.get(0).getId()); List l = map.get(beforeTasks.get(0)); if (CollectionUtils.isEmpty(l)) { map.put(beforeTasks.get(0).getExecutionId(), Arrays.asList(node)); } else { l.add(node); } } } }); for (String key : map.keySet()) { if (StringUtils.isNotBlank(key)) { // 同一执行器上只取最近的一个 dataList.add(map.get(key).get(0)); } } List vos = dataList.stream().map(node -> { if (node.getCurrent()) { if (processLogService.taskIsHangup(taskId, hisTask.getProcessInstanceId())) { node.setTaskStatus(TaskStatusEnum.HANGUP); } } // 判断任务是否存在特殊操作(如跳过、转办等),需要在前端展示出来 ProcessLogQuery query = new ProcessLogQuery(); query.setTaskId(node.getTaskId()); query.setProcessInsId(hisTask.getProcessInstanceId()); Result result = processLogService.projectProcessLogList(query); List logList = (List) result.get("data"); DoFormDetailVO vo = new DoFormDetailVO(); BeanUtils.copyProperties(node, vo); if (CollectionUtils.isNotEmpty(logList)) { vo.setEvents(logList); } return vo; }).collect(Collectors.toList()); return AjaxResult.success(vos); } else { parameters = processInstance.getProcessVariables(); Task task = taskService.createTaskQuery().taskId(taskId).processInstanceId(processInsId).singleResult(); List beforeNodes = new ArrayList<>(); if (Objects.nonNull(task)) { beforeNodes = this.getBeforeNodeForm(parameters, task.getFormKey(), task.getName(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), Boolean.TRUE, Boolean.TRUE); } else { List hisTasks = historyService.createHistoricTaskInstanceQuery() .taskId(taskId) .finished() .includeProcessVariables() .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isNotEmpty(hisTasks) && Objects.isNull(hisTasks.get(0))) { throw new RuntimeException("该任务不存在"); } HistoricTaskInstance hisTask = hisTasks.get(0); beforeNodes = this.getBeforeNodeForm(parameters, hisTask.getFormKey(), hisTask.getName(), hisTask.getProcessDefinitionId(), hisTask.getTaskDefinitionKey(), Boolean.TRUE, Boolean.TRUE); } List dataList = new ArrayList<>(2); Map> map = new HashMap<>(2); beforeNodes.stream().forEach(node -> { if (node.getCurrent()) { node.setTaskId(taskId); dataList.add(node); } else { List beforeTasks = historyService.createHistoricTaskInstanceQuery() .processInstanceId(processInsId) .finished() .taskDefinitionKey(node.getBeforeNodeDefId()) .orderByTaskCreateTime() .desc() .list(); if (CollectionUtils.isNotEmpty(beforeTasks) && Objects.nonNull(beforeTasks.get(0))) { node.setTaskId(beforeTasks.get(0).getId()); List l = map.get(beforeTasks.get(0)); if (CollectionUtils.isEmpty(l)) { map.put(beforeTasks.get(0).getExecutionId(), Arrays.asList(node)); } else { l.add(node); } } } }); for (String key : map.keySet()) { if (StringUtils.isNotBlank(key)) { // 同一执行器上只取最近的一个 dataList.add(map.get(key).get(0)); } } List vos = dataList.stream().map(node -> { if (node.getCurrent()) { if (processLogService.taskIsHangup(taskId, processInsId)) { node.setTaskStatus(TaskStatusEnum.HANGUP); } } // 判断任务是否存在特殊操作(如跳过、转办等),需要在前端展示出来 ProcessLogQuery query = new ProcessLogQuery(); query.setTaskId(node.getTaskId()); query.setProcessInsId(processInsId); Result result = processLogService.projectProcessLogList(query); List logList = (List) result.get("data"); DoFormDetailVO vo = new DoFormDetailVO(); BeanUtils.copyProperties(node, vo); if (CollectionUtils.isNotEmpty(logList)) { vo.setEvents(logList); } return vo; }).collect(Collectors.toList()); return AjaxResult.success(vos); } } /** * 获取当前节点和上一节点的表单内容 * * @param parameters 根据任务查找出来的参数 * @param formKey task自身关联的表单id * @param taskName 任务 * @param processDefId 流程定义id * @param processDefKey 流程实例id * @param disableInput 是否禁用已经有值的输入项 * @return */ private List getBeforeNodeForm(Map parameters, String formKey, String taskName, String processDefId, String processDefKey, Boolean currentNeedData, Boolean disableInput) { // 这里只需要查自身以及上一个节点(如果并行的有多个)的表单数据 List beforeNodes = taskCommonService.getBeforeNodeDefInfo(processDefId, processDefKey, sysFormService, Boolean.TRUE); List beforeNodeDefIds = beforeNodes.stream().filter(item -> !item.getCurrent() || currentNeedData).map(FormDetailVO::getBeforeNodeDefId).collect(Collectors.toList()); // 处理每个表单的数据 for (FormDetailVO formDetailVO : beforeNodes) { if (formDetailVO.getCurrent() && !currentNeedData) { continue; // 跳过当前节点,因为当前节点在获取前置节点时已经设置过了(但表单数据没有给) } Map newP = new HashMap<>(); if (CollectionUtils.isNotEmpty(beforeNodeDefIds)) { for (String key : parameters.keySet()) { // 过滤拿到目标表单数据,将目标表单数据放到新map中 if (key.startsWith(formDetailVO.getBeforeNodeDefId())) { if (key.contains(ProcessConstants.TASK_FORM_KEY)) { newP.put(key, parameters.get(key)); } else { newP.put(key.split("&")[1], parameters.get(key)); } } } } Object form = newP.get(formDetailVO.getBeforeNodeDefId() + "&" + ProcessConstants.TASK_FORM_KEY); if (Objects.nonNull(form)) { JSONObject formJson = JSONObject.parseObject(JSON.toJSONString(form)); List oldFields = JSON.parseObject(JSON.toJSONString(formJson.get(ProcessConstants.WIDGET_LIST)), new TypeReference>() { }); if(CollectionUtils.isNotEmpty(oldFields)) { // 设置已填写的表单为禁用状态 if (disableInput) { for (JSONObject oldField : oldFields) { JSONObject options = oldField.getJSONObject("options"); options.put("disabled", true); } } formJson.put(ProcessConstants.WIDGET_LIST, oldFields); newP.put(ProcessConstants.TASK_FORM_KEY, formJson); newP.remove(formDetailVO.getBeforeNodeDefId() + "&" + ProcessConstants.TASK_FORM_KEY); formDetailVO.setFormJsonObj(newP); } // TODO 暂时只处理用户任务上的表单 // if (StringUtils.isNotBlank(task.getFormKey())) { // SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(task.getFormKey())); // JSONObject data = JSONObject.parseObject(sysForm.getFormContent()); // List newFields = JSON.parseObject(JSON.toJSONString(data.get(ProcessConstants.WIDGET_LIST)), new TypeReference>() { // }); // // 表单回显时 加入子表单信息到流程变量中 // for (JSONObject newField : newFields) { // String key = newField.getString("id"); // // 处理图片上传组件回显问题 // if ("picture-upload".equals(newField.getString("type"))) { // parameters.put(key, new ArrayList<>()); // } else { // parameters.put(key, null); // } // } // oldFields.addAll(newFields); // } } } return beforeNodes; } /** * 流程节点信息 * * @param procInsId * @param elementId * @return */ @Override public AjaxResult flowTaskInfo(String procInsId, String elementId) { List list = historyService.createHistoricActivityInstanceQuery() .processInstanceId(procInsId) .activityId(elementId) .list(); // 退回任务后有多条数据 只取待办任务进行展示 list.removeIf(task -> StringUtils.isNotBlank(task.getDeleteReason())); if (CollectionUtils.isEmpty(list)) { return AjaxResult.success(); } if (list.size() > 1) { list.removeIf(task -> Objects.nonNull(task.getEndTime())); } HistoricActivityInstance histIns = list.get(0); FlowTaskDto flowTask = new FlowTaskDto(); flowTask.setTaskId(histIns.getTaskId()); flowTask.setTaskName(histIns.getActivityName()); flowTask.setCreateTime(histIns.getStartTime()); flowTask.setFinishTime(histIns.getEndTime()); if (StringUtils.isNotBlank(histIns.getAssignee())) { SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee())); flowTask.setAssigneeId(sysUser.getUserId()); flowTask.setAssigneeName(sysUser.getNickName()); flowTask.setDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : ""); } // 流程变量信息 // HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery() // .includeProcessVariables().finished().taskId(histIns.getTaskId()).singleResult(); // flowTask.setVariables(historicTaskInstance.getProcessVariables()); // 展示审批人员 List linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId()); StringBuilder stringBuilder = new StringBuilder(); for (HistoricIdentityLink identityLink : linksForTask) { // 获选人,候选组/角色(多个) if ("candidate".equals(identityLink.getType())) { if (StringUtils.isNotBlank(identityLink.getUserId())) { SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId())); stringBuilder.append(sysUser.getNickName()).append(","); } if (StringUtils.isNotBlank(identityLink.getGroupId())) { SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); stringBuilder.append(sysRole.getRoleName()).append(","); } } } if (StringUtils.isNotBlank(stringBuilder)) { flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); } flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis())); // 获取意见评论内容 List commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId()); commentList.forEach(comment -> { if (histIns.getTaskId().equals(comment.getTaskId())) { flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build()); } }); return AjaxResult.success(flowTask); } /** * 将Object类型的数据转化成Map * * @param obj * @return * @throws Exception */ public Map obj2Map(Object obj) throws Exception { Map map = new HashMap(); Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); map.put(field.getName(), field.get(obj)); } return map; } /** * 流程完成时间处理 * * @param ms * @return */ private String getDate(long ms) { long day = ms / (24 * 60 * 60 * 1000); long hour = (ms / (60 * 60 * 1000) - day * 24); long minute = ((ms / (60 * 1000)) - day * 24 * 60 - hour * 60); long second = (ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60); if (day > 0) { return day + "天" + hour + "小时" + minute + "分钟"; } if (hour > 0) { return hour + "小时" + minute + "分钟"; } if (minute > 0) { return minute + "分钟"; } if (second > 0) { return second + "秒"; } else { return 0 + "秒"; } } }