Sfoglia il codice sorgente

add 增加下一节点执行人是当前任务处理人自动审批
fix 修复已完成的实例删除失败

may 11 mesi fa
parent
commit
2472359adb

+ 5 - 0
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java

@@ -83,4 +83,9 @@ public interface FlowConstant {
      */
     String WF_TASK_STATUS = "wf_task_status";
 
+    /**
+     * 自动通过
+     */
+    String AUTO_PASS = "autoPass";
+
 }

+ 10 - 0
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java

@@ -89,6 +89,16 @@ public class FlwInstanceController extends BaseController {
         return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds));
     }
 
+    /**
+     * 按照实例id删除已完成得流程实例
+     *
+     * @param instanceIds 实例id
+     */
+    @DeleteMapping("/deleteHisByInstanceIds/{instanceIds}")
+    public R<Void> deleteHisByInstanceIds(@PathVariable List<Long> instanceIds) {
+        return toAjax(flwInstanceService.deleteHisByInstanceIds(instanceIds));
+    }
+
     /**
      * 撤销流程
      *

+ 8 - 0
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java

@@ -85,6 +85,14 @@ public interface IFlwInstanceService {
      */
     boolean deleteByInstanceIds(List<Long> instanceIds);
 
+    /**
+     * 按照实例id删除已完成得流程实例
+     *
+     * @param instanceIds 删除的实例id
+     * @return 删除结果
+     */
+    boolean deleteHisByInstanceIds(List<Long> instanceIds);
+
     /**
      * 撤销流程
      *

+ 8 - 0
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java

@@ -165,6 +165,14 @@ public interface IFlwTaskService {
      */
     List<FlowTask> selectByInstId(Long instanceId);
 
