wisdomisite-java/src/main/java/com/zhgd/xmgl/util/FlowSeviceUtil.java
2025-03-26 18:48:45 +08:00

500 lines
26 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<String, Object> 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<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(instanceId).executionId(instanceId).list();
Map<String, Object> 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<String, UserDeptDo> 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<String, ProcessNode<?>> 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<ProcessProgressVo.ProgressNode> 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<String> getMyTodoInstanceIds(String code, String projectSn) {
if (SecurityUtils.getUser() == null) {
ArrayList<String> 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<String> stringSet = processInstanceQuery.list().stream().map(p -> p.getProcessInstanceId()).collect(Collectors.toSet());
taskQuery.active().taskTenantId(projectSn)
.processInstanceIdIn(stringSet)
.taskCandidateOrAssigned(userId)
.orderByTaskCreateTime().desc();
Page<ProcessTaskVo> page = new Page<>();
List<Task> taskList = new ArrayList<>();
taskList = taskQuery.list();
List<String> list = taskList.stream().map(o -> o.getProcessInstanceId()).collect(Collectors.toList());
if (CollUtil.isEmpty(list)) {
list.add("-1");
}
return list;
}
private Set<String> 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<String> ccUsers = new HashSet<>();
List<OrgUser> 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<OrgUser>) 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<ProcessProgressVo.ProgressNode> getFutureTask(HistoricProcessInstance instance, String
startDept, Map<String, Object> context, Map<String, ProcessNode<?>> nodes, String tenantId) {
//根据流程遍历后续节点,期间要穿越后续包含并行网关和条件网关的节点,先找到所有激活的任务节点开始递归
//节点如果处于并行/包容分支内,可能会有多个活动的节点
List<ProcessProgressVo.ProgressNode> progressNodes = new LinkedList<>();
try {
Set<String> 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<String> users = processTaskService.getApprovalUsers(instance.getId(), node.getId(), props, tenantId);
//取已下发的任务
List<HistoricTaskInstance> ingTask = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(instance.getId()).taskDefinitionKey(nodeId).list();
//转交的也要过滤掉,但是只能过滤一次转交的
Set<String> 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<String, OrgUser> 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<String> idSet, List<ProcessProgressVo.ProgressNode> progressNodes,
HistoricProcessInstance instance, Map<String, Object> 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<String> 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<String, OrgUser> 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<String> 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<String, Object> map) {
String projectSn = MapUtils.getString(map, "projectSn");
String userId = SecurityUtils.getUser().getUserId() + "";
////查询我的待办、质量待办、安全待办、抄送我的
//TaskQuery taskQuery = taskService.createTaskQuery();
//ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
//Set<String> stringSet = processInstanceQuery.list().stream().map(p -> p.getProcessInstanceId()).collect(Collectors.toSet());
//taskQuery.active().taskTenantId(projectSn)
// .processInstanceIdIn(stringSet)
// .taskCandidateOrAssigned(userId)
// .orderByTaskCreateTime().desc();
//List<Task> taskList = taskQuery.list();
//Set<String> staterUsers = new HashSet<>();
//Set<String> instanceIds = taskList.stream().map(Task::getProcessInstanceId).collect(Collectors.toSet());
//Map<String, Object> startDept = FlowableUtils.getProcessVars(instanceIds, "startDept");
////把待办任务流程实例一次性取出来,减少查询次数
//Map<String, ProcessInstance> 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<String> 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<String, WflowModels> safeMap = wflowModelsMapper.selectList(Wrappers.<WflowModels>lambdaQuery()
// .eq(WflowModels::getGroupId, 135)).stream().collect(Collectors.toMap(WflowModels::getFormId, Function.identity()));
//Map<String, WflowModels> qualityMap = wflowModelsMapper.selectList(Wrappers.<WflowModels>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<ProcessTaskVo> 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<String, Task> getTaskMap(String processDefinitionKey, String projectSn) {
TaskQuery taskQuery = taskService.createTaskQuery();
taskQuery.processDefinitionKey(processDefinitionKey);
ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
Set<String> 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<Task> taskList = taskQuery.list();
return taskList.stream().collect(Collectors.toMap(Task::getProcessInstanceId, Function.identity(), (o1, o2) -> o1));
}
}