Browse Source

流程优化

24282 1 năm trước cách đây
mục cha
commit
f3f1f76092

+ 11 - 0
hx-flow/src/main/java/com/fjhx/flow/core/FlowDelegate.java

@@ -3,6 +3,7 @@ package com.fjhx.flow.core;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import com.alibaba.fastjson.JSONObject;
+import com.fjhx.flow.enums.FlowStatusEnum;
 import com.ruoyi.common.utils.SecurityUtils;
 import lombok.extern.slf4j.Slf4j;
 
@@ -48,4 +49,14 @@ public abstract class FlowDelegate {
      */
     public abstract void end(Long flowId, Long businessId, JSONObject submitData);
 
+    /**
+     * 流程默认执行方法
+     *
+     * @param flowId         流程id
+     * @param businessId     业务id
+     * @param flowStatusEnum 流程状态
+     * @param submitData     流程入参
+     */
+    public abstract void defaultMethod(Long flowId, Long businessId, FlowStatusEnum flowStatusEnum, JSONObject submitData);
+
 }

+ 112 - 0
hx-flow/src/main/java/com/fjhx/flow/core/FlowJumpContext.java

@@ -0,0 +1,112 @@
+package com.fjhx.flow.core;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.fjhx.flow.entity.flow.dto.JumpDto;
+import com.fjhx.flow.entity.flow.po.FlowDefinitionNode;
+import com.fjhx.flow.entity.flow.po.FlowExample;
+import com.fjhx.flow.enums.FlowStatusEnum;
+import com.fjhx.flow.enums.HandleTypeEnum;
+import com.fjhx.flow.service.flow.FlowDefinitionNodeService;
+import com.fjhx.flow.service.flow.FlowExampleService;
+import com.ruoyi.common.exception.ServiceException;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Objects;
+
+@Getter
+@Setter
+public class FlowJumpContext {
+
+    public static final FlowExampleService flowExampleService = SpringUtil.getBean(FlowExampleService.class);
+    public static final FlowDefinitionNodeService flowDefinitionNodeService = SpringUtil.getBean(FlowDefinitionNodeService.class);
+
+    public FlowJumpContext(JumpDto dto) {
+
+        jumpDto = dto;
+
+        // 获取流程实例
+        flowExample = flowExampleService.getById(dto.getFlowId());
+        if (flowExample == null) {
+            throw new ServiceException("没有找到流程");
+        }
+        if (ObjectUtil.notEqual(flowExample.getVersion(), dto.getVersion())) {
+            throw new ServiceException("流程已被处理");
+        }
+
+        // 获取流程委托对象
+        flowDelegate = FlowBean.getBean(flowExample.getFlowKey());
+
+        // 获取流程节点列表
+        flowDefinitionNodeList = flowDefinitionNodeService.list(
+                q -> q.eq(FlowDefinitionNode::getFlowDefinitionId, flowExample.getDefinitionId()));
+
+        // 获取当前审批节点
+        FlowDefinitionNode tempCurrentNode = null;
+        for (FlowDefinitionNode flowDefinitionNode : flowDefinitionNodeList) {
+            if (Objects.equals(flowDefinitionNode.getId(), flowExample.getDefinitionNodeId())) {
+                tempCurrentNode = flowDefinitionNode;
+                break;
+            }
+        }
+        if (tempCurrentNode == null) {
+            throw new ServiceException("没有找到当前审批节点");
+        }
+        currentNode = tempCurrentNode;
+
+        // 查找跳转类型
+        handleTypeEnum = HandleTypeEnum.getEnum(dto.getHandleType());
+
+        // 跳转节点用户处理id
+        jumpHandleUserId = dto.getHandleUserId();
+
+    }
+
+    /**
+     * 流程提交参数
+     */
+    private final JumpDto jumpDto;
+
+    /**
+     * 流程实例
+     */
+    private final FlowExample flowExample;
+
+    /**
+     * 流程节点列表
+     */
+    private final List<FlowDefinitionNode> flowDefinitionNodeList;
+
+    /**
+     * 当前审批节点
+     */
+    private final FlowDefinitionNode currentNode;
+
+    /**
+     * 跳转类型
+     */
+    private final HandleTypeEnum handleTypeEnum;
+
+    /**
+     * 流程委托对象
+     */
+    private final FlowDelegate flowDelegate;
+
+    /**
+     * 跳转节点
+     */
+    private FlowDefinitionNode jumpNode;
+
+    /**
+     * 跳转节点处理用户id
+     */
+    private Long jumpHandleUserId;
+
+    /**
+     * 流程当前状态
+     */
+    private FlowStatusEnum flowStatusEnum;
+
+}

+ 17 - 0
hx-flow/src/main/java/com/fjhx/flow/core/FlowThreadLocalUtil.java

@@ -1,6 +1,7 @@
 package com.fjhx.flow.core;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fjhx.flow.enums.FlowStatusEnum;
 import com.fjhx.flow.enums.HandleTypeEnum;
 import org.springframework.core.NamedThreadLocal;
 
