From 23855599412c4d61b38d78f0f3abd3430a48b5b1 Mon Sep 17 00:00:00 2001
From: zhangherong <571457620@qq.com>
Date: 星期三, 25 六月 2025 11:51:38 +0800
Subject: [PATCH] Merge branch 'mdc_hyjs_master'

---
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java | 1614 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1,614 insertions(+), 0 deletions(-)

diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java
new file mode 100644
index 0000000..fb5e489
--- /dev/null
+++ b/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();
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.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
+        // 鑾峰彇褰撳墠鑺傜偣鐨勬墍鏈夌埗绾х敤鎴蜂换鍔¤妭鐐�
+        // 娣卞害浼樺厛绠楁硶鎬濇兂锛氬欢杈硅凯浠f繁鍏�
+        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<>();
+        // 閫氳繃鐖剁骇缃戝叧鐨勫嚭鍙h繛绾匡紝缁撳悎 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("浠诲姟鍑虹幇澶氬澶氭儏鍐碉紝鏃犳硶鎾ゅ洖");
+        }
+
+        // 寰幆鑾峰彇閭d簺闇�瑕佽鎾ゅ洖鐨勮妭鐐圭殑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)锛宼argetIds 璺宠浆鍒扮殑鑺傜偣(澶�)
+                runtimeService.createChangeActivityStateBuilder()
+                        .processInstanceId(task.getProcessInstanceId()).
+                        moveSingleActivityIdToActivityIds(currentIds.get(0), targetIds).changeState();
+            }
+            // 濡傛灉鐖剁骇浠诲姟鍙湁涓�涓紝鍥犳褰撳墠浠诲姟鍙兘涓虹綉鍏充腑鐨勪换鍔�
+            if (targetIds.size() == 1) {
+                // 1 瀵� 1 鎴� 澶� 瀵� 1 鎯呭喌锛宑urrentIds 褰撳墠瑕佽烦杞殑鑺傜偣鍒楄〃(1鎴栧)锛宼argetIds.get(0) 璺宠浆鍒扮殑鑺傜偣(1)
+                runtimeService.createChangeActivityStateBuilder()
+                        .processInstanceId(task.getProcessInstanceId())
+                        .moveActivityIdsToSingleActivityId(currentIds, targetIds.get(0)).changeState();
+            }
+            /*======================椹冲洖  鍥炶皟浠ュ強鍏抽敭鏁版嵁淇濆瓨======================*/
+            //涓氬姟鏁版嵁id
+            String dataId = flowTaskVo.getDataId();
+            if (dataId == null) return;
+            //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.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) {
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.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<>();
+        // 閫氳繃鐖剁骇缃戝叧鐨勫嚭鍙h繛绾匡紝缁撳悎 runTaskList 姣斿锛岃幏鍙栭渶瑕佹挙鍥炵殑浠诲姟
+        List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null);
+        currentUserTaskList.forEach(item -> {
+            currentIds.add(item.getId());
+        });
+
+        // 寰幆鑾峰彇閭d簺闇�瑕佽鎾ゅ洖鐨勮妭鐐圭殑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 鎯呭喌锛宑urrentIds 褰撳墠瑕佽烦杞殑鑺傜偣鍒楄〃(1鎴栧)锛宼argetKey 璺宠浆鍒扮殑鑺傜偣(1)
+            runtimeService.createChangeActivityStateBuilder()
+                    .processInstanceId(task.getProcessInstanceId())
+                    .moveActivityIdsToSingleActivityId(currentIds, flowTaskVo.getTargetKey()).changeState();
+
+            /*======================閫�鍥�  鍥炶皟浠ュ強鍏抽敭鏁版嵁淇濆瓨======================*/
+            //涓氬姟鏁版嵁id
+            String dataId = flowTaskVo.getDataId();
+            if (dataId == null) return;
+            //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.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 閫楀彿鍒嗛殧鐨勪换鍔D瀛楃涓�
+     * @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. 鍗曚换鍔$洿鎺ヨ繑鍥瀟rue
+        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 鑾峰彇鑺傜偣鏍囪瘑锛圱askDefinitionKey锛�
+            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);
+    }
+
+    /**
+     * 浠e姙浠诲姟鍒楄〃
+     *
+     * @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)
+        ;
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.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();
+        // *椤哄簭鐨凨ey
+        List<String> orderKeys = Lists.newArrayList();
+        if (flowElements != null) {
+            for (FlowElement flowElement : flowElements) {
+                try {
+                    // 寮�濮嬭妭鐐�
+                    StartEvent stev = (StartEvent) flowElement;
+                    //绗竴涓猭ey鑺傜偣锛�
+                    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()) {
+                        //    宸插埌姝e湪绛夊緟鎵ц鐨勮妭鐐癸紝鍚庨潰鐨勪笉瑕佷簡
+                        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)) {
+            //娌℃湁鐖惰妭鐐� 浠h〃娌℃湁骞惰浠诲姟
+            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 + "绉�";
+        }
+    }
+}

--
Gitblit v1.9.3