zhangherong
2025-06-25 23855599412c4d61b38d78f0f3abd3430a48b5b1
lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1614 @@
package org.jeecg.modules.flowable.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
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.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.flowable.apithird.business.dto.FlowMyBusinessDto;
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.common.exception.CustomException;
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.FlowCommentDto;
import org.jeecg.modules.flowable.domain.dto.FlowNextDto;
import org.jeecg.modules.flowable.domain.dto.FlowTaskDto;
import org.jeecg.modules.flowable.domain.dto.FlowViewerDto;
import org.jeecg.modules.flowable.domain.vo.FlowTaskVo;
import org.jeecg.modules.flowable.factory.FlowServiceFactory;
import org.jeecg.modules.flowable.flow.CustomProcessDiagramGenerator;
import org.jeecg.modules.flowable.flow.FindNextNodeUtil;
import org.jeecg.modules.flowable.flow.FlowableUtils;
import org.jeecg.modules.flowable.service.IFlowTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
 *
 **/
@Service
@Slf4j
@Transactional
public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTaskService {
    @Resource
    private IFlowThirdService iFlowThirdService;
    @Autowired
    FlowMyBusinessServiceImpl flowMyBusinessService;
    /**
     * å®Œæˆä»»åŠ¡
     *
     * @param taskVo è¯·æ±‚实体参数
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result complete(FlowTaskVo taskVo) {
        Task task = taskService.createTaskQuery().taskId(taskVo.getTaskId()).singleResult();
        if (Objects.isNull(task)) {
            return Result.error("任务不存在");
        }
        if (StringUtils.isNotEmpty(taskVo.getComment())) {
            task.setDescription(taskVo.getComment());
            taskService.saveTask(task);
        }
        SysUser loginUser = iFlowThirdService.getLoginUser();
        //判断用户是否有权限
        if (!task.getAssignee().equals(loginUser.getUsername())) {
            return Result.error("当前用户无权限");
        }
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.DELEGATE.getType(), taskVo.getComment());
            //taskService.resolveTask(taskVo.getTaskId(), taskVo.getValues());
        } else {
            System.out.println("taskVo.getTaskId()--->taskVo.getInstanceId()--->FlowComment.NORMAL.getType()--->taskVo.getComment()" + taskVo.getTaskId() + "---" + taskVo.getInstanceId() + "---" + FlowComment.NORMAL.getType() + "---" + taskVo.getComment());
            taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.NORMAL.getType(), taskVo.getComment());
            taskService.setAssignee(taskVo.getTaskId(), loginUser.getUsername());
        }
        /*======================审批结束  å›žè°ƒä»¥åŠå…³é”®æ•°æ®ä¿å­˜======================*/
        //业务数据id
        String dataId = taskVo.getDataId();
        //如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题
        FlowMyBusiness business = flowMyBusinessService.getFlowMyBusiness(taskVo.getInstanceId(), taskVo.getTaskId());
        //spring容器类名
        String serviceImplName = business.getServiceImplName();
        FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
        // æµç¨‹å˜é‡
        Map<String, Object> flowBeforeParamsValues = flowCallBackService.flowValuesOfTask(business.getTaskNameId(), taskVo.getValues());
        //设置数据
        Map<String, Object> values = taskVo.getValues();
        if (MapUtil.isNotEmpty(flowBeforeParamsValues)) {
            //    ä¸šåŠ¡å±‚æœ‰è®¾ç½®å˜é‡ï¼Œä½¿ç”¨ä¸šåŠ¡å±‚çš„å˜é‡
            values = flowBeforeParamsValues;
        }
        //并行网关 å¤šä»»åŠ¡
        List<FlowNextDto> nextFlowNodeList = this.getNextFlowNode(task.getId(), values);
        //下一个实例节点
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.resolveTask(taskVo.getTaskId(), values);
        } else {
            taskService.complete(taskVo.getTaskId(), values);
        }
        List<Task> task2List = taskService.createTaskQuery().processInstanceId(business.getProcessInstanceId()).active().list();
        String doneUsers = business.getDoneUsers();
        // å¤„理过流程的人
        JSONArray doneUserList = new JSONArray();
        if (StrUtil.isNotBlank(doneUsers)) {
            doneUserList = JSON.parseArray(doneUsers);
        }
        if (!doneUserList.contains(loginUser.getUsername())) {
            doneUserList.add(loginUser.getUsername());
        }
        if (CollectionUtils.isEmpty(nextFlowNodeList)) {
            //    **没有下一个节点,流程已经结束了
            business
                    .setDoneUsers(doneUserList.toJSONString())
                    .setTodoUsers("")
                    .setTaskId("")
                    .setTaskNameId("")
                    .setTaskName("")
            ;
            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();
            task2 = first.orElseGet(() -> task2List.get(0));
            if (task2 != null) {
                // ä¸‹ä¸ªèŠ‚ç‚¹å€™é€‰äºº
                List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionKey(), taskVo.getValues());
                List<String> candidateUsers = taskVo.getCandidateUsers();
                if (CollUtil.isNotEmpty(candidateUsers)) {
                    //    å‰ç«¯ä¼ å…¥å€™é€‰äºº è¦†ç›–
                    beforeParamsCandidateUsernames = candidateUsers;
                }
                if (task.getTaskDefinitionKey().equals(task2.getTaskDefinitionKey())) {
                    //多实例 ä¼šç­¾ TODO
                    //    * å½“前节点是会签节点,没有走完
                    business.setTaskId(task2.getId())
//                    .setActStatus(ActStatus.doing)
                            .setDoneUsers(doneUserList.toJSONString())
                    ;
                    String todoUsersStr = business.getTodoUsers();
                    JSONArray todosArr = JSON.parseArray(todoUsersStr);
                    // åˆ é™¤åŽé‡å†™
                    for (Object oldUser : todosArr) {
                        taskService.deleteCandidateUser(task2.getId(), oldUser.toString());
                    }
                    // é‡å†™
                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
                        beforeParamsCandidateUsernames.remove(loginUser.getUsername());
                        // ä¸šåŠ¡å±‚æœ‰æŒ‡å®šå€™é€‰äººï¼Œè¦†ç›–
                        for (String newUser : beforeParamsCandidateUsernames) {
                            taskService.addCandidateUser(task2.getId(), newUser);
                        }
                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
                    } else {
                        todosArr.remove(loginUser.getUsername());
                        for (Object oldUser : todosArr) {
                            taskService.addCandidateUser(task2.getId(), oldUser.toString());
                        }
                        business.setTodoUsers(todosArr.toJSONString());
                    }
                } else {
                    //能够处理下个节点的候选人
                    List<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
                    List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(candidateUsers)) {
                        //    å‰ç«¯ä¼ å…¥å€™é€‰äºº
                        collect_username = candidateUsers;
                    }
                    business
                            .setTaskId(task2.getId())
