当前位置: 首页 > news >正文

简单的springboot整合activiti5-serviceImpl部分(1)

简单的springboot整合activiti5.22.0-serviceImpl部分(1)

原来的流程serviceImpl部分代码过多,所以此处单独记录一下,此处记录的是serviceImpl第一部分代码

package cn.git.workflow.service.impl;import cn.git.cache.api.BaseCacheApi;
import cn.git.cache.entity.CacheTcSysCodes;
import cn.git.common.exception.ServiceException;
import cn.git.common.page.PageBean;
import cn.git.common.page.PaginationContext;
import cn.git.common.util.OracleInQueryUtil;
import cn.git.common.util.WebUtil;
import cn.git.loan.dto.LoanWorkFlowDTO;
import cn.git.manage.api.UserApi;
import cn.git.manage.dto.*;
import cn.git.query.dto.WorkFlowJumpDTO;
import cn.git.workflow.constant.WorkFlowConstant;
import cn.git.workflow.constant.WorkFlowServerConstant;
import cn.git.workflow.dto.*;
import cn.git.workflow.dto.activiti.WorkFlowActHisActInstListDTO;
import cn.git.workflow.dto.activiti.WorkFlowActHisProcessListDTO;
import cn.git.workflow.dto.activiti.WorkFlowLoadTemplateDTO;
import cn.git.workflow.entity.*;
import cn.git.workflow.entity.activiti.WorkFlowLoadTemplate;
import cn.git.workflow.feign.*;
import cn.git.workflow.mapper.*;
import cn.git.workflow.mapstruct.ActivitiConvert;
import cn.git.workflow.mapstruct.WorkFlowConvert;
import cn.git.workflow.page.PageUtil;
import cn.git.workflow.page.WorkFlowPage;
import cn.git.workflow.service.WorkFlowService;
import cn.git.workflow.util.*;
import cn.git.workflow.vo.WorkFlowTraceVO;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;/*** 流程server 通用serviceImpl** @program: bank-credit-sy* @author: lixuchun* @create: 2021-06-08*/
@Service
@Slf4j
public class WorkFlowServiceImpl implements WorkFlowService {/*** todo: 流程模块nacos配置,上线时间 yyyy-MM-dd 格式 暂时设定为2022-08-29,后期修改为上线时间* 主要在流程历史意见信息查看部分使用*/@Value("${workflow.upper.date}")private String nacosUpperDate;@Autowiredprivate BaseCacheApi baseCacheApi;@Autowiredprivate LoanWorkFlowApiClient loanWorkFlowApiClient;@Autowiredprivate WorkFlowFactory workFlowFactory;@Autowiredprivate TbConVoteMapper tbConVoteMapper;@Autowiredprivate TbSysFlowPositionMapper tbSysFlowPositionMapper;@Autowiredprivate TbSysFlowPositionDetailMapper tbSysFlowPositionDetailMapper;@Autowiredprivate WfmidAppProcessInstanceMapper wfmidAppProcessInstanceMapper;@Autowiredprivate WfmidAppProcessInstanceHisMapper wfmidAppProcessInstanceHisMapper;@Autowiredprivate WfmidAppTaskInstanceMapper wfmidAppTaskInstanceMapper;@Autowiredprivate WfmidAppTaskInstanceHisMapper wfmidAppTaskInstanceHisMapper;@Autowiredprivate WfmidProcessInstanceMapper wfmidProcessInstanceMapper;@Autowiredprivate WfmidProcessInstanceHisMapper wfmidProcessInstanceHisMapper;@Autowiredprivate WfmidTaskInstanceMapper wfmidTaskInstanceMapper;@Autowiredprivate WfmidTaskInstanceHisMapper wfmidTaskInstanceHisMapper;@Autowiredprivate TbSysUnfinishedFlowMapper tbSysUnfinishedFlowMapper;@Autowiredprivate TbSysBackPositionInfoMapper tbSysBackPositionInfoMapper;@Autowiredprivate WorkFlowUtil workFlowUtil;@Autowiredprivate WorkFlowConvert workFlowConvert;@Autowiredprivate PageUtil pageUtil;@Autowiredprivate WebUtil webUtil;@Autowiredprivate OrganizationApiFeignClient organizationApiFeignClient;@Autowiredprivate LoanApiFeignClient loanApiFeignClient;@Autowiredprivate ManagementApiClient managementApiClient;@Autowiredprivate AccountApiClient accountApiClient;@Autowiredprivate OracleInQueryUtil oracleInQueryUtil;@Autowiredprivate UserApi userApi;@Autowiredprivate AfterLoanClient afterLoanClient;@Autowiredprivate QueryWorkFlowApiFeignClient queryWorkFlowApiFeignClient;@Autowiredprivate ManageForWorkflowApiClient manageForWorkflowApiClient;@Autowiredprivate ActHiTaskinstBackMapper actHiTaskinstBackMapper;@Autowiredprivate ActHiActinstBackMapper actHiActinstBackMapper;@Autowiredprivate ActHiCommentBackMapper actHiCommentBackMapper;@Autowiredprivate ActHiProcinstBackMapper actHiProcinstBackMapper;@Autowiredprivate ActHiProcinstMapper actHiProcinstMapper;@Autowiredprivate TbSysBackPositionInfoHisMapper tbSysBackPositionInfoHisMapper;@Autowiredprivate TbSysUnfinishedFlowHisMapper tbSysUnfinishedFlowHisMapper;@Autowiredprivate ActHiVarinstBackMapper actHiVarinstBackMapper;@Autowiredprivate ActivitiConvert activitiConvert;@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate TaskService taskService;@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate ProcessEngine processEngine;@Autowiredprivate HistoryService historyService;@Autowiredprivate IdentityService identityService;@Autowiredprivate ActivitiUtil activitiUtil;@Autowiredprivate TbSysWorkflowJumpMapper tbSysWorkflowJumpMapper;@Autowiredprivate HttpServletResponse response;/*** 代办未分类列表信息count查询** @param userCd 柜员号* @param orgCd  机构号* @return WorkFlowPage 分页信息*/@Overridepublic WorkFlowPage<List<Map<String, Object>>> findWorkCountFlowList(String userCd, String orgCd) {// 最终返回数据格式Map<String, Integer> countMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);// 设置查询参数userId为orgCd:userCdString userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE, userCd, orgCd);// 分页查询初始化任务列表信息,processVariableValueEquals可以对参数进行过滤,此处用不到TaskQuery taskQuery = taskService.createTaskQuery()// 当前处理人.taskAssignee(userId)// 活动流程任务.active()// 查询包含参数信息,可以过滤使用.includeProcessVariables()// 创建时间排序.orderByTaskCreateTime()// 倒序排序.desc();// 进行数据查询,此处无需分页处理,直接查询全部List<Task> taskList = taskQuery.list();// 非空判断if (ObjectUtil.isNotEmpty(taskList)) {taskList.forEach(task -> {// 获取任务参数信息Map<String, Object> paramMap = task.getProcessVariables();String bizType = StrUtil.emptyToDefault((String) paramMap.get(WorkFlowServerConstant.BIZ_TYPE_FLAG), StrUtil.EMPTY);String processKey = StrUtil.emptyToDefault((String) paramMap.get(WorkFlowServerConstant.PROCESS_KEY_FLAG), StrUtil.EMPTY);if (StrUtil.isNotBlank(bizType)&& !processKey.startsWith(WorkFlowServerConstant.STORE_PREFIX)&& !processKey.toLowerCase().startsWith(WorkFlowServerConstant.RSK_PREFIX)) {workFlowUtil.countWorkFlow(countMap, bizType);}});}// 设置最终返回结果集 List<Map<String, Object>> Map-> bizType,bizName,countList<Map<String, Object>> workMapList = new ArrayList<>();countMap.forEach((key, value) -> {Map<String, Object> workMap = new HashMap<>(3);workMap.put(WorkFlowServerConstant.BIZ_TYPE_FLAG, key);workMap.put(WorkFlowServerConstant.COUNT_FLAG, value);// 通过缓存平台获取缓存平台对应业务种类名称WorkFlowProductEnum productEnum = workFlowUtil.getProductEnumByBizType(key);if (ObjectUtil.isNotNull(productEnum)) {workMap.put(WorkFlowServerConstant.BIZ_NAME_FLAG, productEnum.getBizTypeName());} else {log.info("流程初始化获取WorkFlowProductEnum失败,对应key为[{}]!", key);}workMapList.add(workMap);});return pageUtil.setFlowListPage(workMapList, PaginationContext.getPageNum(), PaginationContext.getPageSize());}/*** 代办未分类列表信息count查询,新增系统标识参数** @param userCd     柜员号* @param orgCd      机构号* @param systemFlag 系统标识* @return WorkFlowPage 分页信息* @throws cn.git.workflow.webservice.query.BpmException_Exception 流程异常*/@Overridepublic WorkFlowPage<List<Map<String, Object>>> findSysWorkCountFlowList(String userCd,String orgCd,String systemFlag) {// 最终返回数据格式Map<String, Integer> countMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);// 设置查询参数userId为orgCd:userCdString userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE, userCd, orgCd);// 分页查询初始化任务列表信息,processVariableValueEquals可以对参数进行过滤,此处用不到TaskQuery taskQuery = taskService.createTaskQuery()// 当前处理人.taskAssignee(userId)// 活动流程任务.active()// 查询包含参数信息,可以过滤使用.includeProcessVariables()// 创建时间排序.orderByTaskCreateTime()// 倒序排序.desc();// 进行数据查询,此处无需分页处理,直接查询全部List<Task> taskList = taskQuery.list();// 空值判定if (ObjectUtil.isNotEmpty(taskList)) {taskList.forEach(task -> {// 获取参数信息,获取bizType以及流程定义keyMap<String, Object> paramMap = task.getProcessVariables();String bizType = StrUtil.emptyToDefault((String) paramMap.get(WorkFlowServerConstant.BIZ_TYPE_FLAG), StrUtil.EMPTY);String processKey = StrUtil.emptyToDefault((String) paramMap.get(WorkFlowServerConstant.PROCESS_KEY_FLAG), StrUtil.EMPTY);if (StrUtil.isBlank(systemFlag) || WorkFlowServerConstant.FLOW_TYPE_0.equals(systemFlag)) {// 信贷系统if (StrUtil.isNotBlank(bizType)&& !processKey.startsWith(WorkFlowServerConstant.STORE_PREFIX)&& !processKey.toLowerCase().startsWith(WorkFlowServerConstant.RSK_PREFIX)) {workFlowUtil.countWorkFlow(countMap, bizType);}} else if (WorkFlowServerConstant.STRING_NUM_1.equals(systemFlag)) {// 风险系统if (StrUtil.isNotBlank(bizType)&& processKey.toLowerCase().startsWith(WorkFlowServerConstant.RSK_PREFIX)) {workFlowUtil.countWorkFlow(countMap, bizType);}} else if (WorkFlowServerConstant.STRING_NUM_2.equals(systemFlag)) {// 储备系统if (StrUtil.isNotBlank(bizType)&& processKey.toLowerCase().startsWith(WorkFlowServerConstant.STORE_PREFIX)) {workFlowUtil.countWorkFlow(countMap, bizType);}}});}// 设置最终返回结果集 List<Map<String, Object>> Map-> bizType,bizName,countList<Map<String, Object>> workMapList = new ArrayList<>();countMap.forEach((key, value) -> {Map<String, Object> workMap = new HashMap<>(3);workMap.put(WorkFlowServerConstant.BIZ_TYPE_FLAG, key);workMap.put(WorkFlowServerConstant.COUNT_FLAG, value);// 通过缓存平台获取缓存平台对应业务种类名称WorkFlowProductEnum productEnum = workFlowUtil.getProductEnumByBizType(key);if (ObjectUtil.isNotNull(productEnum)) {workMap.put(WorkFlowServerConstant.BIZ_NAME_FLAG, productEnum.getBizTypeName());} else {log.info("流程初始化获取WorkFlowProductEnum失败,对应key为[{}]!", key);}workMapList.add(workMap);});return pageUtil.setFlowListPage(workMapList, PaginationContext.getPageNum(), PaginationContext.getPageSize());}/*** 具体业务代办任务详情列表查询** @param workFlowUndoTaskDTO undoDto* @return WorkFlowPage 代办详情列表信息*/@Overridepublic WorkFlowPage<WorkFlowUndoTask> findUndoWorkTaskDetailList(WorkFlowUndoTaskDTO workFlowUndoTaskDTO) {log.info("具体代办业务查询参数[{}]", workFlowUndoTaskDTO.toString());// 获取业务信息WorkFlowProductEnum workFlowProductEnum = workFlowUtil.getProductEnumByBizType(workFlowUndoTaskDTO.getBizType());if (ObjectUtil.isNull(workFlowProductEnum)) {throw new ServiceException(StrUtil.format("通过流程bizType[{}]获取流程模板信息为空!",workFlowUndoTaskDTO.getBizType()));}// 设置查询参数userId为orgCd:userCdString userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE,workFlowUndoTaskDTO.getUserCd(),workFlowUndoTaskDTO.getOrgCd());// 分页查询初始化任务列表信息,processVariableValueEquals可以对参数进行过滤,此处用不到TaskQuery taskQuery = taskService.createTaskQuery()// 当前处理人.taskAssignee(userId)// 活动流程任务.active()// 查询包含参数信息,可以过滤使用.includeProcessVariables()// 创建时间排序.orderByTaskCreateTime()// 倒序排序.desc();// 进行数据查询,此处无需分页处理,直接查询全部List<Task> taskList = taskQuery.list();// 响应数据信息List<WorkFlowUndoTask> workFlowDtoList = new ArrayList<>();// 非空判定if (ObjectUtil.isNotEmpty(taskList)) {// 获取缓存参数信息,获取bizType对应的中文转义字段名称List<String> codeTypeCdList = new ArrayList<>();codeTypeCdList.add("ProcessTypeCd");Map<String, String> codeInfoMap = baseCacheApi.getTypeCdValueKeyMap(codeTypeCdList);// 获取柜员名称以及机构信息List<String> userInfoList =taskList.stream().map(task -> {Map<String, Object> processVariableMap = task.getProcessVariables();if (workFlowProductEnum.getBizType().equals(StrUtil.toString(processVariableMap.get(WorkFlowServerConstant.BIZ_TYPE_FLAG)))) {return StrUtil.toString(processVariableMap.get(WorkFlowServerConstant.CREATOR_FLAG));} else {return null;}}).collect(Collectors.toList()).stream().distinct().filter(Objects::nonNull).collect(Collectors.toList());// 获取用户信息列表List<String> userCdList = userInfoList.stream().map(userInfo -> {String[] creatorInfo = userInfo.split(WorkFlowServerConstant.SPLIT_FLAG);return creatorInfo[0];}).collect(Collectors.toList());// 判断为空if (ObjectUtil.isEmpty(userCdList)) {return pageUtil.setFlowListPage(workFlowDtoList, PaginationContext.getPageNum(),PaginationContext.getPageSize());}List<ManageUserDTO> userDTOList = managementApiClient.listUserInfoByUserCd(userCdList);Map<String, String> userInfoMap = userDTOList.stream().collect(Collectors.toMap(ManageUserDTO::getUserCd, ManageUserDTO::getUserName, (k1, k2) -> k2));// 获取机构信息列表List<String> orgList = userInfoList.stream().map(userInfo -> {String[] creatorInfo = userInfo.split(WorkFlowServerConstant.SPLIT_FLAG);return creatorInfo[1];}).collect(Collectors.toList());ManageOrganizationListDTO orgDTO = organizationApiFeignClient.listInfoByOrgCdList(orgList);List<ManageOrganizationDTO> organizationInfoList = orgDTO.getOrganizationInfoList();Map<String, String> orgInfoMap = organizationInfoList.stream().collect(Collectors.toMap(ManageOrganizationDTO::getOrgCd,ManageOrganizationDTO::getOrgName, (k1, k2) -> k2));List<WorkFlowUndoTask> finalWorkFlowDtoList = workFlowDtoList;taskList.forEach(task -> {// 获取参数信息Map<String, Object> processVariableMap = task.getProcessVariables();// 类型判定if (workFlowProductEnum.getBizType().equals(StrUtil.toString(processVariableMap.get(WorkFlowServerConstant.BIZ_TYPE_FLAG)))) {WorkFlowUndoTask undoTask = new WorkFlowUndoTask();undoTask.setBizNo(StrUtil.toString(processVariableMap.get(WorkFlowServerConstant.BIZ_ID_FLAG)));undoTask.setCustomerName(StrUtil.toString(processVariableMap.get(WorkFlowServerConstant.CUSTOMER_NAME_FLAG)));// 缓存信息获取码值中文名称String codeName = codeInfoMap.get("ProcessTypeCd".concat(StrUtil.UNDERLINE).concat(workFlowUndoTaskDTO.getBizType()));undoTask.setBizType(workFlowUndoTaskDTO.getBizType());undoTask.setProcessTypeName(codeName);WorkFlowProductEnum productEnum = workFlowUtil.getProductEnumByBizType(workFlowUndoTaskDTO.getBizType());// 设置业务名称undoTask.setBizName(productEnum.getBizTypeName());// 创建柜员String[] creatorInfo = StrUtil.toString(processVariableMap.get(WorkFlowServerConstant.CREATOR_FLAG)).split(WorkFlowServerConstant.SPLIT_FLAG);undoTask.setProcessCreator(creatorInfo[0]);undoTask.setProcessCreatorName(userInfoMap.get(creatorInfo[0]));SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 机构信息undoTask.setOrgCd(creatorInfo[1]);undoTask.setOrgName(orgInfoMap.get(creatorInfo[1]));// 执行ID processVariableMap.get(WorkFlowServerConstant.EXECUTION_ID_FLAG).toString() 修改为task获取undoTask.setExecutionId(task.getExecutionId());// 创建时间字符串undoTask.setProcessCreateTimeStr(sdf.format(task.getCreateTime()));undoTask.setProcessCreateTime(task.getCreateTime());// 岗位idundoTask.setActivityId(task.getName());// 任务idundoTask.setTaskId(task.getId());// 客户名称校验if (StrUtil.isNotBlank(workFlowUndoTaskDTO.getCustomerName())) {String undoCustomerName = StrUtil.toString(processVariableMap.get(WorkFlowServerConstant.CUSTOMER_NAME_FLAG));if (StrUtil.isNotBlank(undoCustomerName)&& undoCustomerName.contains(workFlowUndoTaskDTO.getCustomerName())) {finalWorkFlowDtoList.add(undoTask);}} else {finalWorkFlowDtoList.add(undoTask);}}});}return pageUtil.setFlowListPage(workFlowDtoList, PaginationContext.getPageNum(),PaginationContext.getPageSize());}/*** 代办任务点击,贷审会审批结果校验,任务详情页面跳转** @param taskId 任务编号* @param userCd 用户柜员号* @param orgCd  机构号* @return WorkFlowUndoTaskDetailDTO taskInfo详情*/@Overridepublic WorkFlowUndoTaskDetailDTO findTaskDetailInfo(String taskId, String userCd, String orgCd) {log.info("代办任务点击,贷审会审批结果校验,任务详情页面跳转参数taskId[{}], userCd[{}], orgCd[{}]",taskId, userCd, orgCd);// 最终返回dtoWorkFlowUndoTaskDetailDTO undoTaskDetailDto = new WorkFlowUndoTaskDetailDTO();undoTaskDetailDto.setTaskId(taskId);undoTaskDetailDto.setOrgCd(orgCd);// 通过taskId获取任务信息Task task = taskService.createTaskQuery().taskId(taskId).singleResult();// 非空判定if (ObjectUtil.isNotNull(task)) {// 获取节点名称eg: usertask01以及流程实例idString activityId = task.getName();String processInstanceId = task.getProcessInstanceId();undoTaskDetailDto.setProcessId(processInstanceId);// 通过流程id获取流程实例信息,设置返回路径以及流程模板等信息ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).includeProcessVariables().singleResult();// 业务编号String bizNo = null;// 非空判定if (ObjectUtil.isNotNull(processInstance)) {// 获取业务编号以及流程名称bizNo = processInstance.getBusinessKey();String templateNum = processInstance.getProcessDefinitionName();List<Map<String, String>> urlNameMapList = tbSysFlowPositionDetailMapper.listSysFlowUrlName(templateNum,activityId);if (ObjectUtil.isNotEmpty(urlNameMapList)) {// 返回urlundoTaskDetailDto.setUri(urlNameMapList.get(0).get(WorkFlowServerConstant.URL_NAME_FLAG));// 返回当前登录岗位对应流程模板中节点idundoTaskDetailDto.setCurrentActivityId(urlNameMapList.get(0).get(WorkFlowServerConstant.ACTIVITI_ID_FLAG));}// 获取参数信息Map<String, Object> processVariables = processInstance.getProcessVariables();processVariables.put(WorkFlowServerConstant.ACTIVITY_NAME_FLAG, activityId);undoTaskDetailDto.setBizNo(bizNo);undoTaskDetailDto.setVariableMap(processVariables);}// 判断只有“贷审会秘书录结果岗”,“有权签批岗”,“最高签批岗”进行获取贷审会信息。if (WorkFlowServerConstant.LOAN_MEET_SECRETARY_RESULT.equals(activityId.substring(WorkFlowServerConstant.INT_NUM_2))|| activityId.contains(WorkFlowServerConstant.MEETING_RESULT_POSITION)|| WorkFlowServerConstant.HAVE_SIGN_APPROVE.equals(activityId.substring(WorkFlowServerConstant.INT_NUM_2))|| WorkFlowServerConstant.MOST_SIGN_APPROVE.equals(activityId.substring(WorkFlowServerConstant.INT_NUM_2))|| WorkFlowServerConstant.PROVINCE_REVIEW_APPROVE.equals(activityId)|| WorkFlowServerConstant.PROVINCE_CHECK_APPROVE.equals(activityId)) {// 代办任务点击贷审会校验,最终会返回check结果QueryWrapper<TbConVote> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(TbConVote::getBizNum, bizNo).eq(TbConVote::getStatus, WorkFlowServerConstant.VOTE_STATUS_ACTIVE).orderByDesc(TbConVote::getVoteNum);List<TbConVote> voteList = tbConVoteMapper.selectList(queryWrapper);if (ObjectUtil.isNotEmpty(voteList)) {VoteCheckDTO voteDto = workFlowUtil.checkVoteMeetingResult(voteList, orgCd);if (StrUtil.isNotBlank(voteDto.getErrorMessage())) {undoTaskDetailDto.setErrorMessage(voteDto.getErrorMessage());return undoTaskDetailDto;}undoTaskDetailDto.setVoteCheckDTO(voteDto);// 0 没有发起会议 1发起了会议undoTaskDetailDto.setVoteMessage("1");} else {// 0 没有发起会议 1发起了会议undoTaskDetailDto.setVoteMessage("0");}}}return undoTaskDetailDto;}/*** 获取流程图** @param processId* @return*/@Overridepublic String findProcessPic(String processId) throws IOException {// 获取流程实例信息ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();// 通过流程定义id获取流程定义信息ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();// 获取流程引擎配置信息ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);// 获取流程图生成器ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processDefinition.getId());// 历史信息获取List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).list();// 高亮环节id集合List<String> highLightedActivitis = new ArrayList<>();// 高亮线路id集合List<String> highLightedFlows = getHighLightedFlows(definitionEntity,highLightedActivitList);highLightedActivitList.forEach(tempActivity -> {String activityId = tempActivity.getActivityId();highLightedActivitis.add(activityId);});//中文显示的是口口口,设置字体就好了BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel,"png",highLightedActivitis,highLightedFlows,"宋体","宋体","宋体",null,1.0);// 获取图片的二进制数据byte[] picByte = IOUtils.toByteArray(inputStream);return DatatypeConverter.printBase64Binary(picByte);}/*** 获取高亮线** @param processDefinitionEntity* @param historicActivityInstances* @return*/public List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,List<HistoricActivityInstance> historicActivityInstances) {// 用以保存高亮的线flowIdList<String> highFlows = new ArrayList<>();// 对历史流程节点进行遍历for (int i = 0; i < historicActivityInstances.size() - 1; i++) {ActivityImpl activityImpl = processDefinitionEntity.findActivity(historicActivityInstances.get(i)// 得到节点定义的详细信息.getActivityId());// 用以保存后需开始时间相同的节点List<ActivityImpl> sameStartTimeNodes = new ArrayList<>();ActivityImpl sameActivityImpl1 = processDefinitionEntity.findActivity(historicActivityInstances.get(i + 1).getActivityId());// 将后面第一个节点放在时间相同节点的集合里sameStartTimeNodes.add(sameActivityImpl1);// 取出节点的所有出去的线for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {// 后续第一个节点HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第二个节点HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {// 如果第一个节点和第二个节点开始时间相同保存ActivityImpl sameActivityImpl2 = processDefinitionEntity.findActivity(activityImpl2.getActivityId());sameStartTimeNodes.add(sameActivityImpl2);} else {// 有不相同跳出循环break;}}// 取出节点的所有出去的线List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();for (PvmTransition pvmTransition : pvmTransitions) {// 对所有的线进行遍历ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();// 如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示if (sameStartTimeNodes.contains(pvmActivityImpl)) {highFlows.add(pvmTransition.getId());}}}return highFlows;}/*** 开始一个新流程** @param startProcessDTO 流程参数* @return Map<String, Object> 流程发起参数信息*/@Override@Transactional(rollbackFor = Exception.class)public Map<String, Object> startProcess(WorkFlowStartProcessDTO startProcessDTO) {log.info("开始一个新流程参数信息startProcessDTO[{}]", startProcessDTO.toString());// 拼装流程发起参数String userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE, startProcessDTO.getUserCd(),startProcessDTO.getOrgCd());Map<String, Object> variableMap = startProcessDTO.getVariableMap();// 流程发起用户idvariableMap.put(WorkFlowServerConstant.BIZ_TYPE_FLAG, startProcessDTO.getWorkFlowProductEnum().getBizType());// 流程业务名称variableMap.put(WorkFlowServerConstant.PRODUCT_TYPE_FLAG, startProcessDTO.getWorkFlowProductEnum().getBizTypeName());// 流程发起人variableMap.put(WorkFlowServerConstant.CREATOR_FLAG, userId);// 客户类型 固定 “2” 法人variableMap.put(WorkFlowServerConstant.CUSTOMER_TYPE_FLAG, WorkFlowServerConstant.STRING_NUM_2);// 客户名称variableMap.put(WorkFlowServerConstant.CUSTOMER_NAME_FLAG, startProcessDTO.getCustomerName());// 客户编号variableMap.put(WorkFlowServerConstant.CUSTOMER_NUM_FLAG, startProcessDTO.getCustomerNum());// 业务编号variableMap.put(WorkFlowServerConstant.BIZ_ID_FLAG, startProcessDTO.getBizId());log.info(String.format("开始一个新流程发送参数: %s", JSONObject.toJSONString(variableMap)));// 工作流引擎会基于这个设置的用户ID来检查用户是否有权限执行特定的操作,比如任务分配给自己或者其他人identityService.setAuthenticatedUserId(userId);// 发起流程ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(startProcessDTO.getWorkFlowProductEnum().getTemplateId(),startProcessDTO.getBizId(),variableMap);// 获取当前任务列表,刚刚发起业务,应该只有一个值List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();Map<String, Object> returnVariableMap = new HashMap<>();if (ObjectUtil.isNotEmpty(list)) {Task currentTask = list.get(0);returnVariableMap.put(WorkFlowServerConstant.TASK_ID_FLAG, currentTask.getId());returnVariableMap.put(WorkFlowServerConstant.ACTIVITY_NAME_FLAG, currentTask.getName());returnVariableMap.put(WorkFlowServerConstant.TASK_DEF_KEY, currentTask.getTaskDefinitionKey());returnVariableMap.put(WorkFlowServerConstant.PROCESS_ID_FLAG, processInstance.getProcessInstanceId());}// 新增业务插入到在途业务表中TbSysUnfinishedFlow tbSysUnfinishedFlow = new TbSysUnfinishedFlow();tbSysUnfinishedFlow.setId(IdUtil.simpleUUID());tbSysUnfinishedFlow.setCustomerNum(startProcessDTO.getCustomerNum());tbSysUnfinishedFlow.setCustomerName(startProcessDTO.getCustomerName());tbSysUnfinishedFlow.setBizNo(startProcessDTO.getBizId());tbSysUnfinishedFlow.setProcessId(processInstance.getProcessInstanceId());tbSysUnfinishedFlow.setBizName(startProcessDTO.getWorkFlowProductEnum().getBizTypeName());if (ObjectUtil.isNotNull(startProcessDTO.getWorkFlowSysEnum())) {tbSysUnfinishedFlow.setSystemFlag(startProcessDTO.getWorkFlowSysEnum().getSystemFlag());} else {tbSysUnfinishedFlow.setSystemFlag(WorkFlowSysEnum.DICS.getSystemFlag());}tbSysUnfinishedFlowMapper.insert(tbSysUnfinishedFlow);// 开始插入退回上调查复核岗对应所需信息,包含流程模板编号,以及processId,柜员编号机构号等TbSysBackPositionInfo tbSysBackPositionInfo = new TbSysBackPositionInfo();tbSysBackPositionInfo.setId(IdUtil.simpleUUID());tbSysBackPositionInfo.setProcessId(StrUtil.toString(returnVariableMap.get(WorkFlowServerConstant.PROCESS_ID_FLAG)));tbSysBackPositionInfo.setWorkFlowTemplateId(startProcessDTO.getWorkFlowProductEnum().getTemplateId());tbSysBackPositionInfo.setOptionUserCd(startProcessDTO.getUserCd());tbSysBackPositionInfo.setOptionOrgCd(startProcessDTO.getOrgCd());tbSysBackPositionInfo.setActivitiId(WorkFlowServerConstant.USER_TASK_FLAG_START);tbSysBackPositionInfo.setSubmitTime(new Date());tbSysBackPositionInfo.setBizNo(startProcessDTO.getBizId());tbSysBackPositionInfo.setIsDel(WorkFlowServerConstant.FLOW_TYPE_1);tbSysBackPositionInfoMapper.insert(tbSysBackPositionInfo);return returnVariableMap;}/*** 撤销流程** @param workFlowCancelDTO 流程撤销dto*/@Override@Transactional(rollbackFor = Exception.class)public void cancelProcessByProcessId(WorkFlowCancelDTO workFlowCancelDTO) {log.info("开始调用撤销流程方法,撤销参数信息[{}]", JSONObject.toJSONString(workFlowCancelDTO));// 拼装流程撤销参数String userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE,workFlowCancelDTO.getUserCd(),workFlowCancelDTO.getOrgCd());// 删除在途业务QueryWrapper<TbSysUnfinishedFlow> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(TbSysUnfinishedFlow::getBizNo, workFlowCancelDTO.getBizId());tbSysUnfinishedFlowMapper.delete(queryWrapper);// 删除退出上一岗位信息内容UpdateWrapper<TbSysBackPositionInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.lambda().eq(TbSysBackPositionInfo::getProcessId, workFlowCancelDTO.getProcessId());tbSysBackPositionInfoMapper.delete(updateWrapper);// 权限认证identityService.setAuthenticatedUserId(userId);// 开始进行业务撤销runtimeService.deleteProcessInstance(workFlowCancelDTO.getProcessId(),WorkFlowServerConstant.DEFAULT_CANCEL_REASON);}/*** 回退流程到发起岗位** @param workFlowTaskBackDTO 回退流程到发起岗位dto* @return Map<String, Object> 撤销返回参数*/@Override@Transactional(rollbackFor = Exception.class)public Map<String, Object> submitTaskBack(WorkFlowTaskBackDTO workFlowTaskBackDTO) {// 获取任务信息Task currentTask = taskService.createTaskQuery().taskId(workFlowTaskBackDTO.getTaskId()).singleResult();// 设置意见信息if (ObjectUtil.isNotNull(workFlowTaskBackDTO.getComment())) {//只保留一条批注记录List<Comment> commentList = taskService.getTaskComments(currentTask.getId());if(ObjectUtil.isNotEmpty(commentList)){commentList.forEach(common -> {taskService.deleteComment(common.getId());});}// 添加新的批注信息taskService.addComment(currentTask.getId(), currentTask.getProcessInstanceId(),workFlowTaskBackDTO.getComment());}// 获取流程发起对应柜员信息String processId = workFlowTaskBackDTO.getProcessId();if (StrUtil.isBlank(processId)) {processId = currentTask.getProcessInstanceId();workFlowTaskBackDTO.setProcessId(processId);}TbSysBackPositionInfo backPositionInfo = tbSysBackPositionInfoMapper.getBackPositionInfoByProcessId(processId);if (ObjectUtil.isNull(backPositionInfo)) {throw new ServiceException("通过processId[{}]获取流程发起柜员机构信息为空,流程退回到发起岗失败!");}// 拼装流程回退参数String userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE, backPositionInfo.getOptionUserCd(),backPositionInfo.getOptionOrgCd());// 获取当前操作柜员信息,并且保存退回上一处理人信息String optionUserCd = webUtil.getCurrentUserCd();String optionOrgCd = webUtil.getCurrentOrgCd();TbSysBackPositionInfo tbSysBackPositionInfo = new TbSysBackPositionInfo();tbSysBackPositionInfo.setId(IdUtil.simpleUUID());tbSysBackPositionInfo.setActivitiId(workFlowTaskBackDTO.getCurrentActivityId());tbSysBackPositionInfo.setProcessId(workFlowTaskBackDTO.getProcessId());tbSysBackPositionInfo.setOptionOrgCd(optionOrgCd);tbSysBackPositionInfo.setOptionUserCd(optionUserCd);tbSysBackPositionInfo.setWorkFlowTemplateId(backPositionInfo.getWorkFlowTemplateId());tbSysBackPositionInfo.setBizNo(backPositionInfo.getBizNo());tbSysBackPositionInfo.setSubmitTime(new Date());tbSysBackPositionInfo.setIsDel(WorkFlowServerConstant.STRING_NUM_1);// 设置流程意见信息tbSysBackPositionInfo.setFlowComment(workFlowTaskBackDTO.getComment());log.info("回退流程到发起岗位保存信息[{}]", JSONObject.toJSONString(tbSysBackPositionInfo));tbSysBackPositionInfoMapper.insert(tbSysBackPositionInfo);// 回退参数MapMap<String, Object> backMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);backMap.put(WorkFlowServerConstant.USER_ID_FLAG, userId);// 删除退出上一岗位信息内容if (StrUtil.isNotBlank(workFlowTaskBackDTO.getProcessId())) {UpdateWrapper<TbSysBackPositionInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.lambda().eq(TbSysBackPositionInfo::getProcessId, workFlowTaskBackDTO.getProcessId());log.info("回退流程到发起岗位,删除退回上一岗信息,参数processId[{}]", workFlowTaskBackDTO.getProcessId());tbSysBackPositionInfoMapper.delete(updateWrapper);}// 设置权限信息identityService.setAuthenticatedUserId(userId);// 获取当前任务参数信息Map<String, Object> processVariables = currentTask.getProcessVariables();processVariables.put(WorkFlowServerConstant.COMMENT_FLAG, workFlowTaskBackDTO.getComment());processVariables.put(WorkFlowServerConstant.OPINION_FLAG, workFlowTaskBackDTO.getComment());// 对历史任务进行正序排序,获取最早的任务节点List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()// 流程执行id.executionId(currentTask.getProcessInstanceId())// 按照时间排序.orderByHistoricActivityInstanceStartTime().asc().list();// 找到第一个userTask类型的任务节点,既为发起节点HistoricActivityInstance firstActivityInstance = activityInstanceList.stream().filter(activityInstance ->WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityInstance.getActivityType())).findFirst().orElse(null);// 空值判定if (ObjectUtil.isNull(firstActivityInstance)) {throw new ServiceException("未找到流程发起节点信息,退回到发起节点异常!");}// 获取实际发起节点的流程定义信息ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(firstActivityInstance.getProcessDefinitionId());// 获取发起节点定义信息ActivityImpl startActivity = processDefinition.findActivity(firstActivityInstance.getActivityId());// 获取当前节点定义信息ActivityImpl currentTaskActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());// 退回首节点校验,首节点不能再次退回首节点if(startActivity.getId().equals(currentTask.getTaskDefinitionKey())){throw new ServiceException("当前节点为首节点,无法退回");}// 通过流程实例id以及任务定义key获取同级别任务列表信息,既需要退回的任务List<Task> backTaskList = taskService.createTaskQuery().processInstanceId(workFlowTaskBackDTO.getProcessId()).taskDefinitionKey(currentTask.getTaskDefinitionKey()).list();backTaskList.forEach(task -> {// 进行任务跳转activitiUtil.turnTransitionForUTask(task.getId(),currentTaskActivity,startActivity,processVariables);});// 通过processId获取最新的一个task任务信息List<Task> nextTaskList = taskService.createTaskQuery()// 流程实例id.processInstanceId(processId)// 存活状态.active()// 按照日期排序,最新的一个.orderByTaskCreateTime().desc().list();// 空值判定Map<String, Object> returnVariableMap = null;if (ObjectUtil.isNotEmpty(nextTaskList)) {// 获取当下生效的taskIdString activeTaskId = nextTaskList.get(0).getId();// 进行处理人强制转换,修改流程处理人信息Task nextTask = taskService.createTaskQuery().taskId(activeTaskId).singleResult();nextTask.setAssignee(userId);taskService.saveTask(nextTask);taskService.claim(nextTask.getId(), userId);// 设置响应参数returnVariableMap = new HashMap<>();returnVariableMap.put("nextTaskId", nextTask.getId());returnVariableMap.put("taskName", nextTask.getName());returnVariableMap.put("taskDefKey", nextTask.getTaskDefinitionKey());returnVariableMap.put("creator", nextTask.getAssignee());}return returnVariableMap;}/*** 提交任务到下一岗位** @param workFlowSubmitTaskDTO dto*/@Override@Transactional(rollbackFor = Exception.class)public Map<String, Object> submitNormalTask(WorkFlowSubmitTaskDTO workFlowSubmitTaskDTO) {// 参数校验if (StrUtil.isBlank(workFlowSubmitTaskDTO.getCurrentActivityId())) {throw new ServiceException("提交下一岗位回退上一处理人[currentActivityId]信息为空!");}if (StrUtil.isBlank(workFlowSubmitTaskDTO.getProcessId())) {throw new ServiceException("提交下一岗位当前流程[processId]信息为空!");}// 当前岗位信息不能为usertask0,usertask0为开始流程默认岗位编号if (WorkFlowServerConstant.USER_TASK_FLAG_START.equals(workFlowSubmitTaskDTO.getCurrentActivityId())) {throw new ServiceException("传入当前岗位信息不能为usertask0!");}// 下一处理人格式校验if (StrUtil.isBlank(workFlowSubmitTaskDTO.getWfusers())|| !workFlowSubmitTaskDTO.getWfusers().contains(StrUtil.COLON)) {throw new ServiceException("下一处理人格式为 userCd:orgCd,请确认!");}// 通过流程processId获取bizNo信息,以及流程模板编号信息TbSysBackPositionInfo startPositionInfo = tbSysBackPositionInfoMapper.getBackPositionInfoByProcessId(workFlowSubmitTaskDTO.getProcessId());// 获取当前操作柜员信息,并且保存退回上一处理人信息String optionUserCd = webUtil.getCurrentUserCd();String optionOrgCd = webUtil.getCurrentOrgCd();TbSysBackPositionInfo tbSysBackPositionInfo = new TbSysBackPositionInfo();tbSysBackPositionInfo.setId(IdUtil.simpleUUID());tbSysBackPositionInfo.setActivitiId(workFlowSubmitTaskDTO.getCurrentActivityId());tbSysBackPositionInfo.setProcessId(workFlowSubmitTaskDTO.getProcessId());tbSysBackPositionInfo.setOptionOrgCd(optionOrgCd);tbSysBackPositionInfo.setOptionUserCd(optionUserCd);if (ObjectUtil.isNotNull(startPositionInfo)) {tbSysBackPositionInfo.setWorkFlowTemplateId(startPositionInfo.getWorkFlowTemplateId());tbSysBackPositionInfo.setBizNo(startPositionInfo.getBizNo());}tbSysBackPositionInfo.setSubmitTime(new Date());// 设置流程意见信息tbSysBackPositionInfo.setFlowComment(workFlowSubmitTaskDTO.getComment());log.info("正常提交方法,保存退回上一处理人信息[{}]", JSONObject.toJSONString(tbSysBackPositionInfo));tbSysBackPositionInfoMapper.insert(tbSysBackPositionInfo);// 设置提交流程参数信息Map<String, Object> paramMap = workFlowSubmitTaskDTO.getVariableMap();if (ObjectUtil.isEmpty(paramMap)) {paramMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);}// 下一处理人paramMap.put(WorkFlowServerConstant.WORKFLOW_USERS_FLAG, workFlowSubmitTaskDTO.getWfusers());// 审批信息paramMap.put(WorkFlowServerConstant.COMMENT_FLAG, workFlowSubmitTaskDTO.getComment());// 审批信息paramMap.put(WorkFlowServerConstant.OPINION_FLAG, workFlowSubmitTaskDTO.getComment());// 开始提交到下一审批人log.info("正常提交方法,提交参数[{}]", JSONObject.toJSONString(paramMap));// 设置权限信息identityService.setAuthenticatedUserId(workFlowSubmitTaskDTO.getWfusers());// 获取当前任务信息Task task = taskService.createTaskQuery().taskId(workFlowSubmitTaskDTO.getTaskId()).singleResult();// 获取执行idString executionId = task.getExecutionId();// 设置留言信息,只留一条批注信息List<Comment> commentList = taskService.getTaskComments(task.getId());if(ObjectUtil.isNotEmpty(commentList)){for(Comment comment : commentList){// 删除原有批注信息taskService.deleteComment(comment.getId());}}// 添加批注信息taskService.addComment(task.getId(), task.getProcessInstanceId(), workFlowSubmitTaskDTO.getComment());// 设置参数信息runtimeService.setVariables(executionId, paramMap);// 开始提交任务taskService.complete(task.getId(), paramMap);// 进行用户认领操作List<Task> taskList = taskService.createTaskQuery()// 执行id.executionId(executionId).list();// 进行认领操作Map<String, Object> returnMap = new HashMap<>();if (ObjectUtil.isNotEmpty(taskList)) {// 进行处理人强制转换Task nextTask = taskService.createTaskQuery().taskId(taskList.get(0).getId()).singleResult();nextTask.setAssignee(workFlowSubmitTaskDTO.getWfusers());taskService.saveTask(nextTask);taskService.claim(nextTask.getId(), workFlowSubmitTaskDTO.getWfusers());// 设置响应信息returnMap.put(WorkFlowServerConstant.NEXT_TASK_ID, nextTask.getId());returnMap.put(WorkFlowServerConstant.TASK_DEF_KEY, nextTask.getTaskDefinitionKey());returnMap.put(WorkFlowServerConstant.TASK_NAME_FLAG,  nextTask.getName());}return returnMap;}/*** 回退流程到上一岗位** @param workFlowBackPreviousDTO 流程实例退回上一岗位dto* @return String 撤销信息*/@Transactional(rollbackFor = Exception.class)@Overridepublic String submitBackPrevious(WorkFlowBackPreviousDTO workFlowBackPreviousDTO) {log.info("回退流程到上一岗位参数信息workFlowBackPreviousDTO[{}]", workFlowBackPreviousDTO.toString());// 最终返回信息,非空则有问题String errorMessage;// 获取上一岗位信息String processId = workFlowBackPreviousDTO.getProcessId();QueryWrapper<TbSysBackPositionInfo> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(TbSysBackPositionInfo::getProcessId, processId).eq(TbSysBackPositionInfo::getIsDel, WorkFlowConstant.STRING_NUM_0).orderBy(true, false, TbSysBackPositionInfo::getSubmitTime);List<TbSysBackPositionInfo> backPositionInfoList = tbSysBackPositionInfoMapper.selectList(queryWrapper);if (ObjectUtil.isEmpty(backPositionInfoList)) {errorMessage = StrUtil.format("通过流程实例id[{}]没有找到上一岗位信息!",workFlowBackPreviousDTO.getProcessId());log.error(errorMessage);return errorMessage;}TbSysBackPositionInfo previousInfo = backPositionInfoList.get(0);// 判断当前岗位为贷审会秘书岗时撤回业务,需要校验发起的会议是否已经都投票完成if (StrUtil.isNotBlank(workFlowBackPreviousDTO.getPositionName())&& workFlowBackPreviousDTO.getPositionName().contains(WorkFlowServerConstant.LOAN_MEET_SECRETARY)) {// 校验委员是否全部投票完成QueryWrapper<TbConVote> voteQueryWrapper = new QueryWrapper<>();voteQueryWrapper.lambda().eq(TbConVote::getBizNum, previousInfo.getBizNo()).eq(TbConVote::getStatus, WorkFlowServerConstant.VOTE_STATUS_ACTIVE).isNull(TbConVote::getVote).orderByDesc(TbConVote::getVoteNum);List<TbConVote> voteList = tbConVoteMapper.selectList(voteQueryWrapper);if (ObjectUtil.isNotEmpty(voteList) && voteList.size() > WorkFlowServerConstant.SIZE_0) {// 未进行投票的柜员编号List<String> unVoteUserCdList = voteList.stream().map(TbConVote::getUserNum).collect(Collectors.toList());// 获取userCd对应用户名称String undoVoteUserNames = userApi.listUserInfoByUserCd(unVoteUserCdList).stream().map(nameInfoDTO -> {String appendNameCd = StrUtil.format(WorkFlowServerConstant.APPEND_TEMPLATE,nameInfoDTO.getUserCd(),nameInfoDTO.getUserName());return appendNameCd;}).collect(Collectors.joining(WorkFlowServerConstant.SPLIT_COMMA_FLAG));errorMessage = StrUtil.format(WorkFlowServerConstant.APPEND_TEMPLATE_VOTE_CHECK,WorkFlowServerConstant.UN_VOTE_CHECK_MESSAGE_FRONT,undoVoteUserNames,WorkFlowServerConstant.UN_VOTE_CHECK_RECALL);return errorMessage;}}// 如果未传currentActivityId,需要计算当前业务currentActivityId信息Task currentTask = taskService.createTaskQuery().taskId(workFlowBackPreviousDTO.getTaskId()).singleResult();if (StrUtil.isBlank(workFlowBackPreviousDTO.getCurrentActivityId())) {if (ObjectUtil.isNotNull(currentTask)) {log.info("通过getCurrentActivityId获取activitiId信息为[{}]", currentTask.getTaskDefinitionKey());workFlowBackPreviousDTO.setCurrentActivityId(currentTask.getTaskDefinitionKey());}}// 设置意见信息if (ObjectUtil.isNotNull(workFlowBackPreviousDTO.getOpinion())) {//只保留一条批注记录List<Comment> commentList = taskService.getTaskComments(currentTask.getId());if(ObjectUtil.isNotEmpty(commentList)){commentList.forEach(common -> {taskService.deleteComment(common.getId());});}// 添加新的批注信息taskService.addComment(currentTask.getId(), currentTask.getProcessInstanceId(), workFlowBackPreviousDTO.getOpinion());}// 获取当前操作柜员信息,并且保存退回上一处理人信息String optionUserCd = webUtil.getCurrentUserCd();String optionOrgCd = webUtil.getCurrentOrgCd();TbSysBackPositionInfo tbSysBackPositionInfo = new TbSysBackPositionInfo();tbSysBackPositionInfo.setId(IdUtil.simpleUUID());tbSysBackPositionInfo.setActivitiId(workFlowBackPreviousDTO.getCurrentActivityId());tbSysBackPositionInfo.setProcessId(workFlowBackPreviousDTO.getProcessId());tbSysBackPositionInfo.setOptionOrgCd(optionOrgCd);tbSysBackPositionInfo.setOptionUserCd(optionUserCd);tbSysBackPositionInfo.setWorkFlowTemplateId(previousInfo.getWorkFlowTemplateId());tbSysBackPositionInfo.setBizNo(previousInfo.getBizNo());tbSysBackPositionInfo.setSubmitTime(new Date());tbSysBackPositionInfo.setIsDel(WorkFlowServerConstant.STRING_NUM_1);// 设置流程意见信息tbSysBackPositionInfo.setFlowComment(workFlowBackPreviousDTO.getOpinion());log.info("回退流程到上一岗位保存信息[{}]", JSONObject.toJSONString(tbSysBackPositionInfo));tbSysBackPositionInfoMapper.insert(tbSysBackPositionInfo);// 如果流程节点是usertask1,证明提交到第二个岗位,直接调用回退到发起岗位方法if (WorkFlowServerConstant.FIRST_ACTIVITI_ID.equals(previousInfo.getActivitiId())) {// 任务回退到发起岗位,设置信息字段WorkFlowTaskBackDTO workFlowTaskBackDTO = new WorkFlowTaskBackDTO();workFlowTaskBackDTO.setProcessId(workFlowBackPreviousDTO.getProcessId());workFlowTaskBackDTO.setTaskId(workFlowBackPreviousDTO.getTaskId());workFlowTaskBackDTO.setUserCd(previousInfo.getOptionUserCd());workFlowTaskBackDTO.setOrgCd(previousInfo.getOptionOrgCd());submitTaskBack(workFlowTaskBackDTO);return null;}// 权限设定String nextUserId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE,previousInfo.getOptionUserCd(),previousInfo.getOptionOrgCd());identityService.setAuthenticatedUserId(nextUserId);// 获取实际发起节点的流程定义信息ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(currentTask.getProcessDefinitionId());// 获取目标节点定义ActivityImpl definitionActivity = processDefinition.findActivity(previousInfo.getActivitiId());// 获取当前节点定义信息ActivityImpl currentTaskActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());// 退回首节点校验,首节点不能再次退回首节点if(definitionActivity.getId().equals(currentTask.getTaskDefinitionKey())){throw new ServiceException("当前节点为首节点,无法退回");}// 设置参数信息Map<String, Object> processVariables = currentTask.getProcessVariables();processVariables.put(WorkFlowServerConstant.COMMENT_FLAG, workFlowBackPreviousDTO.getOpinion());processVariables.put(WorkFlowServerConstant.OPINION_FLAG, workFlowBackPreviousDTO.getOpinion());// 通过流程实例id以及任务定义key获取同级别任务列表信息,既需要退回的任务List<Task> backTaskList = taskService.createTaskQuery().processInstanceId(workFlowBackPreviousDTO.getProcessId()).taskDefinitionKey(currentTask.getTaskDefinitionKey()).list();backTaskList.forEach(task -> {// 进行任务跳转activitiUtil.turnTransitionForUTask(task.getId(),currentTaskActivity,definitionActivity,processVariables);});// 通过processId获取最新的一个task任务信息Task nextTask = taskService.createTaskQuery()// 流程实例id.processInstanceId(workFlowBackPreviousDTO.getProcessId())// 存活状态.active()// 按照日期排序,最新的一个.orderByTaskCreateTime().desc().singleResult();// 进行处理人强制转换,修改流程处理人信息nextTask.setAssignee(nextUserId);taskService.saveTask(nextTask);taskService.claim(nextTask.getId(), nextUserId);// 删除回退信息tbSysBackPositionInfoMapper.deleteById(previousInfo);return null;}/*** 结束流程** @param workFlowEndProcessDTO dto*/@Override@Transactional(rollbackFor = Exception.class)public void endProcess(WorkFlowEndProcessDTO workFlowEndProcessDTO) {log.info("调用流程结束任务,结束参数信息为[{}]", JSONObject.toJSONString(workFlowEndProcessDTO));// 流程结束参数信息String userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE, workFlowEndProcessDTO.getUserCd(),workFlowEndProcessDTO.getOrgCd());Map<String, Object> paramMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);paramMap.put(WorkFlowServerConstant.OPINION_FLAG, workFlowEndProcessDTO.getOpinion());// 设置权限信息identityService.setAuthenticatedUserId(userId);// 获取当前task任务信息Task currentTask = taskService.createTaskQuery().taskId(workFlowEndProcessDTO.getTaskId()).singleResult();// 设置意见信息if (ObjectUtil.isNotNull(workFlowEndProcessDTO.getOpinion())) {//只保留一条批注记录List<Comment> commentList = taskService.getTaskComments(currentTask.getId());if(ObjectUtil.isNotEmpty(commentList)){commentList.forEach(common -> {taskService.deleteComment(common.getId());});}// 添加新的批注信息taskService.addComment(currentTask.getId(), currentTask.getProcessInstanceId(), workFlowEndProcessDTO.getOpinion());}// 当前任务节点定义信息String currentActivityId = null;if (ObjectUtil.isNotNull(currentTask)) {// 流程任务定义keycurrentActivityId = currentTask.getTaskDefinitionKey();UpdateWrapper<TbSysBackPositionInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.lambda().eq(TbSysBackPositionInfo::getProcessId, currentTask.getProcessInstanceId());tbSysBackPositionInfoMapper.delete(updateWrapper);}// 通过流程processId获取bizNo信息,以及流程模板编号信息List<TbSysBackPositionInfo> startPositionList = tbSysBackPositionInfoMapper.getBackPositionInfoByBizNo(workFlowEndProcessDTO.getBizId());// 存入返回上一岗位必要信息String optionUserCd = webUtil.getCurrentUserCd();String optionOrgCd = webUtil.getCurrentOrgCd();TbSysBackPositionInfo tbSysBackPositionInfo = new TbSysBackPositionInfo();tbSysBackPositionInfo.setId(IdUtil.simpleUUID());if (StrUtil.isNotBlank(currentActivityId)) {tbSysBackPositionInfo.setActivitiId(currentActivityId);} else {tbSysBackPositionInfo.setActivitiId(WorkFlowServerConstant.WORKFLOW_TASK_END);}if (ObjectUtil.isNotEmpty(startPositionList)) {tbSysBackPositionInfo.setProcessId(startPositionList.get(WorkFlowServerConstant.INT_NUM_0).getProcessId());tbSysBackPositionInfo.setWorkFlowTemplateId(startPositionList.get(WorkFlowServerConstant.INT_NUM_0).getWorkFlowTemplateId());}tbSysBackPositionInfo.setBizNo(workFlowEndProcessDTO.getBizId());tbSysBackPositionInfo.setOptionOrgCd(optionOrgCd);tbSysBackPositionInfo.setOptionUserCd(optionUserCd);tbSysBackPositionInfo.setSubmitTime(new Date());tbSysBackPositionInfo.setFlowComment(workFlowEndProcessDTO.getOpinion());tbSysBackPositionInfo.setIsDel(WorkFlowServerConstant.FLOW_TYPE_1);log.info("结束流程方法,存入退回上一岗位必要信息[{}]", JSONObject.toJSONString(tbSysBackPositionInfo));tbSysBackPositionInfoMapper.insert(tbSysBackPositionInfo);// 通过业务编号删除在途业务QueryWrapper<TbSysUnfinishedFlow> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(TbSysUnfinishedFlow::getBizNo, workFlowEndProcessDTO.getBizId());tbSysUnfinishedFlowMapper.delete(queryWrapper);// 获取流程定义信息ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(currentTask.getProcessDefinitionId());// 获取流程定义节点详情信息List<ActivityImpl> allActivityList = processDefinition.getActivities();// 过滤出end节点信息ActivityImpl endActivity = allActivityList.stream().filter(activity -> {return ObjectUtil.isEmpty(activity.getOutgoingTransitions());}).findAny().orElse(null);if (ObjectUtil.isEmpty(endActivity)) {throw new ServiceException("获取流程end节点信息为空,请确认流程图有end节点信息配置正确!");}// 获取当前节点定义信息ActivityImpl currentTaskActivity = processDefinition.findActivity(currentTask.getTaskDefinitionKey());// 进行任务跳转,既结束任务activitiUtil.turnTransitionForUTask(currentTask.getId(),currentTaskActivity,endActivity,paramMap);}/*** 跟踪列表查询** @param workFlowTraceListDTO dto*/@Overridepublic WorkFlowTraceListDTO findTraceList(WorkFlowTraceListDTO workFlowTraceListDTO) {// 最终返回跟踪列表List<WorkFlowTrace> finalTraceList;// 新流程获取List<WorkFlowTrace> newTraceList;if (WorkFlowServerConstant.STRING_NUM_1.equals(workFlowTraceListDTO.getIfThreeMonthsAgo())) {// 新流程三个月之前信息,从本地workflow备份库中获取列表信息finalTraceList = getNewFlowHistoryTraceList(workFlowTraceListDTO);} else {// 首先获取新流程近三个月信息finalTraceList = getNewFlowTraceList(workFlowTraceListDTO);}// 获取分页信息List<WorkFlowTrace> workFlowTraceList = null;WorkFlowPage page = null;if (ObjectUtil.isNotEmpty(finalTraceList)) {page = pageUtil.setFlowListPage(finalTraceList, PaginationContext.getPageNum(),PaginationContext.getPageSize());workFlowTraceList = page.getResult();}// 设置成分页对象格式if (ObjectUtil.isNotEmpty(workFlowTraceList)) {// 产品码值信息List<String> codeTypeCdList = new ArrayList<>();// 机构信息列表List<String> orgCdList = new ArrayList<>();// 柜员信息List<String> userCdList = new ArrayList<>();codeTypeCdList.add("ProcessTypeCd");Map<String, String> codeInfoMap = baseCacheApi.getTypeCdValueKeyMap(codeTypeCdList);for (WorkFlowTrace trace : workFlowTraceList) {orgCdList.add(trace.getOrgCd());userCdList.add(trace.getCreator());String codeName = codeInfoMap.get("ProcessTypeCd".concat(StrUtil.UNDERLINE).concat(trace.getBizType()));trace.setBizType(codeName);}// 获取机构柜员名称信息ManageOrgUserInfoDTO manageOrgUserInfoDTO = new ManageOrgUserInfoDTO();// 机构编号以及柜员编号去重去空orgCdList.removeIf(StrUtil::isBlank);orgCdList = orgCdList.stream().distinct().collect(Collectors.toList());userCdList.removeIf(StrUtil::isBlank);userCdList = userCdList.stream().distinct().collect(Collectors.toList());// 封装请求参数manageOrgUserInfoDTO.setOrgCdList(orgCdList);manageOrgUserInfoDTO.setUserCdList(userCdList);manageOrgUserInfoDTO = manageForWorkflowApiClient.getOrgUserInfo(manageOrgUserInfoDTO);ManageOrgUserInfoDTO finalManageOrgUserInfoDTO = manageOrgUserInfoDTO;workFlowTraceList.forEach(trace -> {// 设置机构信息if (ObjectUtil.isNotEmpty(finalManageOrgUserInfoDTO.getOrgInfoMap())) {trace.setOrgName(finalManageOrgUserInfoDTO.getOrgInfoMap().get(trace.getOrgCd()));}// 设置机构信息if (ObjectUtil.isNotEmpty(finalManageOrgUserInfoDTO.getUserInfoMap())) {trace.setCreatorName(finalManageOrgUserInfoDTO.getUserInfoMap().get(trace.getCreator()));}});workFlowTraceListDTO.setWorkFlowPage(page);}return workFlowTraceListDTO;}/*** 跟踪列表查询** @param workFlowTraceListDTO dto* @return WorkFlowTraceListDTO dto*/@Overridepublic WorkFlowTraceListDTO findOldTraceList(WorkFlowTraceListDTO workFlowTraceListDTO) {// 最终返回跟踪列表List<WorkFlowTraceVO> oldTraceList = null;if (StrUtil.isBlank(workFlowTraceListDTO.getSystemFlag())|| WorkFlowServerConstant.FLOW_TYPE_0.equals(workFlowTraceListDTO.getSystemFlag())) {oldTraceList = getOldFlowTraceList(workFlowTraceListDTO);}// 设置成分页对象格式if (ObjectUtil.isNotEmpty(oldTraceList)) {// 产品码值信息List<String> codeTypeCdList = new ArrayList<>();// 机构信息列表List<String> orgCdList = new ArrayList<>();// 柜员信息List<String> userCdList = new ArrayList<>();codeTypeCdList.add("ProcessTypeCd");Map<String, String> codeInfoMap = baseCacheApi.getTypeCdValueKeyMap(codeTypeCdList);for (WorkFlowTrace trace : oldTraceList) {orgCdList.add(trace.getOrgCd());userCdList.add(trace.getCreator());String codeName = codeInfoMap.get("ProcessTypeCd".concat(StrUtil.UNDERLINE).concat(trace.getBizType()));trace.setBizType(codeName);}// 获取机构柜员名称信息ManageOrgUserInfoDTO manageOrgUserInfoDTO = new ManageOrgUserInfoDTO();// 机构编号以及柜员编号去重去空orgCdList.removeIf(StrUtil::isBlank);orgCdList = orgCdList.stream().distinct().collect(Collectors.toList());userCdList.removeIf(StrUtil::isBlank);userCdList = userCdList.stream().distinct().collect(Collectors.toList());// 封装请求参数manageOrgUserInfoDTO.setOrgCdList(orgCdList);manageOrgUserInfoDTO.setUserCdList(userCdList);manageOrgUserInfoDTO = manageForWorkflowApiClient.getOrgUserInfo(manageOrgUserInfoDTO);ManageOrgUserInfoDTO finalManageOrgUserInfoDTO = manageOrgUserInfoDTO;oldTraceList.forEach(trace -> {// 设置机构信息if (ObjectUtil.isNotEmpty(finalManageOrgUserInfoDTO.getOrgInfoMap())) {trace.setOrgName(finalManageOrgUserInfoDTO.getOrgInfoMap().get(trace.getOrgCd()));}// 设置机构信息if (ObjectUtil.isNotEmpty(finalManageOrgUserInfoDTO.getUserInfoMap())) {trace.setCreatorName(finalManageOrgUserInfoDTO.getUserInfoMap().get(trace.getCreator()));}});// 设置查询分页信息if (ObjectUtil.isNotEmpty(oldTraceList)) {WorkFlowPage page = new WorkFlowPage();page.setPageNum(workFlowTraceListDTO.getPageNum());page.setPageSize(workFlowTraceListDTO.getPageSize());page.setResult(oldTraceList);workFlowTraceListDTO.setWorkFlowPage(page);}}return workFlowTraceListDTO;}/*** 风险新流程三个月前跟踪列表查询** @param workFlowRiskTraceDTO dto* @return WorkFlowTraceListDTO dto*/@Overridepublic WorkFlowRiskTraceDTO findRiskTraceList(WorkFlowRiskTraceDTO workFlowRiskTraceDTO) {// 获取参数信息WorkFlowTraceListDTO workFlowTraceListDTO = workFlowConvert.riskParamDtoTOTraceListDto(workFlowRiskTraceDTO);workFlowTraceListDTO.setSystemFlag(WorkFlowServerConstant.STRING_NUM_1);// 新流程三个月之前信息,从本地workflow备份库中获取列表信息List<WorkFlowTrace> newTraceList = getNewFlowHistoryTraceList(workFlowTraceListDTO);if (ObjectUtil.isNotEmpty(newTraceList)) {List<WorkFlowRiskTraceDTO.WorkFlowRiskTrace> workFlowRiskTraceList = newTraceList.stream().map(trace ->workFlowConvert.workflowTraceToInnerRiskTrace(trace)).collect(Collectors.toList());workFlowRiskTraceDTO.setWorkFlowRiskTraceList(workFlowRiskTraceList);}return workFlowRiskTraceDTO;}/*** 获取老流程信息,其中包含finish信息以及未完成信息* @param workFlowTraceListDTO* @return*/public List<WorkFlowTraceVO> getOldFlowTraceList(WorkFlowTraceListDTO workFlowTraceListDTO) {// 任务列表信息分頁信息workFlowTraceListDTO.setPageNum(PaginationContext.getPageNum());workFlowTraceListDTO.setPageSize(PaginationContext.getPageSize());workFlowTraceListDTO.setOffSet((PaginationContext.getPageNum() - 1) * PaginationContext.getPageSize());// 查询分支,三个月之前流程跟踪列表信息List<WorkFlowTraceVO> traceVoList = null;if (WorkFlowServerConstant.WORKFLOW_STATUS_FINISHED.equals(workFlowTraceListDTO.getStatus())) {if (WorkFlowServerConstant.STRING_NUM_1.equals(workFlowTraceListDTO.getIfThreeMonthsAgo())) {// 老流程三个月之前业务信息查询,默认查询为finished业务workFlowTraceListDTO.setTraceType(WorkFlowServerConstant.STRING_NUM_6);traceVoList = wfmidAppProcessInstanceMapper.findOldHistoryTraceList(workFlowTraceListDTO);} else {// 老流程服务近三个月流程信息 暂时注释 暂定老流程近三个月全部迁移到历史三个月之前信息表中workFlowTraceListDTO.setTraceType(WorkFlowServerConstant.STRING_NUM_5);traceVoList = wfmidAppProcessInstanceMapper.findOldTraceList(workFlowTraceListDTO);}}// 设置跟踪列表来源标识字段信息if (ObjectUtil.isNotEmpty(traceVoList)) {traceVoList.forEach(trace -> {if (ObjectUtil.isNotNull(trace.getCreateDate())) {trace.setCreateDateStr(DateUtil.format(trace.getCreateDate(), DatePattern.NORM_DATETIME_PATTERN));}trace.setTraceType(workFlowTraceListDTO.getTraceType());});return traceVoList;}return null;}/*** 新流程获取三个月内历史信息* @param workFlowTraceListDTO 参数dto* @return 任务列表*/public List<WorkFlowTrace> getNewFlowTraceList(WorkFlowTraceListDTO workFlowTraceListDTO) {// 任务列表信息List<WorkFlowTrace> traceList = new ArrayList<>();// 拼装流程发起参数String userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE,workFlowTraceListDTO.getUserCd(),workFlowTraceListDTO.getOrgCd());// 开始调用流程server获取服务,新流程三月内处理if (WorkFlowServerConstant.WORKFLOW_STATUS_FINISHED.equals(workFlowTraceListDTO.getStatus())) {workFlowTraceListDTO.setTraceType(WorkFlowServerConstant.STRING_NUM_1);} else {workFlowTraceListDTO.setTraceType(WorkFlowServerConstant.STRING_NUM_2);}// 获取历史信息List<WorkFlowActHisProcessListDTO> actHisProcessListDTOList = queryStatusHisList(userId,workFlowTraceListDTO.getStatus());// 空值判定if (ObjectUtil.isNotEmpty(actHisProcessListDTOList)) {// 合同编号列表List<String> contractNumList = new ArrayList<>();actHisProcessListDTOList.forEach(processInfo -> {// 获取流程模板信息String processDefinitionKey = processInfo.getProcessDefinitionKey();if (StrUtil.isBlank(workFlowTraceListDTO.getSystemFlag())|| WorkFlowServerConstant.FLOW_TYPE_0.equals(workFlowTraceListDTO.getSystemFlag())) {// 信贷系统if (!processDefinitionKey.toLowerCase().startsWith(WorkFlowServerConstant.RSK_PREFIX)&& !processDefinitionKey.toLowerCase().startsWith(WorkFlowServerConstant.STORE_PREFIX)) {// 通过业务名称获取客户号,客户名称contractNumList.add(processInfo.getBusinessKey());}} else if (WorkFlowServerConstant.STRING_NUM_1.equals(workFlowTraceListDTO.getSystemFlag())) {// 风险系统if (processDefinitionKey.toLowerCase().startsWith(WorkFlowServerConstant.RSK_PREFIX)) {contractNumList.add(processInfo.getBusinessKey());}} else if (WorkFlowServerConstant.STRING_NUM_2.equals(workFlowTraceListDTO.getSystemFlag())) {// 储备系统if (processDefinitionKey.toLowerCase().startsWith(WorkFlowServerConstant.STORE_PREFIX)) {contractNumList.add(processInfo.getBusinessKey());}}});// 设置查询参数,根据合同号批量查询客户信息LoanWorkFlowDTO loanWorkFlowDTO = LoanWorkFlowDTO.builder().contractNumList(contractNumList).build();// 原来使用 loanWorkFlowApiClient.getContractInfo(loanWorkFlowDTO);,获取逻辑信息,现在使用本地代办任务表获取if (ObjectUtil.isNotEmpty(contractNumList)) {List<WorkFlowContractInfoDTO> workFlowContractInfoDTOList = tbSysUnfinishedFlowMapper.getContractInfoList(contractNumList);List<LoanWorkFlowDTO.ContractInfo> convertConInfoList = workFlowConvert.workFlowConDtoToConInfo(workFlowContractInfoDTOList);loanWorkFlowDTO.setContractInfoList(convertConInfoList);}if (ObjectUtil.isNotEmpty(loanWorkFlowDTO.getContractInfoList())) {// 过滤满足客户名称数据,参数客户名称为空则直接返回查询数据List<LoanWorkFlowDTO.ContractInfo> contractInfoList = loanWorkFlowDTO.getContractInfoList().stream().filter(contractInfo -> {// 客户名字为空,定义为非法数据过滤 todo: 后续可能修改if (ObjectUtil.isNull(contractInfo.getCustomerName())|| ObjectUtil.isNull(contractInfo.getCustomerNum())) {return false;}boolean checkCustomerName = StrUtil.isBlank(workFlowTraceListDTO.getProcessCustomerName())|| (StrUtil.isNotBlank(workFlowTraceListDTO.getProcessCustomerName())&& contractInfo.getCustomerName().contains(workFlowTraceListDTO.getProcessCustomerName()));return checkCustomerName;}).collect(Collectors.toList());loanWorkFlowDTO.setContractInfoList(contractInfoList);// 合同信息mapMap<String, LoanWorkFlowDTO.ContractInfo> customerMap = loanWorkFlowDTO.getContractInfoList().stream().collect(Collectors.toMap(LoanWorkFlowDTO.ContractInfo::getContractNum, Function.identity(), (k1, k2) -> k1));actHisProcessListDTOList.forEach(processInfo -> {// 创建人String startUserId = processInfo.getStartUserId();// 通过业务名称获取客户号,客户名称if (ObjectUtil.isNotEmpty(startUserId)) {// 将processInfo转关为processMapMap<String, Object> processMap = JSON.parseObject(JSONObject.toJSONString(processInfo));String contractNum = processInfo.getBusinessKey();LoanWorkFlowDTO.ContractInfo contractInfo = customerMap.get(contractNum);if (ObjectUtil.isNotEmpty(contractInfo)) {// workFlowTrace返回信息拼装buildWorkFlowTraceInfo(workFlowTraceListDTO, traceList,processMap,contractInfo.getCustomerName(),contractInfo.getCustomerNum());}}});// 设置跟踪列表来源标识字段信息if (ObjectUtil.isNotEmpty(traceList)) {traceList.forEach(trace -> {trace.setTraceType(workFlowTraceListDTO.getTraceType());});}}}return traceList;}/*** 获取新流程已经结束的历史信息** @param userId 用户id* @param finishStatus 流程状态 finished,running* @return 任务列表*/public List<WorkFlowActHisProcessListDTO> queryStatusHisList(String userId, String finishStatus) {// 参数校验if (StrUtil.isBlank(userId)) {throw new ServiceException("历史信息查询时候,用户id为空,请确认");}// 设置查询条件HistoricProcessInstanceQuery instanceQuery = historyService.createHistoricProcessInstanceQuery()// 参与用户id.involvedUser(userId)// 按照时间倒序排序.orderByProcessInstanceStartTime().desc();// 是否结束条件判定 0否1是if (WorkFlowServerConstant.WORKFLOW_STATUS_FINISHED.equals(finishStatus)) {instanceQuery.finished();} else {// 解决空值情况下,默认查询历史为running状态finishStatus = WorkFlowServerConstant.WORKFLOW_STATUS_RUNNING;instanceQuery.unfinished();}// 获取查询结果集合List<HistoricProcessInstance> historicProcessInstanceList = instanceQuery.list();// 查询信息进行转换List<WorkFlowActHisProcessListDTO> actHisProcessListDTOList = historicProcessInstanceList.stream().map(historyInstance ->activitiConvert.hisProcessInstanceCovertToDTO(historyInstance)).collect(Collectors.toList());// 跟踪列表查询数据不正确 优化处理List<ActHiProcinst> historyInstanceList = actHiProcinstMapper.listHistoryInstance(finishStatus, userId);// 非空判定if (ObjectUtil.isNotEmpty(historyInstanceList)) {Map<String, String> instanceMap = new HashMap<>();for (ActHiProcinst actHiProcinst : historyInstanceList) {String businessKey = actHiProcinst.getBusinessKey();instanceMap.put(businessKey, businessKey);}// 去除不正确处理人List<WorkFlowActHisProcessListDTO> removeList = new ArrayList<>();for (WorkFlowActHisProcessListDTO dto : actHisProcessListDTOList) {if (ObjectUtil.isNull(instanceMap.get(dto.getBusinessKey()))) {removeList.add(dto);}}// 删除错误信息if (removeList.size() > 0) {actHisProcessListDTOList.removeAll(removeList);}} else {// 如果正确查询没有信息,则全部去除即可actHisProcessListDTOList = new ArrayList<>();}return actHisProcessListDTOList;}/*** 新流程获取三个月外历史信息* @param workFlowTraceListDTO 参数dto* @return 任务列表*/public List<WorkFlowTrace> getNewFlowHistoryTraceList(WorkFlowTraceListDTO workFlowTraceListDTO) {// 任务列表信息List<WorkFlowTrace> traceList = new ArrayList<>();// 三个月前信息查询if (WorkFlowServerConstant.WORKFLOW_STATUS_FINISHED.equals(workFlowTraceListDTO.getStatus())) {workFlowTraceListDTO.setTraceType(WorkFlowServerConstant.STRING_NUM_3);// 拼装流程发起参数String userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE,workFlowTraceListDTO.getUserCd(),workFlowTraceListDTO.getOrgCd());// 查询本地备份表信息进行数据查询List<ActProcessTrace> processTraceList = actHiTaskinstBackMapper.getActProcessTraceHisList(userId);if (ObjectUtil.isNotEmpty(processTraceList)) {// 根据系统标识选择自己系统的跟踪列表信息if (StrUtil.isBlank(workFlowTraceListDTO.getSystemFlag())|| WorkFlowServerConstant.FLOW_TYPE_0.equals(workFlowTraceListDTO.getSystemFlag())) {// 信贷系统processTraceList.removeIf(processInfo -> {String tractTemplateId = processInfo.getProcDefKey();return StrUtil.isBlank(tractTemplateId)|| tractTemplateId.toLowerCase().startsWith(WorkFlowServerConstant.RSK_PREFIX)|| tractTemplateId.toLowerCase().startsWith(WorkFlowServerConstant.STORE_PREFIX);});} else if (WorkFlowServerConstant.STRING_NUM_1.equals(workFlowTraceListDTO.getSystemFlag())) {// 风险系统processTraceList.removeIf(processInfo -> {String tractTemplateId = processInfo.getProcDefKey();return StrUtil.isBlank(tractTemplateId)|| !tractTemplateId.toLowerCase().startsWith(WorkFlowServerConstant.RSK_PREFIX);});} else if (WorkFlowServerConstant.STRING_NUM_2.equals(workFlowTraceListDTO.getSystemFlag())) {// 储备子系统processTraceList.removeIf(processInfo -> {String tractTemplateId = processInfo.getProcDefKey();return StrUtil.isBlank(tractTemplateId)|| !tractTemplateId.toLowerCase().startsWith(WorkFlowServerConstant.STORE_PREFIX);});}// 整合processIdList信息List<String> processIdList = processTraceList.stream().map(ActProcessTrace::getProcInstId).collect(Collectors.toList());// 根据流程参数信息获取合同客户信息列表QueryWrapper<ActHiVarinstBack> actHiVarinstQueryWrapper = new QueryWrapper<>();if (processIdList.size() < OracleInQueryUtil.DEFAULT_SPLIT_SIZE) {actHiVarinstQueryWrapper.lambda().in(ActHiVarinstBack::getProcInstId, processIdList);} else {oracleInQueryUtil.queryWrapperIn(actHiVarinstQueryWrapper,"PROC_INST_ID_",processIdList,OracleInQueryUtil.DEFAULT_SPLIT_SIZE);}List<ActHiVarinstBack> varinstList = actHiVarinstBackMapper.selectList(actHiVarinstQueryWrapper);// 将查询信息转换为map信息Map<String, Map<String, Object>> paramsMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);varinstList.forEach(varinst -> {Map<String, Object> paramMap = paramsMap.get(varinst.getProcInstId());if (ObjectUtil.isNull(paramMap)) {paramMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);}if (WorkFlowServerConstant.BIZ_ID_FLAG.equals(varinst.getName())) {paramMap.put(WorkFlowServerConstant.BUSINESS_KEY_FLAG, varinst.getText());} else if (WorkFlowServerConstant.CUSTOMER_NAME_FLAG.equals(varinst.getName())) {paramMap.put(WorkFlowServerConstant.CUSTOMER_NAME_FLAG, varinst.getText());} else if (WorkFlowServerConstant.CUSTOMER_NUM_FLAG.equals(varinst.getName())) {paramMap.put(WorkFlowServerConstant.CUSTOMER_NUM_FLAG, varinst.getText());} else if (WorkFlowServerConstant.PROCESS_KEY_FLAG.equals(varinst.getName())) {paramMap.put(WorkFlowServerConstant.PROCESS_DEFINITION_ID, varinst.getText());paramMap.put(WorkFlowServerConstant.PROCESS_DEFINITION_KEY, varinst.getText());} else if (WorkFlowServerConstant.CREATOR_FLAG.equals(varinst.getName())) {paramMap.put(WorkFlowServerConstant.START_USER_ID_FLAG, varinst.getText());}// 设置processIdparamMap.put(WorkFlowServerConstant.ID_FLAG, varinst.getProcInstId());paramsMap.put(varinst.getProcInstId(), paramMap);});// map信息转换为合同dto列表信息,一个循环中只可以使用一次iterator.nextIterator<Map.Entry<String, Map<String, Object>>> iterator = paramsMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, Map<String, Object>> mapEntry = iterator.next();Map<String, Object> value = mapEntry.getValue();// 获取合同客户信息Object bizNoObj = value.get(WorkFlowServerConstant.BUSINESS_KEY_FLAG);Object customerNumObj = value.get(WorkFlowServerConstant.CUSTOMER_NUM_FLAG);Object customerNameObj = value.get(WorkFlowServerConstant.CUSTOMER_NAME_FLAG);// 空值校验boolean paramCheck = ObjectUtil.isNotNull(bizNoObj)&& ObjectUtil.isNotNull(customerNumObj)&& ObjectUtil.isNotNull(customerNameObj);if (paramCheck) {// 选填客户名称信息校验boolean checkCustomerName = StrUtil.isBlank(workFlowTraceListDTO.getProcessCustomerName())|| (StrUtil.isNotBlank(workFlowTraceListDTO.getProcessCustomerName())&& customerNameObj.toString().contains(workFlowTraceListDTO.getProcessCustomerName()));if (!checkCustomerName) {iterator.remove();}} else {iterator.remove();}}if (ObjectUtil.isNotEmpty(paramsMap)) {processTraceList.forEach(processInfo -> {// 通过业务名称获取客户号,客户名称if (ObjectUtil.isNotEmpty(processInfo.getStartUserId())) {if (ObjectUtil.isNotEmpty(paramsMap.get(processInfo.getProcInstId()))) {Map<String, Object> processMap = paramsMap.get(processInfo.getProcInstId());// 设置start时间为Long类型,下面方法中map获取写死,用于设定开始结束时间Date startTime = processInfo.getStartTime();Date endTime = processInfo.getEndTime();if (ObjectUtil.isNotNull(startTime)) {processMap.put(WorkFlowServerConstant.START_TIME_FLAG, startTime.getTime());}if (ObjectUtil.isNotNull(endTime)) {processMap.put(WorkFlowServerConstant.END_TIME_FLAG, startTime.getTime());}// workFlowTrace返回信息拼装buildWorkFlowTraceInfo(workFlowTraceListDTO, traceList,processMap,processMap.get(WorkFlowServerConstant.CUSTOMER_NAME_FLAG).toString(),processMap.get(WorkFlowServerConstant.CUSTOMER_NUM_FLAG).toString());}}});// 设置跟踪列表来源标识字段信息if (ObjectUtil.isNotEmpty(traceList)) {traceList.forEach(trace -> {trace.setTraceType(workFlowTraceListDTO.getTraceType());});}}}}// 设置跟踪列表来源标识字段信息if (ObjectUtil.isNotEmpty(traceList)) {traceList.forEach(trace -> {trace.setTraceType(workFlowTraceListDTO.getTraceType());});}return traceList;}/*** workFlowTrace返回信息拼装** @param workFlowTraceListDTO* @param traceList* @param processMap* @param customerName* @param customerNum*/private void buildWorkFlowTraceInfo(WorkFlowTraceListDTO workFlowTraceListDTO,List<WorkFlowTrace> traceList,Map<String, Object> processMap,String customerName,String customerNum) {// 新增最终返回trace跟踪信息WorkFlowTraceVO workFlowTrace = new WorkFlowTraceVO();workFlowTrace.setCustomerNum(customerNum);workFlowTrace.setCustomerName(customerName);workFlowTrace.setStatus(workFlowTraceListDTO.getStatus());workFlowTrace.setBizNo(StrUtil.toString(processMap.get(WorkFlowServerConstant.BUSINESS_KEY_FLAG)));// 获取循环trace信息模板id与bizType模板进行判断是否赋值String tractTemplateId = StrUtil.toString(processMap.get(WorkFlowServerConstant.PROCESS_DEFINITION_KEY));if (ObjectUtil.isNotEmpty(workFlowTraceListDTO.getBizTypeTrace())) {// 获取产品类型枚举信息WorkFlowProductEnum workFlowProductEnum =workFlowUtil.getProductEnumByBizType(workFlowTraceListDTO.getBizTypeTrace());// 将tract列表按照bizType 进行过滤,去除非查询type数据if (ObjectUtil.isNotNull(workFlowProductEnum)&& tractTemplateId.equals(workFlowProductEnum.getTemplateId())) {workFlowTrace.setBizType(workFlowProductEnum.getBizType());workFlowTrace.setProductType(workFlowProductEnum.getBizTypeName());workFlowUtil.addTraceInfoList(traceList, workFlowTrace, processMap);}} else {WorkFlowProductEnum workFlowProductEnum = workFlowUtil.getProductEnumByTemplateId(tractTemplateId);// 枚举类型空值判断if (ObjectUtil.isNotNull(workFlowProductEnum)) {workFlowTrace.setBizType(workFlowProductEnum.getBizType());workFlowTrace.setProductType(workFlowProductEnum.getBizTypeName());workFlowUtil.addTraceInfoList(traceList, workFlowTrace, processMap);}}}/*** 查询跟踪列表单条历史数据** @param traceHistoryListDTO dto* @return WorkFlowTraceHistoryListDTO dto*/@Overridepublic WorkFlowTraceHistoryListDTO findTraceHistoryList(WorkFlowTraceHistoryListDTO traceHistoryListDTO) {// 通过traceType信息获取不同时间以及新老流程单条历史提交记录信息String traceType = traceHistoryListDTO.getTraceType();// 如果来源信息为空,默认走近三个月,其中结束流程无退回处理,在途任务有退回处理if (StrUtil.isBlank(traceType)|| WorkFlowServerConstant.STRING_NUM_1.equals(traceType)|| WorkFlowServerConstant.STRING_NUM_2.equals(traceType)) {// 三个月之内activiti(新流程)信息获取,包含完成以及未完成的信息,有回退处理traceHistoryListDTO = getNewFlowCommentInThreeMonth(traceHistoryListDTO);} else if (WorkFlowServerConstant.STRING_NUM_3.equals(traceType)) {// activiti(新流程)三月外,已结束信息traceHistoryListDTO = getNewFlowCommentOutThreeMonth(traceHistoryListDTO);} else if (WorkFlowServerConstant.STRING_NUM_5.equals(traceType) || WorkFlowServerConstant.STRING_NUM_6.equals(traceType)) {// 老流程历史意见信息获取traceHistoryListDTO = getOldFlowCommon(traceHistoryListDTO);}return traceHistoryListDTO;}/*** 获取老流程意见信息* @param traceHistoryListDTO 参数dto* @return 列表信息*/public WorkFlowTraceHistoryListDTO getOldFlowCommon(WorkFlowTraceHistoryListDTO traceHistoryListDTO) {// 意见信息列表List<WorkFlowTaskCommon> commonList;if (WorkFlowServerConstant.STRING_NUM_5.equals(traceHistoryListDTO.getTraceType())) {// 老流程三月内信息commonList = wfmidAppProcessInstanceMapper.findTaskInfoList(traceHistoryListDTO.getProcessId());} else {// 老流程三月外信息commonList = wfmidAppProcessInstanceMapper.findHisTaskInfoList(traceHistoryListDTO.getProcessId());}if (ObjectUtil.isNotEmpty(commonList)) {// 返回意见信息列表信息List<WorkFlowTraceHistory> workFlowTraceHistoryList = new ArrayList<>();commonList.forEach(common -> {WorkFlowTraceHistory workFlowTraceHistory = new WorkFlowTraceHistory();if (ObjectUtil.isNotNull(common.getTaskFinishTime())) {workFlowTraceHistory.setFinishDate(common.getTaskFinishTime());workFlowTraceHistory.setFinishDateStr(DateUtil.format(common.getTaskFinishTime(), DatePattern.NORM_DATETIME_PATTERN));workFlowTraceHistory.setProcessId(traceHistoryListDTO.getProcessId());workFlowTraceHistory.setOpinion(common.getProcessComment());workFlowTraceHistory.setTaskId(common.getTaskId());workFlowTraceHistory.setPositionName(common.getActivityId());workFlowTraceHistory.setOrgCd(common.getTaskOrgCd());workFlowTraceHistory.setUserCd(common.getOwner());// 获取柜员名称ManageUserDTO param = new ManageUserDTO();param.setUserCd(common.getOwner());ManageUserDTO userDTO = managementApiClient.findUserNameByUserCd(param);workFlowTraceHistory.setUserName(userDTO.getUserName());// 获取机构名称if (StrUtil.isNotBlank(common.getTaskOrgCd())) {List<String> params = new ArrayList<>();params.add(common.getTaskOrgCd());ManageOrganizationListDTO orgDTO = organizationApiFeignClient.listInfoByOrgCdList(params);if (ObjectUtil.isNotEmpty(orgDTO.getOrganizationInfoList())) {workFlowTraceHistory.setOrgName(orgDTO.getOrganizationInfoList().get(WorkFlowServerConstant.INT_NUM_0).getOrgName());}} else {workFlowTraceHistory.setOrgName(WorkFlowServerConstant.ORG_LOSE_FLAG);}// 获取业务客户信息if (StrUtil.isBlank(traceHistoryListDTO.getCustomerName())) {traceHistoryListDTO.setCustomerName(common.getCustomerName());}if (StrUtil.isBlank(traceHistoryListDTO.getCustomerNum())) {traceHistoryListDTO.setCustomerNum(common.getCustomerNum());}workFlowTraceHistoryList.add(workFlowTraceHistory);}});if (ObjectUtil.isNotEmpty(workFlowTraceHistoryList)) {// 设置查询分页信息WorkFlowPage page = pageUtil.setFlowListPage(workFlowTraceHistoryList, PaginationContext.getPageNum(),workFlowTraceHistoryList.size());traceHistoryListDTO.setPage(page);}traceHistoryListDTO.setContractStatusInfo(WorkFlowServerConstant.CONTRACT_STATUS_AGREE);}return traceHistoryListDTO;}/*** 三个月之前activiti(新流程)意见信息获取,只有完成任务的信息,且无退回相关信息* @param traceHistoryListDTO 参数dto* @return 列表信息*/public WorkFlowTraceHistoryListDTO getNewFlowCommentOutThreeMonth(WorkFlowTraceHistoryListDTO traceHistoryListDTO) {// 意见列表信息List<WorkFlowTraceHistory> historyList = new ArrayList<>();// 获取所有过程意见信息QueryWrapper<ActHiActinstBack> actHiActinstQueryWrapper = new QueryWrapper<>();actHiActinstQueryWrapper.lambda().eq(ActHiActinstBack::getProcInstId, traceHistoryListDTO.getProcessId());List<ActHiActinstBack> actHiActinstBackList = actHiActinstBackMapper.selectList(actHiActinstQueryWrapper);if (ObjectUtil.isNotEmpty(actHiActinstBackList)) {actHiActinstBackList.forEach(actHiActinstBack -> {// 去除开始以及结束节点信息if (WorkFlowServerConstant.START_FLAG.equals(actHiActinstBack.getActName())|| WorkFlowServerConstant.END_FLAG.equals(actHiActinstBack.getActName())) {return;}// 判断节点是否为task节点boolean ifTask = WorkFlowServerConstant.EXCLUSIVE_GATEWAY.equals(actHiActinstBack.getActId())|| WorkFlowServerConstant.PARALLEL_GATEWAY.equals(actHiActinstBack.getActId())|| WorkFlowServerConstant.INCLUSIVE_GATEWAY.equals(actHiActinstBack.getActId())|| WorkFlowServerConstant.EVENT_GATEWAY.equals(actHiActinstBack.getActId());if (!ifTask && StrUtil.isNotBlank(actHiActinstBack.getTaskId())) {QueryWrapper<ActHiCommentBack> commentQueryWrapper = new QueryWrapper<>();commentQueryWrapper.lambda().eq(ActHiCommentBack::getTaskId, actHiActinstBack.getTaskId()).eq(ActHiCommentBack::getType, WorkFlowServerConstant.COMMENT_FLAG);ActHiCommentBack actHiCommentBack = actHiCommentBackMapper.selectOne(commentQueryWrapper);WorkFlowTraceHistory traceHistory = new WorkFlowTraceHistory();// 结束时间if (ObjectUtil.isNotNull(actHiActinstBack.getEndTime())) {traceHistory.setFinishDate(actHiActinstBack.getEndTime());traceHistory.setFinishDateStr(DateUtil.format(actHiActinstBack.getEndTime(), DatePattern.NORM_DATETIME_PATTERN));}// processIdtraceHistory.setProcessId(actHiActinstBack.getProcInstId());// 岗位名称traceHistory.setPositionName(actHiActinstBack.getActName());// 评论信息if (ObjectUtil.isNotNull(actHiCommentBack)) {traceHistory.setOpinion(actHiCommentBack.getMessage());}// 任务办理人信息if (StrUtil.isNotBlank(actHiActinstBack.getAssignee())) {String[] handingInfo = StrUtil.toString(actHiActinstBack.getAssignee()).split(WorkFlowServerConstant.SPLIT_FLAG);traceHistory.setUserCd(handingInfo[0]);if (ObjectUtil.isNotNull(handingInfo[0])&& !WorkFlowServerConstant.NULL_STR.equalsIgnoreCase(handingInfo[0])) {ManageUserDTO param = new ManageUserDTO();param.setUserCd(handingInfo[0]);ManageUserDTO userNameByUserCd = managementApiClient.findUserNameByUserCd(param);traceHistory.setUserName(userNameByUserCd.getUserName());}if (handingInfo.length > 1) {traceHistory.setOrgCd(handingInfo[1]);List<String> params = new ArrayList<>();params.add(handingInfo[1]);ManageOrganizationListDTO manageOrganizationListDTO = organizationApiFeignClient.listInfoByOrgCdList(params);if (manageOrganizationListDTO.getOrganizationInfoList() != null && manageOrganizationListDTO.getOrganizationInfoList().size() == 1) {traceHistory.setOrgName(manageOrganizationListDTO.getOrganizationInfoList().get(0).getOrgName());}}}// 任务idtraceHistory.setTaskId(actHiActinstBack.getTaskId());// 去除发起头以及结尾信息if (!WorkFlowServerConstant.START_FLAG.equals(actHiActinstBack.getActName())&& !WorkFlowServerConstant.END_FLAG.equals(actHiActinstBack.getActName())) {historyList.add(traceHistory);}}});historyList.sort((history, history2) -> {if (ObjectUtil.isNull(history.getFinishDate()) && ObjectUtil.isNotNull(history2.getFinishDate())) {return -1;} else if (ObjectUtil.isNull(history2.getFinishDate()) && ObjectUtil.isNotNull(history.getFinishDate())) {return 1;} else if (history.getFinishDate().compareTo(history2.getFinishDate()) > 0) {return -1;} else if (history.getFinishDate().compareTo(history2.getFinishDate()) < 0) {return 1;} else {return 0;}});if (ObjectUtil.isNotEmpty(historyList)) {// 设置查询分页信息WorkFlowPage page = pageUtil.setFlowListPage(historyList, PaginationContext.getPageNum(),historyList.size());traceHistoryListDTO.setPage(page);}}// 意见信息String contractStatus = WorkFlowServerConstant.CONTRACT_STATUS_AGREE;traceHistoryListDTO.setContractStatusInfo(contractStatus);// 获取业务客户信息List<TbSysUnfinishedFlowHis> unfinishedFlowList = tbSysUnfinishedFlowHisMapper.getUnFinishedFlowList(traceHistoryListDTO.getBizNo());if (ObjectUtil.isNotEmpty(unfinishedFlowList)) {// 获取业务客户信息if (ObjectUtil.isNotEmpty(unfinishedFlowList)) {traceHistoryListDTO.setCustomerName(unfinishedFlowList.get(WorkFlowServerConstant.PAGE_INDEX).getCustomerName());traceHistoryListDTO.setCustomerNum(unfinishedFlowList.get(WorkFlowServerConstant.PAGE_INDEX).getCustomerNum());}} else {// 为老流程三个月前信息,需要从 ACT_HI_VARINST_BACK 中获取客户信息QueryWrapper<ActHiVarinstBack> actHiVarinstQueryWrapper = new QueryWrapper<>();actHiVarinstQueryWrapper.lambda().eq(ActHiVarinstBack::getProcInstId, traceHistoryListDTO.getProcessId());List<ActHiVarinstBack> varinstList = actHiVarinstBackMapper.selectList(actHiVarinstQueryWrapper);if (ObjectUtil.isNotEmpty(varinstList)) {for (ActHiVarinstBack varinst: varinstList) {if (WorkFlowServerConstant.CUSTOMER_NUM_FLAG.equals(varinst.getName())&& StrUtil.isBlank(traceHistoryListDTO.getCustomerNum())) {traceHistoryListDTO.setCustomerNum(varinst.getText());}if (WorkFlowServerConstant.CUSTOMER_NAME_FLAG.equals(varinst.getName())&& StrUtil.isBlank(traceHistoryListDTO.getCustomerName())) {traceHistoryListDTO.setCustomerName(varinst.getText());}}}}return traceHistoryListDTO;}/*** 三个月之内activiti(新流程)意见信息获取,包含完成以及未完成的信息* @param traceHistoryListDTO 参数dto* @return 意见信息列表*/public WorkFlowTraceHistoryListDTO getNewFlowCommentInThreeMonth(WorkFlowTraceHistoryListDTO traceHistoryListDTO) {// 获取当前登录柜员编号以及机构号String currentOrgCd = webUtil.getCurrentOrgCd();String currentUserCd = webUtil.getCurrentUserCd();// 获取列表List<WorkFlowTraceHistory> historyList = findHistoryList(traceHistoryListDTO.getUserCd(),traceHistoryListDTO.getOrgCd(),traceHistoryListDTO.getProcessId());// 所有列表信息List<TbSysBackPositionInfo> allBackPositionInfoList = null;// 空值校验if (ObjectUtil.isNotEmpty(historyList)) {// 获取结束时间为空的任务信息WorkFlowTraceHistory makTaskHistory = historyList.stream().filter(task ->ObjectUtil.isNull(task.getFinishDate())).findAny().orElse(null);// 获取当前processId全部历史意见信息allBackPositionInfoList = tbSysBackPositionInfoMapper.getAllBackPositionInfoList(traceHistoryListDTO.getProcessId());// 去除删除数据List<TbSysBackPositionInfo> tbSysBackPositionInfoList = null;if (ObjectUtil.isNotNull(allBackPositionInfoList)) {tbSysBackPositionInfoList = allBackPositionInfoList.stream().filter(backPosition ->WorkFlowServerConstant.FLOW_TYPE_0.equals(backPosition.getIsDel())).collect(Collectors.toList());}// 判断是否需要撤销操作if (ObjectUtil.isNotEmpty(tbSysBackPositionInfoList)&& StrUtil.isNotBlank(tbSysBackPositionInfoList.get(WorkFlowServerConstant.INT_NUM_0).getWorkFlowTemplateId())) {// 获取上一岗位对应信息TbSysBackPositionInfo backPositionInfo = tbSysBackPositionInfoList.get(WorkFlowServerConstant.INT_NUM_0);// 获取岗位cd名称对应关系QueryWrapper<TbSysFlowPosition> positionQueryWrapper = new QueryWrapper<>();positionQueryWrapper.lambda().eq(TbSysFlowPosition::getFlowTempletNum, backPositionInfo.getWorkFlowTemplateId());TbSysFlowPosition flowPosition = tbSysFlowPositionMapper.selectOne(positionQueryWrapper);if (ObjectUtil.isNotNull(flowPosition)) {QueryWrapper<TbSysFlowPositionDetail> detailQueryWrapper = new QueryWrapper<>();detailQueryWrapper.lambda().eq(TbSysFlowPositionDetail::getFlowId, flowPosition.getFlowId());List<TbSysFlowPositionDetail> detailList = tbSysFlowPositionDetailMapper.selectList(detailQueryWrapper);// 将岗位信息变更为map,方便使用获取Map<String, String> positionMap = detailList.stream().collect(Collectors.toMap(TbSysFlowPositionDetail::getActivitiId, TbSysFlowPositionDetail::getPositionName, (k1, k2) -> k1));// 通过activitiId获取positionNameString positionName = positionMap.get(backPositionInfo.getActivitiId());// 如果岗位为调查岗确认 则业务不允许上一岗位撤回,撤回按钮不显示if (ObjectUtil.isNotNull(makTaskHistory)&& !WorkFlowServerConstant.POSITION_CONFIRM.equals(makTaskHistory.getPositionName())) {for (WorkFlowTraceHistory history : historyList) {if (history.getPositionName().equals(positionName)&& currentOrgCd.equals(history.getOrgCd())&& currentUserCd.equals(history.getUserCd())) {history.setCancelFlag(WorkFlowServerConstant.STRING_NUM_1);break;}}}// 如果没有结束时间未填的任务节点if (ObjectUtil.isNotNull(makTaskHistory)) {traceHistoryListDTO.setSubmitBackPrefixTaskId(makTaskHistory.getTaskId());}}}}if (ObjectUtil.isNotEmpty(historyList)) {historyList.sort(new Comparator<WorkFlowTraceHistory>() {@Overridepublic int compare(WorkFlowTraceHistory history, WorkFlowTraceHistory history2) {if (ObjectUtil.isNull(history.getFinishDate()) && ObjectUtil.isNotNull(history2.getFinishDate())) {return -1;} else if (ObjectUtil.isNull(history2.getFinishDate()) && ObjectUtil.isNotNull(history.getFinishDate())) {return 1;} else if (history.getFinishDate().compareTo(history2.getFinishDate()) > 0) {return -1;} else if (history.getFinishDate().compareTo(history2.getFinishDate()) < 0) {return 1;} else {return 0;}}});// 判断如果本地记录信息和activiti查询列表信息条数相同,并且activiti无意见信息,则替换本地意见信息if (ObjectUtil.isNotNull(allBackPositionInfoList)&& ObjectUtil.isNotEmpty(historyList)&& allBackPositionInfoList.size() + 1 == historyList.size()) {for (int index = 1; index < historyList.size(); index++) {WorkFlowTraceHistory traceHistory = historyList.get(index);if (ObjectUtil.isNotNull(traceHistory) && StrUtil.isBlank(traceHistory.getOpinion())) {// 替换本地意见信息traceHistory.setOpinion(allBackPositionInfoList.get(index - 1).getFlowComment());}}}// 设置查询分页信息WorkFlowPage page = pageUtil.setFlowListPage(historyList, PaginationContext.getPageNum(),historyList.size());traceHistoryListDTO.setPage(page);}// 获取业务客户信息List<TbSysUnfinishedFlow> unfinishedFlowList = tbSysUnfinishedFlowMapper.getUnFinishedFlowList(traceHistoryListDTO.getBizNo());// 意见信息String contractStatus = WorkFlowServerConstant.CONTRACT_STATUS_AGREE;// 获取业务客户信息if (ObjectUtil.isNotEmpty(unfinishedFlowList)) {traceHistoryListDTO.setCustomerName(unfinishedFlowList.get(WorkFlowServerConstant.PAGE_INDEX).getCustomerName());traceHistoryListDTO.setCustomerNum(unfinishedFlowList.get(WorkFlowServerConstant.PAGE_INDEX).getCustomerNum());}traceHistoryListDTO.setContractStatusInfo(contractStatus);return traceHistoryListDTO;}/*** 查询跟踪列表历史任务通用方法** @param userCd    柜员号* @param orgCd     机构cd* @param processId 流程实例id*/public List<WorkFlowTraceHistory> findHistoryList(String userCd, String orgCd, String processId) {// 拼装流程发起参数String userId = StrUtil.format(WorkFlowServerConstant.USER_ID_APPEND_TEMPLATE, userCd, orgCd);// 设置权限信息identityService.setAuthenticatedUserId(userId);// 格式化时间格式SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);// 查询并且解析查询结果信息List<WorkFlowTraceHistory> historyList = new ArrayList<>();List<WorkFlowActHisActInstListDTO> hisActInstListDTOList = queryHisTaskList(processId);// 传输对象转换为 Map 对象if (ObjectUtil.isNotEmpty(hisActInstListDTOList)) {hisActInstListDTOList.forEach(hisActInst -> {// 最终返回对象WorkFlowTraceHistory traceHistory = new WorkFlowTraceHistory();// 结束时间if (ObjectUtil.isNotEmpty(hisActInst.getEndTime())) {traceHistory.setFinishDate(hisActInst.getEndTime());traceHistory.setFinishDateStr(simpleDateFormat.format(traceHistory.getFinishDate()));}// processIdtraceHistory.setProcessId(hisActInst.getProcessInstanceId());// 岗位名称traceHistory.setPositionName(hisActInst.getActivityName());// 评论信息traceHistory.setOpinion(hisActInst.getOpinion());// 任务办理人信息if (StrUtil.isNotBlank(hisActInst.getAssignee())) {String[] handingInfo = StrUtil.toString(hisActInst.getAssignee()).split(WorkFlowServerConstant.SPLIT_FLAG);traceHistory.setUserCd(handingInfo[0]);if (handingInfo[0] != null && !WorkFlowServerConstant.NULL_STR.equalsIgnoreCase(handingInfo[0])) {ManageUserDTO param = new ManageUserDTO();param.setUserCd(handingInfo[0]);ManageUserDTO userNameByUserCd = managementApiClient.findUserNameByUserCd(param);traceHistory.setUserName(userNameByUserCd.getUserName());}if (handingInfo.length > 1) {traceHistory.setOrgCd(handingInfo[1]);List<String> params = new ArrayList<>();params.add(handingInfo[1]);ManageOrganizationListDTO manageOrganizationListDTO = organizationApiFeignClient.listInfoByOrgCdList(params);if (manageOrganizationListDTO.getOrganizationInfoList() != null && manageOrganizationListDTO.getOrganizationInfoList().size() == 1) {traceHistory.setOrgName(manageOrganizationListDTO.getOrganizationInfoList().get(0).getOrgName());}}}// 任务idtraceHistory.setTaskId(hisActInst.getTaskId());// 去除发起头以及结尾信息if (!WorkFlowServerConstant.START_FLAG.equals(hisActInst.getActivityName())&& !WorkFlowServerConstant.END_FLAG.equals(hisActInst.getActivityName())) {historyList.add(traceHistory);}});}return historyList;}/*** 根据历史流程实例id查询历史任务实例** @param processId 流程实例id*/public List<WorkFlowActHisActInstListDTO> queryHisTaskList(String processId) {// 获取历史活动实例HistoricActivityInstanceQuery activityInstanceQuery = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceId().desc();// 获取历史活动实例列表List<HistoricActivityInstance> activityInstanceList = activityInstanceQuery.list();// 类型信息转换List<WorkFlowActHisActInstListDTO> actHisActInstListDTOList = activityInstanceList.stream().map(instance ->activitiConvert.hisInstanceToActList(instance)).collect(Collectors.toList());// 进行非task节点信息判定,排除无用节点actHisActInstListDTOList = actHisActInstListDTOList.stream().filter(actInst -> {boolean ifRightType = actInst.getActivityType().equals(WorkFlowServerConstant.EXCLUSIVE_GATEWAY)|| actInst.getActivityType().equals(WorkFlowServerConstant.PARALLEL_GATEWAY)|| actInst.getActivityType().equals(WorkFlowServerConstant.INCLUSIVE_GATEWAY)|| actInst.getActivityType().equals(WorkFlowServerConstant.EVENT_GATEWAY);return !ifRightType;}).collect(Collectors.toList());// 设置common评论信息actHisActInstListDTOList.forEach(actInst -> {// 获取common信息List<Comment> commentList = taskService.getTaskComments(actInst.getTaskId());if (ObjectUtil.isNotEmpty(commentList)) {// 设置评论信息actInst.setOpinion(commentList.get(0).getFullMessage());}});return actHisActInstListDTOList;}/*** 获取下一处理环节** @param workFlowNextPositionDTO dto* @return WorkFlowNextPositionDTO dto*/@Overridepublic WorkFlowNextPositionDTO findNextPositionList(WorkFlowNextPositionDTO workFlowNextPositionDTO) {// 参数校验if (StrUtil.isBlank(workFlowNextPositionDTO.getTaskId())) {throw new ServiceException("传入用户taskId信息为空!");}if (StrUtil.isBlank(workFlowNextPositionDTO.getCurrentActivityId())) {throw new ServiceException("传入用户当前activitiId信息为空!");}// 获取task信息Task task = taskService.createTaskQuery().taskId(workFlowNextPositionDTO.getTaskId()).singleResult();// 获取全部流程自定义变量信息Map<String, Object> taskVariables = runtimeService.getVariables(task.getExecutionId());// 如果模板信息没有传递,则通过参数获取if (StrUtil.isBlank(workFlowNextPositionDTO.getProcessName())&& ObjectUtil.isNotNull(taskVariables.get(WorkFlowServerConstant.BIZ_TYPE_FLAG))) {// 通过bizType获取流程产品枚举类型String bizType = taskVariables.get(WorkFlowServerConstant.BIZ_TYPE_FLAG).toString();WorkFlowProductEnum productEnum = workFlowUtil.getProductEnumByBizType(bizType);if (ObjectUtil.isNotNull(productEnum)) {workFlowNextPositionDTO.setProcessName(productEnum.getTemplateId());}}// 任务进行跳节点,获取实际发起节点的流程定义信息ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(task.getProcessDefinitionId());// 获取当前节点信息,可以获取outgoingSequenceFlows,结合自定义变量信息,可以获取下一节点信息ActivityImpl currentActivity = processDefinition.findActivity(task.getTaskDefinitionKey());// 获取当前节点对外指向,并且对指向进行分析List<PvmTransition> transitionList = currentActivity.getOutgoingTransitions();if (ObjectUtil.isEmpty(transitionList)) {return workFlowNextPositionDTO;}// 最终获取全部下一处理岗位定义节点List<PvmActivity> finalActivityList = new ArrayList<>();// 循环获取目标节点信息,当前行内服务,只使用排他网关,所以后续分支只支持单一条件满足,下一节点为单一分支for (PvmTransition transition : transitionList) {// 获取目标节点PvmActivity destinationActivity = transition.getDestination();// 获取目标节点nodeType类型String activityNodeType = StrUtil.toString(destinationActivity.getProperty(WorkFlowServerConstant.NODE_TYPE));// 目标节点不同类型进行不同处理,if (WorkFlowServerConstant.EXCLUSIVE_GATEWAY.equals(activityNodeType) || WorkFlowServerConstant.INCLUSIVE_GATEWAY.equals(activityNodeType)) {// 注意此处为 节点->排他网关/包含网关->节点 形式,更复杂形式需要针对业务进行调整List<PvmActivity> exclusiveGateActivityList = activitiUtil.getNextPositionByExclusiveGateway(destinationActivity, taskVariables);finalActivityList.addAll(exclusiveGateActivityList);} else if (WorkFlowServerConstant.PARALLEL_GATEWAY.equals(activityNodeType)) {// 并行网关 节点->并行网关->节点List<PvmActivity> parallelGateActivityList = activitiUtil.getNextPositionByParallelGateway(destinationActivity);finalActivityList.addAll(parallelGateActivityList);} else if (WorkFlowServerConstant.USER_TASK_FLAG.equalsIgnoreCase(activityNodeType)) {// 普通用户任务 节点->节点finalActivityList.add(destinationActivity);} else {throw new ServiceException(StrUtil.format("当前获取下一岗位信息暂时activityNodeType[{}]暂时不支持!", activityNodeType));}}// 获取下一岗位信息非空判定if (ObjectUtil.isEmpty(finalActivityList)) {throw new ServiceException(StrUtil.format("当前taskId[{}]对应节点[{}]获取下一岗位信息为空!",workFlowNextPositionDTO.getTaskId(), task.getTaskDefinitionKey()));}// 获取下一岗位名称id信息ActivityImpl nextActivity = (ActivityImpl)finalActivityList.get(0);String nextActivityName = nextActivity.getProperty(WorkFlowServerConstant.NAME_FLAG).toString();// 下一岗位idTaskDefinition taskDefinition = (TaskDefinition)nextActivity.getProperty(WorkFlowServerConstant.TASK_DEFINITION);String nextActivityId = taskDefinition.getKey();// 构建页面下拉选择框 "-1" / "请选择"以及其他下拉列表信息List<WorkFlowNextPosition> nextPositionList = new ArrayList<>();Map<String, String> itemMap = new HashMap<>(WorkFlowServerConstant.DEFAULT_MAP_SIZE);itemMap.put(WorkFlowServerConstant.DEFAULT_ITEM_KEY, WorkFlowServerConstant.DEFAULT_ITEM_VALUE);nextPositionList.add(new WorkFlowNextPosition(WorkFlowServerConstant.DEFAULT_ITEM_KEY,WorkFlowServerConstant.DEFAULT_ITEM_VALUE));// 查询岗位信息拼接串,当前岗位信息List<Map<String, String>> currentPositionList = null;if (StrUtil.isNotBlank(workFlowNextPositionDTO.getCurrentActivityId())) {currentPositionList = tbSysFlowPositionDetailMapper.listPositionInfo(workFlowNextPositionDTO.getProcessName(), workFlowNextPositionDTO.getCurrentActivityId());}// 如果返回 nextActivityName 为 end 则不查询下一处理人 证明当前岗位为最后一岗if (ObjectUtil.isNotEmpty(currentPositionList)&& !StrUtil.equalsIgnoreCase(nextActivityName, WorkFlowServerConstant.END_FLAG)) {// 获取流程实例idString processId = task.getProcessInstanceId();if (StrUtil.isBlank(processId)) {throw new ServiceException(StrUtil.format("通过taskId[]获取流程实例信息失败!",workFlowNextPositionDTO.getTaskId()));}// 获取当前业务发起机构TbSysBackPositionInfo tbSysBackPositionInfo = tbSysBackPositionInfoMapper.getBackPositionInfoByProcessId(processId);if (ObjectUtil.isNull(tbSysBackPositionInfo)) {throw new ServiceException(StrUtil.format("通过process[{}]获取发起机构信息失败!", processId));}// 获取当前岗位信息对应跳岗信息,此处传入机构编号,从发起业务机构向上查询,WorkFlowJumpDTO workFlowJumpDTO = new WorkFlowJumpDTO();workFlowJumpDTO.setOrgCd(tbSysBackPositionInfo.getOptionOrgCd());workFlowJumpDTO.setPositionName(workFlowNextPositionDTO.getCurrentActivityId());workFlowJumpDTO.setTemplateNum(workFlowNextPositionDTO.getProcessName());workFlowJumpDTO = queryWorkFlowApiFeignClient.queryJumpWorkFlow(workFlowJumpDTO);log.info("流程processId[{}],下一岗位信息为[{}],获取跳岗信息为[{}],是否有权为[{}]",processId,nextActivityName,JSONObject.toJSONString(workFlowJumpDTO.getNextPositionArray()),workFlowNextPositionDTO.getRuleResult());// 跳岗下一岗位不为空,则正常显示跳岗信息,正常下一岗位不显示// 2022-11-09 新增有权字段 如果为有权 则正常提交下一岗位if (StrUtil.isNotBlank(workFlowJumpDTO.getNextPositionArray())&& !WorkFlowConstant.STRING_NUM_1.equals(workFlowNextPositionDTO.getRuleResult())&& !WorkFlowConstant.STRING_NUM_2.equals(workFlowNextPositionDTO.getRuleResult())) {// 跳岗位岗位名称String activityIds = workFlowJumpDTO.getNextPositionArray();List<String> positionNameList = Arrays.asList(activityIds.split(WorkFlowServerConstant.SPLIT_COMMA_FLAG));// 跳岗返回key格式: activitiId{usertask10},调查岗{positionName},1{positionLevelCd},NPD0001{positionCd}List<Map<String, String>> dropPositionDetailList = tbSysFlowPositionDetailMapper.listDropPositionList(workFlowNextPositionDTO.getProcessName(), positionNameList);dropPositionDetailList.forEach(positionInfo -> {String dropPositionInfo = StrUtil.format(WorkFlowServerConstant.POSITION_TEMPLATE_ACTIVITY_ID,positionInfo.get(WorkFlowServerConstant.ACTIVITI_ID_FLAG),positionInfo.get(WorkFlowServerConstant.POSITION_NAME_FLAG),positionInfo.get(WorkFlowServerConstant.POSITION_LEVEL_CD_FLAG),positionInfo.get(WorkFlowServerConstant.POSITION_CD_FLAG));itemMap.put(dropPositionInfo, positionInfo.get(WorkFlowServerConstant.POSITION_NAME_FLAG));nextPositionList.add(new WorkFlowNextPosition(dropPositionInfo,positionInfo.get(WorkFlowServerConstant.POSITION_NAME_FLAG)));});} else {// 获取正常下一岗位信息,返回key格式: 调查岗{positionName},1{positionLevelCd},NPD0001{positionCd}List<Map<String, String>> nextPositionMapList = tbSysFlowPositionDetailMapper.listPositionInfo(workFlowNextPositionDTO.getProcessName(), nextActivityId);if (ObjectUtil.isNotEmpty(nextPositionMapList)) {Map<String, String> nextPositionMap = nextPositionMapList.get(0);String positionStrInfo = StrUtil.format(WorkFlowServerConstant.POSITION_INFO_APPEND_TEMPLATE,nextActivityName,nextPositionMap.get(WorkFlowServerConstant.POSITION_LEVEL_CD_FLAG),nextPositionMap.get(WorkFlowServerConstant.POSITION_CD_FLAG));itemMap.put(positionStrInfo, nextActivityName);nextPositionList.add(new WorkFlowNextPosition(positionStrInfo, nextActivityName));}}}workFlowNextPositionDTO.setNextPositionMap(itemMap);workFlowNextPositionDTO.setNextPositionList(nextPositionList);return workFlowNextPositionDTO;}
}

相关文章:

简单的springboot整合activiti5-serviceImpl部分(1)

简单的springboot整合activiti5.22.0-serviceImpl部分(1) 原来的流程serviceImpl部分代码过多&#xff0c;所以此处单独记录一下&#xff0c;此处记录的是serviceImpl第一部分代码 package cn.git.workflow.service.impl;import cn.git.cache.api.BaseCacheApi; import cn.gi…...

snat、dnat和firewalld

目录 概述 SNAT源地址转换 DANT目的地址转换 抓包 firewalld 端口管理 概述 snat &#xff1a;源地址转换 内网——外网 内网ip转换成可以访问外网的ip 也就是内网的多个主机可以只有一个有效的公网ip地址访问外部网络 DNAT&#xff1a;目的地址转发 外部用户&#…...

[数据集][目标检测]鸡蛋缺陷检测数据集VOC+YOLO格式2918张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2918 标注数量(xml文件个数)&#xff1a;2918 标注数量(txt文件个数)&#xff1a;2918 标注…...

前后端防重复提交

数据重复提交是一个大忌&#xff0c;会带来无效数据&#xff0c;应该在前端和后端都建议检测防范。 前端一般是按钮按下触发数据提交&#xff0c;如果用户鼠标操作习惯不好&#xff0c;或者鼠标或系统设置问题会导致鼠标连击&#xff0c;如果前端不做相关处理&#xff0c;可能会…...

JVM专题八:JVM如何判断可回收对象

在JVM专题七&#xff1a;JVM垃圾回收机制中提到JVM的垃圾回收机制是一个自动化的后台进程&#xff0c;它通过周期性地检查和回收不可达的对象&#xff08;垃圾&#xff09;&#xff0c;帮助管理内存资源&#xff0c;确保应用程序的高效运行。今天就让我们来看看JVM到底是怎么定…...

binary_cross_entropy_with_logits函数的参数设定

binary_cross_entropy_with_logits 该函数参数&#xff1a; logits (Tensor) - 输入预测值。其数据类型为float16或float32。 label (Tensor) - 输入目标值&#xff0c;shape与 logits 相同。数据类型为float16或float32。 weight (Tensor&#xff0c;可选) - 指定每个批次二…...

Python 面试【★★★★★】

欢迎莅临我的博客 &#x1f49d;&#x1f49d;&#x1f49d;&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…...

C# StringBuilder

以下是一些基本的 StringBuilder 使用方法&#xff1a;创建 StringBuilder 实例&#xff1a;追加字符串&#xff1a;插入字符串&#xff1a;删除字符串&#xff1a;替换字符串&#xff1a;清空 StringBuilder&#xff1a;转换 StringBuilder 为字符串&#xff1a;使用容量&…...

4个文章生成器免费版分享,让文章创作更轻松便捷

在当今这个信息飞速传播的时代&#xff0c;文章创作的重要性愈发凸显。无论是从事内容创作的专业人士&#xff0c;还是偶尔需要撰写文章的普通大众&#xff0c;都希望能更高效地完成文章创作任务。而在实际操作中&#xff0c;我们常常会遇到思路卡顿、没有创作灵感的问题。今天…...

redis-cluster(集群模式搭建)

redis中间件版本: redis-5.0.5环境介绍 这里使用服务器数量3&#xff0c;分别为172.0.0.1&#xff0c;172.0.0.2&#xff0c;172.0.0.3&#xff0c;每台机器redis节点数量2个&#xff0c;共6个redis节点构成redis-cluster模式。编译安装包 在172.0.0.1的机器上进入安装目录 cd …...

使用vite官网和vue3官网分别都可以创建vue3项目

问: npm init vitelatest 和 npm create vuelatest创建的vue3项目有什么区别? 回答: npm init vitelatest 和 npm create vuelatest 分别是使用 Vite 和 Vue CLI 工具创建 Vue 项目的两种方式&#xff0c;它们之间有几个主要区别&#xff1a; 1. **构建工具&#xff1a;** …...

PDF处理篇:如何调整 PDF 图像的大小

将视觉效果无缝集成到 PDF 中的能力使它们成为强大的通信工具。然而&#xff0c;笨拙的图像大小会迅速扰乱文档的流程&#xff0c;阻碍清晰度和专业性。幸运的是&#xff0c;GeekerPDF 和Adobe Acrobat等流行的应用程序提供了用户友好的解决方案来应对这一挑战。这个全面的指南…...

STM32 HAL库里 串口中断回调函数是在怎么被调用的?

跟着正点原子学习的HAL库写串口接收程序的时候一直有困惑&#xff0c;使用HAL_UART_Receive_IT开启接收中断后&#xff0c;为啥处理函数要写在HAL_UART_RxCpltCallback里&#xff0c;中断发生的时候是怎么到这个回调函数里去的&#xff1f; void MX_USART1_UART_Init(void) {h…...

音视频入门基础:H.264专题(5)——FFmpeg源码中 解析NALU Header的函数分析

音视频入门基础&#xff1a;H.264专题系列文章&#xff1a; 音视频入门基础&#xff1a;H.264专题&#xff08;1&#xff09;——H.264官方文档下载 音视频入门基础&#xff1a;H.264专题&#xff08;2&#xff09;——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…...

RT-Thread ENV-Windows v2.0.0安装教程

前言 前几天RT-Thread官方更新了env工具&#xff0c;开源仓库的Kconfig的写法都不大一样了&#xff1b;如果继续用原来的env工具&#xff0c;拉新代码之后很多示例都编译不了 在最新的env工具中menuconfig全面采用kconfiglib&#xff0c;升级env脚本和python版本&#xff0c;改…...

[HBM] HBM TSV (Through Silicon Via) 结构与工艺

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR》 全文 3300 字。 1 概念 1.1 什么是HBM TSV 使用 TSV 堆叠多个DDR DRAM成为一块HBM, 成倍提高了存储器位宽&#xff0c; 一条位宽相当于高速公路的一条车道&#xff0c; 车道越多&#xff…...

基于STM32的温湿度检测TFT屏幕proteus恒温控制仿真系统

一、引言 本文介绍了一个基于STM32的恒温控制箱检测系统&#xff0c;该系统通过DHT11温湿度传感器采集环境中的温湿度数据&#xff0c;并利用TFT LCD屏幕进行实时显示。通过按键切换页面显示&#xff0c;通过按键切换实现恒温控制箱的恒温控制。为了验证系统的可靠性和稳定性&…...

【Qt+opencv】编译、配置opencv

文章目录 前言下载opencv编译opencvmingw版本 总结 前言 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;它包含了超过2500个优化的算法。这些算法可以用来检测和识别面部&#xff0c;识别对象&#x…...

RDMA建链的3次握手和断链的4次挥手流程?

文章目录 基础信息建链 3次握手断链4次挥手建联状态active端passive端 报文结构函数关系其他后记 基础信息 CM: Communication Management 通信管理 连接管理SIDR: Service ID Resolution Protocol. 作用&#xff1a; enables users of Unreliable Datagram service to locate …...

实验4 图像空间滤波

1. 实验目的 ①掌握图像空间滤波的主要原理与方法&#xff1b; ②掌握图像边缘提取的主要原理和方法&#xff1b; ③了解空间滤波在图像处理和机器学习中的应用。 2. 实验内容 ①调用 Matlab / Python OpenCV中的函数&#xff0c;实现均值滤波、高斯滤波、中值滤波等。 ②调…...

独辟蹊径:我是如何用Java自创一套工作流引擎的(下)

作者&#xff1a;后端小肥肠 创作不易&#xff0c;未经允许严禁转载。 姊妹篇&#xff1a;独辟蹊径&#xff1a;我是如何用Java自创一套工作流引擎的&#xff08;上&#xff09;_java工作流引擎-CSDN博客 1. 前言 在上一篇博客中&#xff0c;我们详细介绍了如何利用Java语言从…...

【Python】pycharm常用快捷键操作

目录 一.pycharm自定义修改快捷键 二.pycharm默认常用快捷键 一.pycharm自定义修改快捷键 在file-setting-keymap中可以修改快捷键&#xff0c;建议刚开始没特殊需求就不用修改&#xff0c;先熟悉系统默认的常用快捷键&#xff0c;但是以下情况可以考虑修改: 之前使用其他I…...

es6语法复习一

es6语法 1.var 变量提升 2.let 不存在变量提升&#xff0c;只能定义一次 3.const 先定义再使用&#xff0c;定义好来不能修改 4.解构赋值 [a,b,c][1,2,3],{a,b,c}{a:1,b:2,c:3} 5.模版字符串 let aaa; ${a} is ok 6.对象简化写法 const school{ name, change, improve(){ cons…...

【python入门】自定义函数

文章目录 定义自定义函数的基本语法参数类型示例代码函数作用域匿名函数&#xff08;Lambda&#xff09;闭包装饰器 Python中的自定义函数允许你编写一段可重用的代码块&#xff0c;这段代码可以带参数&#xff08;输入&#xff09;&#xff0c;并可能返回一个值&#xff08;输…...

ONLYOFFICE 桌面编辑器 8.1 版发布:全面提升文档处理效率的新体验

文章目录 什么是ONLYOFFICE &#xff1f;ONLYOFFICE 桌面编辑器 8.1 发布&#xff1a;新功能和改进功能强大的 PDF 编辑器幻灯片版式功能从右至左语言支持多媒体功能增强无缝切换工作模式其他改进和优化总结 什么是ONLYOFFICE &#xff1f; https://www.onlyoffice.com/zh/off…...

ESP32实现UDP连接——micropython版本

代码&#xff1a; import network import socket import timedef wifiInit(name, port):ap network.WLAN(network.AP_IF) # 创建一个热点ap.config(essidname, authmodenetwork.AUTH_OPEN) # 无需密码ap.active(True) # 激活热点ip ap.ifconfig()[0] # 获取ip地址print(…...

Windows Ternimal

Windows Ternimal 安装 Windows 终端概述 | Microsoft Learn wt --help在当前目录打开 lextm/windowsterminal-shell: Install/uninstall scripts for Windows Terminal context menu items 打开指定目录 wt -d %USERPROFILE% ohmyposh 美化 1 安装 2 添加 ohmyposh bin…...

Unity扩展编辑器功能的特性

1.添加分组标题 用于在Unity的Inspector视图中为属性或变量组创建一个自定义的标题或头部&#xff0c;有助于在Inspector中组织和分类不同的属性&#xff0c;使其更易于阅读和管理。 [Header("Common Properties")] public float MouseSensitivity 5; public float…...

API类别 - UI核心

API类别 - UI核心 引言 在当今的数字时代,用户界面(UI)是任何软件或应用成功的关键因素之一。UI核心API作为构建用户界面的基础,提供了丰富的功能和工具,使得开发者能够创建出既美观又实用的用户界面。本文将深入探讨UI核心API的不同类别,以及它们如何影响现代软件开发…...

Redis-主从复制-配置主从关系

文章目录 1、修改配置文件中的 bind ,注释该配置,取消绑定仅主机登录2、修改protected-mode 为no,取消保护模式3、查看redis的进程状态4、配置6380是6379的从机5、配置6381是6379的从机6、查看主机 6379 的主从信息 1、修改配置文件中的 bind ,注释该配置,取消绑定仅主机登录 …...

DigiRL:让 AI 自己学会控制手机

类似于苹果此前发布的Ferret-UI 的安卓开源平替。主要用于在 Android 设备上识别 UI 和执行指令&#xff0c;不同的是它利用了离线到在线强化学习&#xff08;Offline-to-Online RL&#xff09;&#xff0c;能够快速适应应用更新或 UI 变化。...

04.Ambari自定义服务开发-自定义服务配置文件在Ambari中的设置方法

文章目录 设置方法配置文件设置Custom xxx配置文件详细的配置方法.xml文件的整体格式基础参数格式value-attributes配置介绍设置属性在服务安装后不可修改设置允许字段为空是否显示配置名称参数类型设置字符串类型PasswordBooleanIntFloatDirectoryDirectoriesContent-多行文本…...

LSTM时间序列基础学习

时间序列 时间序列可以是一维&#xff0c;二维&#xff0c;三维甚至更高维度的数据&#xff0c;在深度学习的世界中常见的是三维时间序列&#xff0c;这三个维度分别是&#xff08;batch_size,time_step,input_dimensions&#xff09;。 其中time_step是时间步&#xff0c;它…...

『Z-Workshop』 6月22日线下ALCOVE分享活动

2024 求是创新 ZJUBCA Sponsored by the ALCOVE Community TIME&#xff1a;2024/06/22 ADD&#xff1a;浙江大学紫金港校区 --- Alcove 是 Aptos 公链与 Alibaba Cloud 共同打造的亚洲首个 Move 开发者社区&#xff0c;致力于支持开发者使用 Move 语言构建下一代 Web3 应用&am…...

【机器学习】机器学习重要方法——迁移学习:理论、方法与实践

文章目录 迁移学习&#xff1a;理论、方法与实践引言第一章 迁移学习的基本概念1.1 什么是迁移学习1.2 迁移学习的类型1.3 迁移学习的优势 第二章 迁移学习的核心方法2.1 特征重用&#xff08;Feature Reuse&#xff09;2.2 微调&#xff08;Fine-Tuning&#xff09;2.3 领域适…...

uniapp, ‍[⁠TypeError⁠]‍ “Failed to fetch dynamically imported module“ 报错解决思路

文章目录 1. 背景2. 报错3. 解决思路4. 思考参考1. 背景 最近基于uniapp开发一款设备参数调试的APP软件,在使用第三方插件的过程中,出现下面的报错。 2. 报错 [plugin:vite:import-analysis] Cannot find module ‘D:/leaning/uniapp/demo/jk-uts-udp示例/uni_modules/uts-…...

四川省高等职业学校大数据技术专业建设暨专业质量监测研讨活动顺利开展

6月21日&#xff0c;省教育评估院在四川邮电职业技术学院组织开展全省高等职业学校大数据技术专业建设暨专业质量监测研讨活动。省教育评估院副院长赖长春&#xff0c;四川邮电职业技术学院党委副书记、校长冯远洪&#xff0c;四川邮电职业技术学院党委委员、副校长程德杰等出席…...

深入解析三大跨平台开发框架:Flutter、React Native 和 uniapp

深入解析三大跨平台开发框架&#xff1a;Flutter、React Native 和 uniapp 在移动开发中&#xff0c;跨平台开发框架已经成为开发者的首选工具。本篇将深入解析三大主流跨平台开发框架&#xff1a;Flutter、React Native 和 uniapp。下面将详细探讨它们的原理、优势和劣势。 …...

【吊打面试官系列-MyBatis面试题】#{}和${}的区别是什么?

大家好&#xff0c;我是锋哥。今天分享关于 【#{}和${}的区别是什么&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; #{}和${}的区别是什么&#xff1f; #{} 是预编译处理&#xff0c;${}是字符串替换。 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网…...

解决HTTP 400 Bad Request错误的方法

解决HTTP 400 Bad Request错误的方法 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在进行网络通信时&#xff0c;HTTP 400 Bad Request错误是相对常见的问题…...

Html的表单标签。(Java程序员需要掌握的前端)

表单标签 2.5.1 表单 2.5.1.1 介绍 那表单呢,在我们日常的上网的过程中,基本上每天都会遇到。比如&#xff0c;我们经常在访问网站时&#xff0c;出现的登录页面、注册页面、个人信息提交页面&#xff0c;其实都是一个一个的表单 。 当我们在这些表单中录入数据之后&#xf…...

Arduino (esp ) 下String的内存释放

在个人的开源项目 GitHub - StarCompute/tftziku: 这是一个通过单片机在各种屏幕上显示中文的解决方案 中为了方便快速检索使用了string&#xff0c;于是这个string在esp8266中占了40多k,原本以为当string设置为""的时候这个40k就可以回收&#xff0c;结果发觉不行…...

图灵虚拟机配置

导入虚拟机 点击新建&#xff0c;选择虚拟硬盘文件 环境机器.vmdk 配置网络...

【SQL常用日期函数(一)】

SQL 常用日期函数-基于impala 引擎 当前日期&#xff08;YYYY-MM-DD&#xff09; SELECT CURRENT_DATE(); -- 2024-06-30昨天 SELECT CURRENT_DATE(); -- 2024-06-30 SELECT CAST( DAYS_ADD(TO_DATE( CURRENT_DATE() ), -1 ) AS VARCHAR(10) ); -- 2024-06-29 SELECT CAST( …...

C++操作系列(二):VSCode安装和配置C++开发环境

1. VSCode下载 进入VSCode的官网网页&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 下载相应的版本&#xff1a; 2. 安装VSCode 安装到指定位置&#xff1a; 一路下一步&#xff0c;直至安装完成&#xff1a; 3. 安装C插件 3.1. 安装C/C 点击扩展图标&…...

【java12】java12新特性之File的mismatch方法

Java12引入了一个新的方法 mismatch&#xff0c;它属于java.nio.file.Files类。此方法用于比较两个文件的内容&#xff0c;并返回第一个不匹配字节的位置。如果两个文件完全相同&#xff0c;则返回-1。 Files.mismatch 方法声明 public static long mismatch(Path path1, Pat…...

uni-app (通过HBuilderX 和 VS Code 开发)详细连接过程教学。

使用 HBuilderX 创建 uni-app 项目 并编译到微信开发者工具。 uni-app 支持两种方式创建项目&#xff1a; 通过 HBuilderX 创建 通过命令行创建 首先我们需要先下载HBuilderX 下载链接地址&#xff1a;DCloud - HBuilder、HBuilderX、uni-app、uniapp、5、5plus、mui、wap2…...

安宝特方案 | AR术者培养:AR眼镜如何帮助医生从“看”到“做”?

每一种新药品的上市都需要通过大量的临床试验&#xff0c;而每一种新的手术工具在普及使用之前也需要经过反复的实践和验证。医疗器械公司都面临着这样的挑战&#xff1a;如何促使保守谨慎的医生从仅仅观察新工具在手术中的应用&#xff0c;转变为在实际手术中实操这项工具。安…...

20240628每日前端---------解决vue项目滥用watch

主题 滥用watch。 名字解释 watch 例子 先看一个代码例子&#xff1a; <template>{{ dataList }} </template><script setup lang"ts"> import { ref, watch } from "vue";const dataList ref([]); const props defineProps([&q…...

【LLM 评估】GLUE benchmark:NLU 的多任务 benchmark

论文&#xff1a;GLUE: A Multi-Task Benchmark and Analysis Platform for Natural Language Understanding ⭐⭐⭐⭐ arXiv:1804.07461, ICLR 2019 Site: https://gluebenchmark.com/ 文章目录 一、论文速读二、GLUE 任务列表2.1 CoLA&#xff08;Corpus of Linguistic Accep…...

绝区零 Mac 下载安装详细教程(MacOS IPA 砸壳包 playCover 完美运行)

绝区零 7.4 号开始公测&#xff0c;但刚刚就可以开始下载了&#xff0c;我也是第一时间就迫不及待的安装到了我的 Mac 电脑上&#xff0c;感兴趣的朋友可以跟我一起安装试试 我这里是通过 playCover 的形式在 Mac 上安装运行的&#xff0c;根据之前原神的经验所以这次还是同样…...

Vue 路由传参 query方法 bug 记录

问题描述 vue 路由传参 踩坑 this.$router.push({path: "xxxxxxx",query: {opportunity_id:row.opportunity_id,constructor:row.constructor,},});解决方案&#xff1a; 上述方法传入新页面时&#xff0c;访问的 this.$route.query 会有bug 每一次刷新都会在最后一…...

云计算【第一阶段(26)】Linux网络设置

一、查看网络配置 1.查看网络接口信息ifconfig 查看所有活动的网络接口信息 2.ifconfig命令 查看指定网络接口信息 ifconfig 网络接口 &#xff08;1&#xff09;第一行&#xff1a;以太网卡的名字 ens33其中en代表以太网卡&#xff0c; centos6的是eth0&#xff0c; e…...

C# 用户权限界面的测试内容

测试用户权限界面的主要目标是确保权限管理功能按照设计工作&#xff0c;同时保证用户界面响应正确&#xff0c;不会出现意外的行为或安全漏洞。以下是C#中用户权限界面测试的一些关键内容&#xff1a; 1. 功能性测试 权限分配与撤销&#xff1a;测试权限的分配和撤销功能&am…...

数据结构——单向循环链表

文章目录 1. 概念 2. 区别 2.1 结构区别 2.2 访问方式区别 2.3 优缺点对比 3. 流程 4. 基本操作 5. 代码示例 1. 概念 单向循环链表是一种特殊的单链表&#xff0c;其中最后一个节点的后继指针指向头节点&#xff0c;形成一个环。单向循环链表适合用于需要循环访问数据…...

基于jeecgboot-vue3的Flowable流程-集成仿钉钉流程(二)增加基本的发起人审批与多用户多实例

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、AssigneeNode 增加approvalText public abstract class AssigneeNode extends Node {// 审批对象private AssigneeTypeEnum assigneeType;// 表单内人员private String formUser;// 表…...

越级大五座SUV全新一代别克昂科威Plus上市

上汽通用汽车别克品牌宣布,越级大五座SUVmdash;mdash;全新一代别克昂科威Plus正式上市,共推出3款车型,售价22.99万元-25.99万元。全新一代昂科威Plus践行油电同智理念,在带来行业智能化体验的同时,更不止于智能,实现在设计、舒适、安全、品质等全维度129项产品力迭代升级…...

年轻化的新一代迈腾,颜值并不丑,三大屏高通8155

年轻化的新一代迈腾,颜值并不丑,三大屏高通8155,像新势力中国汽车市场的竞争是越来越激烈,要想脱颖而出,即便是合资品牌旗下的主力常青树车型,现在也要拥抱变化了。就拿大众迈腾这款车来说,长期以来已经形成了一套固定的印象标签,无非就是中规中矩的沉稳商务风格。但全…...

深入分析 Android Activity (三)

文章目录 深入分析 Android Activity (三)1. Activity 的配置变化处理1.1 处理配置变化 2. Activity 的存储和恢复状态2.1 保存状态2.2 恢复状态 3. Activity 与 Fragment 的通信3.1 通过接口进行通信3.2 通过 ViewModel 进行通信 4. Activity 的窗口管理和视图层次结构4.1 Dec…...

ios swift5 codable字典转模型,第三方库SmartCodable

文章目录 1.用第三方库SmartCodable, github地址2.使用示例 1.用第三方库SmartCodable, github地址 SmartCodable - github 2.使用示例 import Foundation import SmartCodablestruct CommonModel: SmartCodable {var message: String ""var success: Bool fals…...

计算机毕业设计Hadoop+Hive地震预测系统 地震数据分析可视化 地震爬虫 大数据毕业设计 Spark 机器学习 深度学习 Flink 大数据

2024 届本科毕业论文&#xff08;设计&#xff09; 基于Hadoop的地震预测的 分析与可视化研究 姓 名&#xff1a;____田伟情_________ 系 别&#xff1a;____信息技术学院___ 专 业&#xff1a;数据科学与大数据技术 学 号&#xff1a;__2011103094________ 指导…...

[less配置]vue2引入less

1、终端输入&#xff1a;npm install less less-loader --save-dev 2、在package.json查看是否安装less依赖 3、调用...