package com.zhgd.xmgl.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.gexin.fastjson.JSON; import com.gexin.fastjson.JSONArray; import com.gexin.fastjson.JSONObject; import com.wflow.bean.do_.UserDeptDo; import com.wflow.bean.entity.WflowModelHistorys; import com.wflow.bean.entity.WflowSubProcess; import com.wflow.mapper.WflowModelHistorysMapper; import com.wflow.mapper.WflowModelsMapper; import com.wflow.mapper.WflowSubProcessMapper; import com.wflow.service.OrgRepositoryService; import com.wflow.workflow.UELTools; import com.wflow.workflow.bean.dto.ProcessInstanceOwnerDto; import com.wflow.workflow.bean.process.OrgUser; import com.wflow.workflow.bean.process.ProcessNode; import com.wflow.workflow.bean.process.ProcessStatus; import com.wflow.workflow.bean.process.enums.ApprovalModeEnum; import com.wflow.workflow.bean.process.enums.NodeTypeEnum; import com.wflow.workflow.bean.process.props.ApprovalProps; import com.wflow.workflow.bean.process.props.CcProps; import com.wflow.workflow.bean.vo.ProcessConditionResolveParamsVo; import com.wflow.workflow.bean.vo.ProcessProgressVo; import com.wflow.workflow.bean.vo.ProcessTaskVo; import com.wflow.workflow.config.WflowGlobalVarDef; import com.wflow.workflow.service.*; import com.wflow.workflow.service.impl.ProcessTaskServiceImpl; import com.wflow.workflow.utils.Executor; import com.zhgd.xmgl.modules.baotou.entity.vo.CountFlowVO; import com.zhgd.xmgl.security.util.SecurityUtils; import com.zhgd.xmgl.tenant.TenantContextHolder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.MapUtils; import org.flowable.engine.HistoryService; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstanceQuery; import org.flowable.task.api.Task; import org.flowable.task.api.TaskInfo; import org.flowable.task.api.TaskQuery; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.variable.api.history.HistoricVariableInstance; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @Component @Slf4j public class FlowSeviceUtil { private final static OrgUser UNKNOW_USER = OrgUser.builder().id("5201314").name("人员待定").build(); @Autowired private WflowModelsMapper wflowModelsMapper; @Lazy @Autowired private TaskService taskService; @Lazy @Autowired private RuntimeService runtimeService; @Lazy @Autowired private ProcessInstanceService processService; @Lazy @Autowired private WflowModelHistorysMapper modelHistorysMapper; @Lazy @Autowired private HistoryService historyService; @Lazy @Autowired private RepositoryService repositoryService; @Lazy @Autowired private UserDeptOrLeaderService userDeptOrLeaderService; @Lazy @Autowired private ProcessStepRenderService stepRenderService; @Lazy @Autowired private ProcessTaskServiceImpl processTaskService; @Lazy @Autowired private OrgRepositoryService orgRepositoryService; @Lazy @Autowired private BusinessDataStorageService businessDataService; @Lazy @Autowired private UELTools uelTools; @Lazy @Autowired private WflowSubProcessMapper subProcessMapper; @Lazy @Autowired private ProcessNodeCatchService nodeCatchService; @Autowired private WflowModelHistorysMapper wflowModelHistorysMapper; @Autowired private ProcessModelService modelService; /** * 获取下一个待处理的审批节点 * * @param instanceId * @param dfNodeId * @return */ public ProcessProgressVo.ProgressNode getNextTodoApproval(String instanceId, String dfNodeId) { //先查实例,然后判断是子流程还是主流程 HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(instanceId).singleResult(); //数据分类 表单配置及数据、审批任务结果、 ProcessInstanceOwnerDto owner = null; Map formDatas = new HashMap<>(); //是否是子流程 boolean isSub = StrUtil.isNotBlank(instance.getSuperProcessInstanceId()); HistoricProcessInstance mainInst = isSub ? null : instance; if (isSub) { //查出主流程表单数据 mainInst = historyService.createHistoricProcessInstanceQuery() .processInstanceId(instance.getSuperProcessInstanceId()).singleResult(); formDatas = businessDataService.getProcessInstanceFormData(mainInst.getId()); } //优化查询,把之前查好几次的一次性查出来然后再分类 List variables = historyService.createHistoricVariableInstanceQuery() .processInstanceId(instanceId).executionId(instanceId).list(); Map vars = Objects.nonNull(instance.getEndTime()) ? new HashMap<>() : uelTools.getContextVar(instanceId, instance.getProcessDefinitionId()); //遍历所有变量,将数据分类 for (HistoricVariableInstance var : variables) { vars.put(var.getVariableName(), var.getValue()); if (!isSub && var.getVariableName().startsWith("field")) { formDatas.put(var.getVariableName(), var.getValue()); } else if (WflowGlobalVarDef.OWNER.equals(var.getVariableName())) { owner = (ProcessInstanceOwnerDto) var.getValue(); } else if (WflowGlobalVarDef.START_DEPT.equals(var.getVariableName())) { String key = instance.getStartUserId() + "_" + var.getValue(); Map infoMap = orgRepositoryService.getUserDeptInfos(CollectionUtil.newArrayList(key)); UserDeptDo userDeptDo = infoMap.getOrDefault(key, new UserDeptDo()); owner = ProcessInstanceOwnerDto.builder().ownerDeptId(String.valueOf(var.getValue())) .owner(instance.getStartUserId()).ownerName(userDeptDo.getUserName()) .ownerDeptId(userDeptDo.getDeptId()).ownerDeptName(userDeptDo.getDeptName()).build(); } } Map> nodeMap = Collections.emptyMap(); if (isSub) { WflowSubProcess subProcess = subProcessMapper.selectOne(new LambdaQueryWrapper<>(WflowSubProcess.builder() .procDefId(instance.getProcessDefinitionId()).build())); nodeMap = nodeCatchService.reloadProcessByStr(subProcess.getProcess()); } //搜索当前版本流程的配置 WflowModelHistorys modelHistory = modelHistorysMapper.selectOne(new LambdaQueryWrapper<>(WflowModelHistorys.builder() .processDefId(mainInst.getProcessDefinitionId()).version(mainInst.getProcessDefinitionVersion()).build())); if (StrUtil.isNotBlank(dfNodeId)) { nodeMap = nodeCatchService.reloadProcessByStr(modelHistory.getProcess()); } List progressNodeList = this.getFutureTask(instance, owner.getOwnerDeptId(), vars, nodeMap, modelHistory.getTenantId()); if (CollUtil.isEmpty(progressNodeList)) { log.warn("获取下一个待处理的审批节点超时失败,instanceId=" + instanceId + ",nodeId=" + dfNodeId); return null; } else { return progressNodeList.get(0); } } private boolean isProcessDone(String process, String curNodeId, String dfNodeId) { JSONObject rootJo = JSON.parseObject(process); int i = 0; return getDeepFromProcess(rootJo, curNodeId, i) > getDeepFromProcess(rootJo, dfNodeId, i); } private Integer getDeepFromProcess(JSONObject jo, String curNodeId, int i) { String id = jo.getString("id"); if (id.equals(curNodeId)) { return i; } String type = jo.getString("type"); if (type.equals("CONDITIONS")) { JSONArray array = jo.getJSONArray("branchs"); for (int j = 0; j < array.size(); j++) { i = getDeepFromProcess(array.getJSONObject(j), curNodeId, i); } } else { JSONObject children = jo.getJSONObject("children"); if (CollUtil.isEmpty(children)) { return i; } i = getDeepFromProcess(children, curNodeId, ++i); } return i; } /** * 获取我的待办的instanceIdList * * @param code 表单id,安全检查:wf66f6451c48b718d0aaf27522 * @return */ public List getMyTodoInstanceIds(String code, String projectSn) { if (SecurityUtils.getUser() == null) { ArrayList list = new ArrayList<>(); list.add("-1"); return list; } String userId = String.valueOf(SecurityUtils.getUser().getUserId()); TaskQuery taskQuery = taskService.createTaskQuery(); if (StrUtil.isNotBlank(code)) { taskQuery.processDefinitionKey(code); } ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery(); Set stringSet = processInstanceQuery.list().stream().map(p -> p.getProcessInstanceId()).collect(Collectors.toSet()); taskQuery.active().taskTenantId(projectSn) .processInstanceIdIn(stringSet) .taskCandidateOrAssigned(userId) .orderByTaskCreateTime().desc(); Page page = new Page<>(); List taskList = new ArrayList<>(); taskList = taskQuery.list(); List list = taskList.stream().map(o -> o.getProcessInstanceId()).collect(Collectors.toList()); if (CollUtil.isEmpty(list)) { list.add("-1"); } return list; } private Set getCcTaskUsers(String instanceId, String nodeId) { //获取设置项 HistoricVariableInstance variableInstance = historyService.createHistoricVariableInstanceQuery() .processInstanceId(instanceId) .variableName(WflowGlobalVarDef.WFLOW_NODE_PROPS).singleResult(); Map nodeProps; if (Objects.nonNull(variableInstance)) { nodeProps = (Map) variableInstance.getValue(); } else { //流程首个节点需要从执行实例中取数据 nodeProps = runtimeService.getVariable(instanceId, WflowGlobalVarDef.WFLOW_NODE_PROPS, Map.class); } CcProps ccProps = (CcProps) nodeProps.get(nodeId); //获取变量里面自选的抄送人 Set ccUsers = new HashSet<>(); List orgs = new ArrayList<>(ccProps.getAssignedUser()); if (ccProps.getShouldAdd()) { //获取发起流程时添加的抄送人 HistoricVariableInstance result = historyService.createHistoricVariableInstanceQuery() .processInstanceId(instanceId) .variableName(nodeId).singleResult(); if (Objects.nonNull(result)) { Optional.ofNullable(result.getValue()).ifPresent(us -> orgs.addAll((List) us)); } else { Optional.ofNullable(runtimeService.getVariable(instanceId, nodeId, List.class)).ifPresent(orgs::addAll); } } //解析部门与人员选项 ccUsers.addAll(orgs.stream().filter(org -> "user".equals(org.getType())) .map(OrgUser::getId).collect(Collectors.toSet())); ccUsers.addAll(userDeptOrLeaderService.getUsersByDept(orgs.stream() .filter(org -> "dept".equals(org.getType())) .map(OrgUser::getId).collect(Collectors.toSet()))); return ccUsers; } private List getFutureTask(HistoricProcessInstance instance, String startDept, Map context, Map> nodes, String tenantId) { //根据流程遍历后续节点,期间要穿越后续包含并行网关和条件网关的节点,先找到所有激活的任务节点开始递归 //节点如果处于并行/包容分支内,可能会有多个活动的节点 List progressNodes = new LinkedList<>(); try { Set idSet = new LinkedHashSet<>(); context.put("root", instance.getStartUserId()); taskService.createTaskQuery().processInstanceId(instance.getId()).active().list() .stream().map(TaskInfo::getTaskDefinitionKey) .collect(Collectors.toSet()).forEach(nodeId -> { //根据每个活动的节点进行遍历,最终它们会在合流点汇聚 idSet.add(nodeId); Optional.ofNullable(nodes.get(nodeId)).ifPresent(node -> { //已激活的当前节点,需要进行去重 if (node.getProps() instanceof ApprovalProps) { ApprovalProps props = (ApprovalProps) node.getProps(); List users = processTaskService.getApprovalUsers(instance.getId(), node.getId(), props, tenantId); //取已下发的任务 List ingTask = historyService.createHistoricTaskInstanceQuery() .processInstanceId(instance.getId()).taskDefinitionKey(nodeId).list(); //转交的也要过滤掉,但是只能过滤一次转交的 Set ingTaskUser = ingTask.stream().map(TaskInfo::getAssignee).collect(Collectors.toSet()); ingTaskUser.addAll(ingTask.stream().filter(v -> Objects.nonNull(v.getOwner())) .map(HistoricTaskInstance::getOwner).collect(Collectors.toList())); Map userMaps = userDeptOrLeaderService.getUserMapByIds(users); users.stream().filter(v -> !ingTaskUser.contains(v)) .forEach(us -> { Date createTime = ingTask.get(ingTask.size() - 1).getCreateTime(); //把时间往后延长10ms,使其排列到后方 createTime.setTime(createTime.getTime() + 10); progressNodes.add(ProcessProgressVo.ProgressNode.builder() .nodeId(node.getId()) // .isFuture(true) .name(node.getName()) .user(userMaps.getOrDefault(us, UNKNOW_USER)) .nodeType(node.getType()) .comment(Collections.emptyList()) .approvalMode(props.getMode()) .startTime(createTime) .build()); }); } //遍历后续节点 foreachNode(node.getChildren(), idSet, progressNodes, instance, context, tenantId); }); }); } catch (Exception e) { log.error("获取[{}]未开始任务异常: {}", instance.getId(), e.getMessage()); } return progressNodes; } private void foreachNode(ProcessNode node, Set idSet, List progressNodes, HistoricProcessInstance instance, Map vars, String tenantId) { if (Objects.isNull(node) || StrUtil.isBlank(node.getId()) || idSet.contains(node.getId())) return; idSet.add(node.getId()); if ((NodeTypeEnum.TASK.equals(node.getType()) || NodeTypeEnum.APPROVAL.equals(node.getType()) || NodeTypeEnum.CC.equals(node.getType()))) { //没有遍历过的节点,且是(审批、抄送、办理)把对应的人员解析出来 Collection users; ApprovalModeEnum modeEnum; if (NodeTypeEnum.CC.equals(node.getType())) { modeEnum = null; users = getCcTaskUsers(instance.getId(), node.getId()); } else { ApprovalProps props = (ApprovalProps) node.getProps(); modeEnum = props.getMode(); users = processTaskService.getApprovalUsers(instance.getId(), node.getId(), props, tenantId); } Map userMaps = userDeptOrLeaderService.getUserMapByIds(users); users.forEach(us -> progressNodes.add(ProcessProgressVo.ProgressNode.builder() .nodeId(node.getId()) // .isFuture(true) .name(node.getName()) .user(userMaps.getOrDefault(us, UNKNOW_USER)) .nodeType(node.getType()) .comment(Collections.emptyList()) .approvalMode(modeEnum) .startTime(GregorianCalendar.getInstance().getTime()) .build())); } else if (NodeTypeEnum.CONCURRENTS.equals(node.getType())) { //并行网关,全部需要递归遍历 node.getBranchs().forEach(branch -> { foreachNode(branch, idSet, progressNodes, instance, vars, tenantId); }); //从分支出来继续往下遍历 } else if (NodeTypeEnum.INCLUSIVES.equals(node.getType()) || NodeTypeEnum.CONDITIONS.equals(node.getType())) { //包容网关/条件网关,满足条件的分支都要执行 List trueConditions = stepRenderService.getIsTrueConditions(ProcessConditionResolveParamsVo.builder() .processDfId(instance.getProcessDefinitionId()) .conditionNodeId(node.getId()).context(vars) .multiple(NodeTypeEnum.INCLUSIVES.equals(node.getType())) .build()); //遍历满足条件的分支 node.getBranchs().forEach(bNode -> { if (trueConditions.contains(bNode.getId())) { foreachNode(bNode, idSet, progressNodes, instance, vars, tenantId); } }); } else if (NodeTypeEnum.EMPTY.equals(node.getType())) { //空节点的话是合流点,说明前面有网关,那么要回头再向上去找节点,太复杂了,难搞 //nodes.get(node.getParentId()) } foreachNode(node.getChildren(), idSet, progressNodes, instance, vars, tenantId); } public CountFlowVO countFlow(Map map) { String projectSn = MapUtils.getString(map, "projectSn"); String userId = SecurityUtils.getUser().getUserId() + ""; ////查询我的待办、质量待办、安全待办、抄送我的 //TaskQuery taskQuery = taskService.createTaskQuery(); //ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery(); //Set stringSet = processInstanceQuery.list().stream().map(p -> p.getProcessInstanceId()).collect(Collectors.toSet()); //taskQuery.active().taskTenantId(projectSn) // .processInstanceIdIn(stringSet) // .taskCandidateOrAssigned(userId) // .orderByTaskCreateTime().desc(); //List taskList = taskQuery.list(); //Set staterUsers = new HashSet<>(); //Set instanceIds = taskList.stream().map(Task::getProcessInstanceId).collect(Collectors.toSet()); //Map startDept = FlowableUtils.getProcessVars(instanceIds, "startDept"); ////把待办任务流程实例一次性取出来,减少查询次数 //Map instanceMap = CollectionUtil.isNotEmpty(taskList) ? // runtimeService.createProcessInstanceQuery().processInstanceIds(taskList.stream() // .map(Task::getProcessInstanceId).collect(Collectors.toSet())) // .list().stream().collect(Collectors.toMap(ProcessInstance::getId, v -> v)) : new HashMap<>(); //List formIds = taskList.stream().map(task -> { // ProcessInstance instance = instanceMap.get(task.getProcessInstanceId()); // //构造用户id -> 部门id // staterUsers.add(instance.getStartUserId() + "_" + startDept.getOrDefault(task.getProcessInstanceId(), // //如果没有就从流程变量 owner 里取(之前是存owner变量) // FlowableUtils.getOwnerDept(task.getProcessInstanceId(), true))); // return instance.getProcessDefinitionKey(); //}).filter(Objects::nonNull).collect(Collectors.toList()); ////取用户信息,减少数据库查询,一次构建 //if (CollectionUtil.isEmpty(staterUsers)) { // formIds = new ArrayList<>(); //} //Map safeMap = wflowModelsMapper.selectList(Wrappers.lambdaQuery() // .eq(WflowModels::getGroupId, 135)).stream().collect(Collectors.toMap(WflowModels::getFormId, Function.identity())); //Map qualityMap = wflowModelsMapper.selectList(Wrappers.lambdaQuery() // .eq(WflowModels::getGroupId, 136)).stream().collect(Collectors.toMap(WflowModels::getFormId, Function.identity())); //Integer safe = 0; //Integer quality = 0; //for (String formId : formIds) { // if (safeMap.containsKey(formId)) { // safe++; // } else if (qualityMap.containsKey(formId)) { // quality++; // } //} Page page = processTaskService.todoListBaotou(1, 1, null, null, null, null); CountFlowVO vo = new CountFlowVO(); vo.setTotal((int) page.getTotal()); //vo.setSafe(safe); //vo.setQuality(quality); //vo.setCsMe((int) processService.getCcMeInstance(1, 1, null, null, null, null, null).getTotal()); //查询待催办、已办结 vo.setNeedCall((int) getTaskNum(userId, 1).count()); vo.setDone((int) getTaskNum(userId, 2).count()); return vo; } /** * 查询任务数量 * * @param userId * @param customStatus 1待催办2已办结 * @return */ private HistoricProcessInstanceQuery getTaskNum(String userId, Integer customStatus) { HistoricProcessInstanceQuery instanceQuery = historyService.createHistoricProcessInstanceQuery(); instanceQuery.processInstanceTenantId(TenantContextHolder.getTenantId()); if (Objects.equals(customStatus, 1)) { instanceQuery.or().startedBy(userId + "").involvedUser(userId + "").endOr(); } else if (Objects.equals(customStatus, 2)) { instanceQuery.or().startedBy(userId + "").involvedUser(userId + "").endOr(); instanceQuery.finished(); } Executor.builder() //customStatus 1待催办2已办结3审批进行中4审批被撤销5审批被驳回 .ifTrueNext(Objects.equals(customStatus, 1), instanceQuery::unfinished) .ifNotBlankNext(Objects.equals(customStatus, 5) ? ProcessStatus.REFUSE.toString() : null, instanceQuery::processInstanceBusinessStatus); instanceQuery.count(); return instanceQuery; } /** * 根据示例id获取流程id * * @param instanceId * @return */ public String getFlowIdByInstanceId(String instanceId) { ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult(); if (processInstance == null) { return null; } return processInstance.getProcessDefinitionKey(); } /** * 获取待审批的任务Map * * @param processDefinitionKey 流程定义code * @return */ public Map getTaskMap(String processDefinitionKey, String projectSn) { TaskQuery taskQuery = taskService.createTaskQuery(); taskQuery.processDefinitionKey(processDefinitionKey); ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery(); Set stringSet = processInstanceQuery.list().stream().map(p -> p.getProcessInstanceId()).collect(Collectors.toSet()); taskQuery.active().taskTenantId(projectSn) .processInstanceIdIn(stringSet) .taskCandidateOrAssigned(String.valueOf(SecurityUtils.getUser().getUserId())) .orderByTaskCreateTime().desc(); List taskList = taskQuery.list(); return taskList.stream().collect(Collectors.toMap(Task::getProcessInstanceId, Function.identity(), (o1, o2) -> o1)); } }