//                        .setActStatus(ActStatus.doing)
                            .setTaskNameId(nextTask.getId())
                            .setTaskName(nextTask.getName())
                            .setPriority(nextTask.getPriority())
                            .setDoneUsers(doneUserList.toJSONString())
                            .setTodoUsers(JSON.toJSONString(collect_username))
                    ;
                    // åˆ é™¤åŽé‡å†™
                    for (String oldUser : collect_username) {
                        taskService.deleteCandidateUser(task2.getId(), oldUser);
                    }
                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
                        // å‰ç«¯æ²¡æœ‰ä¼ å…¥å€™é€‰äºº && ä¸šåŠ¡å±‚æœ‰æŒ‡å®šå€™é€‰äººï¼Œè¦†ç›–
                        for (String newUser : beforeParamsCandidateUsernames) {
                            taskService.addCandidateUser(task2.getId(), newUser);
                        }
                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
                    } else {
                        for (String oldUser : collect_username) {
                            taskService.addCandidateUser(task2.getId(), oldUser);
                        }
                        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<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionKey(), taskVo.getValues());
                    List<String> candidateUsers = taskVo.getCandidateUsers();
                    if (CollUtil.isNotEmpty(candidateUsers)) {
                        //    å‰ç«¯ä¼ å…¥å€™é€‰äºº è¦†ç›–
                        beforeParamsCandidateUsernames = candidateUsers;
                    }
                    if (task.getTaskDefinitionKey().equals(task2.getTaskDefinitionKey())) {
                        //多实例 ä¼šç­¾ TODO
                        //    * å½“前节点是会签节点,没有走完
                        newBusiness.setTaskId(task2.getId())
//                    .setActStatus(ActStatus.doing)
                                .setDoneUsers(doneUserList.toJSONString())
                        ;
                        String todoUsersStr = business.getTodoUsers();
                        JSONArray todosArr = JSON.parseArray(todoUsersStr);
                        // åˆ é™¤åŽé‡å†™
                        for (Object oldUser : todosArr) {
                            taskService.deleteCandidateUser(task2.getId(), oldUser.toString());
                        }
                        // é‡å†™
                        if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
                            beforeParamsCandidateUsernames.remove(loginUser.getUsername());
                            // ä¸šåŠ¡å±‚æœ‰æŒ‡å®šå€™é€‰äººï¼Œè¦†ç›–
                            for (String newUser : beforeParamsCandidateUsernames) {
                                taskService.addCandidateUser(task2.getId(), newUser);
                            }
                            newBusiness.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
                        } else {
                            todosArr.remove(loginUser.getUsername());
                            for (Object oldUser : todosArr) {
                                taskService.addCandidateUser(task2.getId(), oldUser.toString());
                            }
                            newBusiness.setTodoUsers(todosArr.toJSONString());
                        }
                    } else {
                        //能够处理下个节点的候选人
                        List<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
                        List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
                        if (CollUtil.isNotEmpty(candidateUsers)) {
                            //    å‰ç«¯ä¼ å…¥å€™é€‰äºº
                            collect_username = candidateUsers;
                        }
                        newBusiness
                                .setTaskId(task2.getId())
//                        .setActStatus(ActStatus.doing)
                                .setTaskNameId(nextTask.getId())
                                .setTaskName(nextTask.getName())
                                .setPriority(nextTask.getPriority())
                                .setDoneUsers(doneUserList.toJSONString())
                                .setTodoUsers(JSON.toJSONString(collect_username))
                        ;
                        // åˆ é™¤åŽé‡å†™
                        for (String oldUser : collect_username) {
                            taskService.deleteCandidateUser(task2.getId(), oldUser);
                        }
                        if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
                            // å‰ç«¯æ²¡æœ‰ä¼ å…¥å€™é€‰äºº && ä¸šåŠ¡å±‚æœ‰æŒ‡å®šå€™é€‰äººï¼Œè¦†ç›–
                            for (String newUser : beforeParamsCandidateUsernames) {
                                taskService.addCandidateUser(task2.getId(), newUser);
                            }
                            newBusiness.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
                        } else {
                            for (String oldUser : collect_username) {
                                taskService.addCandidateUser(task2.getId(), oldUser);
                            }
                            newBusiness.setTodoUsers(JSON.toJSONString(collect_username));
                        }
                    }
                    flowMyBusinessService.save(newBusiness);
                }
                flowMyBusinessService.updateById(business);
            }
            //删除原有的业务数据
            flowMyBusinessService.removeById(business.getId());
        }
        // æµç¨‹å¤„理完后,进行回调业务层
        business.setValues(values);
        if (flowCallBackService != null) {
            flowCallBackService.afterFlowHandle(business);
        }
        return Result.OK();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result completeByDateId(FlowTaskVo flowTaskVo) {
        return this.complete(flowTaskVo);
    }
    @Override
    public void taskRejectByDataId(FlowTaskVo flowTaskVo) {
        FlowMyBusiness business = flowMyBusinessService.getByDataId(flowTaskVo.getDataId());
        flowTaskVo.setTaskId(business.getTaskId());
        this.taskReject(flowTaskVo);
    }
    /**
     * é©³å›žä»»åŠ¡
     *
     * @param flowTaskVo
     */
    @Override
    public void taskReject(FlowTaskVo flowTaskVo) {
        if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) {
            throw new CustomException("任务处于挂起状态");
        }
        // å½“前任务 task
        Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
        // èŽ·å–æµç¨‹å®šä¹‰ä¿¡æ¯
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
        // èŽ·å–æ‰€æœ‰èŠ‚ç‚¹ä¿¡æ¯
        Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
        // èŽ·å–å…¨éƒ¨èŠ‚ç‚¹åˆ—è¡¨ï¼ŒåŒ…å«å­èŠ‚ç‚¹
        Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null);
        // èŽ·å–å½“å‰ä»»åŠ¡èŠ‚ç‚¹å…ƒç´ 
        FlowElement source = null;
        if (allElements != null) {
            for (FlowElement flowElement : allElements) {
                // ç±»åž‹ä¸ºç”¨æˆ·èŠ‚ç‚¹
                if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
                    // èŽ·å–èŠ‚ç‚¹ä¿¡æ¯
                    source = flowElement;
                }
            }
        }
        // ç›®çš„获取所有跳转到的节点 targetIds
        // èŽ·å–å½“å‰èŠ‚ç‚¹çš„æ‰€æœ‰çˆ¶çº§ç”¨æˆ·ä»»åŠ¡èŠ‚ç‚¹
        // æ·±åº¦ä¼˜å…ˆç®—法思想:延边迭代深入
        List<UserTask> parentUserTaskList = FlowableUtils.iteratorFindParentUserTasks(source, null, null);
        if (parentUserTaskList == null || parentUserTaskList.size() == 0) {
            throw new CustomException("当前节点为初始任务节点,不能驳回");
        }
        // èŽ·å–æ´»åŠ¨ ID å³èŠ‚ç‚¹ Key
        List<String> parentUserTaskKeyList = new ArrayList<>();
        parentUserTaskList.forEach(item -> parentUserTaskKeyList.add(item.getId()));
        // èŽ·å–å…¨éƒ¨åŽ†å²èŠ‚ç‚¹æ´»åŠ¨å®žä¾‹ï¼Œå³å·²ç»èµ°è¿‡çš„èŠ‚ç‚¹åŽ†å²ï¼Œæ•°æ®é‡‡ç”¨å¼€å§‹æ—¶é—´å‡åº
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceStartTime().asc().list();
        // æ•°æ®æ¸…洗,将回滚导致的脏数据清洗掉
        List<String> lastHistoricTaskInstanceList = FlowableUtils.historicTaskInstanceClean(allElements, historicTaskInstanceList);
        // æ­¤æ—¶åŽ†å²ä»»åŠ¡å®žä¾‹ä¸ºå€’åºï¼ŒèŽ·å–æœ€åŽèµ°çš„èŠ‚ç‚¹
        List<String> targetIds = new ArrayList<>();
        // å¾ªçŽ¯ç»“æŸæ ‡è¯†ï¼Œé‡åˆ°å½“å‰ç›®æ ‡èŠ‚ç‚¹çš„æ¬¡æ•°
        int number = 0;
        StringBuilder parentHistoricTaskKey = new StringBuilder();
        for (String historicTaskInstanceKey : lastHistoricTaskInstanceList) {
            // å½“会签时候会出现特殊的,连续都是同一个节点历史数据的情况,这种时候跳过
            if (parentHistoricTaskKey.toString().equals(historicTaskInstanceKey)) {
                continue;
            }
            parentHistoricTaskKey = new StringBuilder(historicTaskInstanceKey);
            if (historicTaskInstanceKey.equals(task.getTaskDefinitionKey())) {
                number++;
            }
            // åœ¨æ•°æ®æ¸…洗后,历史节点就是唯一一条从起始到当前节点的历史记录,理论上每个点只会出现一次
            // åœ¨æµç¨‹ä¸­å¦‚果出现循环,那么每次循环中间的点也只会出现一次,再出现就是下次循环
            // number == 1,第一次遇到当前节点
            // number == 2,第二次遇到,代表最后一次的循环范围
            if (number == 2) {
                break;
            }
            // å¦‚果当前历史节点,属于父级的节点,说明最后一次经过了这个点,需要退回这个点
            if (parentUserTaskKeyList.contains(historicTaskInstanceKey)) {
                targetIds.add(historicTaskInstanceKey);
            }
        }
        // ç›®çš„获取所有需要被跳转的节点 currentIds
        // å–其中一个父级任务,因为后续要么存在公共网关,要么就是串行公共线路
        UserTask oneUserTask = parentUserTaskList.get(0);
        // èŽ·å–æ‰€æœ‰æ­£å¸¸è¿›è¡Œçš„ä»»åŠ¡èŠ‚ç‚¹ Key,这些任务不能直接使用,需要找出其中需要撤回的任务
        List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        List<String> runTaskKeyList = new ArrayList<>();
        runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
        // éœ€é©³å›žä»»åŠ¡åˆ—è¡¨
        List<String> currentIds = new ArrayList<>();
        // é€šè¿‡çˆ¶çº§ç½‘关的出口连线,结合 runTaskList æ¯”对,获取需要撤回的任务
        List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(oneUserTask, runTaskKeyList, null, null);
        currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
        // è§„定:并行网关之前节点必须需存在唯一用户任务节点,如果出现多个任务节点,则并行网关节点默认为结束节点,原因为不考虑多对多情况
        if (targetIds.size() > 1 && currentIds.size() > 1) {
            throw new CustomException("任务出现多对多情况,无法撤回");
        }
        // å¾ªçŽ¯èŽ·å–é‚£äº›éœ€è¦è¢«æ’¤å›žçš„èŠ‚ç‚¹çš„ID,用来设置驳回原因
        List<String> currentTaskIds = new ArrayList<>();
        currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
            if (currentId.equals(runTask.getTaskDefinitionKey())) {
                currentTaskIds.add(runTask.getId());
            }
        }));
        // è®¾ç½®é©³å›žæ„è§
        currentTaskIds.forEach(item -> taskService.addComment(item, task.getProcessInstanceId(), FlowComment.REJECT.getType(), flowTaskVo.getComment()));
        SysUser loginUser = iFlowThirdService.getLoginUser();
        try {
            // è®¾ç½®å¤„理人
            taskService.setAssignee(task.getId(), loginUser.getUsername());
            // å¦‚果父级任务多于 1 ä¸ªï¼Œè¯´æ˜Žå½“前节点不是并行节点,原因为不考虑多对多情况
            if (targetIds.size() > 1) {
                // 1 å¯¹ å¤šä»»åŠ¡è·³è½¬ï¼ŒcurrentIds å½“前节点(1),targetIds è·³è½¬åˆ°çš„节点(多)
                runtimeService.createChangeActivityStateBuilder()
                        .processInstanceId(task.getProcessInstanceId()).
                        moveSingleActivityIdToActivityIds(currentIds.get(0), targetIds).changeState();
            }
            // å¦‚果父级任务只有一个,因此当前任务可能为网关中的任务
            if (targetIds.size() == 1) {
                // 1 å¯¹ 1 æˆ– å¤š å¯¹ 1 æƒ…况,currentIds å½“前要跳转的节点列表(1或多),targetIds.get(0) è·³è½¬åˆ°çš„节点(1)
                runtimeService.createChangeActivityStateBuilder()
                        .processInstanceId(task.getProcessInstanceId())
                        .moveActivityIdsToSingleActivityId(currentIds, targetIds.get(0)).changeState();
            }
            /*======================驳回  å›žè°ƒä»¥åŠå…³é”®æ•°æ®ä¿å­˜======================*/
            //业务数据id
            String dataId = flowTaskVo.getDataId();
            if (dataId == null) return;
            //如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题
            FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
            // é©³å›žåˆ°äº†ä¸Šä¸€ä¸ªèŠ‚ç‚¹ç­‰å¾…å¤„ç†
            List<Task> task2List = taskService.createTaskQuery().processInstanceId(business.getProcessInstanceId()).active().list();
            Task task2 = task2List.get(0);
            //spring容器类名
            String serviceImplName = business.getServiceImplName();
            FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
            Map<String, Object> values = flowTaskVo.getValues();
            if (values == null) {
                values = MapUtil.newHashMap();
                values.put("dataId", dataId);
            } else {
                values.put("dataId", dataId);
            }
            List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionKey(), values);
            //设置数据
            String doneUsers = business.getDoneUsers();
            // å¤„理过流程的人
            JSONArray doneUserList = new JSONArray();
            if (StrUtil.isNotBlank(doneUsers)) {
                doneUserList = JSON.parseArray(doneUsers);
            }
            if (!doneUserList.contains(loginUser.getUsername())) {
                doneUserList.add(loginUser.getUsername());
            }
            business
                    .setTaskId(task2.getId())
