소스 검색

流程引擎更新

yzc 1 년 전
부모
커밋
64546e77c1
26개의 변경된 파일813개의 추가작업 그리고 261개의 파일을 삭제
  1. 48 22
      hx-flow/src/main/java/com/fjhx/flow/core/FlowJumpContext.java
  2. 16 7
      hx-flow/src/main/java/com/fjhx/flow/core/FlowThreadLocalUtil.java
  3. 8 0
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/dto/FlowDefinitionDto.java
  4. 29 0
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/dto/FlowResult.java
  5. 2 1
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/dto/InitiateDto.java
  6. 2 1
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/dto/JumpDto.java
  7. 44 0
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowDefinitionLine.java
  8. 12 0
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowDefinitionNode.java
  9. 8 8
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowExample.java
  10. 33 0
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowExampleCurrent.java
  11. 2 0
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/vo/FlowDefinitionVo.java
  12. 5 0
      hx-flow/src/main/java/com/fjhx/flow/entity/flow/vo/FlowExampleVo.java
  13. 1 0
      hx-flow/src/main/java/com/fjhx/flow/enums/HandleObjectTypeEnum.java
  14. 39 0
      hx-flow/src/main/java/com/fjhx/flow/enums/NodeHandleTypeEnum.java
  15. 15 0
      hx-flow/src/main/java/com/fjhx/flow/mapper/flow/FlowDefinitionLineMapper.java
  16. 15 0
      hx-flow/src/main/java/com/fjhx/flow/mapper/flow/FlowExampleCurrentMapper.java
  17. 14 0
      hx-flow/src/main/java/com/fjhx/flow/service/flow/FlowDefinitionLineService.java
  18. 15 0
      hx-flow/src/main/java/com/fjhx/flow/service/flow/FlowExampleCurrentService.java
  19. 5 0
      hx-flow/src/main/java/com/fjhx/flow/service/flow/FlowExampleService.java
  20. 19 0
      hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowDefinitionLineServiceImpl.java
  21. 31 0
      hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowDefinitionServiceImpl.java
  22. 19 0
      hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowExampleCurrentServiceImpl.java
  23. 79 31
      hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowExampleServiceImpl.java
  24. 344 189
      hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowProcessServiceImpl.java
  25. 4 0
      hx-flow/src/main/resources/mapper/flow/FlowDefinitionLineMapper.xml
  26. 4 2
      hx-flow/src/main/resources/mapper/flow/FlowExampleMapper.xml

+ 48 - 22
hx-flow/src/main/java/com/fjhx/flow/core/FlowJumpContext.java

@@ -2,18 +2,25 @@ package com.fjhx.flow.core;
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.extra.spring.SpringUtil;
+import com.fjhx.flow.entity.flow.dto.FlowResult;
 import com.fjhx.flow.entity.flow.dto.JumpDto;
+import com.fjhx.flow.entity.flow.po.FlowDefinitionLine;
 import com.fjhx.flow.entity.flow.po.FlowDefinitionNode;
 import com.fjhx.flow.entity.flow.po.FlowExample;
+import com.fjhx.flow.entity.flow.po.FlowExampleCurrent;
 import com.fjhx.flow.enums.FlowStatusEnum;
 import com.fjhx.flow.enums.HandleTypeEnum;
 import com.fjhx.flow.enums.NodeTypeEnum;
+import com.fjhx.flow.service.flow.FlowDefinitionLineService;
 import com.fjhx.flow.service.flow.FlowDefinitionNodeService;