@@ -45,6 +46,11 @@ public class FlowThreadLocalUtil {
     private HandleTypeEnum handleTypeEnum;
 
     /**
+     * 流程状态
+     */
+    private FlowStatusEnum flowStatusEnum;
+
+    /**
      * 下个节点审批用户id
      */
     private Long nextHandleUserId;
@@ -124,6 +130,17 @@ public class FlowThreadLocalUtil {
     }
 
     // ===================================================
+    //  流程状态
+    // ===================================================
+    public static FlowStatusEnum getFlowStatusEnum() {
+        return getData().flowStatusEnum;
+    }
+
+    public static void setFlowStatusEnum(FlowStatusEnum flowStatusEnum) {
+        getData().flowStatusEnum = flowStatusEnum;
+    }
+
+    // ===================================================
     //  下个节点审批用户id
     // ===================================================
     public static Long getNextHandleUserId() {

+ 8 - 0
hx-flow/src/main/java/com/fjhx/flow/entity/flow/dto/FlowResult.java

@@ -10,6 +10,14 @@ import java.util.List;
 @Setter
 public class FlowResult {
 
+    public FlowResult() {
+
+    }
+
+    public FlowResult(Boolean success) {
+        this.success = success;
+    }
+
     /**
      * 1成功 0失败
      */

+ 5 - 1
hx-flow/src/main/java/com/fjhx/flow/entity/flow/dto/JumpDto.java

@@ -23,11 +23,15 @@ public class JumpDto {
      * 1跳转下一节点
      * 2返回上一节点
      * 3结束流程
+     * 4退回到发起人
      */
     @NotNull(message = "跳转节点不能为空")
     private Integer handleType;
 
-    @NotNull(message = "实例版本不能为空")
+    /**
+     * 流程实例版本
+     */
+    @NotNull(message = "流程实例版本不能为空")
     private Integer version;
 
     /**

+ 1 - 1
hx-flow/src/main/java/com/fjhx/flow/enums/HandleTypeEnum.java

@@ -32,7 +32,7 @@ public enum HandleTypeEnum {
     public static HandleTypeEnum getEnum(Integer key) {
         HandleTypeEnum handleTypeEnum = map.get(key);
         if (handleTypeEnum == null) {
-            throw new ServiceException("未知处理方法");
+            throw new ServiceException("未知流程跳转类型");
         }
         return handleTypeEnum;
     }

+ 293 - 217
hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowProcessServiceImpl.java

@@ -1,7 +1,6 @@
 package com.fjhx.flow.service.flow.impl;
 
 import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
@@ -11,6 +10,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fjhx.file.utils.ObsFileUtil;
 import com.fjhx.flow.core.FlowBean;
 import com.fjhx.flow.core.FlowDelegate;
+import com.fjhx.flow.core.FlowJumpContext;
 import com.fjhx.flow.core.FlowThreadLocalUtil;
 import com.fjhx.flow.entity.flow.dto.FlowResult;
 import com.fjhx.flow.entity.flow.dto.InitiateDto;
@@ -96,7 +96,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
                 .findFirst().orElse(null);
 
         if (startNode == null) {
-            throw new ServiceException("没有找到开始节点");
+            throw new ServiceException("流程定义错误:没有找到开始节点");
         }
 
         // 生成流程id
@@ -108,6 +108,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         FlowThreadLocalUtil.setStartData(dto.getData());
         FlowThreadLocalUtil.setCurrentData(dto.getData());
         FlowThreadLocalUtil.setFlowId(flowId);
+        FlowThreadLocalUtil.setHandleTypeEnum(HandleTypeEnum.SKIP_TO_NEXT);
 
         // 寻找下一节点
         FlowDefinitionNode nextUserNode = getNextUserNode(startNode, flowDefinitionNodeList);
@@ -131,9 +132,11 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             }
             // 流程进行中
             flowExample.setStatus(FlowStatusEnum.IN_PROGRESS.getKey());
+            FlowThreadLocalUtil.setFlowStatusEnum(FlowStatusEnum.IN_PROGRESS);
         } else {
             // 流程已通过
             flowExample.setStatus(FlowStatusEnum.PASS.getKey());
+            FlowThreadLocalUtil.setFlowStatusEnum(FlowStatusEnum.PASS);
         }
 
         // 执行开始流程方法
@@ -190,213 +193,74 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         ObsFileUtil.saveFile(dto.getFileList(), startExampleDetail.getId());
 
         // 推送
-        pushInitiate(flowId, flowDefinition, nextNodeType, flowExample);
+        pushInitiateMessage(flowId, flowDefinition, nextNodeType, flowExample);
 
-        FlowResult flowResult = new FlowResult();
-        flowResult.setSuccess(true);
-        return flowResult;
+        return new FlowResult(true);
     }
 
     @DSTransactional
     @Override
     public FlowResult jump(JumpDto dto) {
-        Long flowId = dto.getFlowId();
 
-        FlowExample flowExample = flowExampleService.getById(flowId);
-
-        if (flowExample == null) {
-            throw new ServiceException("没有找到流程");
-        }
-
-        // if (flowExample.getStatus() > 1) {
-        //     throw new ServiceException("流程已结束");
-        // }
-
-        if (ObjectUtil.notEqual(flowExample.getVersion(), dto.getVersion())) {
-            throw new ServiceException("流程已被处理");
-        }
-
-        // 获取流程委托对象
-        FlowDelegate flowDelegate = FlowBean.getBean(flowExample.getFlowKey());
-
-        // 流程节点列表
-        List<FlowDefinitionNode> flowDefinitionNodeList = flowDefinitionNodeService.list(q -> q
-                .eq(FlowDefinitionNode::getFlowDefinitionId, flowExample.getDefinitionId()));
-
-        // 获取当前审批节点
-        FlowDefinitionNode currentNode = flowDefinitionNodeList.stream()
-                .filter(item -> item.getId().equals(flowExample.getDefinitionNodeId()))
-                .findFirst().orElse(null);
-
-        if (currentNode == null) {
-            throw new ServiceException("没有找到当前审批节点");
-        }
-
-        // 查找跳转类型
-        HandleTypeEnum handleTypeEnum = HandleTypeEnum.getEnum(dto.getHandleType());
+        FlowJumpContext context = new FlowJumpContext(dto);
 
         // 发起流程参数
-        JSONObject startData = JSONObject.parseObject(flowExample.getStartData());
-        Map<String, Object> templateMap = flowDelegate.initTemplateMap(dto.getData(), startData);
+        JSONObject startData = JSONObject.parseObject(context.getFlowExample().getStartData());
+        Map<String, Object> templateMap = context.getFlowDelegate().initTemplateMap(dto.getData(), startData);
         FlowThreadLocalUtil.setTemplateData(templateMap);
         FlowThreadLocalUtil.setStartData(startData);
         FlowThreadLocalUtil.setCurrentData(dto.getData());
-        FlowThreadLocalUtil.setFlowId(flowId);
-        FlowThreadLocalUtil.setBusinessId(flowExample.getBusinessId());
-        FlowThreadLocalUtil.setHandleTypeEnum(handleTypeEnum);
+        FlowThreadLocalUtil.setFlowId(dto.getFlowId());
+        FlowThreadLocalUtil.setBusinessId(context.getFlowExample().getBusinessId());
 
-        // 跳转节点
-        FlowDefinitionNode nextUserNode = null;
-        switch (handleTypeEnum) {
+        FlowResult flowResult;
+
+        // 流程处理逻辑
+        switch (context.getHandleTypeEnum()) {
 
             // 跳转下一节点
             case SKIP_TO_NEXT:
-
-                // 寻找下一节点
-                nextUserNode = getNextUserNode(currentNode, flowDefinitionNodeList);
-
-                // 赋值流程所在id
-                flowExample.setDefinitionNodeId(nextUserNode.getId());
-
-                // 如果下一节点为结束节点
-                if (NodeTypeEnum.END.equals(NodeTypeEnum.getEnum(nextUserNode.getNodeType()))) {
-                    // 流程已通过
-                    flowExample.setStatus(FlowStatusEnum.PASS.getKey());
-                }
-                // 如果下一节点不为结束节点
-                else {
-                    FlowResult handleUser = getHandleUser(nextUserNode, dto.getHandleUserId());
-
-                    // 如果下一节点处理用户只有1人,赋值用户id
-                    if (handleUser.getSuccess()) {
-                        flowExample.setHandleUserId(handleUser.getUserId());
-                        FlowThreadLocalUtil.setNextHandleUserId(handleUser.getUserId());
-                    }
-                    // 如果下一节点处理用户有多人,则返回用户列表让用户选择下一节点处理人id
-                    else {
-                        return handleUser;
-                    }
-
-                    // 流程进行中
-                    flowExample.setStatus(FlowStatusEnum.IN_PROGRESS.getKey());
-                }
+                flowResult = skipToNext(context);
                 break;
 
             // 结束流程
             case REJECT:
-                flowExample.setStatus(FlowStatusEnum.REJECT.getKey());
+                flowResult = reject(context);
                 break;
 
             // 返回上一节点
             case RETURN_TO_PREVIOUS:
-
-                // 查找上一个节点
-                FlowDefinitionNode lastOneUserNode = getLastOneUserNode(currentNode, flowDefinitionNodeList);
-
-                // 赋值流程所在id
-                flowExample.setDefinitionNodeId(lastOneUserNode.getId());
-
-                // 如果流程回退到开始节点
-                if (NodeTypeEnum.START.getKey().equals(lastOneUserNode.getNodeType())) {
-                    // 流程未发起
-                    flowExample.setStatus(FlowStatusEnum.READY_START.getKey());
-                } else {
-                    FlowResult handleUser = getHandleUser(lastOneUserNode, dto.getHandleUserId());
-
-                    // 如果上一节点处理用户只有1人,赋值用户id
-                    if (handleUser.getSuccess()) {
-                        flowExample.setHandleUserId(handleUser.getUserId());
-                        FlowThreadLocalUtil.setNextHandleUserId(handleUser.getUserId());
-                    }
-                    // 如果下一节点处理用户有多人,则返回用户列表让用户选择上一节点处理人id
-                    else {
-                        return handleUser;
-                    }
-
-                    // 流程进行中
-                    flowExample.setStatus(FlowStatusEnum.IN_PROGRESS.getKey());
-                }
+                flowResult = returnToPrevious(context);
                 break;
 
             // 退回到发起人
             case RETURN_TO_SUBMITTER:
-
-                // 获取第一个用户操作节点
-                FlowExampleDetail exampleDetail = flowExampleDetailService.getOne(q -> q
-                        .eq(FlowExampleDetail::getFlowExampleId, flowId));
-
-                flowExample.setHandleUserId(exampleDetail.getCreateUser());
-                flowExample.setDefinitionNodeId(exampleDetail.getFlowDefinitionNodeId());
-                flowExample.setStatus(FlowStatusEnum.READY_START.getKey());
-                FlowThreadLocalUtil.setNextHandleUserId(exampleDetail.getCreateUser());
+                flowResult = returnToSubmitter(context);
                 break;
 
             default:
-                throw new ServiceException("未知节点处理类型");
-
-        }
+                throw new ServiceException("未知流程跳转类型");
 
-        // 执行当前节点方法
-        String handlingMethod = currentNode.getHandlingMethod();
-        if (StrUtil.isNotBlank(handlingMethod)) {
-            try {
-                invokeMethod(flowDelegate, handlingMethod);
-            } catch (Exception e) {
-                if (e instanceof InvocationTargetException) {
-                    Throwable targetException = ((InvocationTargetException) e).getTargetException();
-                    log.error("跳转节点方法异常", targetException);
-                    throw new ServiceException("跳转节点方法异常:" + targetException.getMessage());
-                }
-                log.error("跳转节点方法异常", e);
-                throw new ServiceException("跳转节点方法异常:" + e.getMessage());
-            }
         }
 
-        // 节点处理明细
-        List<FlowExampleDetail> flowExampleDetailList = new ArrayList<>();
-        FlowExampleDetail nodeExampleDetail = new FlowExampleDetail();
-        nodeExampleDetail.setFlowExampleId(flowId);
-        nodeExampleDetail.setFlowDefinitionNodeId(currentNode.getId());
-        nodeExampleDetail.setFlowDefinitionNodeType(currentNode.getNodeType());
-        nodeExampleDetail.setHandleType(dto.getHandleType());
-        nodeExampleDetail.setHandleRemark(dto.getRemark());
-        nodeExampleDetail.setSubmitData(JSONObject.toJSONString(dto));
-        flowExampleDetailList.add(nodeExampleDetail);
-
-        // 如果流程已结束
-        if (FlowStatusEnum.PASS.getKey().equals(flowExample.getStatus())) {
-
-            // 执行结束方法
-            invokeEndMethod(nextUserNode, flowDelegate);
-
-            // 结束流程明细
-            FlowExampleDetail endExampleDetail = new FlowExampleDetail();
-            endExampleDetail.setFlowExampleId(flowId);
-            endExampleDetail.setFlowDefinitionNodeId(nextUserNode.getId());
-            endExampleDetail.setFlowDefinitionNodeType(nextUserNode.getNodeType());
-            endExampleDetail.setHandleType(HandleTypeEnum.SKIP_TO_NEXT.getKey());
-            flowExampleDetailList.add(endExampleDetail);
-
+        // 如果跳转节点审批人有多个,则返回用户列表让当前节点审批人选择下一节点审批人id
+        if (!flowResult.getSuccess()) {
+            return flowResult;
         }
 
-        flowExample.setVersion(dto.getVersion());
+        FlowThreadLocalUtil.setFlowStatusEnum(context.getFlowStatusEnum());
+        FlowThreadLocalUtil.setHandleTypeEnum(context.getHandleTypeEnum());
+        FlowThreadLocalUtil.setNextHandleUserId(context.getJumpHandleUserId());
 
-        // 不修改发起数据
-        flowExample.setStartData(null);
-        boolean updateFlag = flowExampleService.updateById(flowExample);
-        if (!updateFlag) {
-            throw new ServiceException("流程已被处理");
-        }
-        flowExampleDetailService.saveBatch(flowExampleDetailList);
+        // 执行节点方法
+        executiveNodeMethod(context);
 
-        // 保存节点附件
-        ObsFileUtil.saveFile(dto.getFileList(), nodeExampleDetail.getId());
+        // 保存数据
+        editExample(context);
 
         // 消息推送
-        pushJump(handleTypeEnum, nextUserNode, flowExample, currentNode);
+        pushJumpMessage(context);
 
-        FlowResult flowResult = new FlowResult();
-        flowResult.setSuccess(true);
         return flowResult;
     }
 
@@ -413,15 +277,151 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     }
 
     /**
+     * 流程跳转到下一个节点
+     */
+    private FlowResult skipToNext(FlowJumpContext context) {
+
+        // 寻找跳转节点
+        FlowDefinitionNode jumpNode = getNextUserNode(context.getCurrentNode(), context.getFlowDefinitionNodeList());
+        context.setJumpNode(jumpNode);
+
+        // 如果下一节点为结束节点
+        if (NodeTypeEnum.END.equals(NodeTypeEnum.getEnum(jumpNode.getNodeType()))) {
+            // 流程已通过
+            context.setFlowStatusEnum(FlowStatusEnum.PASS);
+            // 流程结束,则流程节点审批人不存在
+            context.setJumpHandleUserId(null);
+            return new FlowResult(true);
+        }
+
+        // 寻找节点审批人
+        FlowResult flowResult = getHandleUser(jumpNode, context.getJumpHandleUserId());
+        // 流程进行中
+        context.setFlowStatusEnum(FlowStatusEnum.IN_PROGRESS);
+        // 赋值流程节点审批人
+        context.setJumpHandleUserId(flowResult.getUserId());
+
+        return flowResult;
+    }
+
+    /**
+     * 拒绝流程
+     */
+    private FlowResult reject(FlowJumpContext context) {
+
+        // 流程已驳回
+        context.setFlowStatusEnum(FlowStatusEnum.REJECT);
+        // 流程结束,则流程节点审批人不存在
+        context.setJumpHandleUserId(null);
+
+        for (FlowDefinitionNode flowDefinitionNode : context.getFlowDefinitionNodeList()) {
+            if (NodeTypeEnum.END.getKey().equals(flowDefinitionNode.getNodeType())) {
+                context.setJumpNode(flowDefinitionNode);
+                return new FlowResult(true);
+            }
+        }
+
+        throw new ServiceException("流程定义错误:未找到结束节点");
+    }
+
+    /**
+     * 流程跳转到上一个节点
+     */
+    private FlowResult returnToPrevious(FlowJumpContext context) {
+
+        // 寻找跳转节点
+        FlowDefinitionNode jumpNode = getLastOneUserNode(context.getCurrentNode(), context.getFlowDefinitionNodeList());
+        context.setJumpNode(jumpNode);
+
+        // 如果流程回退到开始节点
+        if (NodeTypeEnum.START.getKey().equals(jumpNode.getNodeType())) {
+            // 流程未发起
+            context.setFlowStatusEnum(FlowStatusEnum.READY_START);
+            // 流程节点处理人为流程发起人
+            context.setJumpHandleUserId(context.getFlowExample().getCreateUser());
+            return new FlowResult(true);
+        }
+
+        FlowResult flowResult = getHandleUser(jumpNode, context.getJumpHandleUserId());
+        // 流程进行中
+        context.setFlowStatusEnum(FlowStatusEnum.IN_PROGRESS);
+        // 赋值流程节点审批人
+        context.setJumpHandleUserId(flowResult.getUserId());
+
+        return flowResult;
+    }
+
+    /**
+     * 退回到发起人
+     */
+    private FlowResult returnToSubmitter(FlowJumpContext context) {
+
+        // 流程未发起
+        context.setFlowStatusEnum(FlowStatusEnum.READY_START);
+        // 赋值发起人为节点审批人
+        context.setJumpHandleUserId(context.getFlowExample().getCreateUser());
+
+        for (FlowDefinitionNode flowDefinitionNode : context.getFlowDefinitionNodeList()) {
+            if (NodeTypeEnum.START.getKey().equals(flowDefinitionNode.getNodeType())) {
+                context.setJumpNode(flowDefinitionNode);
+                return new FlowResult(true);
+            }
+        }
+
+        throw new ServiceException("流程定义错误:未找到开始节点");
+    }
+
+    /**
      * 执行节点方法
-     *
-     * @param flowDelegate   流程代理对象
-     * @param handlingMethod 流程执行方法名
      */
-    private void invokeMethod(FlowDelegate flowDelegate, String handlingMethod) throws Exception {
-        Class<? extends FlowDelegate> flowDelegateCls = flowDelegate.getClass();
-        Method method = flowDelegateCls.getMethod(handlingMethod.trim());
-        method.invoke(flowDelegate);
+    private void executiveNodeMethod(FlowJumpContext context) {
+
+        // 当前节点方法
+        String handlingMethod = context.getCurrentNode().getHandlingMethod();
+
+        // 流程委托对象
+        FlowDelegate flowDelegate = context.getFlowDelegate();
+
+        // 流程状态
+        FlowStatusEnum flowStatusEnum = context.getFlowStatusEnum();
+
+        // 自定义方法不为空,走自定义方法
+        if (StrUtil.isNotBlank(handlingMethod)) {
+            try {
+                invokeMethod(flowDelegate, handlingMethod);
+            } catch (Exception e) {
+                if (e instanceof InvocationTargetException) {
+                    Throwable targetException = ((InvocationTargetException) e).getTargetException();
+                    log.error("跳转节点方法异常", targetException);
+                    throw new ServiceException("跳转节点方法异常:" + targetException.getMessage());
+                }
+                log.error("跳转节点方法异常", e);
+                throw new ServiceException("跳转节点方法异常:" + e.getMessage());
+            }
+        }
+
+        // 执行默认方法
+        else {
+            try {
+                FlowExample flowExample = context.getFlowExample();
+                Long flowId = flowExample.getId();
+                Long businessId = flowExample.getBusinessId();
+
+                JSONObject data = context.getJumpDto().getData();
+
+                flowDelegate.defaultMethod(flowId, businessId, flowStatusEnum, data);
+            } catch (Exception e) {
+
+                log.error("跳转节点方法异常", e);
+                throw new ServiceException("跳转节点方法异常:" + e.getMessage());
+            }
+        }
+
+        // 结束节点
+        if (flowStatusEnum == FlowStatusEnum.PASS) {
+            invokeEndMethod(context.getJumpNode(), flowDelegate);
+        }
+
     }
 
     /**
@@ -456,6 +456,64 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     }
 
     /**
+     * 执行节点方法
+     *
+     * @param flowDelegate   流程代理对象
+     * @param handlingMethod 流程执行方法名
+     */
+    private void invokeMethod(FlowDelegate flowDelegate, String handlingMethod) throws Exception {
+        Class<? extends FlowDelegate> flowDelegateCls = flowDelegate.getClass();
+        Method method = flowDelegateCls.getMethod(handlingMethod.trim());
+        method.invoke(flowDelegate);
+    }
+
+    /**
+     * 保存数据
+     */
+    private void editExample(FlowJumpContext context) {
+
+        JumpDto dto = context.getJumpDto();
+        FlowExample flowExample = context.getFlowExample();
+        FlowDefinitionNode currentNode = context.getCurrentNode();
+        FlowDefinitionNode jumpNode = context.getJumpNode();
+
+        // 更新流程实例
+        flowExample.setStartData(null);
+        boolean updateFlag = flowExampleService.updateById(flowExample);
+        if (!updateFlag) {
+            throw new ServiceException("流程已被处理");
+        }
+
+        // 节点处理明细
+        List<FlowExampleDetail> flowExampleDetailList = new ArrayList<>();
+        FlowExampleDetail nodeExampleDetail = new FlowExampleDetail();
+        nodeExampleDetail.setFlowExampleId(flowExample.getId());
+        nodeExampleDetail.setFlowDefinitionNodeId(currentNode.getId());
+        nodeExampleDetail.setFlowDefinitionNodeType(currentNode.getNodeType());
+        nodeExampleDetail.setHandleType(dto.getHandleType());
+        nodeExampleDetail.setHandleRemark(dto.getRemark());
+        nodeExampleDetail.setSubmitData(JSONObject.toJSONString(dto));
+        flowExampleDetailList.add(nodeExampleDetail);
+
+        // 如果流程已结束
+        if (FlowStatusEnum.PASS.equals(context.getFlowStatusEnum())) {
+            FlowExampleDetail endExampleDetail = new FlowExampleDetail();
+            endExampleDetail.setFlowExampleId(flowExample.getId());
+            endExampleDetail.setFlowDefinitionNodeId(jumpNode.getId());
+            endExampleDetail.setFlowDefinitionNodeType(jumpNode.getNodeType());
+            endExampleDetail.setHandleType(HandleTypeEnum.SKIP_TO_NEXT.getKey());
+            flowExampleDetailList.add(endExampleDetail);
+        }
+
+        // 保存流程明细
+        flowExampleDetailService.saveBatch(flowExampleDetailList);
+
+        // 保存节点附件
+        ObsFileUtil.saveFile(dto.getFileList(), nodeExampleDetail.getId());
+
+    }
+
+    /**
      * 查找上一个节点
      *
      * @param currentNode            当前节点
@@ -486,12 +544,15 @@ public class FlowProcessServiceImpl implements FlowProcessService {
      * @return 用户节点
      */
     private FlowDefinitionNode getNextUserNode(FlowDefinitionNode currentNode, List<FlowDefinitionNode> flowDefinitionNodeList) {
+
         // 父级节点map
-        Map<Long, List<FlowDefinitionNode>> parentNodeMap =
-                flowDefinitionNodeList.stream().collect(Collectors.groupingBy(FlowDefinitionNode::getParentId));
+        Map<Long, List<FlowDefinitionNode>> parentNodeMap = flowDefinitionNodeList.stream()
+                .collect(Collectors.groupingBy(FlowDefinitionNode::getParentId));
+
         // 查找下个节点
         List<FlowDefinitionNode> nextNodeList = parentNodeMap.get(currentNode.getId());
         FlowDefinitionNode nextNode = null;
+
         // 如果为分支
         if (NodeTypeEnum.BRANCH.equals(NodeTypeEnum.getEnum(currentNode.getNodeType()))) {
             // 循环分支
@@ -509,21 +570,27 @@ public class FlowProcessServiceImpl implements FlowProcessService {
                 }
             }
             if (nextNode == null) {
-                throw new ServiceException("未识别到分支跳转节点");
+                throw new ServiceException("流程定义错误:分支节点未识别到有效跳转节点");
             }
         }
+
         // 如果不为分支
         else {
-            if (nextNodeList == null || nextNodeList.size() != 1) {
-                throw new ServiceException("流程定义错误");
+            if (nextNodeList == null || nextNodeList.size() == 0) {
+                throw new ServiceException("流程定义错误:用户节点未找到跳转节点");
+            }
+            if (nextNodeList.size() > 1) {
+                throw new ServiceException("流程定义错误:用户节点找到多个跳转节点");
             }
             // 查找下一个节点方法
             nextNode = nextNodeList.get(0);
         }
+
         // 如果下一节点为分支,递归找下一节点
         if (NodeTypeEnum.BRANCH.equals(NodeTypeEnum.getEnum(nextNode.getNodeType()))) {
             return getNextUserNode(nextNode, flowDefinitionNodeList);
         }
+
         return nextNode;
     }
 
@@ -558,13 +625,13 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             case DEPT_DIRECTOR:
                 SysDept sysDept = sysDeptService.getById(handleObjectId);
                 if (sysDept == null) {
-                    throw new ServiceException("部门为空");
+                    throw new ServiceException("流程节点处理人异常:没有找到节点处理部门");
                 }
                 // 部门负责人
                 if (HandleObjectTypeEnum.DETP_LEADER.equals(handleObjectTypeEnum)) {
                     Long leaderId = sysDept.getLeaderId();
                     if (leaderId == null) {
-                        throw new ServiceException("部门负责人为空");
+                        throw new ServiceException("流程节点处理人异常:没有找到节点处理部门负责人");
                     }
                     flowResult.setUserId(leaderId);
                 }
@@ -572,7 +639,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
                 else {
                     Long directorId = sysDept.getDirectorId();
                     if (directorId == null) {
-                        throw new ServiceException("部门总监为空");
+                        throw new ServiceException("流程节点处理人异常:没有找到节点处理部门总监");
                     }
                     flowResult.setUserId(directorId);
                 }
@@ -582,7 +649,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             case POST:
                 List<SysUser> postUserList = sysUserService.getListByPostId(handleObjectId);
                 if (postUserList.size() == 0) {
-                    throw new ServiceException("岗位无用户");
+                    throw new ServiceException("流程节点处理人异常:节点处理岗位无用户");
                 }
                 if (postUserList.size() == 1) {
                     flowResult.setSuccess(true);
@@ -596,7 +663,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             case ROLE:
                 List<SysUser> roleUserList = sysUserService.getListByRoleId(handleObjectId);
                 if (roleUserList.size() == 0) {
-                    throw new ServiceException("角色无用户");
+                    throw new ServiceException("流程节点处理人异常:节点处理角色无用户");
                 }
                 if (roleUserList.size() == 1) {
                     flowResult.setSuccess(true);
@@ -614,23 +681,9 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     }
 
     /**
-     * 校验el表达式
-     */
-    public boolean expressionResult(Map<String, Object> map, String expression) {
-        try {
-            Expression exp = AviatorEvaluator.compile(expression);
-            Object execute = exp.execute(map);
-            return Boolean.parseBoolean(String.valueOf(execute));
-        } catch (Exception e) {
-            log.error("el表达式校验错误", e);
-            throw new ServiceException("el表达式校验错误:" + e.getMessage());
-        }
-    }
-
-    /**
      * 开始节点消息推送
      */
-    private void pushInitiate(long flowId, FlowDefinition flowDefinition, NodeTypeEnum nextNodeType, FlowExample flowExample) {
+    private void pushInitiateMessage(long flowId, FlowDefinition flowDefinition, NodeTypeEnum nextNodeType, FlowExample flowExample) {
         Map<String, Object> businessData = new HashMap<>();
         businessData.put("flowId", flowId);
         businessData.put("flowKey", flowDefinition.getFlowKey());
@@ -654,7 +707,15 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     /**
      * 跳转节点消息推送
      */
-    private void pushJump(HandleTypeEnum handleTypeEnum, FlowDefinitionNode nextUserNode, FlowExample flowExample, FlowDefinitionNode currentNode) {
+    private void pushJumpMessage(FlowJumpContext context) {
+
+        FlowExample flowExample = context.getFlowExample();
+        HandleTypeEnum handleTypeEnum = context.getHandleTypeEnum();
+        FlowStatusEnum flowStatusEnum = context.getFlowStatusEnum();
+        FlowDefinitionNode jumpNode = context.getJumpNode();
+        FlowDefinitionNode currentNode = context.getCurrentNode();
+        Long jumpHandleUserId = context.getJumpHandleUserId();
+
         Map<String, Object> businessData = new HashMap<>();
         businessData.put("flowId", flowExample.getId());
         businessData.put("flowKey", flowExample.getFlowKey());
@@ -668,8 +729,8 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         switch (handleTypeEnum) {
             // 跳转下一节点
             case SKIP_TO_NEXT:
-                // 如果下一节点为结束节点
-                if (NodeTypeEnum.END.equals(NodeTypeEnum.getEnum(nextUserNode.getNodeType()))) {
+                // 如果流程结束
+                if (FlowStatusEnum.PASS.equals(flowStatusEnum)) {
                     title = StrUtil.format("您于【{}】发起的【{}】已经审批通过。",
                             DateUtil.formatDateTime(flowExample.getCreateTime()),
                             flowName);
@@ -678,7 +739,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
                 // 如果下一节点不为结束节点
                 else {
                     title = "您有一条新的待审批事项,请及时处理。";
-                    pushUserId = flowExample.getHandleUserId();
+                    pushUserId = jumpHandleUserId;
                 }
                 break;
 
@@ -691,27 +752,35 @@ public class FlowProcessServiceImpl implements FlowProcessService {
                 pushUserId = flowExample.getCreateUser();
                 break;
 
-            // 退回上一节点,退回到发起人
+            // 退回上一节点
             case RETURN_TO_PREVIOUS:
-            case RETURN_TO_SUBMITTER:
 
                 // 查找上次审批节点
                 FlowExampleDetail flowExampleDetail = flowExampleDetailService.getOne(
                         Wrappers.<FlowExampleDetail>lambdaQuery()
                                 .eq(FlowExampleDetail::getFlowExampleId, flowExample.getId())
+                                .eq(FlowExampleDetail::getFlowDefinitionNodeId, jumpNode.getId())
                                 .orderByDesc(BaseIdPo::getId)
-                                .last("limit 1,1")
-                );
+                                .last("limit 1,1"));
 
                 title = StrUtil.format("您于【{}】提交的【{}】被退回,请及时处理。",
                         DateUtil.formatDateTime(flowExampleDetail.getCreateTime()),
                         flowName);
 
-                pushUserId = flowExampleDetail.getCreateUser();
+                pushUserId = jumpHandleUserId;
+                break;
+
+            // 退回到发起人
+            case RETURN_TO_SUBMITTER:
+                title = StrUtil.format("您于【{}】提交的【{}】被退回,请及时处理。",
+                        DateUtil.formatDateTime(flowExample.getCreateTime()),
+                        flowName);
+
+                pushUserId = jumpHandleUserId;
                 break;
 
             default:
-                throw new ServiceException("未知处理方法");
+                throw new ServiceException("未知流程跳转类型");
         }
 
         WebSocketPush.byUser(PushTypeEnum.MESSAGE, pushUserId, title, 0, businessData);
@@ -719,35 +788,42 @@ public class FlowProcessServiceImpl implements FlowProcessService {
 
     // public static void main(String[] args) {
     //     HashMap<String, Object> map = new HashMap<>();
-    //
     //     HashMap<Object, Object> dd = new HashMap<>();
     //     dd.put("A", "a1");
     //     dd.put("B", "b1");
     //     dd.put("C", "c1");
-    //
-    //
     //     map.put("aa", "aa");
     //     map.put("bb", "bb");
     //     map.put("cc", Arrays.asList("A", "B", "C", "D"));
     //     map.put("dd", dd);
-    //
     //     System.out.println(expressionResult(map,
     //             "aa == 'aa' && bb == 'bb' && cc[0] == 'A' && dd.A == 'a1' "
     //     ));
-    //
     // }
 
     // public static void main(String[] args) {
-    //
     //     System.out.println(
     //             templateParse(
     //                     "测试1:${Integer.parseInt(a)+1};  测试2:${a+1};  测试3:${b.tt};  测试4:${b.vv};  测试5:${b.vv[0]};",
     //                     JSONObject.parseObject("{a: \"1\", b: {tt: \"t\", vv: [\"aa\", \"bb\", \"cc\"] }}"))
     //     );
-    //
     // }
 
     /**
+     * 校验el表达式
+     */
+    public boolean expressionResult(Map<String, Object> map, String expression) {
+        try {
+            Expression exp = AviatorEvaluator.compile(expression);
+            Object execute = exp.execute(map);
+            return Boolean.parseBoolean(String.valueOf(execute));
+        } catch (Exception e) {
+            log.error("el表达式校验错误", e);
+            throw new ServiceException("el表达式校验错误:" + e.getMessage());
+        }
+    }
+
+    /**
      * 模板替换
      *
      * <p>

+ 6 - 0
ruoyi-admin/src/main/java/com/ruoyi/test/TestFlow.java

@@ -4,6 +4,7 @@ package com.ruoyi.test;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.fjhx.flow.core.FlowDelegate;
+import com.fjhx.flow.enums.FlowStatusEnum;
 import com.ruoyi.system.domain.SysConfig;
 import com.ruoyi.system.service.ISysConfigService;
 import lombok.extern.slf4j.Slf4j;
@@ -36,6 +37,11 @@ public class TestFlow extends FlowDelegate {
         System.out.println("默认结束方法");
     }
 
+    @Override
+    public void defaultMethod(Long flowId, Long businessId, FlowStatusEnum flowStatusEnum, JSONObject submitData) {
+
+    }
+
     public void testEnd() {
         log.error("测试结束方法");
         SysConfig sysConfig = new SysConfig();