//                    .setActStatus(ActStatus.reject)
                    .setTaskNameId(task2.getTaskDefinitionKey())
                    .setTaskName(task2.getName())
                    .setDoneUsers(doneUserList.toJSONString())
            ;
            FlowElement targetElement = null;
            if (allElements != null) {
                for (FlowElement flowElement : allElements) {
                    // ç±»åž‹ä¸ºç”¨æˆ·èŠ‚ç‚¹
                    if (flowElement.getId().equals(task2.getTaskDefinitionKey())) {
                        // èŽ·å–èŠ‚ç‚¹ä¿¡æ¯
                        targetElement = flowElement;
                    }
                }
            }
            if (targetElement != null) {
                UserTask targetTask = (UserTask) targetElement;
                business.setPriority(targetTask.getPriority());
                if (StrUtil.equals(business.getTaskNameId(), ProcessConstants.START_NODE)) {
                    //    å¼€å§‹èŠ‚ç‚¹ã€‚è®¾ç½®å¤„ç†äººä¸ºç”³è¯·äºº
                    business.setTodoUsers(JSON.toJSONString(Lists.newArrayList(business.getProposer())));
                    taskService.setAssignee(business.getTaskId(), business.getProposer());
                } else {
                    List<SysUser> sysUserFromTask = getSysUserFromTask(targetTask);
                    List<String> collect_username = sysUserFromTask.stream().map(SysUser::getUsername).collect(Collectors.toList());
                    // å‰ç«¯å­˜å…¥çš„候选人
                    List<String> candidateUsers = flowTaskVo.getCandidateUsers();
                    if (CollUtil.isNotEmpty(candidateUsers)) {
                        collect_username = candidateUsers;
                    }
                    business.setTodoUsers(JSON.toJSONString(collect_username));
                    // åˆ é™¤åŽé‡å†™
                    for (Task task2One : task2List) {
                        for (String oldUser : collect_username) {
                            taskService.deleteCandidateUser(task2One.getId(), oldUser);
                        }
                    }
                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
                        if (CollUtil.isNotEmpty(candidateUsers)) {
                            beforeParamsCandidateUsernames = candidateUsers;
                        }
                        // ä¸šåŠ¡å±‚æœ‰æŒ‡å®šå€™é€‰äººï¼Œè¦†ç›–
                        for (Task task2One : task2List) {
                            for (String newUser : beforeParamsCandidateUsernames) {
                                taskService.addCandidateUser(task2One.getId(), newUser);
                            }
                        }
                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
                    } else {
                        for (Task task2One : task2List) {
                            for (String oldUser : collect_username) {
                                taskService.addCandidateUser(task2One.getId(), oldUser);
                            }
                        }
                    }
                }
            }
            flowMyBusinessService.updateById(business);
            // æµç¨‹å¤„理完后,进行回调业务层
            business.setValues(values);
            if (flowCallBackService != null) flowCallBackService.afterFlowHandle(business);
        } catch (FlowableObjectNotFoundException e) {
            throw new CustomException("未找到流程实例,流程可能已发生变化");
        } catch (FlowableException e) {
            throw new CustomException("无法取消或开始活动");
        }
    }
    @Override
    public void taskReturnByDataId(FlowTaskVo flowTaskVo) {
        //如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题
        FlowMyBusiness business = flowMyBusinessService.getByDataId(flowTaskVo.getDataId());
        flowTaskVo.setTaskId(business.getTaskId());
        taskReturn(flowTaskVo);
    }
    /**
     * é€€å›žä»»åŠ¡
     *
     * @param flowTaskVo è¯·æ±‚实体参数
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void taskReturn(FlowTaskVo flowTaskVo) {
        if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) {
            throw new CustomException("任务处于挂起状态");
        }
        // å½“前任务 task
        Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
        // èŽ·å–æµç¨‹å®šä¹‰ä¿¡æ¯
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
        // èŽ·å–æ‰€æœ‰èŠ‚ç‚¹ä¿¡æ¯
        Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
        // èŽ·å–å…¨éƒ¨èŠ‚ç‚¹åˆ—è¡¨ï¼ŒåŒ…å«å­èŠ‚ç‚¹
        Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null);
        // èŽ·å–å½“å‰ä»»åŠ¡èŠ‚ç‚¹å…ƒç´ 
        FlowElement source = null;
        // èŽ·å–è·³è½¬çš„èŠ‚ç‚¹å…ƒç´ 
        FlowElement target = null;
        if (allElements != null) {
            for (FlowElement flowElement : allElements) {
                // å½“前任务节点元素
                if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
                    source = flowElement;
                }
                // è·³è½¬çš„节点元素
                if (flowElement.getId().equals(flowTaskVo.getTargetKey())) {
                    target = flowElement;
                }
            }
        }
        // ä»Žå½“前节点向前扫描
        // å¦‚果存在路线上不存在目标节点,说明目标节点是在网关上或非同一路线上,不可跳转
        // å¦åˆ™ç›®æ ‡èŠ‚ç‚¹ç›¸å¯¹äºŽå½“å‰èŠ‚ç‚¹ï¼Œå±žäºŽä¸²è¡Œ
        Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, flowTaskVo.getTargetKey(), null, null);
        if (!isSequential) {
            throw new CustomException("当前节点相对于目标节点,不属于串行关系,无法回退");
        }
        // èŽ·å–æ‰€æœ‰æ­£å¸¸è¿›è¡Œçš„ä»»åŠ¡èŠ‚ç‚¹ Key,这些任务不能直接使用,需要找出其中需要撤回的任务
        List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        List<String> runTaskKeyList = new ArrayList<>();
        runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
        // éœ€é€€å›žä»»åŠ¡åˆ—è¡¨
        List<String> currentIds = new ArrayList<>();
        // é€šè¿‡çˆ¶çº§ç½‘关的出口连线,结合 runTaskList æ¯”对,获取需要撤回的任务
        List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null);
        currentUserTaskList.forEach(item -> {
            currentIds.add(item.getId());
        });
        // å¾ªçŽ¯èŽ·å–é‚£äº›éœ€è¦è¢«æ’¤å›žçš„èŠ‚ç‚¹çš„ID,用来设置驳回原因
        List<String> currentTaskIds = new ArrayList<>();
        currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
            if (currentId.equals(runTask.getTaskDefinitionKey())) {
                currentTaskIds.add(runTask.getId());
            }
        }));
        // è®¾ç½®å›žé€€æ„è§
        for (String currentTaskId : currentTaskIds) {
            taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), flowTaskVo.getComment());
        }
        SysUser loginUser = iFlowThirdService.getLoginUser();
        try {
            // è®¾ç½®å¤„理人
            taskService.setAssignee(task.getId(), loginUser.getUsername());
            // 1 å¯¹ 1 æˆ– å¤š å¯¹ 1 æƒ…况,currentIds å½“前要跳转的节点列表(1或多),targetKey è·³è½¬åˆ°çš„节点(1)
            runtimeService.createChangeActivityStateBuilder()
                    .processInstanceId(task.getProcessInstanceId())
                    .moveActivityIdsToSingleActivityId(currentIds, flowTaskVo.getTargetKey()).changeState();
            /*======================退回  å›žè°ƒä»¥åŠå…³é”®æ•°æ®ä¿å­˜======================*/
            //业务数据id
            String dataId = flowTaskVo.getDataId();
            if (dataId == null) return;
            //如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题
            FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
            //spring容器类名
            String serviceImplName = business.getServiceImplName();
            FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
            //设置数据
            String doneUsers = business.getDoneUsers();
            // å¤„理过流程的人
            JSONArray doneUserList = new JSONArray();
            if (StrUtil.isNotBlank(doneUsers)) {
                doneUserList = JSON.parseArray(doneUsers);
            }
            if (!doneUserList.contains(loginUser.getUsername())) {
                doneUserList.add(loginUser.getUsername());
            }
            //**跳转到目标节点
            List<Task> task2List = taskService.createTaskQuery().processInstanceId(business.getProcessInstanceId()).active().list();
            Task targetTask = task2List.get(0);
            business
                    .setTaskId(targetTask.getId())
