package org.jeecg.modules.flowable.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.commons.io.IOUtils; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.ProcessEngineConfiguration; import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinitionQuery; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.image.ProcessDiagramGenerator; import org.flowable.image.impl.DefaultProcessDiagramGenerator; import org.flowable.task.api.Task; import org.jeecg.common.api.vo.Result; import org.jeecg.common.util.SpringContextUtils; import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness; import org.jeecg.modules.flowable.apithird.business.service.impl.FlowMyBusinessServiceImpl; import org.jeecg.modules.flowable.apithird.common.constant.ProcessConstants; import org.jeecg.modules.flowable.apithird.common.enums.FlowComment; import org.jeecg.modules.flowable.apithird.entity.SysUser; import org.jeecg.modules.flowable.apithird.service.FlowCallBackServiceI; import org.jeecg.modules.flowable.apithird.service.IFlowThirdService; import org.jeecg.modules.flowable.domain.dto.FlowNextDto; import org.jeecg.modules.flowable.domain.dto.FlowProcDefDto; import org.jeecg.modules.flowable.factory.FlowServiceFactory; import org.jeecg.modules.flowable.service.IFlowDefinitionService; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; /** * 流程定义 */ @Service public class FlowDefinitionServiceImpl extends FlowServiceFactory implements IFlowDefinitionService { @Autowired IFlowThirdService iFlowThirdService; @Autowired FlowMyBusinessServiceImpl flowMyBusinessService; @Autowired FlowTaskServiceImpl flowTaskService; private static final String BPMN_FILE_SUFFIX = ".bpmn"; @Override public boolean exist(String processDefinitionKey) { ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey); long count = processDefinitionQuery.count(); return count > 0; } /** * 流程定义列表 * * @param pageNum 当前页码 * @param pageSize 每页条数 * @param flowProcDefDto * @return 流程定义分页列表数据 */ @Override public Page list(Integer pageNum, Integer pageSize, FlowProcDefDto flowProcDefDto) { Page page = new Page<>(); // 流程定义列表数据查询 ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery(); processDefinitionQuery //.processDefinitionId("cs:5:15e953ed-4d09-11ec-85b8-e884a5deddfc") .orderByProcessDefinitionKey().asc().orderByProcessDefinitionVersion().desc(); /*=====参数=====*/ if (StrUtil.isNotBlank(flowProcDefDto.getName())) { processDefinitionQuery.processDefinitionNameLike("%" + flowProcDefDto.getName() + "%"); } if (StrUtil.isNotBlank(flowProcDefDto.getCategory())) { processDefinitionQuery.processDefinitionCategory(flowProcDefDto.getCategory()); } if (flowProcDefDto.getSuspensionState() == 1) { processDefinitionQuery.active(); } if (StrUtil.isNotBlank(flowProcDefDto.getKey())) { processDefinitionQuery.processDefinitionKey(flowProcDefDto.getKey()); } if (flowProcDefDto.getIsLastVersion() == 1) { processDefinitionQuery.latestVersion(); } /*============*/ page.setTotal(processDefinitionQuery.count()); List processDefinitionList = processDefinitionQuery.listPage((pageNum - 1) * pageSize, pageSize); List dataList = new ArrayList<>(); for (ProcessDefinition processDefinition : processDefinitionList) { String deploymentId = processDefinition.getDeploymentId(); Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult(); FlowProcDefDto reProcDef = new FlowProcDefDto(); BeanUtils.copyProperties(processDefinition, reProcDef); // 流程定义时间 reProcDef.setDeploymentTime(deployment.getDeploymentTime()); dataList.add(reProcDef); } page.setRecords(dataList); return page; } /** * 导入流程文件 * * @param name * @param category * @param in */ @Override public void importFile(String name, String category, InputStream in) { Deployment deploy = repositoryService.createDeployment().addInputStream(name + BPMN_FILE_SUFFIX, in).name(name).category(category).deploy(); ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult(); repositoryService.setProcessDefinitionCategory(definition.getId(), category); } /** * 读取xml * * @param deployId * @return */ @Override public Result readXml(String deployId) throws IOException { ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName()); String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8); return Result.OK("", result); } @Override public Result readXmlByDataId(String dataId) throws IOException { LambdaQueryWrapper flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>(); flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId) ; //如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题 FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper); ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(business.getProcessDefinitionId()).singleResult(); InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName()); String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8); return Result.OK("", result); } /** * 读取xml 根据业务Id * * @param dataId * @return */ @Override public InputStream readImageByDataId(String dataId) { FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId); String processId = business.getProcessInstanceId(); ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); //流程走完的 显示全图 if (pi == null) { ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(business.getProcessDefinitionId()).singleResult(); return this.readImage(processDefinition.getDeploymentId()); } List historyProcess = historyService.createHistoricActivityInstanceQuery() .processInstanceId(processId).list(); List activityIds = new ArrayList<>(); List flows = new ArrayList<>(); //获取流程图 BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); for (HistoricActivityInstance hi : historyProcess) { String activityType = hi.getActivityType(); if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) { flows.add(hi.getActivityId()); } else if (activityType.equals("userTask") || activityType.equals("startEvent")) { activityIds.add(hi.getActivityId()); } } List tasks = taskService.createTaskQuery().processInstanceId(processId).list(); for (Task task : tasks) { activityIds.add(task.getTaskDefinitionKey()); } ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration(); //定义流程画布生成器 ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator(); InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true); return in; } /** * 读取xml * * @param deployId * @return */ @Override public InputStream readImage(String deployId) { ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); //获得图片流 DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator(); BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); //输出为图片 return diagramGenerator.generateDiagram( bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), "宋体", "宋体", "宋体", null, 1.0, false); } /** * 根据流程定义ID启动流程实例 * * @param procDefKey 流程定义Id * @param variables 流程变量 * @return */ @Override @Transactional(rollbackFor = {Exception.class}) public Result startProcessInstanceByKey(String procDefKey, Map variables) { ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionKey(procDefKey) .latestVersion().singleResult(); Result result = startProcessInstanceById(processDefinition.getId(), variables); return result; } /** * 根据流程定义ID启动流程实例 * * @param procDefId 流程定义Id * @param variables 流程变量 * @return */ @Override @Transactional public Result startProcessInstanceById(String procDefId, Map variables) { ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionId(procDefId) .singleResult(); if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) { return Result.error("流程已被挂起,请先激活流程"); } // variables.put("skip", true); // variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true); // 设置流程发起人Id到流程中 SysUser sysUser = iFlowThirdService.getLoginUser(); identityService.setAuthenticatedUserId(sysUser.getUsername()); variables.put(ProcessConstants.PROCESS_INITIATOR, sysUser.getUsername()); ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables); // 给第一步申请人节点设置任务执行人和意见 Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().singleResult(); if (Objects.nonNull(task)) { taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), variables.get("organization").toString()); taskService.setAssignee(task.getId(), sysUser.getUsername()); task.setDescription(variables.get("organization").toString()); //taskService.complete(task.getId(), variables); } //设置所有申请人 /*======================todo 启动之后 回调以及关键数据保存======================*/ //业务数据id String dataId = variables.get("dataId").toString(); //如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题 FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId); //设置数据 List nextFlowNodeList = flowTaskService.getNextFlowNode(task.getId(), variables); taskService.complete(task.getId(), variables); //下一个实例节点 多实例会是一个list,随意取一个即可 数组中定义Key是一致的 //Task task2 = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().singleResult(); List task2List = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().list(); String doneUsers = business.getDoneUsers(); // 处理过流程的人 JSONArray doneUserList = new JSONArray(); if (StrUtil.isNotBlank(doneUsers)) { doneUserList = JSON.parseArray(doneUsers); } if (!doneUserList.contains(sysUser.getUsername())) { doneUserList.add(sysUser.getUsername()); } if (CollectionUtil.isEmpty(nextFlowNodeList)) { // **没有下一个节点,流程已经结束了 business.setProcessDefinitionId(procDefId) .setProcessInstanceId(processInstance.getProcessInstanceId()) // .setActStatus(ActStatus.pass) .setProposer(sysUser.getUsername()) .setDoneUsers(doneUserList.toJSONString()) ; flowMyBusinessService.updateById(business); } else if (nextFlowNodeList.size() == 1) { //下个节点只有一个 FlowNextDto nextFlowNode = nextFlowNodeList.get(0); UserTask nextTask = nextFlowNode.getUserTask(); Task task2 = null; Optional first = task2List.stream().filter(t -> t.getTaskDefinitionKey().equals(nextTask.getId())).findFirst(); if (first.isPresent()) { task2 = first.get(); } if (task2 != null) { //能够处理下个节点的候选人 List nextFlowNodeUserList = nextFlowNode.getUserList(); List collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList()); //spring容器类名 String serviceImplName = business.getServiceImplName(); FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName); List beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionId(), variables); business.setProcessDefinitionId(procDefId) .setProcessInstanceId(processInstance.getProcessInstanceId()) //// .setActStatus(ActStatus.start) .setProposer(sysUser.getUsername()) .setTaskId(task2.getId()) .setTaskName(nextTask.getName()) .setTaskNameId(nextTask.getId()) .setPriority(nextTask.getPriority()) .setDoneUsers(doneUserList.toJSONString()); if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) { // 删除后重写 for (String oldUser : collect_username) { taskService.deleteCandidateUser(task2.getId(), oldUser); } // 业务层有指定候选人,覆盖 for (String newUser : beforeParamsCandidateUsernames) { taskService.addCandidateUser(task2.getId(), newUser); } business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames)); } else { // 业务层没有指定候选人,直接覆盖 business.setTodoUsers(JSON.toJSONString(collect_username)); } flowMyBusinessService.updateById(business); } } else { for (FlowNextDto nextFlowNode : nextFlowNodeList) { //**有下一个节点 UserTask nextTask = nextFlowNode.getUserTask(); Task task2 = null; Optional first = task2List.stream().filter(t -> t.getTaskDefinitionKey().equals(nextTask.getId())).findFirst(); if (first.isPresent()) { task2 = first.get(); } if (task2 != null) { //新的业务流程节点 FlowMyBusiness newBusiness = BeanUtil.copyProperties(business, FlowMyBusiness.class, "id"); //能够处理下个节点的候选人 List nextFlowNodeUserList = nextFlowNode.getUserList(); List collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList()); //spring容器类名 String serviceImplName = newBusiness.getServiceImplName(); FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName); List beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionId(), variables); newBusiness.setProcessDefinitionId(procDefId) .setProcessInstanceId(processInstance.getProcessInstanceId()) //// .setActStatus(ActStatus.start) .setProposer(sysUser.getUsername()) .setTaskId(task2.getId()) .setTaskName(nextTask.getName()) .setTaskNameId(nextTask.getId()) .setPriority(nextTask.getPriority()) .setDoneUsers(doneUserList.toJSONString()); if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) { // 删除后重写 for (Task task2One : task2List) { for (String oldUser : beforeParamsCandidateUsernames) { taskService.deleteCandidateUser(task2One.getId(), oldUser); } } // 业务层有指定候选人,覆盖 for (Task task2One : task2List) { for (String newUser : beforeParamsCandidateUsernames) { taskService.addCandidateUser(task2One.getId(), newUser); } } newBusiness.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames)); } else { // 业务层没有指定候选人,直接覆盖 newBusiness.setTodoUsers(JSON.toJSONString(collect_username)); // 删除后重写 for (Task task2One : task2List) { for (String oldUser : collect_username) { taskService.deleteCandidateUser(task2One.getId(), oldUser); } } // 业务层有指定候选人,覆盖 for (Task task2One : task2List) { for (String newUser : collect_username) { taskService.addCandidateUser(task2One.getId(), newUser); } } } flowMyBusinessService.save(newBusiness); } } //删除原有的业务数据 flowMyBusinessService.removeById(business.getId()); } //spring容器类名 String serviceImplName = business.getServiceImplName(); FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName); // 流程处理完后,进行回调业务层 business.setValues(variables); if (flowCallBackService != null) { flowCallBackService.afterFlowHandle(business); } return Result.OK("流程启动成功"); } @Override public Result startProcessInstanceByDataId(String dataId, Map variables) { LambdaQueryWrapper flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>(); flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId) ; FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper); if (business == null) { return Result.error("未找到dataId:" + dataId); } if (StrUtil.isNotBlank(business.getProcessDefinitionId())) { return this.startProcessInstanceById(business.getProcessDefinitionId(), variables); } return this.startProcessInstanceByKey(business.getProcessDefinitionKey(), variables); } /** * 激活或挂起流程定义 * * @param state 状态 激活1 挂起2 * @param deployId 流程部署ID */ @Override public void updateState(Integer state, String deployId) { ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); // 激活 if (state == 1) { repositoryService.activateProcessDefinitionById(procDef.getId(), true, null); } // 挂起 if (state == 2) { repositoryService.suspendProcessDefinitionById(procDef.getId(), true, null); } } /** * 删除流程定义 * * @param deployId 流程部署ID act_ge_bytearray 表中 deployment_id值 */ @Override public void delete(String deployId) { // true 允许级联删除 ,不设置会导致数据库外键关联异常 repositoryService.deleteDeployment(deployId, true); } }