+    /**
+     * 按照实例id查询任务
+     *
+     * @param instanceIds 列表
+     * @return 结果
+     */
+    List<FlowTask> selectByInstIds(List<Long> instanceIds);
+
     /**
      * 判断流程是否已结束(即该流程实例下是否还有未完成的任务)
      *

+ 63 - 10
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java

@@ -211,18 +211,71 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
             Function.identity()
         );
 
-        // 逐一触发删除事件
-        instances.forEach(instance -> {
-            Definition definition = definitionMap.get(instance.getDefinitionId());
-            if (ObjectUtil.isNull(definition)) {
-                log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
-                return;
+        try {
+            // 逐一触发删除事件
+            instances.forEach(instance -> {
+                Definition definition = definitionMap.get(instance.getDefinitionId());
+                if (ObjectUtil.isNull(definition)) {
+                    log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
+                    return;
+                }
+                flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
+            });
+            // 删除实例
+            boolean remove = insService.remove(instanceIds);
+            if (!remove) {
+                log.warn("删除流程实例失败!");
+                throw new ServiceException("删除流程实例失败");
             }
-            flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
-        });
+        } catch (Exception e) {
+            log.warn("操作失败!{}", e.getMessage());
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
+    }
 
-        // 删除实例
-        return insService.remove(instanceIds);
+    /**
+     * 按照实例id删除已完成的流程实例
+     *
+     * @param instanceIds 实例id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteHisByInstanceIds(List<Long> instanceIds) {
+        // 获取实例信息
+        List<Instance> instances = insService.getByIds(instanceIds);
+        if (CollUtil.isEmpty(instances)) {
+            log.warn("未找到对应的流程实例信息,无法执行删除操作。");
+            return false;
+        }
+        // 获取定义信息
+        Map<Long, Definition> definitionMap = StreamUtils.toMap(
+            defService.getByIds(StreamUtils.toList(instances, Instance::getDefinitionId)),
+            Definition::getId,
+            Function.identity()
+        );
+        try {
+            // 逐一触发删除事件
+            instances.forEach(instance -> {
+                Definition definition = definitionMap.get(instance.getDefinitionId());
+                if (ObjectUtil.isNull(definition)) {
+                    log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
+                    return;
+                }
+                flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
+            });
+            List<FlowTask> flowTaskList = flwTaskService.selectByInstIds(instanceIds);
+            if (CollUtil.isNotEmpty(flowTaskList)) {
+                FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTaskList, FlowTask::getId));
+            }
+            FlowEngine.taskService().deleteByInsIds(instanceIds);
+            FlowEngine.hisTaskService().deleteByInsIds(instanceIds);
+            FlowEngine.insService().removeByIds(instanceIds);
+        } catch (Exception e) {
+            log.warn("操作失败!{}", e.getMessage());
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
     }
 
     /**

+ 69 - 59
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java

@@ -3,6 +3,7 @@ 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.lang.Dict;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -21,6 +22,7 @@ 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.json.utils.JsonUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.satoken.utils.LoginHelper;
@@ -33,10 +35,7 @@ import org.dromara.warm.flow.core.service.*;
 import org.dromara.warm.flow.core.utils.ExpressionUtil;
 import org.dromara.warm.flow.core.utils.MapUtil;
 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.FlowNodeMapper;
-import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
+import org.dromara.warm.flow.orm.mapper.*;
 import org.dromara.workflow.common.ConditionalOnEnable;
 import org.dromara.workflow.common.constant.FlowConstant;
 import org.dromara.workflow.common.enums.TaskAssigneeType;
@@ -85,6 +84,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
     private final IFlwTaskAssigneeService flwTaskAssigneeService;
     private final IFlwCommonService flwCommonService;
     private final IFlwNodeExtService flwNodeExtService;
+    private final FlowDefinitionMapper flowDefinitionMapper;
 
     /**
      * 启动任务
@@ -167,6 +167,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
                 throw new ServiceException("流程任务不存在或任务已审批!");
             }
             Instance ins = insService.getById(flowTask.getInstanceId());
+            FlowDefinition flowDefinition = flowDefinitionMapper.selectOne(new LambdaQueryWrapper<>(FlowDefinition.class).eq(FlowDefinition::getId, ins.getDefinitionId()));
             // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听
             if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) {
                 completeTaskBo.getVariables().put(FlowConstant.SUBMIT, true);
@@ -177,15 +178,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
                 completeTaskBo.getVariables().putAll(assigneeMap);
             }
             // 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息
-            FlowParams flowParams = FlowParams.build()
-                .variable(completeTaskBo.getVariables())
-                .skipType(SkipType.PASS.getKey())
-                .message(completeTaskBo.getMessage())
-                .flowStatus(BusinessStatusEnum.WAITING.getStatus())
-                .hisStatus(TaskStatusEnum.PASS.getStatus())
-                .hisTaskExt(completeTaskBo.getFileId());
-            // 执行任务跳转,并根据返回的处理人设置下一步处理人
-            taskService.skip(taskId, flowParams);
+            FlowParams flowParams = FlowParams.build().variable(completeTaskBo.getVariables()).skipType(SkipType.PASS.getKey()).message(completeTaskBo.getMessage()).flowStatus(BusinessStatusEnum.WAITING.getStatus()).hisStatus(TaskStatusEnum.PASS.getStatus()).hisTaskExt(completeTaskBo.getFileId());
+            skipTask(taskId, flowParams, flowTask.getInstanceId(), flowDefinition);
             return true;
         } catch (Exception e) {
             log.error(e.getMessage(), e);
@@ -193,6 +187,45 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         }
     }
 
+    /**
+     * 流程办理
+     *
+     * @param taskId         任务ID
+     * @param flowParams     参数
+     * @param instanceId     实例ID
+     * @param flowDefinition 流程定义
+     */
+    private void skipTask(Long taskId, FlowParams flowParams, Long instanceId, FlowDefinition flowDefinition) {
+        // 执行任务跳转,并根据返回的处理人设置下一步处理人
+        taskService.skip(taskId, flowParams);
+        List<FlowTask> flowTaskList = selectByInstId(instanceId);
+        if (CollUtil.isEmpty(flowTaskList)) {
+            return;
+        }
+        List<User> userList = FlowEngine.userService().getByAssociateds(StreamUtils.toList(flowTaskList, FlowTask::getId));
+        if (CollUtil.isEmpty(userList)) {
+            return;
+        }
+        Dict dict = JsonUtils.parseMap(flowDefinition.getExt());
+        for (FlowTask task : flowTaskList) {
+            //自动审批
+            boolean autoPass = !ObjectUtil.isNull(dict) && cn.hutool.core.map.MapUtil.getBool(dict, AUTO_PASS);
+            if (!task.getId().equals(taskId) && autoPass) {
+                List<User> users = StreamUtils.filter(userList, e -> ObjectUtil.equals(task.getId(), e.getAssociated()) && ObjectUtil.equal(e.getProcessedBy(), LoginHelper.getUserIdStr()));
+                if (CollUtil.isEmpty(users)) {
+                    continue;
+                }
+                flowParams.
+                    message("流程引擎自动审批!").
+                    variable(Map.of(
+                        FlowConstant.SUBMIT, false,
+                        FlowConstant.FLOW_COPY_LIST, Collections.emptyList(),
+                        FlowConstant.MESSAGE_NOTICE, StringUtils.EMPTY));
+                skipTask(task.getId(), flowParams, instanceId, flowDefinition);
+            }
+        }
+    }
+
     /**
      * 设置弹窗处理人
      *
@@ -245,20 +278,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         task.setId(taskId);
         task.setNodeName("【抄送】" + task.getNodeName());
         Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000);
-        FlowParams flowParams = FlowParams.build()
-            .skipType(SkipType.NONE.getKey())
-            .hisStatus(TaskStatusEnum.COPY.getStatus())
-            .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName));
+        FlowParams flowParams = FlowParams.build().skipType(SkipType.NONE.getKey()).hisStatus(TaskStatusEnum.COPY.getStatus()).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 = StreamUtils.toList(flowCopyList, x ->
-            new FlowUser()
-                .setType(TaskAssigneeType.COPY.getCode())
-                .setProcessedBy(String.valueOf(x.getUserId()))
-                .setAssociated(taskId)
-        );
+        List<User> userList = StreamUtils.toList(flowCopyList, x -> new FlowUser().setType(TaskAssigneeType.COPY.getCode()).setProcessedBy(String.valueOf(x.getUserId())).setAssociated(taskId));
         // 批量保存抄送人员
         FlowEngine.userService().saveBatch(userList);
     }
@@ -320,8 +345,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         if (CollUtil.isEmpty(taskList)) {
             return;
         }
-        List<User> associatedUsers = FlowEngine.userService()
-            .getByAssociateds(StreamUtils.toList(taskList, FlowTaskVo::getId));
+        List<User> associatedUsers = FlowEngine.userService().getByAssociateds(StreamUtils.toList(taskList, FlowTaskVo::getId));
         Map<Long, List<User>> taskUserMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
         // 组装用户数据回任务列表
         for (FlowTaskVo task : taskList) {
@@ -399,14 +423,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
             // 消息通知
             variable.put("notice", notice);
 
-            FlowParams flowParams = FlowParams.build()
-                .nodeCode(bo.getNodeCode())
-                .variable(variable)
-                .message(message)
-                .skipType(SkipType.REJECT.getKey())
-                .flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus())
-                .hisStatus(TaskStatusEnum.BACK.getStatus())
-                .hisTaskExt(bo.getFileId());
+            FlowParams flowParams = FlowParams.build().nodeCode(bo.getNodeCode()).variable(variable).message(message).skipType(SkipType.REJECT.getKey()).flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()).hisStatus(TaskStatusEnum.BACK.getStatus()).hisTaskExt(bo.getFileId());
             taskService.skip(task.getId(), flowParams);
             return true;
         } catch (Exception e) {
@@ -458,10 +475,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
             if (ObjectUtil.isNotNull(instance)) {
                 BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
             }
-            FlowParams flowParams = FlowParams.build()
-                .message(bo.getComment())
-                .flowStatus(BusinessStatusEnum.TERMINATION.getStatus())
-                .hisStatus(TaskStatusEnum.TERMINATION.getStatus());
+            FlowParams flowParams = FlowParams.build().message(bo.getComment()).flowStatus(BusinessStatusEnum.TERMINATION.getStatus()).hisStatus(TaskStatusEnum.TERMINATION.getStatus());
             taskService.termination(taskId, flowParams);
             return true;
         } catch (Exception e) {
@@ -477,8 +491,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
      */
     @Override
     public List<FlowTask> selectByIdList(List<Long> taskIdList) {
-        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
-            .in(FlowTask::getId, taskIdList));
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).in(FlowTask::getId, taskIdList));
     }
 
     /**
@@ -535,9 +548,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
             //办理人变量替换
             ExpressionUtil.evalVariable(buildNextTaskList, FlowParams.build().variable(mergeVariable));
             for (FlowNode flowNode : nextFlowNodes) {
-                Optional<Task> first = buildNextTaskList.stream()
-                    .filter(t -> t.getNodeCode().equals(flowNode.getNodeCode()))
-                    .findFirst();
+                Optional<Task> first = buildNextTaskList.stream().filter(t -> t.getNodeCode().equals(flowNode.getNodeCode())).findFirst();
                 first.ifPresent(t -> {
                     if (CollUtil.isNotEmpty(t.getPermissionList())) {
                         List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList()));
@@ -559,8 +570,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
      */
     @Override
     public FlowHisTask selectHisTaskById(Long taskId) {
-        return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class)
-            .eq(FlowHisTask::getId, taskId));
+        return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getId, taskId));
     }
 
     /**
@@ -570,8 +580,17 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
      */
     @Override
     public List<FlowTask> selectByInstId(Long instanceId) {
-        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
-            .eq(FlowTask::getInstanceId, instanceId));
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).eq(FlowTask::getInstanceId, instanceId));
+    }
+
+    /**
+     * 按照实例id查询任务
+     *
+     * @param instanceIds 流程实例id
+     */
+    @Override
+    public List<FlowTask> selectByInstIds(List<Long> instanceIds) {
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).in(FlowTask::getInstanceId, instanceIds));
     }
 
     /**
@@ -582,8 +601,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
      */
     @Override
     public boolean isTaskEnd(Long instanceId) {
-        boolean exists = flowTaskMapper.exists(new LambdaQueryWrapper<FlowTask>()
-            .eq(FlowTask::getInstanceId, instanceId));
+        boolean exists = flowTaskMapper.exists(new LambdaQueryWrapper<FlowTask>().eq(FlowTask::getInstanceId, instanceId));
         return !exists;
     }
 