//                        .setActStatus(ActStatus.reject)
                    .setTaskNameId(targetTask.getTaskDefinitionKey())
                    .setTaskName(targetTask.getName())
                    .setPriority(targetTask.getPriority() + "")
                    .setDoneUsers(doneUserList.toJSONString())
            ;
            if (target != null) {
                UserTask target2 = (UserTask) target;
                business.setPriority(target2.getPriority());
                if (StrUtil.equals(business.getTaskNameId(), ProcessConstants.START_NODE)) {
                    //    å¼€å§‹èŠ‚ç‚¹ã€‚è®¾ç½®å¤„ç†äººä¸ºç”³è¯·äºº
                    business.setTodoUsers(JSON.toJSONString(Lists.newArrayList(business.getProposer())));
                    taskService.setAssignee(business.getTaskId(), business.getProposer());
                } else {
                    List<SysUser> sysUserFromTask = getSysUserFromTask(target2);
                    List<String> collect_username = sysUserFromTask.stream().map(SysUser::getUsername).collect(Collectors.toList());
                    List<String> candidateUsers = flowTaskVo.getCandidateUsers();
                    if (CollUtil.isNotEmpty(candidateUsers)) {
                        collect_username = candidateUsers;
                    }
                    business.setTodoUsers(JSON.toJSONString(collect_username));
                    // åˆ é™¤åŽé‡å†™
                    for (Task task2One : task2List) {
                        for (String oldUser : collect_username) {
                            taskService.deleteCandidateUser(task2One.getId(), oldUser);
                        }
                    }
                    Map<String, Object> values = flowTaskVo.getValues();
                    if (values == null) {
                        values = MapUtil.newHashMap();
                        values.put("dataId", dataId);
                    } else {
                        values.put("dataId", dataId);
                    }
                    List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(targetTask.getTaskDefinitionKey(), values);
                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
                        if (CollUtil.isNotEmpty(candidateUsers)) {
                            beforeParamsCandidateUsernames = candidateUsers;
                        }
                        // ä¸šåŠ¡å±‚æœ‰æŒ‡å®šå€™é€‰äººï¼Œè¦†ç›–
                        for (Task task2One : task2List) {
                            for (String newUser : beforeParamsCandidateUsernames) {
                                taskService.addCandidateUser(task2One.getId(), newUser);
                            }
                        }
                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
                    } else {
                        for (Task task2One : task2List) {
                            for (String oldUser : collect_username) {
                                taskService.addCandidateUser(task2One.getId(), oldUser);
                            }
                        }
                    }
                }
            }
            flowMyBusinessService.updateById(business);
            // æµç¨‹å¤„理完后,进行回调业务层
            business.setValues(flowTaskVo.getValues());
            if (flowCallBackService != null) flowCallBackService.afterFlowHandle(business);
        } catch (FlowableObjectNotFoundException e) {
            throw new CustomException("未找到流程实例,流程可能已发生变化");
        } catch (FlowableException e) {
            throw new CustomException("无法取消或开始活动");
        }
    }
    @Override
    public Result findReturnTaskListByDataId(FlowTaskVo flowTaskVo) {
        FlowMyBusiness business = flowMyBusinessService.getByDataId(flowTaskVo.getDataId());
        flowTaskVo.setTaskId(business.getTaskId());
        return findReturnTaskList(flowTaskVo);
    }
    /**
     * ç»“束流程
     *
     * @param processInstanceId æµç¨‹å®žä¾‹ ID
     * @param deleteReason      å®šä¹‰åˆ é™¤åŽŸå› 
     */
    public Result<?> end(String processInstanceId, String deleteReason) {
        try {
            // å¼ºåˆ¶ç»“束流程实例
            runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
            // åˆ é™¤å…³è”流程的业务
            FlowMyBusiness flowMyBusiness = flowMyBusinessService.getFlowMyBusiness(processInstanceId);
            flowMyBusinessService.removeById(flowMyBusiness.getId());
            System.out.println("Process instance with ID " + processInstanceId + " has been forcefully ended.");
        } catch (Exception e) {
            System.err.println("Failed to force end process instance: " + e.getMessage());
        }
        // å…³é—­æµç¨‹å¼•擎
        processEngine.close();
        return Result.OK("流程已结束");
    }
    /**
     * èŽ·å–æ‰€æœ‰å¯å›žé€€çš„èŠ‚ç‚¹
     *
     * @param flowTaskVo
     * @return
     */
    @Override
    public Result findReturnTaskList(FlowTaskVo flowTaskVo) {
        // å½“前任务 task
        Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
        // èŽ·å–æµç¨‹å®šä¹‰ä¿¡æ¯
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
        // èŽ·å–æ‰€æœ‰èŠ‚ç‚¹ä¿¡æ¯ï¼Œæš‚ä¸è€ƒè™‘å­æµç¨‹æƒ…å†µ
        Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
        Collection<FlowElement> flowElements = process.getFlowElements();
        // èŽ·å–å½“å‰ä»»åŠ¡èŠ‚ç‚¹å…ƒç´ 
        UserTask source = null;
        if (flowElements != null) {
            for (FlowElement flowElement : flowElements) {
                // ç±»åž‹ä¸ºç”¨æˆ·èŠ‚ç‚¹
                if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
                    source = (UserTask) flowElement;
                }
            }
        }
        // èŽ·å–èŠ‚ç‚¹çš„æ‰€æœ‰è·¯çº¿
        List<List<UserTask>> roads = FlowableUtils.findRoad(source, null, null, null);
        // å¯å›žé€€çš„节点列表
        List<UserTask> userTaskList = new ArrayList<>();
        for (List<UserTask> road : roads) {
            if (userTaskList.size() == 0) {
                // è¿˜æ²¡æœ‰å¯å›žé€€èŠ‚ç‚¹ç›´æŽ¥æ·»åŠ 
                userTaskList = road;
            } else {
                // å¦‚果已有回退节点,则比对取交集部分
                userTaskList.retainAll(road);
            }
        }
        return Result.OK(userTaskList);
    }
    /**
     * åˆ é™¤ä»»åŠ¡
     *
     * @param flowTaskVo è¯·æ±‚实体参数
     */
    @Override
    public void deleteTask(FlowTaskVo flowTaskVo) {
        // todo å¾…确认删除任务是物理删除任务 è¿˜æ˜¯é€»è¾‘删除,让这个任务直接通过?
        taskService.deleteTask(flowTaskVo.getTaskId(), flowTaskVo.getComment());
    }
    /**
     * è®¤é¢†/签收任务
     *
     * @param flowTaskVo è¯·æ±‚实体参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void claim(FlowTaskVo flowTaskVo) {
        taskService.claim(flowTaskVo.getTaskId(), flowTaskVo.getUserId());
    }
    /**
     * å–消认领/签收任务
     *
     * @param flowTaskVo è¯·æ±‚实体参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unClaim(FlowTaskVo flowTaskVo) {
        taskService.unclaim(flowTaskVo.getTaskId());
    }
    /**
     * å§”派任务
     *
     * @param flowTaskVo è¯·æ±‚实体参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delegateTask(FlowTaskVo flowTaskVo) {
        taskService.delegateTask(flowTaskVo.getTaskId(), flowTaskVo.getAssignee());
    }
    /**
     * è½¬åŠžä»»åŠ¡
     *
     * @param flowTaskVo è¯·æ±‚实体参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignTask(FlowTaskVo flowTaskVo) {
        taskService.setAssignee(flowTaskVo.getTaskId(), flowTaskVo.getAssignee());
    }
    /**
     * æˆ‘发起的流程
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Result myProcess(Integer pageNum, Integer pageSize) {
        Page<FlowTaskDto> page = new Page<>();
        String username = iFlowThirdService.getLoginUser().getUsername();
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .startedBy(username)
                .orderByProcessInstanceStartTime()
                .desc();
        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage((pageNum - 1) * pageSize, pageSize);
        page.setTotal(historicProcessInstanceQuery.count());
        List<FlowTaskDto> flowList = new ArrayList<>();
        for (HistoricProcessInstance hisIns : historicProcessInstances) {
            FlowTaskDto flowTask = new FlowTaskDto();
            flowTask.setCreateTime(hisIns.getStartTime());
            flowTask.setFinishTime(hisIns.getEndTime());
            flowTask.setProcInsId(hisIns.getId());
            // è®¡ç®—耗时
            if (Objects.nonNull(hisIns.getEndTime())) {
                long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime();
                flowTask.setDuration(getDate(time));
            } else {
                long time = System.currentTimeMillis() - hisIns.getStartTime().getTime();
                flowTask.setDuration(getDate(time));
            }
            // æµç¨‹å®šä¹‰ä¿¡æ¯
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(hisIns.getProcessDefinitionId())
                    .singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setCategory(pd.getCategory());
            flowTask.setProcDefVersion(pd.getVersion());
            // å½“前所处流程 todo: æœ¬åœ°å¯åŠ¨æ”¾å¼€ä»¥ä¸‹æ³¨é‡Š
            List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list();
            if (CollectionUtils.isNotEmpty(taskList)) {
                flowTask.setTaskId(taskList.get(0).getId());
            } else {
                List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
                flowTask.setTaskId(historicTaskInstance.get(0).getId());
            }
            flowList.add(flowTask);
        }
        page.setRecords(flowList);
        return Result.OK(page);
    }
    /**
     * å–消申请
     *
     * @param flowTaskVo
     * @return
     */
    @Override
    public Result stopProcess(FlowTaskVo flowTaskVo) {
        List<Task> task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list();
        if (CollectionUtils.isEmpty(task)) {
            throw new CustomException("流程未启动或已执行完成,取消申请失败");
        }
        SysUser loginUser = iFlowThirdService.getLoginUser();
        ProcessInstance processInstance =
                runtimeService.createProcessInstanceQuery().processInstanceId(flowTaskVo.getInstanceId()).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        if (Objects.nonNull(bpmnModel)) {
            Process process = bpmnModel.getMainProcess();
            List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
            if (CollectionUtils.isNotEmpty(endNodes)) {
                Authentication.setAuthenticatedUserId(loginUser.getUsername());
                taskService.addComment(task.get(0).getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(),
                        StringUtils.isBlank(flowTaskVo.getComment()) ? "取消申请" : flowTaskVo.getComment());
                String endId = endNodes.get(0).getId();
                List<Execution> executions =
                        runtimeService.createExecutionQuery().parentId(processInstance.getProcessInstanceId()).list();
                List<String> executionIds = new ArrayList<>();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds,
                        endId).changeState();
            }
        }
        return Result.OK();
    }
    /**
     * æ’¤å›žæµç¨‹  todo ç›®å‰å­˜åœ¨é”™è¯¯
     *
     * @param flowTaskVo
     * @return
     */
    @Override
    public Result revokeProcess(FlowTaskVo flowTaskVo) {
        Task task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).singleResult();
        if (task == null) {
            throw new CustomException("流程未启动或已执行完成,无法撤回");
        }
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .orderByTaskCreateTime()
                .asc()
                .list();
        String myTaskId = null;
        HistoricTaskInstance myTask = null;
        for (HistoricTaskInstance hti : htiList) {
            if (loginUser.getUsername().equals(hti.getAssignee())) {
                myTaskId = hti.getId();
                myTask = hti;
                break;
            }
        }
        if (null == myTaskId) {
            throw new CustomException("该任务非当前用户提交,无法撤回");
        }
        String processDefinitionId = myTask.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        //变量
