zhangherong
2025-06-25 23855599412c4d61b38d78f0f3abd3430a48b5b1
lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowDefinitionServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,480 @@
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<FlowProcDefDto> list(Integer pageNum, Integer pageSize, FlowProcDefDto flowProcDefDto) {
        Page<FlowProcDefDto> 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<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage((pageNum - 1) * pageSize, pageSize);
        List<FlowProcDefDto> 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<FlowMyBusiness> 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<HistoricActivityInstance> historyProcess = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId).list();
        List<String> activityIds = new ArrayList<>();
        List<String> 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<Task> 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<String, Object> 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<String, Object> 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<FlowNextDto> nextFlowNodeList = flowTaskService.getNextFlowNode(task.getId(), variables);
        taskService.complete(task.getId(), variables);
        //下一个实例节点  å¤šå®žä¾‹ä¼šæ˜¯ä¸€ä¸ªlist,随意取一个即可  æ•°ç»„中定义Key是一致的
        //Task task2 = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().singleResult();
        List<Task> 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<Task> first = task2List.stream().filter(t -> t.getTaskDefinitionKey().equals(nextTask.getId())).findFirst();
            if (first.isPresent()) {
                task2 = first.get();
            }
            if (task2 != null) {
                //能够处理下个节点的候选人
                List<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
                List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
                //spring容器类名
                String serviceImplName = business.getServiceImplName();
                FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
                List<String> 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<Task> 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<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
                    List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
                    //spring容器类名
                    String serviceImplName = newBusiness.getServiceImplName();
                    FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
                    List<String> 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<String, Object> variables) {
        LambdaQueryWrapper<FlowMyBusiness> 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);
    }
}