+import com.fjhx.flow.service.flow.FlowExampleCurrentService;
 import com.fjhx.flow.service.flow.FlowExampleService;
 import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.SecurityUtils;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -23,6 +30,9 @@ public class FlowJumpContext {
 
     public static final FlowExampleService flowExampleService = SpringUtil.getBean(FlowExampleService.class);
     public static final FlowDefinitionNodeService flowDefinitionNodeService = SpringUtil.getBean(FlowDefinitionNodeService.class);
+    public static final FlowExampleCurrentService flowExampleCurrentService = SpringUtil.getBean(FlowExampleCurrentService.class);
+    public static final FlowDefinitionLineService flowDefinitionLineService = SpringUtil.getBean(FlowDefinitionLineService.class);
+
 
     public FlowJumpContext(JumpDto dto) {
 
@@ -43,19 +53,28 @@ public class FlowJumpContext {
         // 获取流程节点列表
         flowDefinitionNodeList = flowDefinitionNodeService.list(
                 q -> q.eq(FlowDefinitionNode::getFlowDefinitionId, flowExample.getDefinitionId()));
+        // 获取流程节点连线列表
+        flowDefinitionLineList = flowDefinitionLineService.list(
+                q -> q.eq(FlowDefinitionLine::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;
+//        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;
+        FlowExampleCurrent one = flowExampleCurrentService.getOne(q -> q
+                .eq(FlowExampleCurrent::getFlowExampleId, flowExample.getId())
+                .eq(FlowExampleCurrent::getHandleUserId, SecurityUtils.getUserId())
+        );
+        currentNode = flowDefinitionNodeService.getById(one.getNodeId());
 
         // 当前节点类型
         currentNodeType = NodeTypeEnum.getEnum(currentNode.getNodeType());
@@ -63,8 +82,9 @@ public class FlowJumpContext {
         // 查找跳转类型
         handleType = HandleTypeEnum.getEnum(dto.getHandleType());
 
-        // 跳转节点用户处理id
-        jumpHandleUserId = dto.getHandleUserId();
+//        // 跳转节点用户处理id
+//        jumpHandleUserId = dto.getHandleUserId();
+        selectUserList = dto.getSelectUserList()==null?new ArrayList<>():dto.getSelectUserList();
 
     }
 
@@ -82,6 +102,10 @@ public class FlowJumpContext {
      * 流程节点列表
      */
     private final List<FlowDefinitionNode> flowDefinitionNodeList;
+    /**
+     * 流程节点列表
+     */
+    private final List<FlowDefinitionLine> flowDefinitionLineList;
 
     /**
      * 当前审批节点
@@ -103,15 +127,17 @@ public class FlowJumpContext {
      */
     private final FlowDelegate flowDelegate;
 
-    /**
-     * 跳转节点
-     */
-    private FlowDefinitionNode jumpNode;
-
-    /**
-     * 跳转节点处理用户id
-     */
-    private String jumpHandleUserId;
+//    /**
+//     * 跳转节点
+//     */
+//    private FlowDefinitionNode jumpNode;
+        private List<FlowDefinitionNode> jumpNodeList;
+
+//    /**
+//     * 跳转节点处理用户id
+//     */
+//    private String jumpHandleUserId;
+private List<FlowResult.SelectUser> selectUserList;
 
     /**
      * 流程当前状态

+ 16 - 7
hx-flow/src/main/java/com/fjhx/flow/core/FlowThreadLocalUtil.java

@@ -50,10 +50,10 @@ public class FlowThreadLocalUtil {
      */
     private FlowStatusEnum flowStatusEnum;
 
-    /**
-     * 下个节点审批用户id
-     */
-    private String nextHandleUserId;
+//    /**
+//     * 下个节点审批用户id
+//     */
+//    private String nextHandleUserId;
 
     /**
      * 当前节点状态
@@ -65,6 +65,11 @@ public class FlowThreadLocalUtil {
      */
     private List<Long> dynamicUserIds;
 
+    /**
+     * 流程创建人
+     */
+    private Long flowCreateUser;
+
 
     public static Long getFlowId() {
         return FLOW_HOLDER.get().flowId;
@@ -94,14 +99,18 @@ public class FlowThreadLocalUtil {
         return FLOW_HOLDER.get().flowStatusEnum;
     }
 
-    public static String getNextHandleUserId() {
-        return FLOW_HOLDER.get().nextHandleUserId;
-    }
+//    public static String getNextHandleUserId() {
+//        return FLOW_HOLDER.get().nextHandleUserId;
+//    }
 
     public static NodeTypeEnum getCurrentNodeTypeEnum() {
         return FLOW_HOLDER.get().currentNodeTypeEnum;
     }
 
+    public static Long getFlowCreateUser() {
+        return FLOW_HOLDER.get().flowCreateUser;
+    }
+
     public static FlowThreadLocalUtil create() {
         FlowThreadLocalUtil flowThreadLocalUtil = new FlowThreadLocalUtil();
         FLOW_HOLDER.set(flowThreadLocalUtil);

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

@@ -1,6 +1,7 @@
 package com.fjhx.flow.entity.flow.dto;
 
 import com.fjhx.flow.entity.flow.po.FlowDefinition;
+import com.fjhx.flow.entity.flow.po.FlowDefinitionLine;
 import com.fjhx.flow.entity.flow.po.FlowDefinitionNode;
 import lombok.Getter;
 import lombok.Setter;
@@ -20,4 +21,11 @@ public class FlowDefinitionDto extends FlowDefinition {
     @NotEmpty(message = "流程节点列表不能为空")
     private List<FlowDefinitionNode> flowDefinitionNodeList;
 
+    /**
+     * 流程连线列表
+     */
+    @Valid
+    @NotEmpty(message = "流程节点连线列表不能为空")
+    private List<FlowDefinitionLine> flowDefinitionLineList;
+
 }

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

@@ -39,4 +39,33 @@ public class FlowResult {
      */
     private List<FlowDefinitionNode> flowDefinitionNodeList;
 
+    /**
+     * 用户选择列表
+     */
+    private List<SelectUser> selectUserList;
+
+    @Getter
+    @Setter
+    public static class SelectUser {
+        /**
+         * 节点id
+         */
+        private Long nodeId;
+
+        /**
+         * 节点名称
+         */
+        private String nodeName;
+
+        /**
+         * 用户id
+         */
+        private String handleUserId;
+
+        /**
+         * 处理用户
+         */
+        private List<SysUser> userList;
+    }
+
 }

+ 2 - 1
hx-flow/src/main/java/com/fjhx/flow/entity/flow/dto/InitiateDto.java

@@ -26,7 +26,8 @@ public class InitiateDto {
     /**
      * 下级节点审批人
      */
-    private String handleUserId;
+//    private String handleUserId;
+    private List<FlowResult.SelectUser> selectUserList;
 
     /**
      * 提交数据

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

@@ -42,7 +42,8 @@ public class JumpDto {
     /**
      * 下级节点审批人
      */
-    private String handleUserId;
+//    private String handleUserId;
+    private List<FlowResult.SelectUser> selectUserList;
 
     /**
      * 处理备注

+ 44 - 0
hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowDefinitionLine.java

@@ -0,0 +1,44 @@
+package com.fjhx.flow.entity.flow.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.BaseIdPo;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 流程连线定义
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+@Getter
+@Setter
+@TableName("flow_definition_line")
+public class FlowDefinitionLine extends BaseIdPo {
+
+    /**
+     * 流程定义id
+     */
+    private Long flowDefinitionId;
+
+    /**
+     * 跳转条件
+     */
+    private String jumpCondition;
+
+    /**
+     * 源头节点id
+     */
+    private Long sourceId;
+
+    /**
+     * 目标节点id
+     */
+    private Long targetId;
+
+    /**
+     * 线UUID 前端使用
+     */
+    private String lineUuid;
+
+}

+ 12 - 0
hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowDefinitionNode.java

@@ -1,5 +1,6 @@
 package com.fjhx.flow.entity.flow.po;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.ruoyi.common.core.domain.BaseIdPo;
 import lombok.Getter;
@@ -81,6 +82,17 @@ public class FlowDefinitionNode extends BaseIdPo {
      */
     private String handleObjectId;
 
+    /**
+     * 节点处理类型 10常规 20聚和 30抄送
+     */
+    private Integer nodeHandleType;
+
+    /**
+     * 处理人用户id(逗号分隔)
+     */
+    @TableField(exist = false)
+    private String jumpHandleUserId;
+
     @NotNull(message = "流程节点id不能为空")
     public Long getId() {
         return super.getId();

+ 8 - 8
hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowExample.java

@@ -35,15 +35,15 @@ public class FlowExample extends BasePo {
      */
     private Long definitionId;
 
-    /**
-     * 流程所在节点id
-     */
-    private Long definitionNodeId;
+//    /**
+//     * 流程所在节点id
+//     */
+//    private Long definitionNodeId;
 
-    /**
-     * 节点处理人id
-     */
-    private String handleUserId;
+//    /**
+//     * 节点处理人id
+//     */
+//    private String handleUserId;
 
     /**
      * 业务id

+ 33 - 0
hx-flow/src/main/java/com/fjhx/flow/entity/flow/po/FlowExampleCurrent.java

@@ -0,0 +1,33 @@
+package com.fjhx.flow.entity.flow.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.BaseIdPo;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 流程实例当前信息
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+
+@Getter
+@Setter
+@TableName("flow_example_current")
+public class FlowExampleCurrent extends BaseIdPo {
+    /**
+     * 流程实例id
+     */
+    private Long flowExampleId;
+
+    /**
+     * 节点id
+     */
+    private Long nodeId;
+
+    /**
+     * 处理人id
+     */
+    private Long handleUserId;
+}

+ 2 - 0
hx-flow/src/main/java/com/fjhx/flow/entity/flow/vo/FlowDefinitionVo.java

@@ -1,6 +1,7 @@
 package com.fjhx.flow.entity.flow.vo;
 
 import com.fjhx.flow.entity.flow.po.FlowDefinition;
+import com.fjhx.flow.entity.flow.po.FlowDefinitionLine;
 import com.fjhx.flow.entity.flow.po.FlowDefinitionNode;
 import lombok.Getter;
 import lombok.Setter;
@@ -12,5 +13,6 @@ import java.util.List;
 public class FlowDefinitionVo extends FlowDefinition {
 
     private List<FlowDefinitionNode> flowDefinitionNodeList;
+    private List<FlowDefinitionLine> flowDefinitionLineList;
 
 }

+ 5 - 0
hx-flow/src/main/java/com/fjhx/flow/entity/flow/vo/FlowExampleVo.java

@@ -34,4 +34,9 @@ public class FlowExampleVo extends FlowExample {
      */
     private String flowName;
 
+    /**
+     * 节点处理类型
+     */
+    private Integer nodeHandleType;
+
 }

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

@@ -18,6 +18,7 @@ public enum HandleObjectTypeEnum {
     ROLE(5, "角色"),
     PARALLEL(6, "动态用户"),
     DEPT_MANAGER(8, "部门主管"),
+    BUSINESS_USER(9, "用户表达式"),
     ;
 
     private final Integer key;

+ 39 - 0
hx-flow/src/main/java/com/fjhx/flow/enums/NodeHandleTypeEnum.java

@@ -0,0 +1,39 @@
+package com.fjhx.flow.enums;
+
+import com.ruoyi.common.exception.ServiceException;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+@AllArgsConstructor
+public enum NodeHandleTypeEnum {
+
+    ORDINARY(10, "常规"),
+    POLYMERIZE(20, "聚合"),
+    CARBON_COPY(30, "抄送"),
+    ;
+
+    private final Integer key;
+
+    private final String value;
+
+    private static final Map<Integer, NodeHandleTypeEnum> map = new HashMap<>();
+
+    static {
+        for (NodeHandleTypeEnum value : NodeHandleTypeEnum.values()) {
+            map.put(value.getKey(), value);
+        }
+    }
+
+    public static NodeHandleTypeEnum getEnum(Integer key) {
+        NodeHandleTypeEnum nodeTypeEnum = map.get(key);
+        if (nodeTypeEnum == null) {
+            throw new ServiceException("未知节点处理类型");
+        }
+        return nodeTypeEnum;
+    }
+
+}

+ 15 - 0
hx-flow/src/main/java/com/fjhx/flow/mapper/flow/FlowDefinitionLineMapper.java

@@ -0,0 +1,15 @@
+package com.fjhx.flow.mapper.flow;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fjhx.flow.entity.flow.po.FlowDefinitionLine;
+
+
+/**
+ * 流程节点定义 Mapper 接口
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+public interface FlowDefinitionLineMapper extends BaseMapper<FlowDefinitionLine> {
+
+}

+ 15 - 0
hx-flow/src/main/java/com/fjhx/flow/mapper/flow/FlowExampleCurrentMapper.java

@@ -0,0 +1,15 @@
+package com.fjhx.flow.mapper.flow;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fjhx.flow.entity.flow.po.FlowExampleCurrent;
+
+
+/**
+ * 流程示例当前处理信息表 Mapper 接口
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+public interface FlowExampleCurrentMapper extends BaseMapper<FlowExampleCurrent> {
+
+}

+ 14 - 0
hx-flow/src/main/java/com/fjhx/flow/service/flow/FlowDefinitionLineService.java

@@ -0,0 +1,14 @@
+package com.fjhx.flow.service.flow;
+
+import com.fjhx.flow.entity.flow.po.FlowDefinitionLine;
+import com.ruoyi.common.core.service.BaseService;
+
+/**
+ * 流程节点连线定义 服务类
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+public interface FlowDefinitionLineService extends BaseService<FlowDefinitionLine> {
+
+}

+ 15 - 0
hx-flow/src/main/java/com/fjhx/flow/service/flow/FlowExampleCurrentService.java

@@ -0,0 +1,15 @@
+package com.fjhx.flow.service.flow;
+
+import com.fjhx.flow.entity.flow.po.FlowExampleCurrent;
+import com.ruoyi.common.core.service.BaseService;
+
+
+/**
+ * 流程示例当前处理信息表 服务类
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+public interface FlowExampleCurrentService extends BaseService<FlowExampleCurrent> {
+
+}

+ 5 - 0
hx-flow/src/main/java/com/fjhx/flow/service/flow/FlowExampleService.java

@@ -1,5 +1,6 @@
 package com.fjhx.flow.service.flow;
 
+import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.fjhx.flow.entity.flow.dto.FlowExampleSelectDto;
 import com.fjhx.flow.entity.flow.dto.FlowNodeDto;
@@ -94,4 +95,8 @@ public interface FlowExampleService extends BaseService<FlowExample> {
         setFlowId(Collections.singletonList(entity), getIdFun, setFun);
     }
 
+    /**
+     * 流程作废
+     */
+    void cancellation(Long id);
 }

+ 19 - 0
hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowDefinitionLineServiceImpl.java

@@ -0,0 +1,19 @@
+package com.fjhx.flow.service.flow.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fjhx.flow.entity.flow.po.FlowDefinitionLine;
+import com.fjhx.flow.mapper.flow.FlowDefinitionLineMapper;
+import com.fjhx.flow.service.flow.FlowDefinitionLineService;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * 流程节点连线定义 服务实现类
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+@Service
+public class FlowDefinitionLineServiceImpl extends ServiceImpl<FlowDefinitionLineMapper, FlowDefinitionLine> implements FlowDefinitionLineService {
+
+}

+ 31 - 0
hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowDefinitionServiceImpl.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fjhx.flow.entity.flow.dto.FlowDefinitionDto;
 import com.fjhx.flow.entity.flow.dto.FlowDefinitionSelectDto;
 import com.fjhx.flow.entity.flow.po.FlowDefinition;
+import com.fjhx.flow.entity.flow.po.FlowDefinitionLine;
 import com.fjhx.flow.entity.flow.po.FlowDefinitionNode;
 import com.fjhx.flow.entity.flow.po.FlowInfo;
 import com.fjhx.flow.entity.flow.vo.FlowDefinitionPageVo;
@@ -16,6 +17,7 @@ import com.fjhx.flow.entity.flow.vo.FlowDefinitionVo;
 import com.fjhx.flow.enums.HandleTypeEnum;
 import com.fjhx.flow.enums.NodeTypeEnum;
 import com.fjhx.flow.mapper.flow.FlowDefinitionMapper;
+import com.fjhx.flow.service.flow.FlowDefinitionLineService;
 import com.fjhx.flow.service.flow.FlowDefinitionNodeService;
 import com.fjhx.flow.service.flow.FlowDefinitionService;
 import com.fjhx.flow.service.flow.FlowInfoService;
@@ -49,6 +51,8 @@ public class FlowDefinitionServiceImpl extends ServiceImpl<FlowDefinitionMapper,
 
     @Autowired
     private FlowDefinitionNodeService flowDefinitionNodeService;
+    @Autowired
+    private FlowDefinitionLineService flowDefinitionLineService;
 
     @Override
     public Page<FlowDefinitionPageVo> getPage(FlowDefinitionSelectDto dto) {
@@ -107,6 +111,14 @@ public class FlowDefinitionServiceImpl extends ServiceImpl<FlowDefinitionMapper,
         endNode.setParentId(startNode.getId());
 
         flowDefinitionNodeService.saveBatch(Arrays.asList(startNode, endNode));
+
+        //添加默认连线
+        FlowDefinitionLine startLine = new FlowDefinitionLine();
+        startLine.setId(IdWorker.getId());
+        startLine.setFlowDefinitionId(flowDefinition.getId());
+        startLine.setSourceId(startNode.getId());
+        startLine.setTargetId(endNode.getId());
+        flowDefinitionLineService.save(startLine);
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -132,6 +144,7 @@ public class FlowDefinitionServiceImpl extends ServiceImpl<FlowDefinitionMapper,
 
         // 添加流程节点
         List<FlowDefinitionNode> flowDefinitionNodeList = dto.getFlowDefinitionNodeList();
+        List<FlowDefinitionLine> flowDefinitionLineList = dto.getFlowDefinitionLineList();
 
         for (FlowDefinitionNode flowDefinitionNode : flowDefinitionNodeList) {
             flowDefinitionNode.setFlowDefinitionId(dto.getId());
@@ -145,9 +158,21 @@ public class FlowDefinitionServiceImpl extends ServiceImpl<FlowDefinitionMapper,
                     item.setParentId(newId);
                 }
             }
+            for (FlowDefinitionLine flowDefinitionLine : flowDefinitionLineList) {
+                flowDefinitionLine.setId(IdWorker.getId());
+                flowDefinitionLine.setFlowDefinitionId(dto.getId());
+
+                if (flowDefinitionLine.getSourceId().equals(oldId)) {
+                    flowDefinitionLine.setSourceId(newId);
+                }
+                if (flowDefinitionLine.getTargetId().equals(oldId)) {
+                    flowDefinitionLine.setTargetId(newId);
+                }
+            }
         }
 
         flowDefinitionNodeService.saveBatch(flowDefinitionNodeList);
+        flowDefinitionLineService.saveBatch(flowDefinitionLineList);
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -207,6 +232,12 @@ public class FlowDefinitionServiceImpl extends ServiceImpl<FlowDefinitionMapper,
 
         flowDefinitionVo.setFlowDefinitionNodeList(flowDefinitionNodeList);
 
+        List<FlowDefinitionLine> flowDefinitionLineList = flowDefinitionLineService.list(q -> q
+                .eq(FlowDefinitionLine::getFlowDefinitionId, id)
+        );
+        flowDefinitionVo.setFlowDefinitionLineList(flowDefinitionLineList);
+
+
         return flowDefinitionVo;
     }
 

+ 19 - 0
hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowExampleCurrentServiceImpl.java

@@ -0,0 +1,19 @@
+package com.fjhx.flow.service.flow.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fjhx.flow.entity.flow.po.FlowExampleCurrent;
+import com.fjhx.flow.mapper.flow.FlowExampleCurrentMapper;
+import com.fjhx.flow.service.flow.FlowExampleCurrentService;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * 流程示例当前处理信息表 服务实现类
+ *
+ * @author yzc
+ * @since 2024-04-19
+ */
+@Service
+public class FlowExampleCurrentServiceImpl extends ServiceImpl<FlowExampleCurrentMapper, FlowExampleCurrent> implements FlowExampleCurrentService {
+
+}

+ 79 - 31
hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowExampleServiceImpl.java

@@ -2,6 +2,7 @@ package com.fjhx.flow.service.flow.impl;
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -11,9 +12,7 @@ import com.fjhx.flow.entity.flow.dto.SetStartDataDto;
 import com.fjhx.flow.entity.flow.po.*;
 import com.fjhx.flow.entity.flow.vo.ApprovalRecordVo;
 import com.fjhx.flow.entity.flow.vo.FlowExampleVo;
-import com.fjhx.flow.enums.FlowStatusEnum;
-import com.fjhx.flow.enums.HandleTypeEnum;
-import com.fjhx.flow.enums.NodeTypeEnum;
+import com.fjhx.flow.enums.*;
 import com.fjhx.flow.mapper.flow.FlowExampleMapper;
 import com.fjhx.flow.service.flow.*;
 import com.ruoyi.common.constant.BaseSourceConstant;
@@ -57,6 +56,13 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
     @Autowired
     private FlowDefinitionNodeService flowDefinitionNodeService;
 
+    @Autowired
+    private FlowDefinitionLineService flowDefinitionLineService;
+
+    @Autowired
+    private FlowExampleCurrentService flowExampleCurrentService;
+
+
     @Override
     public List<FlowInfo> getFlowType() {
         List<Long> flowInofIdList = flowDefinitionService.getDistinctList(FlowDefinition::getFlowInfoId);
@@ -70,9 +76,10 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
     public Page<FlowExampleVo> getToBeProcessedPage(FlowExampleSelectDto dto) {
 
         IWrapper<FlowExample> wrapper = getWrapper()
-                .lt("fe", FlowExample::getStatus, 2)
-//                .eq("fe", FlowExample::getHandleUserId, SecurityUtils.getUserId())
-                .apply("FIND_IN_SET( {0}, fe.handle_user_id )",SecurityUtils.getUserId());
+                .eq("fec.handle_user_id", SecurityUtils.getUserId())
+                .and(q -> q.eq("fdn.node_handle_type", 30)
+                        .or(q1 -> q1.lt("fe", FlowExample::getStatus, 2))
+                );
 
         return doSelectExample(dto, wrapper);
     }
@@ -146,8 +153,12 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
         Integer status = flowExample.getStatus();
 
         if (!FlowStatusEnum.PASS.getKey().equals(status) && !FlowStatusEnum.REJECT.getKey().equals(status)) {
+            FlowExampleCurrent currentNode = flowExampleCurrentService.getOne(q -> q
+                    .eq(FlowExampleCurrent::getFlowExampleId, flowExample.getId())
+            );
+            Long currentNodeId = currentNode == null ? null : currentNode.getNodeId();
             // 添加未开始记录
-            addNotStarted(recordList, flowDefinitionNodeList, flowExample.getDefinitionNodeId());
+            addNotStarted(recordList, flowDefinitionNodeList, currentNodeId, flowExample.getDefinitionId());
         }
 
         // 获取button列表
@@ -205,7 +216,7 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
         }
 
         // 查找节点
-        addNotStarted(recordList, flowDefinitionNodeList, 0L);
+        addNotStarted(recordList, flowDefinitionNodeList, startNode.getId(), flowDefinition.getId());
 
         // 赋值开始节点创作人
         recordList.get(0).setProcessedUser(SecurityUtils.getLoginUser().getUser().getNickName());
@@ -245,6 +256,20 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
         DynamicDataSourceContextHolder.poll();
     }
 
+    @DSTransactional
+    @Override
+    public void cancellation(Long id) {
+        this.update(q -> q
+                .eq(FlowExample::getId, id)
+                .in(FlowExample::getStatus, FlowStatusEnum.READY_START.getKey(), FlowStatusEnum.IN_PROGRESS.getKey())
+                .set(FlowExample::getStatus, FlowStatusEnum.CANCELLATION.getKey())
+                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
+                .set(BasePo::getUpdateTime, new Date())
+        );
+
+        flowExampleCurrentService.remove(q->q.eq(FlowExampleCurrent::getFlowExampleId,id));
+    }
+
     private List<ApprovalRecordVo.ButtonInfo> getButtonInfoList(FlowExample flowExample,
                                                                 List<FlowDefinitionNode> flowDefinitionNodeList) {
 
@@ -252,23 +277,41 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
 
         Integer status = flowExample.getStatus();
 
-        List<Long> handleUserIds = Arrays.stream(flowExample.getHandleUserId().split(",")).map(Long::valueOf).collect(Collectors.toList());
-        if (FlowStatusEnum.PASS.getKey().equals(status)
-                || FlowStatusEnum.REJECT.getKey().equals(status)
-//                || !Objects.equals(flowExample.getHandleUserId(), SecurityUtils.getUserId())
-                || !handleUserIds.contains(SecurityUtils.getUserId())
-        ) {
-            return buttonInfoList;
+        List<Long> handleUserIds = flowExampleCurrentService.listObject(FlowExampleCurrent::getHandleUserId, q -> q
+                .eq(FlowExampleCurrent::getFlowExampleId, flowExample.getId())
+        );
+
+        if(!handleUserIds.contains(SecurityUtils.getUserId())) {
+            if (FlowStatusEnum.PASS.getKey().equals(status)
+                    || FlowStatusEnum.REJECT.getKey().equals(status)
+                    || !handleUserIds.contains(SecurityUtils.getUserId())
+            ) {
+                return buttonInfoList;
+            }
         }
 
+
+        FlowExampleCurrent flowExampleCurrent = flowExampleCurrentService.getOne(q -> q
+                .eq(FlowExampleCurrent::getFlowExampleId, flowExample.getId())
+                .eq(FlowExampleCurrent::getHandleUserId, SecurityUtils.getUserId())
+        );
+
         FlowDefinitionNode flowDefinitionNode = flowDefinitionNodeList.stream()
-                .filter(item -> Objects.equals(item.getId(), flowExample.getDefinitionNodeId()))
+                .filter(item -> Objects.equals(item.getId(), flowExampleCurrent.getNodeId()))
                 .findFirst().orElse(null);
 
         if (flowDefinitionNode == null) {
             return buttonInfoList;
         }
 
+        //如果节点是抄送节点
+        if(NodeHandleTypeEnum.CARBON_COPY.equals(NodeHandleTypeEnum.getEnum(flowDefinitionNode.getNodeHandleType()))){
+            ApprovalRecordVo.ButtonInfo buttonInfo = new ApprovalRecordVo.ButtonInfo();
+            buttonInfo.setType(HandleTypeEnum.SKIP_TO_NEXT.getKey());
+            buttonInfo.setName("已读");
+            return Collections.singletonList(buttonInfo);
+        }
+
         String nodeButtonSet = flowDefinitionNode.getNodeButtonSet();
 
         //按特定顺序排序按钮(通过,退回(指定节点),审批驳回,加签,移交)
@@ -322,15 +365,20 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
      */
     private void addNotStarted(List<ApprovalRecordVo.Record> recordList,
                                List<FlowDefinitionNode> flowDefinitionNodeList,
-                               Long definitionNodeId) {
+                               Long definitionNodeId, Long definitionId) {
+        // 获取节点线路
+        Map<Long, List<FlowDefinitionLine>> flowLineMap = flowDefinitionLineService.mapKGroup(FlowDefinitionLine::getSourceId, q -> q
+                .eq(FlowDefinitionLine::getFlowDefinitionId, definitionId)
+        );
 
-        // 父节点id map
+        // 节点Map
         Map<Long, FlowDefinitionNode> flowDefinitionNodeMap = flowDefinitionNodeList.stream()
-                .collect(Collectors.toMap(FlowDefinitionNode::getParentId, Function.identity(), (t1, t2) -> t2));
+                .collect(Collectors.toMap(FlowDefinitionNode::getId, Function.identity(), (t1, t2) -> t2));
 
-        FlowDefinitionNode nextNode = flowDefinitionNodeMap.get(definitionNodeId);
-
-        while (nextNode != null) {
+        List<FlowDefinitionLine> flowDefinitionLineList = flowLineMap.get(definitionNodeId);
+        while (flowDefinitionLineList != null) {
+            Long targetId = flowDefinitionLineList.get(0).getTargetId();
+            FlowDefinitionNode nextNode = flowDefinitionNodeMap.get(targetId);
 
             Integer nodeType = nextNode.getNodeType();
 
@@ -341,12 +389,11 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
             record.setNodeName(nextNode.getNodeName());
             recordList.add(record);
 
-            if (NodeTypeEnum.BRANCH.getKey().equals(nodeType) || NodeTypeEnum.END.getKey().equals(nodeType)) {
-                nextNode = null;
+            if (NodeTypeEnum.END.getKey().equals(nodeType)) {
+                break;
             } else {
-                nextNode = flowDefinitionNodeMap.get(nextNode.getId());
+                flowDefinitionLineList = flowLineMap.get(nextNode.getId());
             }
-
         }
     }
 
@@ -381,13 +428,14 @@ public class FlowExampleServiceImpl extends ServiceImpl<FlowExampleMapper, FlowE
             return;
         }
 
-        String handleUserIds = flowExample.getHandleUserId();
-        String[] split = handleUserIds.split(",");
-        for (String handleUserId : split) {
+        List<FlowExampleCurrent> handleUserList = flowExampleCurrentService.list(q -> q
+                .eq(FlowExampleCurrent::getFlowExampleId, flowExample.getId())
+        );
+        for (FlowExampleCurrent handleUser : handleUserList) {
             ApprovalRecordVo.Record record = new ApprovalRecordVo.Record();
             record.setStatus(2);
-            record.setNodeId(flowExample.getDefinitionNodeId());
-            record.setProcessedUserId(Long.valueOf(handleUserId));
+            record.setNodeId(handleUser.getNodeId());
+            record.setProcessedUserId(handleUser.getHandleUserId());
             recordList.add(record);
         }
     }

+ 344 - 189
hx-flow/src/main/java/com/fjhx/flow/service/flow/impl/FlowProcessServiceImpl.java

@@ -17,11 +17,9 @@ import com.fjhx.flow.entity.flow.dto.FlowResult;
 import com.fjhx.flow.entity.flow.dto.InitiateDto;
 import com.fjhx.flow.entity.flow.dto.JumpDto;
 import com.fjhx.flow.entity.flow.po.*;
-import com.fjhx.flow.enums.FlowStatusEnum;
-import com.fjhx.flow.enums.HandleObjectTypeEnum;
-import com.fjhx.flow.enums.HandleTypeEnum;
-import com.fjhx.flow.enums.NodeTypeEnum;
+import com.fjhx.flow.enums.*;
 import com.fjhx.flow.service.flow.*;
+import com.fjhx.socket.core.PushParam;
 import com.fjhx.socket.core.PushTypeEnum;
 import com.fjhx.socket.core.WebSocketPush;
 import com.googlecode.aviator.AviatorEvaluator;
@@ -36,6 +34,7 @@ import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.system.service.ISysDeptService;
 import com.ruoyi.system.service.ISysUserIdentityService;
 import com.ruoyi.system.service.ISysUserService;
+import com.ruoyi.system.utils.UserUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -57,6 +56,8 @@ public class FlowProcessServiceImpl implements FlowProcessService {
 
     @Autowired
     private FlowDefinitionNodeService flowDefinitionNodeService;
+    @Autowired
+    private FlowDefinitionLineService flowDefinitionLineService;
 
     @Autowired
     private FlowExampleService flowExampleService;
@@ -74,10 +75,13 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     private FlowInfoService flowInfoService;
     @Autowired
     private ISysUserIdentityService sysUserIdentityService;
+    @Autowired
+    private FlowExampleCurrentService flowExampleCurrentService;
 
     @DSTransactional
     @Override
     public FlowResult initiate(InitiateDto dto) {
+        dto.getData().put("createUser",SecurityUtils.getUserId());
 
         // 获取流程委托对象
         FlowDelegate flowDelegate = FlowBean.getBean(dto.getFlowKey());
@@ -91,14 +95,15 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             throw new ServiceException("流程未配置,请联系管理员");
         }
 
-        // 流程节点列表
-        List<FlowDefinitionNode> flowDefinitionNodeList = flowDefinitionNodeService.list(q -> q
-                .eq(FlowDefinitionNode::getFlowDefinitionId, flowDefinition.getId()));
+//        // 流程节点列表
+//        List<FlowDefinitionNode> flowDefinitionNodeList1 = flowDefinitionNodeService.list(q -> q
+//                .eq(FlowDefinitionNode::getFlowDefinitionId, flowDefinition.getId()));
 
         // 寻找开始节点
-        FlowDefinitionNode startNode = flowDefinitionNodeList.stream()
-                .filter(item -> NodeTypeEnum.START.getKey().equals(item.getNodeType()))
-                .findFirst().orElse(null);
+        FlowDefinitionNode startNode = flowDefinitionNodeService.getOne(q -> q
+                .eq(FlowDefinitionNode::getFlowDefinitionId, flowDefinition.getId())
+                .eq(FlowDefinitionNode::getNodeType, NodeTypeEnum.START.getKey())
+        );
 
         if (startNode == null) {
             throw new ServiceException("流程定义错误:没有找到开始节点");
@@ -116,27 +121,36 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         flowThreadLocal.setHandleTypeEnum(HandleTypeEnum.SKIP_TO_NEXT);
         flowThreadLocal.setCurrentNodeTypeEnum(NodeTypeEnum.START);
         flowThreadLocal.setDynamicUserIds(flowDelegate.getHandlingUserList(flowId, dto.getData()));
+        flowThreadLocal.setFlowCreateUser(SecurityUtils.getUserId());
 
         // 寻找下一节点
-        FlowDefinitionNode nextUserNode = getNextUserNode(startNode, flowDefinitionNodeList);
-        NodeTypeEnum nextNodeType = NodeTypeEnum.getEnum(nextUserNode.getNodeType());
+        List<FlowDefinitionLine> flowLineList = flowDefinitionLineService.list(q -> q
+                .eq(FlowDefinitionLine::getFlowDefinitionId, flowDefinition.getId())
+                .eq(FlowDefinitionLine::getSourceId, startNode.getId())
+        );
+        List<FlowDefinitionNode> nextUserNodes = getNextUserNode(startNode, flowLineList);
+
+        FlowDefinitionNode endNode = nextUserNodes.stream()
+                .filter(item -> ObjectUtil.equals(NodeTypeEnum.getEnum(item.getNodeType()), NodeTypeEnum.END))
+                .findFirst().orElse(null);
 
         // 流程实例
         FlowExample flowExample = new FlowExample();
 
-        // 如果下一节点不为结束节点,赋值下一个节点处理用户id
-        if (!NodeTypeEnum.END.equals(nextNodeType)) {
-
-            FlowResult handleUser = getHandleUser(nextUserNode, dto.getHandleUserId());
-            // 如果下一节点处理用户只有1人,赋值用户id
-            if (handleUser.getSuccess()) {
-                flowExample.setHandleUserId(handleUser.getUserId());
-                flowThreadLocal.setNextHandleUserId(handleUser.getUserId());
+        // 如果下一节点不包含结束节点,赋值下一个节点处理用户id
+        if (endNode == null) {
+            List<FlowResult.SelectUser> selectUserList = dto.getSelectUserList();
+            if (selectUserList == null) {
+                selectUserList = new ArrayList<>();
             }
-            // 如果下一节点处理用户有多人,则返回用户列表让用户选择下一节点处理人id
-            else {
-                return handleUser;
+            //检查并赋值下一节点处理人信息,以及待办
+            FlowResult flowResult = setNextHandleNodeHandleUser(nextUserNodes, selectUserList);
+            if (!flowResult.getSuccess()) {
+                return flowResult;
             }
+            //创建待办信息
+            createPendingInfo(nextUserNodes, flowId);
+
             // 流程进行中
             flowExample.setStatus(FlowStatusEnum.IN_PROGRESS.getKey());
             flowThreadLocal.setFlowStatusEnum(FlowStatusEnum.IN_PROGRESS);
@@ -170,7 +184,11 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         startExampleDetail.setSubmitData(JSONObject.toJSONString(dto));
         flowExampleDetailList.add(startExampleDetail);
 
-        if (NodeTypeEnum.END.equals(nextNodeType)) {
+
+        // 如果下一节点包含结束节点
+        if (endNode != null) {
+            FlowDefinitionNode nextUserNode = endNode;
+
 
             // 赋值业务id到租户线程
             flowThreadLocal.setBusinessId(businessId);
@@ -187,11 +205,12 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             flowExampleDetailList.add(endExampleDetail);
         }
 
+
         flowExample.setId(flowId);
         flowExample.setTitle(templateParse(flowDefinition.getTitleTemplate(), templateMap));
         flowExample.setFlowKey(dto.getFlowKey());
         flowExample.setDefinitionId(flowDefinition.getId());
-        flowExample.setDefinitionNodeId(nextUserNode.getId());
+//        flowExample.setDefinitionNodeId(nextUserNode.getId());
         flowExample.setBusinessId(businessId);
         flowExample.setStartData(dto.getData().toJSONString());
         flowExample.setDefinitionVersion(flowDefinition.getVersionNumber());
@@ -203,7 +222,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         ObsFileUtil.saveFile(dto.getFileList(), startExampleDetail.getId());
 
         // 推送
-        pushInitiateMessage(flowId, flowDefinition, nextNodeType, flowExample);
+        pushInitiateMessage(flowId, flowDefinition, nextUserNodes);
 
         // 清空ThreadLocal
         FlowThreadLocalUtil.remove();
@@ -229,6 +248,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         flowThreadLocal.setFlowId(dto.getFlowId());
         flowThreadLocal.setBusinessId(context.getFlowExample().getBusinessId());
         flowThreadLocal.setDynamicUserIds(flowDelegate.getHandlingUserList(dto.getFlowId(), startData));
+        flowThreadLocal.setFlowCreateUser(context.getFlowExample().getCreateUser());
 
         FlowResult flowResult;
 
@@ -284,13 +304,22 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             return flowResult;
         }
 
+        //删除当前用户待审批数据
+        flowExampleCurrentService.remove(q -> q
+                .eq(FlowExampleCurrent::getFlowExampleId, context.getFlowExample().getId())
+                .eq(FlowExampleCurrent::getHandleUserId, SecurityUtils.getUserId())
+        );
+
         flowThreadLocal.setFlowStatusEnum(context.getFlowStatus());
         flowThreadLocal.setHandleTypeEnum(context.getHandleType());
-        flowThreadLocal.setNextHandleUserId(context.getJumpHandleUserId());
+//        flowThreadLocal.setNextHandleUserId(context.getJumpHandleUserId());
         flowThreadLocal.setCurrentNodeTypeEnum(context.getCurrentNodeType());
 
-        // 执行节点方法
-        executiveNodeMethod(context);
+        //如果非 抄送节点
+        if (!NodeHandleTypeEnum.CARBON_COPY.getKey().equals(context.getCurrentNode().getNodeHandleType())) {
+            // 执行节点方法
+            executiveNodeMethod(context);
+        }
 
         // 保存数据
         editExample(context);
@@ -316,43 +345,103 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         return JSONObject.parseObject(flowExample.getStartData());
     }
 
+    private FlowResult setNextHandleNodeHandleUser(List<FlowDefinitionNode> nextUserNodes, List<FlowResult.SelectUser> selectUserList) {
+        List<FlowResult.SelectUser> reSelectUserList = new ArrayList<>();
+
+        for (FlowDefinitionNode nextUserNode : nextUserNodes) {
+            FlowResult handleUser = getHandleUser(nextUserNode, selectUserList);
+            // 如果下一节点处理用户只有1人,赋值用户id
+            if (handleUser.getSuccess()) {
+                nextUserNode.setJumpHandleUserId(handleUser.getUserId());
+            }
+            // 如果下一节点处理用户有多人,则返回用户列表让用户选择下一节点处理人id
+            else {
+                FlowResult.SelectUser selectUser = new FlowResult.SelectUser();
+                selectUser.setNodeId(nextUserNode.getId());
+                selectUser.setNodeName(nextUserNode.getNodeName());
+                selectUser.setUserList(handleUser.getUserList());
+
+                reSelectUserList.add(selectUser);
+            }
+        }
+
+        //返回选择用户列表
+        if (reSelectUserList.size() > 0) {
+            FlowResult flowResult = new FlowResult();
+            flowResult.setSuccess(false);
+            flowResult.setSelectUserList(reSelectUserList);
+            return flowResult;
+        }
+
+        FlowResult flowResult = new FlowResult();
+        flowResult.setSuccess(true);
+        return flowResult;
+    }
+
     /**
      * 流程跳转到下一个节点
      */
     private FlowResult skipToNext(FlowJumpContext context) {
 
+        FlowDefinitionNode currentNode = context.getCurrentNode();
         // 寻找跳转节点
-        FlowDefinitionNode jumpNode = getNextUserNode(context.getCurrentNode(), context.getFlowDefinitionNodeList());
-
-        //如果当前节点是动态并行节点
-        if (HandleObjectTypeEnum.PARALLEL.getKey().equals(context.getCurrentNode().getHandleObjectType())) {
-            String jumpHandleUserId = context.getFlowExample().getHandleUserId();
-            List<Long> collect = Arrays.stream(jumpHandleUserId.split(",")).map(item -> Long.valueOf(item)).collect(Collectors.toList());
-            collect.remove(SecurityUtils.getUserId());
-            if (ObjectUtil.isNotEmpty(collect)) {
-                jumpHandleUserId = collect.stream().map(item -> String.valueOf(item)).collect(Collectors.joining(","));
-                jumpNode = context.getCurrentNode();
-            }
-            context.setJumpHandleUserId(jumpHandleUserId);
+        List<FlowDefinitionNode> jumpNodes = getNextUserNode(currentNode, context.getFlowDefinitionLineList());
+
+        //检查当前节点是否全部审批完成
+        long count = flowExampleCurrentService.count(q -> q
+                .eq(FlowExampleCurrent::getFlowExampleId, context.getFlowExample().getId())
+                .eq(FlowExampleCurrent::getNodeId, currentNode.getId())
+                .ne(FlowExampleCurrent::getHandleUserId, SecurityUtils.getUserId())
+        );
+
+        //如果当前节点没有全部审批完成 || 当前节点处理方式是抄送 直接跳过
+        if (count > 0 || NodeHandleTypeEnum.CARBON_COPY.getKey().equals(currentNode.getNodeHandleType())) {
+            //回填流程当前状态
+            context.setFlowStatus(FlowStatusEnum.getEnum(context.getFlowExample().getStatus()));
+            context.setJumpNodeList(new ArrayList<>());
+            return new FlowResult(true);
         }
 
-        context.setJumpNode(jumpNode);
+        List<FlowDefinitionNode> newJumpNodes = new ArrayList<>();
 
-        // 如果下一节点为结束节点
-        if (NodeTypeEnum.END.equals(NodeTypeEnum.getEnum(jumpNode.getNodeType()))) {
-            // 流程已通过
-            context.setFlowStatus(FlowStatusEnum.PASS);
-            // 流程结束,则流程节点审批人不存在
-            context.setJumpHandleUserId(null);
-            return new FlowResult(true);
+        for (FlowDefinitionNode jumpNode : jumpNodes) {
+            // 如果下一节点包含结束节点
+            if (NodeTypeEnum.END.getKey().equals(jumpNode.getNodeType())) {
+                // 流程已通过
+                context.setFlowStatus(FlowStatusEnum.PASS);
+                context.setJumpNodeList(Collections.singletonList(jumpNode));
+                // 流程结束,则流程节点审批人不存在
+                jumpNode.setJumpHandleUserId(null);
+                return new FlowResult(true);
+            }
+
+            // 如果下一节点包含聚合节点
+            if (NodeHandleTypeEnum.POLYMERIZE.getKey().equals(jumpNode.getNodeHandleType())) {
+                List<FlowDefinitionNode> lastUserNodeList = getLastOneUserNode(jumpNode, context.getFlowDefinitionNodeList(), context.getFlowExample().getDefinitionId());
+                List<Long> lastNodeIds = lastUserNodeList.stream().map(FlowDefinitionNode::getId).collect(Collectors.toList());
+                long count1 = flowExampleCurrentService.count(q -> q
+                        .eq(FlowExampleCurrent::getFlowExampleId, context.getFlowExample().getId())
+                        .in(FlowExampleCurrent::getNodeId, lastNodeIds)
+                        .ne(FlowExampleCurrent::getHandleUserId, SecurityUtils.getUserId())
+                );
+                //聚合节点存在未完成的前置节点
+                if (count1 > 0) {
+                    continue;
+                }
+            }
+
+
+            newJumpNodes.add(jumpNode);
         }
 
-        // 寻找节点审批人
-        FlowResult flowResult = getHandleUser(jumpNode, context.getJumpHandleUserId());
+        // 寻找节点审批人,并生成待审批数据
+//        FlowResult flowResult = getHandleUser(jumpNode, context.getSelectUserList());
+        FlowResult flowResult = setNextHandleNodeHandleUser(newJumpNodes, context.getSelectUserList());
         // 流程进行中
         context.setFlowStatus(FlowStatusEnum.IN_PROGRESS);
-        // 赋值流程节点审批人
-        context.setJumpHandleUserId(flowResult.getUserId());
+//        // 赋值流程节点审批人
+//        context.setJumpHandleUserId(flowResult.getUserId());
+        context.setJumpNodeList(newJumpNodes);
 
         return flowResult;
     }
@@ -363,12 +452,14 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     private FlowResult reject(FlowJumpContext context) {
         // 流程已驳回
         context.setFlowStatus(FlowStatusEnum.REJECT);
-        // 流程结束,则流程节点审批人不存在
-        context.setJumpHandleUserId(null);
+//        // 流程结束,则流程节点审批人不存在
+//        context.setJumpHandleUserId(null);
+
+        flowExampleCurrentService.remove(q -> q.eq(FlowExampleCurrent::getFlowExampleId, context.getFlowExample().getId()));
 
         for (FlowDefinitionNode flowDefinitionNode : context.getFlowDefinitionNodeList()) {
             if (NodeTypeEnum.END.getKey().equals(flowDefinitionNode.getNodeType())) {
-                context.setJumpNode(flowDefinitionNode);
+                context.setJumpNodeList(new ArrayList<>());
                 return new FlowResult(true);
             }
         }
@@ -380,24 +471,32 @@ public class FlowProcessServiceImpl implements FlowProcessService {
      */
     private FlowResult returnToPrevious(FlowJumpContext context) {
 
+        FlowDefinitionNode currentNode = context.getCurrentNode();
+
         // 寻找跳转节点
-        FlowDefinitionNode jumpNode = getLastOneUserNode(context.getCurrentNode(), context.getFlowDefinitionNodeList());
-        context.setJumpNode(jumpNode);
+        Long definitionId = context.getFlowExample().getDefinitionId();
+        List<FlowDefinitionNode> jumpNodes = getLastOneUserNode(currentNode, context.getFlowDefinitionNodeList(), definitionId);
+        context.setJumpNodeList(jumpNodes);
+
+        FlowDefinitionNode startNode = jumpNodes.stream()
+                .filter(item -> ObjectUtil.equals(NodeTypeEnum.getEnum(item.getNodeType()), NodeTypeEnum.START))
+                .findFirst().orElse(null);
 
         // 如果流程回退到开始节点
-        if (NodeTypeEnum.START.getKey().equals(jumpNode.getNodeType())) {
+        if (startNode != null) {
             // 流程未发起
             context.setFlowStatus(FlowStatusEnum.READY_START);
             // 流程节点处理人为流程发起人
-            context.setJumpHandleUserId(String.valueOf(context.getFlowExample().getCreateUser()));
+            startNode.setJumpHandleUserId(String.valueOf(context.getFlowExample().getCreateUser()));
+
+            context.setJumpNodeList(Collections.singletonList(startNode));
             return new FlowResult(true);
         }
 
-        FlowResult flowResult = getHandleUser(jumpNode, context.getJumpHandleUserId());
+        // 赋值流程节点审批人
+        FlowResult flowResult = setNextHandleNodeHandleUser(jumpNodes, context.getSelectUserList());
         // 流程进行中
         context.setFlowStatus(FlowStatusEnum.IN_PROGRESS);
-        // 赋值流程节点审批人
-        context.setJumpHandleUserId(flowResult.getUserId());
 
         return flowResult;
     }
@@ -408,12 +507,13 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     private FlowResult returnToSubmitter(FlowJumpContext context) {
         // 流程未发起
         context.setFlowStatus(FlowStatusEnum.READY_START);
-        // 赋值发起人为节点审批人
-        context.setJumpHandleUserId(String.valueOf(context.getFlowExample().getCreateUser()));
 
         for (FlowDefinitionNode flowDefinitionNode : context.getFlowDefinitionNodeList()) {
             if (NodeTypeEnum.START.getKey().equals(flowDefinitionNode.getNodeType())) {
-                context.setJumpNode(flowDefinitionNode);
+                // 赋值发起人为节点审批人
+                flowDefinitionNode.setJumpHandleUserId(String.valueOf(context.getFlowExample().getCreateUser()));
+
+                context.setJumpNodeList(Collections.singletonList(flowDefinitionNode));
                 return new FlowResult(true);
             }
         }
@@ -426,12 +526,15 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     private FlowResult cancellation(FlowJumpContext context) {
         // 流程未发起
         context.setFlowStatus(FlowStatusEnum.CANCELLATION);
-        // 流程作废,则流程节点审批人不存在
-        context.setJumpHandleUserId(null);
+
+        flowExampleCurrentService.remove(q -> q.eq(FlowExampleCurrent::getFlowExampleId, context.getFlowExample().getId()));
 
         for (FlowDefinitionNode flowDefinitionNode : context.getFlowDefinitionNodeList()) {
             if (NodeTypeEnum.END.getKey().equals(flowDefinitionNode.getNodeType())) {
-                context.setJumpNode(flowDefinitionNode);
+                // 流程作废,则流程节点审批人不存在
+                flowDefinitionNode.setJumpHandleUserId(null);
+
+                context.setJumpNodeList(new ArrayList<>());
                 return new FlowResult(true);
             }
         }
@@ -439,8 +542,8 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     }
 
     private FlowResult transfer(FlowJumpContext context, JumpDto dto) {
-        String handleUserId = dto.getHandleUserId();
-        if (ObjectUtil.isEmpty(handleUserId)) {
+        List<FlowResult.SelectUser> handleUserList = dto.getSelectUserList();
+        if (ObjectUtil.isEmpty(handleUserList)) {
             List<SysUser> userList = sysUserService.list(Wrappers.<SysUser>query().eq("company_id", SecurityUtils.getCompanyId()));
 
             FlowResult flowResult = new FlowResult();
@@ -450,29 +553,15 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         }
 
         //生成下一节点信息(复制当前节点)
-        FlowResult flowResult = getHandleUser(context.getCurrentNode(), context.getJumpHandleUserId());
+        FlowDefinitionNode currentNode = context.getCurrentNode();
         // 流程进行中
         context.setFlowStatus(FlowStatusEnum.IN_PROGRESS);
 
-        //如果当前节点是动态并行节点
-        if (HandleObjectTypeEnum.PARALLEL.getKey().equals(context.getCurrentNode().getHandleObjectType())) {
-            String jumpHandleUserId = context.getJumpHandleUserId();
-            List<Long> collect = Arrays.stream(jumpHandleUserId.split(",")).map(item -> Long.valueOf(item)).collect(Collectors.toList());
-            collect.remove(SecurityUtils.getUserId());
-            //添加加签用户
-            collect.add(Long.valueOf(jumpHandleUserId));
-            if (ObjectUtil.isNotEmpty(collect)) {
-                jumpHandleUserId = collect.stream().map(item -> String.valueOf(item)).collect(Collectors.joining(","));
-            }
-            context.setJumpHandleUserId(jumpHandleUserId);
-        } else {
-            // 赋值流程节点审批人为加签用户
-            context.setJumpHandleUserId(handleUserId);
-        }
-
+        String handleUserIdStr = handleUserList.stream().map(FlowResult.SelectUser::getHandleUserId).collect(Collectors.joining(","));
+        currentNode.setJumpHandleUserId(handleUserIdStr);
 
-        context.setJumpNode(context.getCurrentNode());
-        return flowResult;
+        context.setJumpNodeList(Collections.singletonList(currentNode));
+        return new FlowResult(true);
     }
 
     /**
@@ -511,22 +600,22 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         // 查找指定节点信息
         FlowDefinitionNode jumpNode = nodeMap.get(handleNodeId);
 
-        context.setJumpNode(jumpNode);
+        context.setJumpNodeList(Collections.singletonList(jumpNode));
 
         // 如果流程回退到开始节点
         if (NodeTypeEnum.START.getKey().equals(jumpNode.getNodeType())) {
             // 流程未发起
             context.setFlowStatus(FlowStatusEnum.READY_START);
             // 流程节点处理人为流程发起人
-            context.setJumpHandleUserId(String.valueOf(context.getFlowExample().getCreateUser()));
+            jumpNode.setJumpHandleUserId(String.valueOf(context.getFlowExample().getCreateUser()));
             return new FlowResult(true);
         }
 
-        FlowResult flowResult = getHandleUser(jumpNode, context.getJumpHandleUserId());
+        FlowResult flowResult = getHandleUser(jumpNode, context.getSelectUserList());
         // 流程进行中
         context.setFlowStatus(FlowStatusEnum.IN_PROGRESS);
         // 赋值流程节点审批人
-        context.setJumpHandleUserId(flowResult.getUserId());
+        jumpNode.setJumpHandleUserId(flowResult.getUserId());
 
         return flowResult;
     }
@@ -579,7 +668,10 @@ public class FlowProcessServiceImpl implements FlowProcessService {
 
         // 结束节点
         if (FlowStatusEnum.PASS.equals(flowStatus)) {
-            invokeEndMethod(context.getJumpNode(), flowDelegate);
+            FlowDefinitionNode endNode = context.getJumpNodeList().stream()
+                    .filter(item -> ObjectUtil.equals(NodeTypeEnum.getEnum(item.getNodeType()), NodeTypeEnum.END))
+                    .findFirst().orElse(null);
+            invokeEndMethod(endNode, flowDelegate);
         }
 
     }
@@ -635,7 +727,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         JumpDto dto = context.getJumpDto();
         FlowExample flowExample = context.getFlowExample();
         FlowDefinitionNode currentNode = context.getCurrentNode();
-        FlowDefinitionNode jumpNode = context.getJumpNode();
+//        FlowDefinitionNode jumpNode = context.getJumpNode();
 
         //退回发起人后 重新赋值流程标题
         if (ObjectUtil.isNotEmpty(dto.getData())) {
@@ -658,8 +750,8 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         }
 
         // 更新流程实例
-        flowExample.setDefinitionNodeId(jumpNode.getId());
-        flowExample.setHandleUserId(context.getJumpHandleUserId());
+//        flowExample.setDefinitionNodeId(jumpNode.getId());
+//        flowExample.setHandleUserId(context.getJumpHandleUserId());
         flowExample.setStatus(context.getFlowStatus().getKey());
         boolean updateFlag = flowExampleService.updateById(flowExample);
         if (!updateFlag) {
@@ -677,14 +769,23 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         nodeExampleDetail.setSubmitData(JSONObject.toJSONString(dto));
         flowExampleDetailList.add(nodeExampleDetail);
 
+
+        List<FlowDefinitionNode> jumpNodeList = context.getJumpNodeList();
         // 如果流程已结束
         if (FlowStatusEnum.PASS.equals(context.getFlowStatus())) {
-            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);
+            for (FlowDefinitionNode flowDefinitionNode : jumpNodeList) {
+                if (NodeTypeEnum.END.equals(NodeTypeEnum.getEnum(flowDefinitionNode.getNodeType()))) {
+                    FlowExampleDetail endExampleDetail = new FlowExampleDetail();
+                    endExampleDetail.setFlowExampleId(flowExample.getId());
+                    endExampleDetail.setFlowDefinitionNodeId(flowDefinitionNode.getId());
+                    endExampleDetail.setFlowDefinitionNodeType(flowDefinitionNode.getNodeType());
+                    endExampleDetail.setHandleType(HandleTypeEnum.SKIP_TO_NEXT.getKey());
+                    flowExampleDetailList.add(endExampleDetail);
+                }
+            }
+        } else {
+            //保存待办信息
+            createPendingInfo(jumpNodeList, context.getFlowExample().getId());
         }
 
         // 保存流程明细
@@ -696,85 +797,90 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     }
 
     /**
+     * 创建待办信息
+     */
+    void createPendingInfo(List<FlowDefinitionNode> jumpNodeList, Long flowId) {
+        List<FlowExampleCurrent> flowExampleCurrentList = new ArrayList<>();
+        for (FlowDefinitionNode flowDefinitionNode : jumpNodeList) {
+            String jumpHandleUserId = flowDefinitionNode.getJumpHandleUserId();
+            List<Long> collect = Arrays.stream(jumpHandleUserId.split(",")).map(Long::valueOf).collect(Collectors.toList());
+            for (Long userId : collect) {
+                FlowExampleCurrent flowExampleCurrent = new FlowExampleCurrent();
+                flowExampleCurrent.setFlowExampleId(flowId);
+                flowExampleCurrent.setNodeId(flowDefinitionNode.getId());
+                flowExampleCurrent.setHandleUserId(userId);
+                flowExampleCurrentList.add(flowExampleCurrent);
+            }
+        }
+        //保存待办信息
+        flowExampleCurrentService.saveBatch(flowExampleCurrentList);
+    }
+
+    /**
      * 查找上一个节点
      *
      * @param currentNode            当前节点
      * @param flowDefinitionNodeList 流程节点列表
      * @return 用户节点
      */
-    private FlowDefinitionNode getLastOneUserNode(FlowDefinitionNode currentNode, List<FlowDefinitionNode> flowDefinitionNodeList) {
+    private List<FlowDefinitionNode> getLastOneUserNode(FlowDefinitionNode currentNode, List<FlowDefinitionNode> flowDefinitionNodeList, Long flowDefinitionId) {
+        List<Long> lastNodeIds = flowDefinitionLineService.listObject(FlowDefinitionLine::getSourceId, q -> q
+                .eq(FlowDefinitionLine::getFlowDefinitionId, flowDefinitionId)
+                .eq(FlowDefinitionLine::getTargetId, currentNode.getId()));
+
         // 节点map
         Map<Long, FlowDefinitionNode> nodeMap = flowDefinitionNodeList.stream()
                 .collect(Collectors.toMap(FlowDefinitionNode::getId, Function.identity()));
 
         // 查找上个节点
-        FlowDefinitionNode lastNode = nodeMap.get(currentNode.getParentId());
-
-        // 如果为分支
-        if (NodeTypeEnum.BRANCH.equals(NodeTypeEnum.getEnum(lastNode.getNodeType()))) {
-            return getLastOneUserNode(lastNode, flowDefinitionNodeList);
+        List<FlowDefinitionNode> lastNodeList = new ArrayList<>();
+        for (Long lastNodeId : lastNodeIds) {
+            lastNodeList.add(nodeMap.get(lastNodeId));
         }
+//
+//        // 如果为分支
+//        if (NodeTypeEnum.BRANCH.equals(NodeTypeEnum.getEnum(lastNode.getNodeType()))) {
+//            return getLastOneUserNode(lastNode, flowDefinitionNodeList);
+//        }
 
-        return lastNode;
+        return lastNodeList;
     }
 
     /**
      * 查找下一个节点
      *
      * @param currentNode            当前节点
-     * @param flowDefinitionNodeList 流程节点列表
+     * @param flowDefinitionLineList 流程节点连线列表
      * @return 用户节点
      */
-    private FlowDefinitionNode getNextUserNode(FlowDefinitionNode currentNode, List<FlowDefinitionNode> flowDefinitionNodeList) {
-
-        // 父级节点map
-        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()))) {
-            // 循环分支
-            for (FlowDefinitionNode flowDefinitionNode : nextNodeList) {
-                // 获取跳转条件
-                String jumpCondition = flowDefinitionNode.getJumpCondition();
-                // 跳转条件为空表示默认跳转
-                if (StrUtil.isBlank(jumpCondition)) {
-                    nextNode = flowDefinitionNode;
-                    continue;
-                }
-                // 符合条件
-                if (expressionResult(FlowThreadLocalUtil.getTemplateData(), jumpCondition)) {
-                    nextNode = flowDefinitionNode;
-                    break;
-                }
-            }
-            if (nextNode == null) {
-                throw new ServiceException("流程定义错误:分支节点未识别到有效跳转节点");
-            }
-        }
+    private List<FlowDefinitionNode> getNextUserNode(FlowDefinitionNode currentNode, List<FlowDefinitionLine> flowDefinitionLineList) {
 
-        // 如果不为分支
-        else {
-            if (nextNodeList == null || nextNodeList.size() == 0) {
-                throw new ServiceException("流程定义错误:用户节点未找到跳转节点");
-            }
-            if (nextNodeList.size() > 1) {
-                throw new ServiceException("流程定义错误:用户节点找到多个跳转节点");
-            }
-            // 查找下一个节点方法
-            nextNode = nextNodeList.get(0);
+        //获取当前节点之后的连线
+        List<FlowDefinitionLine> nextLineList = flowDefinitionLineList.stream()
+                .filter(item -> ObjectUtil.equals(item.getSourceId(), currentNode.getId()))
+                .collect(Collectors.toList());
+
+        List<Long> targetIds = nextLineList.stream().map(FlowDefinitionLine::getTargetId).collect(Collectors.toList());
+        Map<Long, FlowDefinitionNode> targetNodeMap = new HashMap<>();
+        if (ObjectUtil.isNotEmpty(targetIds)) {
+            targetNodeMap = flowDefinitionNodeService.mapKEntity(FlowDefinitionNode::getId, q -> q.in(FlowDefinitionNode::getId, targetIds));
         }
 
-        // 如果下一节点为分支,递归找下一节点
-        if (NodeTypeEnum.BRANCH.equals(NodeTypeEnum.getEnum(nextNode.getNodeType()))) {
-            return getNextUserNode(nextNode, flowDefinitionNodeList);
+        List<FlowDefinitionNode> nextNodeList = new ArrayList<>();
+        for (FlowDefinitionLine flowDefinitionLine : nextLineList) {
+            // 获取跳转条件
+            String jumpCondition = flowDefinitionLine.getJumpCondition();
+            // 跳转条件为空表示默认跳转,或者符合表达式条件
+            if (StrUtil.isBlank(jumpCondition) || expressionResult(FlowThreadLocalUtil.getTemplateData(), jumpCondition)) {
+                FlowDefinitionNode targetNode = targetNodeMap.get(flowDefinitionLine.getTargetId());
+                if (ObjectUtil.isEmpty(flowDefinitionLine)) {
+                    throw new ServiceException("目标节点不存在!");
+                }
+                nextNodeList.add(targetNode);
+            }
         }
 
-        return nextNode;
+        return nextNodeList;
     }
 
     /**
@@ -783,9 +889,11 @@ public class FlowProcessServiceImpl implements FlowProcessService {
      * @param node 处理节点
      * @return 处理用户
      */
-    private FlowResult getHandleUser(FlowDefinitionNode node, String handleUserId) {
+    private FlowResult getHandleUser(FlowDefinitionNode node, List<FlowResult.SelectUser> handleUserList) {
+        Map<Long, String> handleUserMap = handleUserList.stream().collect(Collectors.toMap(FlowResult.SelectUser::getNodeId, FlowResult.SelectUser::getHandleUserId));
         FlowResult flowResult = new FlowResult();
 
+        String handleUserId = handleUserMap.get(node.getId());
         if (ObjectUtil.isNotEmpty(handleUserId)) {
             flowResult.setSuccess(true);
             flowResult.setUserId(handleUserId);
@@ -873,8 +981,9 @@ public class FlowProcessServiceImpl implements FlowProcessService {
                 flowResult.setUserId(dynamicUserIdsStr);
                 return flowResult;
             case DEPT_MANAGER:
+                SysUser createUser = sysUserService.getById(FlowThreadLocalUtil.getFlowCreateUser());
                 List<SysUserIdentity> identityList = sysUserIdentityService.list(Wrappers.<SysUserIdentity>lambdaQuery()
-                        .eq(SysUserIdentity::getDeptId, SecurityUtils.getDeptId())
+                        .eq(SysUserIdentity::getDeptId, createUser.getDeptId())
                         .eq(SysUserIdentity::getIdentity, 20)
                 );
                 if (identityList.size() == 0) {
@@ -890,6 +999,20 @@ public class FlowProcessServiceImpl implements FlowProcessService {
                 flowResult.setSuccess(false);
                 flowResult.setUserList(identityUserList);
                 return flowResult;
+            case BUSINESS_USER:
+                Expression exp = AviatorEvaluator.compile(node.getJumpCondition());
+                Object execute = exp.execute(FlowThreadLocalUtil.getTemplateData());
+                if (ObjectUtil.isEmpty(execute)) {
+                    throw new ServiceException("节点用户表达式结果不能为空!");
+                }
+                String userId = String.valueOf(execute);
+                SysUser sysUser = sysUserService.getById(Long.valueOf(userId));
+                if (ObjectUtil.isEmpty(sysUser)) {
+                    throw new ServiceException("节点表达式用户不存在!");
+                }
+                flowResult.setSuccess(true);
+                flowResult.setUserId(userId);
+                return flowResult;
 
             default:
                 throw new ServiceException("未知用户处理类型:" + handleObjectType);
@@ -900,22 +1023,30 @@ public class FlowProcessServiceImpl implements FlowProcessService {
     /**
      * 开始节点消息推送
      */
-    private void pushInitiateMessage(long flowId, FlowDefinition flowDefinition, NodeTypeEnum nextNodeType, FlowExample flowExample) {
+    private void pushInitiateMessage(long flowId, FlowDefinition flowDefinition, List<FlowDefinitionNode> nextNodes) {
         Map<String, Object> businessData = new HashMap<>();
         businessData.put("flowId", flowId);
         businessData.put("flowKey", flowDefinition.getFlowKey());
 
+        FlowDefinitionNode endNode = nextNodes.stream()
+                .filter(item -> ObjectUtil.equals(NodeTypeEnum.getEnum(item.getNodeType()), NodeTypeEnum.END))
+                .findFirst().orElse(null);
+
         List<Long> pushUserIds = new ArrayList<>();
         String title;
-        if (NodeTypeEnum.END.equals(nextNodeType)) {
+
+        //下一节点包含 结束节点
+        if (endNode != null) {
             FlowInfo flowInfo = flowInfoService.getById(flowDefinition.getFlowInfoId());
             String flowName = flowInfo == null ? StringPool.EMPTY : flowInfo.getFlowName();
 
             pushUserIds.add(SecurityUtils.getUserId());
             title = StrUtil.format("您于【{}】发起的【{}】已经审批通过。", DateUtil.formatDateTime(new Date()), flowName);
         } else {
-            for (String s : flowExample.getHandleUserId().split(",")) {
-                pushUserIds.add(Long.valueOf(s));
+            for (FlowDefinitionNode nextNode : nextNodes) {
+                for (String s : nextNode.getJumpHandleUserId().split(",")) {
+                    pushUserIds.add(Long.valueOf(s));
+                }
             }
             title = "您有一条新的待审批事项,请及时处理。";
         }
@@ -938,9 +1069,19 @@ public class FlowProcessServiceImpl implements FlowProcessService {
 
         FlowExample flowExample = context.getFlowExample();
         FlowStatusEnum flowStatusEnum = context.getFlowStatus();
-        FlowDefinitionNode jumpNode = context.getJumpNode();
         FlowDefinitionNode currentNode = context.getCurrentNode();
-        String jumpHandleUserId = context.getJumpHandleUserId();
+
+        //获取所有下一节点处理用户
+        List<Long> jumpHandleUserIdList = new ArrayList<>();
+        List<FlowDefinitionNode> jumpNodeList = context.getJumpNodeList();
+        String jumpHandleUserIds = jumpNodeList.stream()
+                .map(FlowDefinitionNode::getJumpHandleUserId).collect(Collectors.joining(","));
+        if (ObjectUtil.isNotEmpty(jumpHandleUserIdList)) {
+            String[] split = jumpHandleUserIds.split(",");
+            for (String s : split) {
+                jumpHandleUserIdList.add(Long.valueOf(s));
+            }
+        }
 
         Map<String, Object> businessData = new HashMap<>();
         businessData.put("flowId", flowExample.getId());
@@ -949,8 +1090,7 @@ public class FlowProcessServiceImpl implements FlowProcessService {
         FlowInfo flowInfo = flowInfoService.getOne(q -> q.eq(FlowInfo::getFlowKey, flowExample.getFlowKey()));
         String flowName = flowInfo == null ? StringPool.EMPTY : flowInfo.getFlowName();
 
-        String title;
-        List<Long> pushUserIds = new ArrayList<>();
+        List<PushParam> pushUserList = new ArrayList<>();
 
         switch (handleTypeEnum) {
             // 跳转下一节点
@@ -959,65 +1099,80 @@ public class FlowProcessServiceImpl implements FlowProcessService {
             case SKIP_TO_NEXT:
                 // 如果流程结束
                 if (FlowStatusEnum.PASS.equals(flowStatusEnum)) {
-                    title = StrUtil.format("您于【{}】发起的【{}】已经审批通过。",
+                    String title = StrUtil.format("您于【{}】发起的【{}】已经审批通过。",
                             DateUtil.formatDateTime(flowExample.getCreateTime()),
                             flowName);
-                    pushUserIds.add(flowExample.getCreateUser());
+                    PushParam pushParam = new PushParam();
+                    pushParam.setUserId(flowExample.getCreateUser());
+                    pushParam.setTitle(title);
+                    pushUserList.add(pushParam);
                 }
                 // 如果下一节点不为结束节点
                 else {
-                    title = "您有一条新的待审批事项,请及时处理。";
-                    for (String s : jumpHandleUserId.split(",")) {
-                        pushUserIds.add(Long.valueOf(s));
+                    String title = "您有一条新的待审批事项,请及时处理。";
+                    for (Long userId : jumpHandleUserIdList) {
+                        PushParam pushParam = new PushParam();
+                        pushParam.setUserId(userId);
+                        pushParam.setTitle(title);
+                        pushUserList.add(pushParam);
                     }
                 }
                 break;
 
             // 驳回流程
             case REJECT:
-                title = StrUtil.format("您于【{}】发起的【{}】在【{}】被驳回。",
+                String title = StrUtil.format("您于【{}】发起的【{}】在【{}】被驳回。",
                         DateUtil.formatDateTime(flowExample.getCreateTime()),
                         flowName,
                         currentNode.getNodeName());
-                pushUserIds.add(flowExample.getCreateUser());
+                PushParam pushParam = new PushParam();
+                pushParam.setUserId(flowExample.getCreateUser());
+                pushParam.setTitle(title);
+                pushUserList.add(pushParam);
                 break;
 
             // 退回上一节点
             case RETURN_TO_NODE:
             case RETURN_TO_PREVIOUS:
 
+                List<Long> lastNodeIds = flowDefinitionLineService.listObject(FlowDefinitionLine::getSourceId, q -> q
+                        .eq(FlowDefinitionLine::getFlowDefinitionId, context.getFlowExample().getDefinitionId())
+                        .eq(FlowDefinitionLine::getTargetId, context.getCurrentNode().getId()));
+
                 // 查找上次审批节点
-                FlowExampleDetail flowExampleDetail = flowExampleDetailService.getOne(q -> q
+                List<FlowExampleDetail> flowExampleDetailList = flowExampleDetailService.list(q -> q
                         .eq(FlowExampleDetail::getFlowExampleId, flowExample.getId())
-                        .eq(FlowExampleDetail::getFlowDefinitionNodeId, jumpNode.getId())
+                        .in(FlowExampleDetail::getFlowDefinitionNodeId, lastNodeIds)
                         .orderByDesc(BaseIdPo::getId));
-
-                title = StrUtil.format("您于【{}】提交的【{}】被退回,请及时处理。",
-                        DateUtil.formatDateTime(flowExampleDetail.getCreateTime()),
-                        flowName);
-
-                for (String s : jumpHandleUserId.split(",")) {
-                    pushUserIds.add(Long.valueOf(s));
+                for (FlowExampleDetail flowExampleDetail : flowExampleDetailList) {
+                    String title1 = StrUtil.format("您于【{}】提交的【{}】被退回,请及时处理。",
+                            DateUtil.formatDateTime(flowExampleDetail.getCreateTime()),
+                            flowName);
+                    PushParam pushParam1 = new PushParam();
+                    pushParam1.setUserId(flowExampleDetail.getCreateUser());
+                    pushParam1.setTitle(title1);
+                    pushUserList.add(pushParam1);
                 }
                 break;
 
             // 退回到发起人
             case RETURN_TO_SUBMITTER:
-                title = StrUtil.format("您于【{}】提交的【{}】被退回,请及时处理。",
+                String title2 = StrUtil.format("您于【{}】提交的【{}】被退回,请及时处理。",
                         DateUtil.formatDateTime(flowExample.getCreateTime()),
                         flowName);
 
-                for (String s : jumpHandleUserId.split(",")) {
-                    pushUserIds.add(Long.valueOf(s));
-                }
+                PushParam pushParam2 = new PushParam();
+                pushParam2.setUserId(flowExample.getCreateUser());
+                pushParam2.setTitle(title2);
+                pushUserList.add(pushParam2);
                 break;
 
             default:
                 throw new ServiceException("未知流程跳转类型");
         }
 
-        for (Long pushUserId : pushUserIds) {
-            WebSocketPush.byUser(PushTypeEnum.MESSAGE, pushUserId, title, 0, businessData);
+        for (PushParam pushParam : pushUserList) {
+            WebSocketPush.byUser(PushTypeEnum.MESSAGE, pushParam.getUserId(), pushParam.getTitle(), 0, businessData);
         }
     }
 

+ 4 - 0
hx-flow/src/main/resources/mapper/flow/FlowDefinitionLineMapper.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fjhx.flow.mapper.flow.FlowDefinitionLineMapper">
+</mapper>

+ 4 - 2
hx-flow/src/main/resources/mapper/flow/FlowExampleMapper.xml

@@ -12,11 +12,13 @@
                fe.create_time,
                fe.business_id,
                fe.version,
-               fdn.node_name
+               fdn.node_name,
+               fdn.node_handle_type
         from flow_info fi
                  inner join flow_definition fd on fd.flow_info_id = fi.id
                  inner join flow_example fe on fe.definition_id = fd.id
-                 INNER JOIN flow_definition_node fdn ON fe.definition_node_id = fdn.id
+                 LEFT JOIN flow_example_current fec ON fec.flow_example_id = fe.id
+                 LEFT JOIN flow_definition_node fdn ON fec.node_id = fdn.id
             ${ew.customSqlSegment}
     </select>