//      Map<String, VariableInstance> variables = runtimeService.getVariableInstances(currentTask.getExecutionId());
        String myActivityId = null;
        List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
                .executionId(myTask.getExecutionId()).finished().list();
        for (HistoricActivityInstance hai : haiList) {
            if (myTaskId.equals(hai.getTaskId())) {
                myActivityId = hai.getActivityId();
                break;
            }
        }
        FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
        Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
        String activityId = execution.getActivityId();
        FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
        //记录原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<>(flowNode.getOutgoingFlows());
        return Result.OK();
    }
    /**
     * åˆ¤æ–­å¤šä¸ªä»»åŠ¡æ˜¯å¦å¤„äºŽåŒä¸€æµç¨‹èŠ‚ç‚¹
     *
     * @param taskIds é€—号分隔的任务ID字符串
     * @return ç»Ÿä¸€ç»“果封装
     */
    @Override
    public Result isSameNode(String taskIds) {
        // 1. å‚数校验
        if (StringUtils.isBlank(taskIds)) {
            return Result.error("任务ID不能为空");
        }
        // 2. åˆ†å‰²ä»»åŠ¡ID
        String[] taskIdArray = taskIds.split(",");
        if (taskIdArray.length == 0) {
            return Result.error("未提供有效的任务ID");
        }
        // 3. å•任务直接返回true
        if (taskIdArray.length == 1) {
            return Result.ok(true);
        }
        // 4. å¤šä»»åŠ¡æ£€æŸ¥é€»è¾‘
        String referenceNodeId = null;
        String currentNodeId = null;
        for (String taskId : taskIdArray) {
            // 4.1 æŸ¥è¯¢ä»»åŠ¡å®žä¾‹
            Task task = taskService.createTaskQuery()
                    .taskId(taskId.trim())
                    .singleResult();
            // 4.2 ä»»åŠ¡ä¸å­˜åœ¨å¤„ç†
            if (task == null) {
                return Result.error("任务不存在: " + taskId);
            }
            // 4.3 èŽ·å–èŠ‚ç‚¹æ ‡è¯†ï¼ˆTaskDefinitionKey)
            currentNodeId = task.getTaskDefinitionKey();
            // 4.4 é¦–次遍历初始化参考节点
            if (referenceNodeId == null) {
                referenceNodeId = currentNodeId;
                continue;
            }
            // 4.5 èŠ‚ç‚¹ä¸ä¸€è‡´ç›´æŽ¥è¿”å›ž
            if (!referenceNodeId.equals(currentNodeId)) {
                return Result.ok("节点不一致");
            }
        }
        // 5. æ‰€æœ‰ä»»åŠ¡èŠ‚ç‚¹ä¸€è‡´
        return Result.ok(currentNodeId);
    }
    /**
     * ä»£åŠžä»»åŠ¡åˆ—è¡¨
     *
     * @param pageNum  å½“前页码
     * @param pageSize æ¯é¡µæ¡æ•°
     * @return
     */
    @Override
    public Result todoList(Integer pageNum, Integer pageSize) {
        Page<FlowTaskDto> page = new Page<>();
        String username = iFlowThirdService.getLoginUser().getUsername();
        TaskQuery taskQuery = taskService.createTaskQuery()
                .active()
                .includeProcessVariables()
                .taskAssignee(username)
                .orderByTaskCreateTime().desc();
        page.setTotal(taskQuery.count());
        List<Task> taskList = taskQuery.listPage((pageNum - 1) * pageSize, pageSize);
        List<FlowTaskDto> flowList = new ArrayList<>();
        for (Task task : taskList) {
            FlowTaskDto flowTask = new FlowTaskDto();
            // å½“前流程信息
            flowTask.setTaskId(task.getId());
            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
            flowTask.setCreateTime(task.getCreateTime());
            flowTask.setProcDefId(task.getProcessDefinitionId());
            flowTask.setTaskName(task.getName());
            // æµç¨‹å®šä¹‰ä¿¡æ¯
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(task.getProcessDefinitionId())
                    .singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(task.getProcessInstanceId());
            // æµç¨‹å‘起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId())
                    .singleResult();
            SysUser startUser = iFlowThirdService.getUserByUsername(historicProcessInstance.getStartUserId());
            List<String> departNamesByUsername = iFlowThirdService.getDepartNamesByUsername(historicProcessInstance.getStartUserId());
            flowTask.setStartUserId(startUser.getUsername());
            flowTask.setStartUserName(startUser.getRealname());
            flowTask.setStartDeptName(CollUtil.join(departNamesByUsername, ","));
            flowList.add(flowTask);
        }
        page.setRecords(flowList);
        return Result.OK(page);
    }
    /**
     * å·²åŠžä»»åŠ¡åˆ—è¡¨
     *
     * @param pageNum  å½“前页码
     * @param pageSize æ¯é¡µæ¡æ•°
     * @return
     */
    @Override
    public Result finishedList(Integer pageNum, Integer pageSize, FlowMyBusinessDto flowMyBusinessDto) {
        //修改查询,添加查询条件
        Page page = new Page(pageNum, pageSize);
        String username = iFlowThirdService.getLoginUser().getUsername();
        flowMyBusinessDto.setCurrentUser(username);
        List<FlowTaskDto> list = flowMyBusinessService.ListMyBusiness(flowMyBusinessDto);
        list.forEach(flowTaskDto -> {
            // æµç¨‹å‘起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(flowTaskDto.getProcInsId())
                    .singleResult();
            if (historicProcessInstance != null) {
                SysUser startUser = iFlowThirdService.getUserByUsername(historicProcessInstance.getStartUserId());
                if (startUser != null) {
                    flowTaskDto.setStartUserId(startUser.getUsername());
                    flowTaskDto.setStartUserName(startUser.getRealname());
                }
                List<String> departNamesByUsername = iFlowThirdService.getDepartNamesByUsername(historicProcessInstance.getStartUserId());
                flowTaskDto.setStartDeptName(CollUtil.join(departNamesByUsername, ","));
                if (flowTaskDto.getTodoUsers() == null) {
                    flowTaskDto.setTodoUsers("");
                } else {
                    //去除[]
                    flowTaskDto.setTodoUsers(flowTaskDto.getTodoUsers().replaceAll("\\[", "").replaceAll("\\]", ""));
                    flowTaskDto.setTodoUsers(flowTaskDto.getTodoUsers().replaceAll("\"", ""));
                }
            }
        });
        IPage<FlowTaskDto> flowTaskDtoIPage = new Page<>();
        flowTaskDtoIPage.setRecords(list);
        flowTaskDtoIPage.setTotal(page.getTotal());
        return Result.OK(flowTaskDtoIPage);
    }
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }
    /**
     * æµç¨‹åŽ†å²æµè½¬è®°å½•
     *
     * @param dataId æµç¨‹æ•°æ®Id
     * @return
     */
    @Override
    public Result flowRecord(String dataId) {
        FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
        String procInsId = business.getProcessInstanceId();
        Map<String, Object> map = new HashMap<String, Object>();
        if (StringUtils.isNotBlank(procInsId)) {
            List<HistoricActivityInstance> list = historyService
                    .createHistoricActivityInstanceQuery()
                    .processInstanceId(procInsId)
                    .orderByHistoricActivityInstanceStartTime()
                    .desc().list();
            List<FlowTaskDto> hisFlowList = new ArrayList<>();
            for (HistoricActivityInstance histIns : list) {
                if (StringUtils.isNotBlank(histIns.getTaskId())) {
                    FlowTaskDto flowTask = new FlowTaskDto();
                    flowTask.setTaskId(histIns.getTaskId());
                    flowTask.setTaskName(histIns.getActivityName());
                    flowTask.setTaskDefKey(histIns.getActivityId());
                    flowTask.setCreateTime(histIns.getStartTime());
                    flowTask.setFinishTime(histIns.getEndTime());
                    if (StringUtils.isNotBlank(histIns.getAssignee())) {
                        SysUser sysUser = iFlowThirdService.getUserByUsername(histIns.getAssignee());
                        flowTask.setAssigneeId(sysUser.getUsername());
                        flowTask.setAssigneeName(sysUser.getRealname());
                        List<String> departNamesByUsername = iFlowThirdService.getDepartNamesByUsername(histIns.getAssignee());
                        flowTask.setDeptName(CollUtil.join(departNamesByUsername, ","));
                        if (StrUtil.equals(histIns.getActivityId(), ProcessConstants.START_NODE)) {
                            //    å¼€å§‹èŠ‚ç‚¹ï¼ŒæŠŠå€™é€‰äººè®¾ç½®ä¸ºå‘èµ·äººï¼Œè¿™ä¸ªå€¼å·²è¢«å…¶ä»–åœ°æ–¹è®¾ç½®è¿‡ï¼Œä¸Žå®žé™…åŠžç†äººä¸€è‡´å³å¯
                            flowTask.setCandidate(sysUser.getRealname());
                        }
                    }
                    // å±•示审批人员
                    List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId());
                    StringBuilder stringBuilder = new StringBuilder();
                    for (HistoricIdentityLink identityLink : linksForTask) {
                        if (IdentityLinkType.CANDIDATE.equals(identityLink.getType())) {
                            if (StringUtils.isNotBlank(identityLink.getUserId())) {
                                SysUser sysUser = iFlowThirdService.getUserByUsername(identityLink.getUserId());
                                stringBuilder.append(sysUser.getRealname()).append(",");
                            }
                            /*已经全部设置到 CANDIDATE äº†ï¼Œä¸æ‹¿ç»„了*/
                            /*if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                                List<SysRole> allRole = iFlowThirdService.getAllRole();
                                SysRole sysRole = allRole.stream().filter(o -> StringUtils.equals(identityLink.getGroupId(), o.getId())).findAny().orElse(new SysRole());
                                stringBuilder.append(sysRole.getRoleName()).append(",");
                            }*/
                        }
                    }
                    if (StringUtils.isNotBlank(stringBuilder)) {
                        flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
                    }
                    flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis()));
                    // èŽ·å–æ„è§è¯„è®ºå†…å®¹
                    List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId());
                    commentList.forEach(comment -> {
                        if (histIns.getTaskId().equals(comment.getTaskId())) {
                            flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build());
                        }
                    });
                    hisFlowList.add(flowTask);
                }
            }
            map.put("flowList", hisFlowList);
        }
        // èŽ·å–åˆå§‹åŒ–è¡¨å•
        String serviceImplName = business.getServiceImplName();
        FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
        // æµç¨‹å¤„理完后,进行回调业务层
        if (flowCallBackService != null) {
            Object businessDataById = flowCallBackService.getBusinessDataById(dataId);
            map.put("formData", businessDataById);
        }
        return Result.OK(map);
    }
    /**
     * æ ¹æ®ä»»åŠ¡ID查询挂载的表单信息
     *
     * @param taskId ä»»åŠ¡Id
     * @return
     */
    @Override
    public Task getTaskForm(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        return task;
    }
    /**
     * èŽ·å–æµç¨‹è¿‡ç¨‹å›¾
     *
     * @param processId
     * @return
     */
    @Override
    public InputStream diagram(String processId) {
        String processDefinitionId;
        // èŽ·å–å½“å‰çš„æµç¨‹å®žä¾‹
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        // å¦‚果流程已经结束,则得到结束节点
        if (Objects.isNull(processInstance)) {
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        } else {// å¦‚果流程没有结束,则取当前活动节点
            // æ ¹æ®æµç¨‹å®žä¾‹ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }
        // èŽ·å¾—æ´»åŠ¨çš„èŠ‚ç‚¹
        List<HistoricActivityInstance> highLightedFlowList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> highLightedFlows = new ArrayList<>();
        List<String> highLightedNodes = new ArrayList<>();
        //高亮线
        for (HistoricActivityInstance tempActivity : highLightedFlowList) {
            if ("sequenceFlow".equals(tempActivity.getActivityType())) {
                //高亮线
                highLightedFlows.add(tempActivity.getActivityId());
            } else {
                //高亮节点
                highLightedNodes.add(tempActivity.getActivityId());
            }
        }
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
        //获取自定义图片生成器
        ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(),
                configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true);
        return in;
    }
    /**
     * èŽ·å–æµç¨‹æ‰§è¡Œè¿‡ç¨‹
     *
     * @param procInsId
     * @return
     */
    @Override
    public List<FlowViewerDto> getFlowViewer(String procInsId) {
        List<FlowViewerDto> flowViewerList = new ArrayList<>();
        FlowViewerDto flowViewerDto;
        // èŽ·å¾—æ´»åŠ¨çš„èŠ‚ç‚¹
        List<HistoricActivityInstance> hisActIns = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInsId)
                .orderByHistoricActivityInstanceStartTime()
                .asc().list();
        for (HistoricActivityInstance activityInstance : hisActIns) {
            if (!"sequenceFlow".equals(activityInstance.getActivityType())) {
                flowViewerDto = new FlowViewerDto();
                flowViewerDto.setKey(activityInstance.getActivityId());
                flowViewerDto.setCompleted(!Objects.isNull(activityInstance.getEndTime()));
                for (FlowViewerDto viewerDto : flowViewerList) {
                    String key = viewerDto.getKey();
                    if (key.equals(flowViewerDto.getKey())) {
                        //    é‡å¤åˆ é™¤åŽé¢æ›´æ–°
                        flowViewerList.remove(viewerDto);
                        break;
                    }
                }
                flowViewerList.add(flowViewerDto);
            }
        }
        return flowViewerList;
    }
    @Override
    public List<FlowViewerDto> getFlowViewerByDataId(String dataId) {
        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId)
        ;
        //如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题
        FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper);
        // 1.执行过的步骤
        List<FlowViewerDto> flowViewers = this.getFlowViewer(business.getProcessInstanceId());
        // 2.获取所有节点信息,根据所有节点 æŒ‰é¡ºåº  å’Œæ‰§è¡Œè¿‡çš„æ¯”较,驳回的节点就被跳过
        Process process = repositoryService.getBpmnModel(business.getProcessDefinitionId()).getProcesses().get(0);
        List<FlowElement> flowElements = Lists.newArrayList(process.getFlowElements());
        // èŽ·å–å½“å‰ä»»åŠ¡èŠ‚ç‚¹å…ƒç´ 
        List<FlowViewerDto> reflowViewers = Lists.newArrayList();
        // *顺序的Key
        List<String> orderKeys = Lists.newArrayList();
        if (flowElements != null) {
            for (FlowElement flowElement : flowElements) {
                try {
                    // å¼€å§‹èŠ‚ç‚¹
                    StartEvent stev = (StartEvent) flowElement;
                    //第一个key节点,
                    String firstKey = stev.getId();
                    orderKeys.add(firstKey);
                    //顺序获取节点
                    this.appendKeys(orderKeys, firstKey, flowElements);
                } catch (Exception e) {
                    break;
                }
            }
            for (String key : orderKeys) {
                Optional<FlowViewerDto> any = flowViewers.stream().filter(o -> StrUtil.equals(o.getKey(), key)).findAny();
                if (any.isPresent()) {
                    FlowViewerDto viewerDto = any.get();
                    reflowViewers.add(viewerDto);
                    if (!viewerDto.isCompleted()) {
                        //    å·²åˆ°æ­£åœ¨ç­‰å¾…执行的节点,后面的不要了
                        break;
                    }
                }
            }
        }
        for (FlowViewerDto flowViewer : flowViewers) {
            boolean present = reflowViewers.stream().filter(o -> StrUtil.equals(o.getKey(), flowViewer.getKey())).findAny().isPresent();
            flowViewer.setBack(!present);
        }
        //return reflowViewers;
        return flowViewers;
    }
    /**
     * é¡ºåºæŠ½å–节点
     *
     * @param orderKeys    å®¹å™¨
     * @param sourceKey    æº
     * @param flowElements æ‰€æœ‰çš„节点对象
     */
    private void appendKeys(List<String> orderKeys, String sourceKey, List<FlowElement> flowElements) {
        for (FlowElement flowElement : flowElements) {
            try {
                SequenceFlow sf = (SequenceFlow) flowElement;
                String sourceRef = sf.getSourceRef();
                String targetRef = sf.getTargetRef();
                if (sourceKey.equals(sourceRef) && targetRef != null) {
                    orderKeys.add(targetRef);
                    this.appendKeys(orderKeys, targetRef, flowElements);
                }
            } catch (Exception e) {
                continue;
            }
        }
    }
    /**
     * èŽ·å–æµç¨‹å˜é‡
     *
     * @param taskId
     * @return
     */
    @Override
    public Result processVariables(String taskId) {
        // æµç¨‹å˜é‡
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().includeProcessVariables().finished().taskId(taskId).singleResult();
        if (Objects.nonNull(historicTaskInstance)) {
            return Result.OK(historicTaskInstance.getProcessVariables());
        } else {
            Map<String, Object> variables = taskService.getVariables(taskId);
            return Result.OK(variables);
        }
    }
    /**
     * èŽ·å–ä¸‹ä¸€èŠ‚ç‚¹
     *
     * @param flowTaskVo ä»»åŠ¡
     * @return
     */
    @Override
    public Result<List<FlowNextDto>> getNextFlowNode(FlowTaskVo flowTaskVo) {
        // todo ä¼¼ä¹Žé€»è¾‘未写完,待检查
        List<FlowNextDto> nextDtoList = this.getNextFlowNode(flowTaskVo.getTaskId(), flowTaskVo.getValues());
        if (CollectionUtils.isEmpty(nextDtoList)) {
            return Result.OK("流程已完结", null);
        }
        return Result.OK(nextDtoList);
    }
    @Override
    public boolean checkParallelCompletion(String currentTaskId) {
        //获取当前任务
        Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();
        if (currentTask == null) {
            return false;
        }
        //获取当前执行
        Execution execution = runtimeService.createExecutionQuery().executionId(currentTask.getExecutionId()).singleResult();
        if (execution == null) {
            return false;
        }
        String parentId = execution.getParentId();
        if (StringUtils.isBlank(parentId)) {
            //没有父节点 ä»£è¡¨æ²¡æœ‰å¹¶è¡Œä»»åŠ¡
            return true;
        }
        // èŽ·å–æ‰€æœ‰å…„å¼Ÿæ‰§è¡Œ
        List<Execution> siblingExecutions = runtimeService.createExecutionQuery()
                .parentId(parentId)
                .list();
        for (Execution siblingExecution : siblingExecutions) {
            if (!siblingExecution.getId().equals(execution.getId())) {
                //非自身的兄弟节点
                long count = runtimeService.createActivityInstanceQuery().executionId(siblingExecution.getId()).unfinished().count();
                if (count > 0) {
                    return false;
                }
            }
        }
        return true;
    }
    /**
     * èŽ·å–ä¸‹ä¸€ä¸ªèŠ‚ç‚¹ä¿¡æ¯,流程定义上的节点信息
     *
     * @param taskId å½“前节点id
     * @param values æµç¨‹å˜é‡
     * @return å¦‚果返回null,表示没有下一个节点,流程结束
     */
    public List<FlowNextDto> getNextFlowNode(String taskId, Map<String, Object> values) {
        //当前节点
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.nonNull(task)) {
            // ä¸‹ä¸ªä»»åŠ¡èŠ‚ç‚¹
            List<UserTask> nextUserTask = FindNextNodeUtil.getNextUserTasks(repositoryService, task, values);
            if (CollectionUtils.isNotEmpty(nextUserTask)) {
                List<FlowNextDto> nextDtoList = Lists.newArrayList();
                FlowNextDto flowNextDto;
                for (UserTask userTask : nextUserTask) {
                    flowNextDto = new FlowNextDto();
                    flowNextDto.setUserTask(userTask);
                    //待办人员
                    List<SysUser> sysUserFromTask = this.getSysUserFromTask(userTask);
                    flowNextDto.setUserList(sysUserFromTask);
                    //多任务并行
                    Object colObj = values.get(userTask.getId());
                    if (Objects.nonNull(colObj)) {
                        List<String> userNameList = (List) colObj;
                        // å¾…办人员从变量中获取  å¦åˆ™å°±æ˜¯èŠ‚ç‚¹ä¸­é…ç½®çš„ç”¨æˆ· sysUserFromTask
                        List<SysUser> userList = Lists.newArrayList();
                        for (String username : userNameList) {
                            SysUser userByUsername = iFlowThirdService.getUserByUsername(username);
                            if (userByUsername == null) {
                                throw new CustomException(username + " ç”¨æˆ·åæœªæ‰¾åˆ°");
                            } else {
                                userList.add(userByUsername);
                            }
                        }
                        flowNextDto.setUserList(userList);
                    } else {
                        // å˜é‡ä¸­æ²¡æœ‰ä¼ å…¥ï¼Œå†™å…¥èŠ‚ç‚¹ä¸­é…ç½®çš„ç”¨æˆ·
                        List<String> collect_username = sysUserFromTask.stream().map(SysUser::getUsername).collect(Collectors.toList());
                        values.put(userTask.getId(), collect_username);
                    }
                    nextDtoList.add(flowNextDto);
                }
                return nextDtoList;
            }
        }
        return null;
    }
    public List<SysUser> getSysUserFromTask(UserTask userTask) {
        String assignee = userTask.getAssignee();
        if (StrUtil.isNotBlank(assignee)) {
            // æŒ‡å®šå•人
            SysUser userByUsername = iFlowThirdService.getUserByUsername(assignee);
            return Lists.newArrayList(userByUsername);
        }
        List<String> candidateUsers = userTask.getCandidateUsers();
        if (CollUtil.isNotEmpty(candidateUsers)) {
            // æŒ‡å®šå¤šäºº
            List<SysUser> list = iFlowThirdService.getAllUser();
            return list.stream().filter(o -> candidateUsers.contains(o.getUsername())).collect(Collectors.toList());
        }
        List<String> candidateGroups = userTask.getCandidateGroups();
        if (CollUtil.isNotEmpty(candidateGroups)) {
            //    æŒ‡å®šå¤šç»„
            List<SysUser> userList = Lists.newArrayList();
            for (String candidateGroup : candidateGroups) {
                List<SysUser> usersByRoleId = iFlowThirdService.getUsersByRoleId(candidateGroup);
                userList.addAll(usersByRoleId);
            }
            return userList;
        }
        return Lists.newArrayList();
    }
    /**
     * æµç¨‹å®Œæˆæ—¶é—´å¤„理
     *
     * @param ms
     * @return
     */
    private String getDate(long ms) {
        long day = ms / (24 * 60 * 60 * 1000);
        long hour = (ms / (60 * 60 * 1000) - day * 24);
        long minute = ((ms / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long second = (ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60);
        if (day > 0) {
            return day + "天" + hour + "小时" + minute + "分钟";
        }
        if (hour > 0) {
            return hour + "小时" + minute + "分钟";
        }
        if (minute > 0) {
            return minute + "分钟";
        }
        if (second > 0) {
            return second + "秒";
        } else {
            return 0 + "秒";
        }
    }
}