From 3c8d864b5f68af5167199e0d5c9ff6c0c5852638 Mon Sep 17 00:00:00 2001
From: 疯狂的狮子Li <15040126243@163.com>
Date: 星期一, 20 一月 2025 11:35:45 +0800
Subject: [PATCH] !639 发布 5.3.0-BETA 公测版本 Merge pull request !639 from 疯狂的狮子Li/dev

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

diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java
new file mode 100644
index 0000000..f95821d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java
@@ -0,0 +1,679 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.enums.BusinessStatusEnum;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+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.warm.flow.core.dto.FlowParams;
+import org.dromara.warm.flow.core.entity.*;
+import org.dromara.warm.flow.core.enums.NodeType;
+import org.dromara.warm.flow.core.enums.SkipType;
+import org.dromara.warm.flow.core.service.*;
+import org.dromara.warm.flow.orm.entity.*;
+import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
+import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
+import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.enums.TaskAssigneeType;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.FlowHisTaskVo;
+import org.dromara.workflow.domain.vo.FlowTaskVo;
+import org.dromara.workflow.handler.FlowProcessEventHandler;
+import org.dromara.workflow.handler.WorkflowPermissionHandler;
+import org.dromara.workflow.mapper.FlwCategoryMapper;
+import org.dromara.workflow.mapper.FlwTaskMapper;
+import org.dromara.workflow.service.IFlwTaskService;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.dromara.workflow.common.constant.FlowConstant.*;
+
+/**
+ * 浠诲姟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class FlwTaskServiceImpl implements IFlwTaskService {
+
+    private final TaskService taskService;
+    private final InsService insService;
+    private final DefService defService;
+    private final HisTaskService hisTaskService;
+    private final NodeService nodeService;
+    private final FlowInstanceMapper flowInstanceMapper;
+    private final FlowTaskMapper flowTaskMapper;
+    private final FlowHisTaskMapper flowHisTaskMapper;
+    private final IdentifierGenerator identifierGenerator;
+    private final FlowProcessEventHandler flowProcessEventHandler;
+    private final UserService userService;
+    private final FlwTaskMapper flwTaskMapper;
+    private final FlwCategoryMapper flwCategoryMapper;
+
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> startWorkFlow(StartProcessBo startProcessBo) {
+        String businessId = startProcessBo.getBusinessId();
+        if (StringUtils.isBlank(businessId)) {
+            throw new ServiceException("鍚姩宸ヤ綔娴佹椂蹇呴』鍖呭惈涓氬姟ID");
+        }
+        // 鍚姩娴佺▼瀹炰緥锛堟彁浜ょ敵璇凤級
+        Map<String, Object> variables = startProcessBo.getVariables();
+        // 娴佺▼鍙戣捣浜�
+        variables.put(INITIATOR, LoginHelper.getUserIdStr());
+        // 涓氬姟id
+        variables.put(BUSINESS_ID, businessId);
+        FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class)
+            .eq(FlowInstance::getBusinessId, businessId));
+        if (ObjectUtil.isNotNull(flowInstance)) {
+            BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus());
+            List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId()));
+            return Map.of(PROCESS_INSTANCE_ID, taskList.get(0).getInstanceId(), TASK_ID, taskList.get(0).getId());
+        }
+        FlowParams flowParams = new FlowParams();
+        flowParams.flowCode(startProcessBo.getFlowCode());
+        flowParams.variable(startProcessBo.getVariables());
+        flowParams.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
+        Instance instance;
+        try {
+            instance = insService.start(businessId, flowParams);
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+        // 鐢宠浜烘墽琛屾祦绋�
+        List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId()));
+        if (taskList.size() > 1) {
+            throw new ServiceException("璇锋鏌ユ祦绋嬬涓�涓幆鑺傛槸鍚︿负鐢宠浜猴紒");
+        }
+        return Map.of(PROCESS_INSTANCE_ID, instance.getId(), TASK_ID, taskList.get(0).getId());
+    }
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean completeTask(CompleteTaskBo completeTaskBo) {
+        try {
+            // 鑾峰彇浠诲姟ID骞舵煡璇㈠搴旂殑娴佺▼浠诲姟鍜屽疄渚嬩俊鎭�
+            Long taskId = completeTaskBo.getTaskId();
+            List<String> messageType = completeTaskBo.getMessageType();
+            String notice = completeTaskBo.getNotice();
+            // 鑾峰彇鎶勯�佷汉
+            List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
+            FlowTask flowTask = flowTaskMapper.selectById(taskId);
+            if (ObjectUtil.isNull(flowTask)) {
+                throw new ServiceException("娴佺▼浠诲姟涓嶅瓨鍦ㄦ垨浠诲姟宸插鎵癸紒");
+            }
+            Instance ins = insService.getById(flowTask.getInstanceId());
+            // 鑾峰彇娴佺▼瀹氫箟淇℃伅
+            Definition definition = defService.getById(flowTask.getDefinitionId());
+            // 妫�鏌ユ祦绋嬬姸鎬佹槸鍚︿负鑽夌銆佸凡鎾ら攢鎴栧凡閫�鍥炵姸鎬侊紝鑻ユ槸鍒欐墽琛屾祦绋嬫彁浜ょ洃鍚�
+            if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) {
+                flowProcessEventHandler.processHandler(definition.getFlowCode(), ins.getBusinessId(), ins.getFlowStatus(), true);
+            }
+            // 鏋勫缓娴佺▼鍙傛暟锛屽寘鎷彉閲忋�佽烦杞被鍨嬨�佹秷鎭�佸鐞嗕汉銆佹潈闄愮瓑淇℃伅
+            FlowParams flowParams = new FlowParams();
+            flowParams.variable(completeTaskBo.getVariables());
+            flowParams.skipType(SkipType.PASS.getKey());
+            flowParams.message(completeTaskBo.getMessage());
+            flowParams.flowStatus(BusinessStatusEnum.WAITING.getStatus()).hisStatus(TaskStatusEnum.PASS.getStatus());
+
+            flowParams.hisTaskExt(completeTaskBo.getFileId());
+            // 鎵ц浠诲姟璺宠浆锛屽苟鏍规嵁杩斿洖鐨勫鐞嗕汉璁剧疆涓嬩竴姝ュ鐞嗕汉
+            Instance instance = taskService.skip(taskId, flowParams);
+            this.setHandler(instance, flowTask, flowCopyList);
+            // 娑堟伅閫氱煡
+            WorkflowUtils.sendMessage(definition.getFlowName(), ins.getId(), messageType, notice);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 璁剧疆鍔炵悊浜�
+     *
+     * @param instance     瀹炰緥
+     * @param task         (褰撳墠浠诲姟)鏈姙鐞嗙殑浠诲姟
+     * @param flowCopyList 鎶勯�佷汉
+     */
+    private void setHandler(Instance instance, FlowTask task, List<FlowCopyBo> flowCopyList) {
+        if (ObjectUtil.isNull(instance)) {
+            return;
+        }
+        // 娣诲姞鎶勯�佷汉
+        this.setCopy(task, flowCopyList);
+        // 鏍规嵁娴佺▼瀹炰緥ID鏌ヨ鎵�鏈夊叧鑱旂殑浠诲姟
+        List<FlowTask> flowTasks = this.selectByInstId(instance.getId());
+        if (CollUtil.isEmpty(flowTasks)) {
+            return;
+        }
+        List<Long> taskIdList = StreamUtils.toList(flowTasks, FlowTask::getId);
+        // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃
+        List<User> associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList);
+        if (CollUtil.isEmpty(associatedUsers)) {
+            return;
+        }
+        List<User> userList = new ArrayList<>();
+        // 閬嶅巻浠诲姟鍒楄〃锛屽鐞嗘瘡涓换鍔$殑鍔炵悊浜�
+        for (FlowTask flowTask : flowTasks) {
+            List<User> users = StreamUtils.filter(associatedUsers, user -> Objects.equals(user.getAssociated(), flowTask.getId()));
+            if (CollUtil.isNotEmpty(users)) {
+                userList.addAll(WorkflowUtils.buildUser(users, flowTask.getId()));
+            }
+        }
+        // 鎵归噺鍒犻櫎鐜版湁浠诲姟鐨勫姙鐞嗕汉璁板綍
+        WorkflowUtils.getFlowUserService().deleteByTaskIds(taskIdList);
+        // 纭繚瑕佷繚瀛樼殑 userList 涓嶄负绌�
+        if (CollUtil.isEmpty(userList)) {
+            return;
+        }
+        WorkflowUtils.getFlowUserService().saveBatch(userList);
+    }
+
+    /**
+     * 娣诲姞鎶勯�佷汉
+     *
+     * @param task         浠诲姟淇℃伅
+     * @param flowCopyList 鎶勯�佷汉
+     */
+    public void setCopy(FlowTask task, List<FlowCopyBo> flowCopyList) {
+        if (CollUtil.isEmpty(flowCopyList)) {
+            return;
+        }
+        // 娣诲姞鎶勯�佷汉璁板綍
+        FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0);
+        FlowNode flowNode = new FlowNode();
+        flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
+        flowNode.setNodeName(flowHisTask.getTargetNodeName());
+        //鐢熸垚鏂扮殑浠诲姟id
+        long taskId = identifierGenerator.nextId(null).longValue();
+        task.setId(taskId);
+        task.setNodeName("銆愭妱閫併��" + task.getNodeName());
+        Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000);
+        FlowParams flowParams = FlowParams.build();
+        flowParams.skipType(SkipType.NONE.getKey());
+        flowParams.hisStatus(TaskStatusEnum.COPY.getStatus());
+        flowParams.message("銆愭妱閫佺粰銆�" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName));
+        HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams);
+        hisTask.setCreateTime(updateTime);
+        hisTask.setUpdateTime(updateTime);
+        hisTaskService.save(hisTask);
+        List<User> userList = flowCopyList.stream()
+            .map(flowCopy -> {
+                FlowUser flowUser = new FlowUser();
+                flowUser.setType(TaskAssigneeType.COPY.getCode());
+                flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId()));
+                flowUser.setAssociated(taskId);
+                return flowUser;
+            }).collect(Collectors.toList());
+        // 鎵归噺淇濆瓨鎶勯�佷汉鍛�
+        WorkflowUtils.getFlowUserService().saveBatch(userList);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
+        queryWrapper.in("t.processed_by", SpringUtils.getBean(WorkflowPermissionHandler.class).permissions());
+        queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus());
+        Page<FlowTaskVo> page = this.getFlowTaskVoPage(pageQuery, queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
+        queryWrapper.in("t.approver", LoginHelper.getUserIdStr());
+        queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
+        Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ寰呭姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
+        Page<FlowTaskVo> page = getFlowTaskVoPage(pageQuery, queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    private Page<FlowTaskVo> getFlowTaskVoPage(PageQuery pageQuery, QueryWrapper<FlowTaskBo> queryWrapper) {
+        Page<FlowTaskVo> page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper);
+        List<FlowTaskVo> records = page.getRecords();
+        if (CollUtil.isNotEmpty(records)) {
+            List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId);
+            Map<Long, List<UserDTO>> listMap = currentTaskAllUser(taskIds);
+            records.forEach(t -> {
+                List<UserDTO> userList = listMap.getOrDefault(t.getId(), Collections.emptyList());
+                if (CollUtil.isNotEmpty(userList)) {
+                    t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId())));
+                    t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName));
+                }
+            });
+        }
+        return page;
+    }
+
+    /**
+     * 鏌ヨ宸插姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
+        Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    private QueryWrapper<FlowTaskBo> buildQueryWrapper(FlowTaskBo flowTaskBo) {
+        QueryWrapper<FlowTaskBo> wrapper = Wrappers.query();
+        wrapper.like(StringUtils.isNotBlank(flowTaskBo.getNodeName()), "t.node_name", flowTaskBo.getNodeName());
+        wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowName()), "t.flow_name", flowTaskBo.getFlowName());
+        wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode());
+        wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds());
+        if (StringUtils.isNotBlank(flowTaskBo.getCategory())) {
+            List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
+            wrapper.in("t.category", categoryIds);
+        }
+        wrapper.orderByDesc("t.create_time");
+        return wrapper;
+    }
+
+    /**
+     * 椹冲洖浠诲姟
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean backProcess(BackProcessBo bo) {
+        try {
+            Long taskId = bo.getTaskId();
+            String notice = bo.getNotice();
+            List<String> messageType = bo.getMessageType();
+            String message = bo.getMessage();
+            FlowTask task = flowTaskMapper.selectById(taskId);
+            if (ObjectUtil.isNull(task)) {
+                throw new ServiceException("浠诲姟涓嶅瓨鍦紒");
+            }
+            Instance inst = insService.getById(task.getInstanceId());
+            BusinessStatusEnum.checkBackStatus(inst.getFlowStatus());
+            Long definitionId = task.getDefinitionId();
+            Definition definition = defService.getById(definitionId);
+            String applyNodeCode = WorkflowUtils.applyNodeCode(definitionId);
+            FlowParams flowParams = FlowParams.build();
+            flowParams.nodeCode(bo.getNodeCode());
+            flowParams.message(message);
+            flowParams.skipType(SkipType.REJECT.getKey());
+            flowParams.flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus())
+                .hisStatus(TaskStatusEnum.BACK.getStatus());
+            taskService.skip(task.getId(), flowParams);
+
+            Instance instance = insService.getById(inst.getId());
+            this.setHandler(instance, task, null);
+            // 娑堟伅閫氱煡
+            WorkflowUtils.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @param nowNodeCode  褰撳墠鑺傜偣
+     */
+    @Override
+    public List<Node> getBackTaskNode(Long definitionId, String nowNodeCode) {
+        List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId);
+        if (!CollUtil.isNotEmpty(nodeCodes)) {
+            return nodeCodes;
+        }
+        //鍒ゆ柇鏄惁閰嶇疆浜嗗浐瀹氶┏鍥炶妭鐐�
+        Node node = nodeCodes.get(0);
+        if (StringUtils.isNotBlank(node.getAnyNodeSkip())) {
+            return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId);
+        }
+        //鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣
+        List<Node> nodes = nodeService.previousNodeList(definitionId, nowNodeCode);
+        if (CollUtil.isNotEmpty(nodes)) {
+            return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
+        }
+        return nodes;
+    }
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean terminationTask(FlowTerminationBo bo) {
+        try {
+            Long taskId = bo.getTaskId();
+            Task task = taskService.getById(taskId);
+            if (task == null) {
+                throw new ServiceException("浠诲姟涓嶅瓨鍦紒");
+            }
+            Instance instance = insService.getById(task.getInstanceId());
+            if (ObjectUtil.isNotNull(instance)) {
+                BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
+            }
+            FlowParams flowParams = new FlowParams();
+            flowParams.message(bo.getComment());
+            flowParams.flowStatus(BusinessStatusEnum.TERMINATION.getStatus())
+                .hisStatus(TaskStatusEnum.TERMINATION.getStatus());
+            taskService.termination(taskId, flowParams);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskIdList 浠诲姟id
+     */
+    @Override
+    public List<FlowTask> selectByIdList(List<Long> taskIdList) {
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
+            .in(FlowTask::getId, taskIdList));
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public FlowTaskVo selectById(Long taskId) {
+        Task task = taskService.getById(taskId);
+        if (ObjectUtil.isNull(task)) {
+            return null;
+        }
+        FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class);
+        Instance instance = insService.getById(task.getInstanceId());
+        Definition definition = defService.getById(task.getDefinitionId());
+        flowTaskVo.setFlowStatus(instance.getFlowStatus());
+        flowTaskVo.setVersion(definition.getVersion());
+        flowTaskVo.setFlowCode(definition.getFlowCode());
+        flowTaskVo.setFlowName(definition.getFlowName());
+        flowTaskVo.setBusinessId(instance.getBusinessId());
+        List<Node> nodeList = nodeService.getByNodeCodes(Collections.singletonList(flowTaskVo.getNodeCode()), instance.getDefinitionId());
+        if (CollUtil.isNotEmpty(nodeList)) {
+            Node node = nodeList.get(0);
+            flowTaskVo.setNodeRatio(node.getNodeRatio());
+        }
+        return flowTaskVo;
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskIdList 浠诲姟id
+     * @return 缁撴灉
+     */
+    @Override
+    public List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList) {
+        return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class)
+            .in(FlowHisTask::getId, taskIdList));
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    @Override
+    public FlowHisTask selectHisTaskById(Long taskId) {
+        return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class)
+            .eq(FlowHisTask::getId, taskId));
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ浠诲姟
+     *
+     * @param instanceIdList 娴佺▼瀹炰緥id
+     */
+    @Override
+    public List<FlowTask> selectByInstIdList(List<Long> instanceIdList) {
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
+            .in(FlowTask::getInstanceId, instanceIdList));
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ浠诲姟
+     *
+     * @param instanceId 娴佺▼瀹炰緥id
+     */
+    @Override
+    public List<FlowTask> selectByInstId(Long instanceId) {
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
+            .eq(FlowTask::getInstanceId, instanceId));
+    }
+
+    /**
+     * 浠诲姟鎿嶄綔
+     *
+     * @param bo            鍙傛暟
+     * @param taskOperation 鎿嶄綔绫诲瀷锛屽娲� delegateTask銆佽浆鍔� transferTask銆佸姞绛� addSignature銆佸噺绛� reductionSignature
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
+        FlowParams flowParams = new FlowParams();
+        flowParams.message(bo.getMessage());
+        if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
+            flowParams.ignore(true);
+        }
+
+        // 鏍规嵁鎿嶄綔绫诲瀷鏋勫缓 FlowParams
+        switch (taskOperation) {
+            case DELEGATE_TASK, TRANSFER_TASK -> {
+                ValidatorUtils.validate(bo, AddGroup.class);
+                flowParams.addHandlers(Collections.singletonList(bo.getUserId()));
+            }
+            case ADD_SIGNATURE -> {
+                ValidatorUtils.validate(bo, EditGroup.class);
+                flowParams.addHandlers(bo.getUserIds());
+            }
+            case REDUCTION_SIGNATURE -> {
+                ValidatorUtils.validate(bo, EditGroup.class);
+                flowParams.reductionHandlers(bo.getUserIds());
+            }
+            default -> {
+                log.error("Invalid operation type:{} ", taskOperation);
+                throw new ServiceException("Invalid operation type " + taskOperation);
+            }
+        }
+
+        Long taskId = bo.getTaskId();
+        FlowTaskVo flowTaskVo = selectById(taskId);
+        if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) {
+            if (flowTaskVo.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
+                throw new ServiceException(flowTaskVo.getNodeName() + "涓嶆槸浼氱鑺傜偣锛�");
+            }
+        }
+        // 璁剧疆浠诲姟鐘舵�佸苟鎵ц瀵瑰簲鐨勪换鍔℃搷浣�
+        switch (taskOperation) {
+            //濮旀淳浠诲姟
+            case DELEGATE_TASK -> {
+                flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus());
+                return taskService.depute(taskId, flowParams);
+            }
+            //杞姙浠诲姟
+            case TRANSFER_TASK -> {
+                flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus());
+                return taskService.transfer(taskId, flowParams);
+            }
+            //鍔犵锛屽鍔犲姙鐞嗕汉
+            case ADD_SIGNATURE -> {
+                flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus());
+                return taskService.addSignature(taskId, flowParams);
+            }
+            //鍑忕锛屽噺灏戝姙鐞嗕汉
+            case REDUCTION_SIGNATURE -> {
+                flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus());
+                return taskService.reductionSignature(taskId, flowParams);
+            }
+            default -> {
+                log.error("Invalid operation type:{} ", taskOperation);
+                throw new ServiceException("Invalid operation type " + taskOperation);
+            }
+        }
+    }
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜猴紙姝ゆ柟娉曞皢浼氭壒閲忎慨鏀规墍鏈変换鍔$殑鍔炵悊浜猴級
+     *
+     * @param taskIdList 浠诲姟id
+     * @param userId     鐢ㄦ埛id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateAssignee(List<Long> taskIdList, String userId) {
+        if (CollUtil.isEmpty(taskIdList)) {
+            return false;
+        }
+        try {
+            List<FlowTask> flowTasks = this.selectByIdList(taskIdList);
+            // 鎵归噺鍒犻櫎鐜版湁浠诲姟鐨勫姙鐞嗕汉璁板綍
+            if (CollUtil.isNotEmpty(flowTasks)) {
+                WorkflowUtils.getFlowUserService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
+                List<User> userList = flowTasks.stream()
+                    .map(flowTask -> {
+                        FlowUser flowUser = new FlowUser();
+                        flowUser.setType(TaskAssigneeType.APPROVER.getCode());
+                        flowUser.setProcessedBy(userId);
+                        flowUser.setAssociated(flowTask.getId());
+                        return flowUser;
+                    })
+                    .collect(Collectors.toList());
+                if (CollUtil.isNotEmpty(userList)) {
+                    WorkflowUtils.getFlowUserService().saveBatch(userList);
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * 鑾峰彇浠诲姟鎵�鏈夊姙鐞嗕汉
+     *
+     * @param taskIdList 浠诲姟id
+     */
+    @Override
+    public Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList) {
+        Map<Long, List<UserDTO>> map = new HashMap<>();
+        // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃
+        List<User> associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList);
+        Map<Long, List<User>> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
+        for (Map.Entry<Long, List<User>> entry : listMap.entrySet()) {
+            List<User> value = entry.getValue();
+            if (CollUtil.isNotEmpty(value)) {
+                List<UserDTO> userDTOS = userService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy())));
+                map.put(entry.getKey(), userDTOS);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟鐨勬墍鏈夊姙鐞嗕汉
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public List<UserDTO> currentTaskAllUser(Long taskId) {
+        // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃
+        List<User> userList = WorkflowUtils.getFlowUserService().getByAssociateds(Collections.singletonList(taskId));
+        if (CollUtil.isEmpty(userList)) {
+            return Collections.emptyList();
+        }
+        return userService.selectListByIds(StreamUtils.toList(userList, e -> Long.valueOf(e.getProcessedBy())));
+    }
+}

--
Gitblit v1.9.3