@@ -596,8 +614,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
-        FlowParams flowParams = FlowParams.build()
-            .message(bo.getMessage());
+        FlowParams flowParams = FlowParams.build().message(bo.getMessage());
         if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
             flowParams.ignore(true);
         }
@@ -676,12 +693,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
             // 批量删除现有任务的办理人记录
             if (CollUtil.isNotEmpty(flowTasks)) {
                 FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
-                List<User> userList = StreamUtils.toList(flowTasks, flowTask ->
-                    new FlowUser()
-                        .setType(TaskAssigneeType.APPROVER.getCode())
-                        .setProcessedBy(userId)
-                        .setAssociated(flowTask.getId())
-                );
+                List<User> userList = StreamUtils.toList(flowTasks, flowTask -> new FlowUser().setType(TaskAssigneeType.APPROVER.getCode()).setProcessedBy(userId).setAssociated(flowTask.getId()));
                 if (CollUtil.isNotEmpty(userList)) {
                     FlowEngine.userService().saveBatch(userList);
                 }
@@ -716,9 +728,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
      */
     @Override
     public FlowNode getByNodeCode(String nodeCode, Long definitionId) {
-        return flowNodeMapper.selectOne(new LambdaQueryWrapper<FlowNode>()
-            .eq(FlowNode::getNodeCode, nodeCode)
-            .eq(FlowNode::getDefinitionId, definitionId));
+        return flowNodeMapper.selectOne(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getNodeCode, nodeCode).eq(FlowNode::getDefinitionId, definitionId));
     }
 
     /**