From 69e3afc7707d467b758858b52d3784947f7a502b Mon Sep 17 00:00:00 2001
From: 疯狂的狮子Li <15040126243@163.com>
Date: 星期一, 20 五月 2024 10:25:23 +0800
Subject: [PATCH] !538 ♥️发布 5.2.0-BETA 公测版本 Merge pull request !538 from 疯狂的狮子Li/dev

---
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java |  872 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 872 insertions(+), 0 deletions(-)

diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
new file mode 100644
index 0000000..1a4866d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
@@ -0,0 +1,872 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.dto.RoleDTO;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.common.enums.BusinessStatusEnum;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.domain.ActHiTaskinst;
+import org.dromara.workflow.domain.WfTaskBackNode;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.*;
+import org.dromara.workflow.flowable.cmd.*;
+import org.dromara.workflow.flowable.strategy.FlowEventStrategy;
+import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler;
+import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler;
+import org.dromara.workflow.mapper.ActHiTaskinstMapper;
+import org.dromara.workflow.mapper.ActTaskMapper;
+import org.dromara.workflow.service.IActTaskService;
+import org.dromara.workflow.service.IWfDefinitionConfigService;
+import org.dromara.workflow.service.IWfNodeConfigService;
+import org.dromara.workflow.service.IWfTaskBackNodeService;
+import org.dromara.workflow.utils.ModelUtils;
+import org.dromara.workflow.utils.QueryUtils;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.flowable.common.engine.api.FlowableObjectNotFoundException;
+import org.flowable.common.engine.impl.identity.Authentication;
+import org.flowable.engine.*;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.history.HistoricProcessInstanceQuery;
+import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
+import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.identitylink.api.history.HistoricIdentityLink;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.TaskQuery;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+import org.flowable.variable.api.persistence.entity.VariableInstance;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.dromara.workflow.common.constant.FlowConstant.*;
+
+/**
+ * 浠诲姟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@RequiredArgsConstructor
+@Service
+public class ActTaskServiceImpl implements IActTaskService {
+
+    private final RuntimeService runtimeService;
+    private final TaskService taskService;
+    private final HistoryService historyService;
+    private final IdentityService identityService;
+    private final ManagementService managementService;
+    private final FlowEventStrategy flowEventStrategy;
+    private final ActTaskMapper actTaskMapper;
+    private final IWfTaskBackNodeService wfTaskBackNodeService;
+    private final ActHiTaskinstMapper actHiTaskinstMapper;
+    private final IWfNodeConfigService wfNodeConfigService;
+    private final IWfDefinitionConfigService wfDefinitionConfigService;
+    private final UserService userService;
+
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> startWorkFlow(StartProcessBo startProcessBo) {
+        Map<String, Object> map = new HashMap<>();
+        if (StringUtils.isBlank(startProcessBo.getBusinessKey())) {
+            throw new ServiceException("鍚姩宸ヤ綔娴佹椂蹇呴』鍖呭惈涓氬姟ID");
+        }
+        // 鍒ゆ柇褰撳墠涓氬姟鏄惁鍚姩杩囨祦绋�
+        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery();
+        HistoricProcessInstance historicProcessInstance = query.processInstanceBusinessKey(startProcessBo.getBusinessKey()).singleResult();
+        if (ObjectUtil.isNotEmpty(historicProcessInstance)) {
+            BusinessStatusEnum.checkStartStatus(historicProcessInstance.getBusinessStatus());
+        }
+        List<Task> taskResult = QueryUtils.taskQuery().processInstanceBusinessKey(startProcessBo.getBusinessKey()).list();
+        if (CollUtil.isNotEmpty(taskResult)) {
+            if (CollUtil.isNotEmpty(startProcessBo.getVariables())) {
+                taskService.setVariables(taskResult.get(0).getId(), startProcessBo.getVariables());
+            }
+            map.put(PROCESS_INSTANCE_ID, taskResult.get(0).getProcessInstanceId());
+            map.put("taskId", taskResult.get(0).getId());
+            return map;
+        }
+        WfDefinitionConfigVo wfDefinitionConfigVo = wfDefinitionConfigService.getByTableNameLastVersion(startProcessBo.getTableName());
+        if (wfDefinitionConfigVo == null) {
+            throw new ServiceException("璇峰埌娴佺▼瀹氫箟缁戝畾涓氬姟琛ㄥ悕涓庢祦绋婯EY锛�");
+        }
+        // 璁剧疆鍚姩浜�
+        identityService.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId()));
+        Authentication.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId()));
+        // 鍚姩娴佺▼瀹炰緥锛堟彁浜ょ敵璇凤級
+        Map<String, Object> variables = startProcessBo.getVariables();
+        // 鍚姩璺宠繃琛ㄨ揪寮�
+        variables.put(FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
+        // 娴佺▼鍙戣捣浜�
+        variables.put(INITIATOR, (String.valueOf(LoginHelper.getUserId())));
+        ProcessInstance pi;
+        try {
+            if (TenantHelper.isEnable()) {
+                pi = runtimeService.startProcessInstanceByKeyAndTenantId(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables, TenantHelper.getTenantId());
+            } else {
+                pi = runtimeService.startProcessInstanceByKey(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables);
+            }
+        } catch (FlowableObjectNotFoundException e) {
+            throw new ServiceException("鎵句笉鍒板綋鍓嶃��" + wfDefinitionConfigVo.getProcessKey() + "銆戞祦绋嬪畾涔夛紒");
+        }
+        // 灏嗘祦绋嬪畾涔夊悕绉� 浣滀负 娴佺▼瀹炰緥鍚嶇О
+        runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());
+        // 鐢宠浜烘墽琛屾祦绋�
+        List<Task> taskList = QueryUtils.taskQuery(pi.getId()).list();
+        if (taskList.size() > 1) {
+            throw new ServiceException("璇锋鏌ユ祦绋嬬涓�涓幆鑺傛槸鍚︿负鐢宠浜猴紒");
+        }
+
+        runtimeService.updateBusinessStatus(pi.getProcessInstanceId(), BusinessStatusEnum.DRAFT.getStatus());
+        taskService.setAssignee(taskList.get(0).getId(), LoginHelper.getUserId().toString());
+        taskService.setVariable(taskList.get(0).getId(), PROCESS_INSTANCE_ID, pi.getProcessInstanceId());
+        taskService.setVariable(taskList.get(0).getId(), BUSINESS_KEY, pi.getBusinessKey());
+        map.put("processInstanceId", pi.getProcessInstanceId());
+        map.put("taskId", taskList.get(0).getId());
+        return map;
+    }
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean completeTask(CompleteTaskBo completeTaskBo) {
+        try {
+            List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
+            String userId = String.valueOf(LoginHelper.getUserId());
+            TaskQuery taskQuery = QueryUtils.taskQuery();
+            taskQuery.taskId(completeTaskBo.getTaskId()).taskCandidateOrAssigned(userId);
+            if (CollUtil.isNotEmpty(roles)) {
+                List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
+                taskQuery.taskCandidateGroupIn(groupIds);
+            }
+            Task task = taskQuery.singleResult();
+            if (task == null) {
+                throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+            }
+            if (task.isSuspended()) {
+                throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+            }
+            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
+            //鍔炵悊濮旀墭浠诲姟
+            if (ObjectUtil.isNotEmpty(task.getDelegationState()) && FlowConstant.PENDING.equals(task.getDelegationState().name())) {
+                taskService.resolveTask(completeTaskBo.getTaskId());
+                TaskEntity newTask = WorkflowUtils.createNewTask(task);
+                taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isNotBlank(completeTaskBo.getMessage()) ? completeTaskBo.getMessage() : StrUtil.EMPTY);
+                taskService.complete(newTask.getId());
+                return true;
+            }
+            //闄勪欢涓婁紶
+            AttachmentCmd attachmentCmd = new AttachmentCmd(completeTaskBo.getFileId(), task.getId(), task.getProcessInstanceId());
+            managementService.executeCommand(attachmentCmd);
+            FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
+            String businessStatus = WorkflowUtils.getBusinessStatus(task.getProcessInstanceId());
+            if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) {
+                if (processHandler != null) {
+                    processHandler.handleProcess(processInstance.getBusinessKey(), businessStatus, true);
+                }
+            }
+            runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus());
+            String key = processInstance.getProcessDefinitionKey() + "_" + task.getTaskDefinitionKey();
+            FlowTaskEventHandler taskHandler = flowEventStrategy.getTaskHandler(key);
+            if (taskHandler != null) {
+                taskHandler.handleTask(task.getId(), processInstance.getBusinessKey());
+            }
+            //鍔炵悊鎰忚
+            taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "鍚屾剰" : completeTaskBo.getMessage());
+            //鍔炵悊浠诲姟
+            taskService.setAssignee(task.getId(), userId);
+            if (CollUtil.isNotEmpty(completeTaskBo.getVariables())) {
+                taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables());
+            } else {
+                taskService.complete(completeTaskBo.getTaskId());
+            }
+            //璁板綍鎵ц杩囩殑娴佺▼浠诲姟鑺傜偣
+            wfTaskBackNodeService.recordExecuteNode(task);
+            ProcessInstance pi = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
+            if (pi == null) {
+                UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus());
+                managementService.executeCommand(updateBusinessStatusCmd);
+                if (processHandler != null) {
+                    processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.FINISH.getStatus(), false);
+                }
+            } else {
+                List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+                for (Task t : list) {
+                    if (ModelUtils.isUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey())) {
+                        List<HistoricIdentityLink> links = historyService.getHistoricIdentityLinksForTask(t.getId());
+                        if (CollUtil.isEmpty(links) && StringUtils.isBlank(t.getAssignee())) {
+                            throw new ServiceException("涓嬩竴鑺傜偣銆�" + t.getName() + "銆戞病鏈夊姙鐞嗕汉!");
+                        }
+                    }
+                }
+
+                if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(completeTaskBo.getWfCopyList())) {
+                    TaskEntity newTask = WorkflowUtils.createNewTask(task);
+                    taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), LoginHelper.getLoginUser().getNickname() + "銆愭妱閫併�戠粰" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName)));
+                    taskService.complete(newTask.getId());
+                    List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+                    WorkflowUtils.createCopyTask(taskList, StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserId));
+                }
+                sendMessage(list, processInstance.getName(), completeTaskBo.getMessageType(), null);
+            }
+            return true;
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鍙戦�佹秷鎭�
+     *
+     * @param list        浠诲姟
+     * @param name        娴佺▼鍚嶇О
+     * @param messageType 娑堟伅绫诲瀷
+     * @param message     娑堟伅鍐呭锛屼负绌哄垯鍙戦�侀粯璁ら厤缃殑娑堟伅鍐呭
+     */
+    @Async
+    public void sendMessage(List<Task> list, String name, List<String> messageType, String message) {
+        WorkflowUtils.sendMessage(list, name, messageType, message);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) {
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
+        List<String> roleIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
+        String userId = String.valueOf(LoginHelper.getUserId());
+        queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus());
+        queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId());
+        queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' " + "and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN " + getInParam(roleIds) + " ) ))", userId)));
+        if (StringUtils.isNotBlank(taskBo.getName())) {
+            queryWrapper.like("t.name_", taskBo.getName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
+            queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
+            queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        }
+        Page<TaskVo> page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                task.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId()));
+                task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    private String getInParam(List<String> param) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("(");
+        for (int i = 0; i < param.size(); i++) {
+            sb.append("'").append(param.get(i)).append("'");
+            if (i != param.size() - 1) {
+                sb.append(",");
+            }
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) {
+        TaskQuery query = QueryUtils.taskQuery();
+        if (StringUtils.isNotBlank(taskBo.getName())) {
+            query.taskNameLike("%" + taskBo.getName() + "%");
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
+            query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%");
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
+            query.processDefinitionKey(taskBo.getProcessDefinitionKey());
+        }
+        query.orderByTaskCreateTime().desc();
+        List<Task> taskList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
+        List<ProcessInstance> processInstanceList = null;
+        if (CollUtil.isNotEmpty(taskList)) {
+            Set<String> processInstanceIds = StreamUtils.toSet(taskList, Task::getProcessInstanceId);
+            processInstanceList = QueryUtils.instanceQuery(processInstanceIds).list();
+        }
+        List<TaskVo> list = new ArrayList<>();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, Task::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (Task task : taskList) {
+                TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
+                if (CollUtil.isNotEmpty(processInstanceList)) {
+                    processInstanceList.stream().filter(e -> e.getId().equals(task.getProcessInstanceId())).findFirst().ifPresent(e -> {
+                        taskVo.setBusinessStatus(e.getBusinessStatus());
+                        taskVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(taskVo.getBusinessStatus()));
+                        taskVo.setProcessDefinitionKey(e.getProcessDefinitionKey());
+                        taskVo.setProcessDefinitionName(e.getProcessDefinitionName());
+                        taskVo.setProcessDefinitionVersion(e.getProcessDefinitionVersion());
+                        taskVo.setBusinessKey(e.getBusinessKey());
+                    });
+                }
+                taskVo.setAssignee(StringUtils.isNotBlank(task.getAssignee()) ? Long.valueOf(task.getAssignee()) : null);
+                taskVo.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId()));
+                taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
+                }
+                list.add(taskVo);
+            }
+        }
+        long count = query.count();
+        TableDataInfo<TaskVo> build = TableDataInfo.build();
+        build.setRows(list);
+        build.setTotal(count);
+        return build;
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
+        String userId = String.valueOf(LoginHelper.getUserId());
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName());
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName());
+        queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        queryWrapper.eq("t.assignee_", userId);
+        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) {
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        String userId = String.valueOf(LoginHelper.getUserId());
+        if (StringUtils.isNotBlank(taskBo.getName())) {
+            queryWrapper.like("t.name_", taskBo.getName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
+            queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
+            queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        }
+        queryWrapper.eq("t.assignee_", userId);
+        Page<TaskVo> page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊凡鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName());
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName());
+        queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 濮旀淳浠诲姟
+     *
+     * @param delegateBo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean delegateTask(DelegateBo delegateBo) {
+        TaskQuery query = QueryUtils.taskQuery();
+        TaskEntity task = (TaskEntity) query.taskId(delegateBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        try {
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PENDING.getStatus(), "銆�" + LoginHelper.getLoginUser().getNickname() + "銆戝娲剧粰銆�" + delegateBo.getNickName() + "銆�");
+            //濮旀墭浠诲姟
+            taskService.delegateTask(delegateBo.getTaskId(), delegateBo.getUserId());
+            //鍔炵悊鐢熸垚鐨勪换鍔¤褰�
+            taskService.complete(newTask.getId());
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param terminationBo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean terminationTask(TerminationBo terminationBo) {
+        TaskQuery query = QueryUtils.taskQuery();
+        Task task = query.taskId(terminationBo.getTaskId()).singleResult();
+
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
+        BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
+        try {
+            if (StringUtils.isBlank(terminationBo.getComment())) {
+                terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "缁堟浜嗙敵璇�");
+            } else {
+                terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "缁堟浜嗙敵璇凤細" + terminationBo.getComment());
+            }
+            taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TERMINATION.getStatus(), terminationBo.getComment());
+            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+            if (CollUtil.isNotEmpty(list)) {
+                List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
+                if (CollUtil.isNotEmpty(subTasks)) {
+                    subTasks.forEach(e -> taskService.deleteTask(e.getId()));
+                }
+                runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus());
+                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY);
+            }
+            FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey());
+            if (processHandler != null) {
+                processHandler.handleProcess(historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
+            }
+            return true;
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 杞姙浠诲姟
+     *
+     * @param transmitBo 鍙傛暟
+     */
+    @Override
+    public boolean transferTask(TransmitBo transmitBo) {
+        Task task = QueryUtils.taskQuery().taskId(transmitBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        try {
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.TRANSFER.getStatus(), StringUtils.isNotBlank(transmitBo.getComment()) ? transmitBo.getComment() : LoginHelper.getUsername() + "杞姙浜嗕换鍔�");
+            taskService.complete(newTask.getId());
+            taskService.setAssignee(task.getId(), transmitBo.getUserId());
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 浼氱浠诲姟鍔犵
+     *
+     * @param addMultiBo 鍙傛暟
+     */
+    @Override
+    public boolean addMultiInstanceExecution(AddMultiBo addMultiBo) {
+        TaskQuery taskQuery = QueryUtils.taskQuery();
+        taskQuery.taskId(addMultiBo.getTaskId());
+        if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) {
+            taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
+        }
+        Task task = taskQuery.singleResult();
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        String taskDefinitionKey = task.getTaskDefinitionKey();
+        String processInstanceId = task.getProcessInstanceId();
+        String processDefinitionId = task.getProcessDefinitionId();
+
+        try {
+            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
+            if (multiInstanceVo == null) {
+                throw new ServiceException("褰撳墠鐜妭涓嶆槸浼氱鑺傜偣");
+            }
+            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
+                for (Long assignee : addMultiBo.getAssignees()) {
+                    runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap(multiInstanceVo.getAssignee(), assignee));
+                }
+            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
+                AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getExecutionId(), multiInstanceVo.getAssigneeList(), addMultiBo.getAssignees());
+                managementService.executeCommand(addSequenceMultiInstanceCmd);
+            }
+            List<String> assigneeNames = addMultiBo.getAssigneeNames();
+            String username = LoginHelper.getUsername();
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN.getStatus(), username + "鍔犵銆�" + String.join(StringUtils.SEPARATOR, assigneeNames) + "銆�");
+            taskService.complete(newTask.getId());
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 浼氱浠诲姟鍑忕
+     *
+     * @param deleteMultiBo 鍙傛暟
+     */
+    @Override
+    public boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo) {
+        TaskQuery taskQuery = QueryUtils.taskQuery();
+        taskQuery.taskId(deleteMultiBo.getTaskId());
+        if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) {
+            taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
+        }
+        Task task = taskQuery.singleResult();
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        String taskDefinitionKey = task.getTaskDefinitionKey();
+        String processInstanceId = task.getProcessInstanceId();
+        String processDefinitionId = task.getProcessDefinitionId();
+        try {
+            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
+            if (multiInstanceVo == null) {
+                throw new ServiceException("褰撳墠鐜妭涓嶆槸浼氱鑺傜偣");
+            }
+            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
+                for (String executionId : deleteMultiBo.getExecutionIds()) {
+                    runtimeService.deleteMultiInstanceExecution(executionId, false);
+                }
+                for (String taskId : deleteMultiBo.getTaskIds()) {
+                    historyService.deleteHistoricTaskInstance(taskId);
+                }
+            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
+                DeleteSequenceMultiInstanceCmd deleteSequenceMultiInstanceCmd = new DeleteSequenceMultiInstanceCmd(task.getAssignee(), task.getExecutionId(), multiInstanceVo.getAssigneeList(), deleteMultiBo.getAssigneeIds());
+                managementService.executeCommand(deleteSequenceMultiInstanceCmd);
+            }
+            List<String> assigneeNames = deleteMultiBo.getAssigneeNames();
+            String username = LoginHelper.getUsername();
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN_OFF.getStatus(), username + "鍑忕銆�" + String.join(StringUtils.SEPARATOR, assigneeNames) + "銆�");
+            taskService.complete(newTask.getId());
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 椹冲洖瀹℃壒
+     *
+     * @param backProcessBo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String backProcess(BackProcessBo backProcessBo) {
+        TaskQuery query = QueryUtils.taskQuery();
+        String userId = String.valueOf(LoginHelper.getUserId());
+        Task task = query.taskId(backProcessBo.getTaskId()).taskCandidateOrAssigned(userId).singleResult();
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        try {
+            String processInstanceId = task.getProcessInstanceId();
+            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
+            //鑾峰彇骞惰缃戝叧鎵ц鍚庝繚鐣欑殑鎵ц瀹炰緥鏁版嵁
+            ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId());
+            List<ExecutionEntity> executionEntities = managementService.executeCommand(childByExecutionIdCmd);
+            //鏍¢獙鍗曟嵁
+            BusinessStatusEnum.checkBackStatus(processInstance.getBusinessStatus());
+            //鍒ゆ柇鏄惁鏈夊涓换鍔�
+            List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
+            String backTaskDefinitionKey = backProcessBo.getTargetActivityId();
+            taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.BACK.getStatus(), StringUtils.isNotBlank(backProcessBo.getMessage()) ? backProcessBo.getMessage() : "閫�鍥�");
+            if (taskList.size() > 1) {
+                //褰撳墠澶氫釜浠诲姟椹冲洖鍒板崟涓妭鐐�
+                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdsToSingleActivityId(taskList.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList()), backTaskDefinitionKey).changeState();
+                ActHiTaskinst actHiTaskinst = new ActHiTaskinst();
+                actHiTaskinst.setAssignee(userId);
+                actHiTaskinst.setId(task.getId());
+                actHiTaskinstMapper.updateById(actHiTaskinst);
+            } else {
+                //褰撳墠鍗曚釜鑺傜偣椹冲洖鍗曚釜鑺傜偣
+                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdTo(task.getTaskDefinitionKey(), backTaskDefinitionKey).changeState();
+            }
+            //鍒犻櫎骞惰鐜妭鏈姙鐞嗚褰�
+            MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+            if (multiInstance == null && taskList.size() > 1) {
+                List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
+                actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId));
+            }
+
+
+            List<HistoricTaskInstance> instanceList = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().desc().list();
+            List<Task> list = QueryUtils.taskQuery(processInstanceId).list();
+            for (Task t : list) {
+                instanceList.stream().filter(e -> e.getTaskDefinitionKey().equals(t.getTaskDefinitionKey())).findFirst().ifPresent(e -> {
+                    taskService.setAssignee(t.getId(), e.getAssignee());
+                });
+            }
+            //鍙戦�佹秷鎭�
+            String message = "鎮ㄧ殑銆�" + processInstance.getName() + "銆戝崟鎹凡缁忚椹冲洖锛岃鎮ㄦ敞鎰忔煡鏀躲��";
+            sendMessage(list, processInstance.getName(), backProcessBo.getMessageType(), message);
+            //鍒犻櫎娴佺▼瀹炰緥鍨冨溇鏁版嵁
+            for (ExecutionEntity executionEntity : executionEntities) {
+                DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId());
+                managementService.executeCommand(deleteExecutionCmd);
+            }
+
+            WfTaskBackNode wfTaskBackNode = wfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId());
+            if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) {
+                runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus());
+                FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
+                if (processHandler != null) {
+                    processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
+                }
+            }
+            //鍒犻櫎椹冲洖鍚庣殑娴佺▼鑺傜偣
+            wfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId());
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+        return task.getProcessInstanceId();
+    }
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜�
+     *
+     * @param taskIds 浠诲姟id
+     * @param userId  鍔炵悊浜篿d
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateAssignee(String[] taskIds, String userId) {
+        try {
+            List<Task> list = QueryUtils.taskQuery().taskIds(Arrays.asList(taskIds)).list();
+            for (Task task : list) {
+                taskService.setAssignee(task.getId(), userId);
+            }
+        } catch (Exception e) {
+            throw new ServiceException("淇敼澶辫触锛�" + e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * 鏌ヨ娴佺▼鍙橀噺
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public List<VariableVo> getInstanceVariable(String taskId) {
+        List<VariableVo> variableVoList = new ArrayList<>();
+        Map<String, VariableInstance> variableInstances = taskService.getVariableInstances(taskId);
+        if (CollUtil.isNotEmpty(variableInstances)) {
+            for (Map.Entry<String, VariableInstance> entry : variableInstances.entrySet()) {
+                VariableVo variableVo = new VariableVo();
+                variableVo.setKey(entry.getKey());
+                variableVo.setValue(entry.getValue().getValue().toString());
+                variableVoList.add(variableVo);
+            }
+        }
+        return variableVoList;
+    }
+
+    /**
+     * 鏌ヨ宸ヤ綔娴佷换鍔$敤鎴烽�夋嫨鍔犵浜哄憳
+     *
+     * @param taskId 浠诲姟id
+     * @return
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public String getTaskUserIdsByAddMultiInstance(String taskId) {
+        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
+        if (task == null) {
+            throw new ServiceException("浠诲姟涓嶅瓨鍦�");
+        }
+        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+        if (multiInstance == null) {
+            return "";
+        }
+        List<Long> userIds;
+        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
+            userIds = (List<Long>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
+        } else {
+            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+            userIds = StreamUtils.toList(list, e -> Long.valueOf(e.getAssignee()));
+        }
+        return StringUtils.join(userIds, StringUtils.SEPARATOR);
+    }
+
+    /**
+     * 鏌ヨ宸ヤ綔娴侀�夋嫨鍑忕浜哄憳
+     *
+     * @param taskId 浠诲姟id 浠诲姟id
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<TaskVo> getListByDeleteMultiInstance(String taskId) {
+        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
+        List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+        List<TaskVo> taskListVo = new ArrayList<>();
+        if (multiInstance == null) {
+            return List.of();
+        }
+        List<Long> assigneeList = new ArrayList<>();
+        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
+            List<Object> variable = (List<Object>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
+            for (Object o : variable) {
+                assigneeList.add(Long.valueOf(o.toString()));
+            }
+        }
+
+        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
+            List<Long> userIds = StreamUtils.filter(assigneeList, e -> !String.valueOf(e).equals(task.getAssignee()));
+            List<UserDTO> userList = userService.selectListByIds(userIds);
+            for (Long userId : userIds) {
+                TaskVo taskVo = new TaskVo();
+                taskVo.setId("涓茶浼氱");
+                taskVo.setExecutionId("涓茶浼氱");
+                taskVo.setProcessInstanceId(task.getProcessInstanceId());
+                taskVo.setName(task.getName());
+                taskVo.setAssignee(userId);
+                if (CollUtil.isNotEmpty(userList)) {
+                    userList.stream().filter(u -> u.getUserId().toString().equals(userId.toString())).findFirst().ifPresent(u -> taskVo.setAssigneeName(u.getNickName()));
+                }
+                taskListVo.add(taskVo);
+            }
+            return taskListVo;
+        } else if (multiInstance.getType() instanceof ParallelMultiInstanceBehavior) {
+            List<Task> tasks = StreamUtils.filter(taskList, e -> StringUtils.isBlank(e.getParentTaskId()) && !e.getExecutionId().equals(task.getExecutionId()) && e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
+            if (CollUtil.isNotEmpty(tasks)) {
+                List<Long> userIds = StreamUtils.toList(tasks, e -> Long.valueOf(e.getAssignee()));
+                List<UserDTO> userList = userService.selectListByIds(userIds);
+                for (Task t : tasks) {
+                    TaskVo taskVo = new TaskVo();
+                    taskVo.setId(t.getId());
+                    taskVo.setExecutionId(t.getExecutionId());
+                    taskVo.setProcessInstanceId(t.getProcessInstanceId());
+                    taskVo.setName(t.getName());
+                    taskVo.setAssignee(Long.valueOf(t.getAssignee()));
+                    if (CollUtil.isNotEmpty(userList)) {
+                        userList.stream().filter(u -> u.getUserId().toString().equals(t.getAssignee())).findFirst().ifPresent(e -> taskVo.setAssigneeName(e.getNickName()));
+                    }
+                    taskListVo.add(taskVo);
+                }
+                return taskListVo;
+            }
+        }
+        return List.of();
+    }
+}

--
Gitblit v1.9.3