From dc5e5c07549b493e21c11dc7929c32ea9fd732b0 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期四, 08 十月 2026 17:08:26 +0800
Subject: [PATCH] 协同办公系统模块优化

---
 src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java     |  380 ++++++++++------
 src/main/java/com/ruoyi/approve/mapper/ApproveFlowDefinitionMapper.java         |    7 
 src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java                        |   35 +
 src/main/java/com/ruoyi/approve/vo/ApproveGetAndUpdateVo.java                   |   36 +
 src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java                        |   36 +
 src/main/resources/mapper/approve/ApproveLogMapper.xml                          |    8 
 src/main/java/com/ruoyi/approve/service/IApproveProcessService.java             |    2 
 src/main/java/com/ruoyi/approve/pojo/ApproveFlowNodeDefinition.java             |   59 ++
 src/main/java/com/ruoyi/approve/pojo/ApproveFlowDefinition.java                 |   50 ++
 src/main/java/com/ruoyi/approve/pojo/ApproveLog.java                            |   22 
 src/main/resources/mapper/approve/ApproveProcessMapper.xml                      |   17 
 src/main/java/com/ruoyi/approve/enums/ApproveType.java                          |   34 +
 src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java        |  320 ++++++++-----
 src/main/java/com/ruoyi/approve/vo/ApproveNodeVO.java                           |   25 +
 src/main/resources/mapper/approve/ApproveNodeMapper.xml                         |   10 
 src/main/java/com/ruoyi/approve/controller/ApproveFlowDefinitionController.java |  159 ++++++
 src/main/java/com/ruoyi/approve/mapper/ApproveFlowNodeDefinitionMapper.java     |    7 
 src/main/java/com/ruoyi/approve/controller/ApproveProcessController.java        |   61 +-
 src/main/java/com/ruoyi/approve/pojo/ApproveNode.java                           |   35 +
 src/main/java/com/ruoyi/approve/vo/ApproveFlowDefinitionVO.java                 |   17 
 src/main/java/com/ruoyi/approve/service/IApproveNodeService.java                |    4 
 21 files changed, 1,022 insertions(+), 302 deletions(-)

diff --git a/src/main/java/com/ruoyi/approve/controller/ApproveFlowDefinitionController.java b/src/main/java/com/ruoyi/approve/controller/ApproveFlowDefinitionController.java
new file mode 100644
index 0000000..6ddbf7c
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/controller/ApproveFlowDefinitionController.java
@@ -0,0 +1,159 @@
+package com.ruoyi.approve.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.approve.mapper.ApproveFlowDefinitionMapper;
+import com.ruoyi.approve.mapper.ApproveFlowNodeDefinitionMapper;
+import com.ruoyi.approve.mapper.ApproveProcessMapper;
+import com.ruoyi.approve.pojo.ApproveFlowDefinition;
+import com.ruoyi.approve.pojo.ApproveFlowNodeDefinition;
+import com.ruoyi.approve.pojo.ApproveProcess;
+import com.ruoyi.approve.vo.ApproveFlowDefinitionVO;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+
+@RestController
+@RequestMapping("/approveFlowDefinition")
+public class ApproveFlowDefinitionController {
+    private final ApproveFlowDefinitionMapper definitionMapper;
+    private final ApproveFlowNodeDefinitionMapper nodeMapper;
+    private final ApproveProcessMapper processMapper;
+
+    public ApproveFlowDefinitionController(ApproveFlowDefinitionMapper definitionMapper,
+                                           ApproveFlowNodeDefinitionMapper nodeMapper,
+                                           ApproveProcessMapper processMapper) {
+        this.definitionMapper = definitionMapper;
+        this.nodeMapper = nodeMapper;
+        this.processMapper = processMapper;
+    }
+
+    @GetMapping("/list")
+    public AjaxResult list(Integer approveType) {
+        LambdaQueryWrapper<ApproveFlowDefinition> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(ApproveFlowDefinition::getTenantId, SecurityUtils.getLoginUser().getTenantId())
+                .eq(ApproveFlowDefinition::getDeleteFlag, 0)
+                .eq(approveType != null, ApproveFlowDefinition::getApproveType, approveType)
+                .orderByDesc(ApproveFlowDefinition::getIsDefault)
+                .orderByDesc(ApproveFlowDefinition::getUpdateTime);
+        return AjaxResult.success(definitionMapper.selectList(wrapper));
+    }
+
+    @GetMapping("/{id}")
+    public AjaxResult get(@PathVariable Long id) {
+        ApproveFlowDefinition definition = getOwned(id);
+        ApproveFlowDefinitionVO result = new ApproveFlowDefinitionVO();
+        result.setDefinition(definition);
+        result.setNodes(nodeMapper.selectList(new LambdaQueryWrapper<ApproveFlowNodeDefinition>()
+                .eq(ApproveFlowNodeDefinition::getFlowDefinitionId, id)
+                .eq(ApproveFlowNodeDefinition::getTenantId, definition.getTenantId())
+                .eq(ApproveFlowNodeDefinition::getDeleteFlag, 0)
+                .orderByAsc(ApproveFlowNodeDefinition::getNodeOrder)));
+        return AjaxResult.success(result);
+    }
+
+    @PostMapping
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult add(@RequestBody ApproveFlowDefinitionVO request) {
+        saveDefinition(request, false);
+        return AjaxResult.success();
+    }
+
+    @PutMapping("/{id}")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult update(@PathVariable Long id, @RequestBody ApproveFlowDefinitionVO request) {
+        getOwned(id);
+        request.getDefinition().setId(id);
+        saveDefinition(request, true);
+        return AjaxResult.success();
+    }
+
+    @PutMapping("/{id}/enabled")
+    public AjaxResult enabled(@PathVariable Long id, @RequestParam Integer enabled) {
+        ApproveFlowDefinition definition = getOwned(id);
+        definition.setEnabled(enabled == null || enabled == 0 ? 0 : 1);
+        definition.setUpdateUser(SecurityUtils.getUserId());
+        definition.setUpdateTime(LocalDateTime.now());
+        definitionMapper.updateById(definition);
+        return AjaxResult.success();
+    }
+
+    @DeleteMapping("/{id}")
+    public AjaxResult delete(@PathVariable Long id) {
+        ApproveFlowDefinition definition = getOwned(id);
+        Long activeCount = processMapper.selectCount(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getTenantId, definition.getTenantId())
+                .eq(ApproveProcess::getFlowDefinitionId, id)
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .in(ApproveProcess::getApproveStatus, 0, 1));
+        if (activeCount != null && activeCount > 0) throw new RuntimeException("璇ユ祦绋嬩粛鏈夎繘琛屼腑鐨勫鎵癸紝涓嶈兘鍒犻櫎");
+        definition.setDeleteFlag(1);
+        definition.setUpdateUser(SecurityUtils.getUserId());
+        definition.setUpdateTime(LocalDateTime.now());
+        definitionMapper.updateById(definition);
+        return AjaxResult.success();
+    }
+
+    private void saveDefinition(ApproveFlowDefinitionVO request, boolean update) {
+        if (request == null || request.getDefinition() == null) throw new RuntimeException("娴佺▼瀹氫箟涓嶈兘涓虹┖");
+        List<ApproveFlowNodeDefinition> nodes = request.getNodes() == null ? Collections.emptyList() : request.getNodes();
+        if (nodes.isEmpty()) throw new RuntimeException("瀹℃壒娴佺▼鑷冲皯鍖呭惈涓�涓妭鐐�");
+        Long tenantId = SecurityUtils.getLoginUser().getTenantId();
+        Long userId = SecurityUtils.getUserId();
+        ApproveFlowDefinition definition = request.getDefinition();
+        definition.setTenantId(tenantId);
+        definition.setUpdateUser(userId);
+        definition.setUpdateTime(LocalDateTime.now());
+        definition.setDeleteFlag(0);
+        if (definition.getEnabled() == null) definition.setEnabled(1);
+        if (definition.getIsDefault() == null) definition.setIsDefault(0);
+        if (definition.getIsDefault() == 1) {
+            List<ApproveFlowDefinition> oldDefaults = definitionMapper.selectList(new LambdaQueryWrapper<ApproveFlowDefinition>()
+                    .eq(ApproveFlowDefinition::getTenantId, tenantId)
+                    .eq(ApproveFlowDefinition::getApproveType, definition.getApproveType())
+                    .eq(ApproveFlowDefinition::getIsDefault, 1)
+                    .eq(ApproveFlowDefinition::getDeleteFlag, 0));
+            oldDefaults.stream().filter(item -> !item.getId().equals(definition.getId())).forEach(item -> {
+                item.setIsDefault(0);
+                definitionMapper.updateById(item);
+            });
+        }
+        if (update) {
+            definitionMapper.updateById(definition);
+            nodeMapper.delete(new LambdaQueryWrapper<ApproveFlowNodeDefinition>()
+                    .eq(ApproveFlowNodeDefinition::getFlowDefinitionId, definition.getId())
+                    .eq(ApproveFlowNodeDefinition::getTenantId, tenantId));
+        } else {
+            definition.setCreateUser(userId);
+            definition.setCreateTime(LocalDateTime.now());
+            definitionMapper.insert(definition);
+        }
+        int order = 1;
+        for (ApproveFlowNodeDefinition node : nodes) {
+            node.setId(null);
+            node.setFlowDefinitionId(definition.getId());
+            node.setNodeOrder(order++);
+            node.setTenantId(tenantId);
+            node.setCreateUser(userId);
+            node.setUpdateUser(userId);
+            node.setCreateTime(LocalDateTime.now());
+            node.setUpdateTime(LocalDateTime.now());
+            node.setDeleteFlag(0);
+            if (node.getConditionOperator() == null) node.setConditionOperator("ALWAYS");
+            nodeMapper.insert(node);
+        }
+    }
+
+    private ApproveFlowDefinition getOwned(Long id) {
+        ApproveFlowDefinition definition = definitionMapper.selectOne(new LambdaQueryWrapper<ApproveFlowDefinition>()
+                .eq(ApproveFlowDefinition::getId, id)
+                .eq(ApproveFlowDefinition::getTenantId, SecurityUtils.getLoginUser().getTenantId())
+                .eq(ApproveFlowDefinition::getDeleteFlag, 0));
+        if (definition == null) throw new RuntimeException("娴佺▼瀹氫箟涓嶅瓨鍦�");
+        return definition;
+    }
+}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApproveProcessController.java b/src/main/java/com/ruoyi/approve/controller/ApproveProcessController.java
index 6fb9986..cc08b52 100644
--- a/src/main/java/com/ruoyi/approve/controller/ApproveProcessController.java
+++ b/src/main/java/com/ruoyi/approve/controller/ApproveProcessController.java
@@ -2,7 +2,6 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.pojo.AccountExpense;
 import com.ruoyi.approve.pojo.ApproveProcess;
 import com.ruoyi.approve.service.IApproveProcessService;
 import com.ruoyi.approve.vo.ApproveGetAndUpdateVo;
@@ -20,7 +19,6 @@
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.text.ParseException;
 import java.util.List;
 
 @RestController
@@ -115,7 +113,7 @@
     @DeleteMapping("/deleteIds")
     @ApiOperation(value = "鍒犻櫎瀹℃壒")
     @Transactional(rollbackFor = Exception.class)
-    public AjaxResult deleteIds(@RequestBody Long[] ids) {
+    public AjaxResult deleteIds(@RequestBody String[] ids) {
         if (ids == null || ids.length == 0) {
             return AjaxResult.warn("鍙傛暟涓嶈兘涓虹┖");
         }
@@ -123,42 +121,34 @@
         return AjaxResult.success("鎿嶄綔鎴愬姛");
     }
 
-    @ApiOperation(value = "鍏嚭绠$悊瀵煎嚭")
+    @ApiOperation(value = "鑷敱鍗忓悓瀹℃壒瀵煎嚭")
     @PostMapping("/exportOne")
     public void exportOne(HttpServletResponse response) {
-        List<ApproveProcess> accountExpenses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getApproveType, 1));
+        List<ApproveProcess> accountExpenses = exportList(1);
         ExcelUtil<ApproveProcess> util = new ExcelUtil<ApproveProcess>(ApproveProcess.class);
-        util.exportExcel(response, accountExpenses, "鍏嚭绠$悊瀵煎嚭");
+        util.exportExcel(response, accountExpenses, "鑷敱鍗忓悓瀹℃壒琛�");
     }
 
     @ApiOperation(value = "璇峰亣绠$悊瀵煎嚭")
     @PostMapping("/exportTwo")
     public void exportTwo(HttpServletResponse response) {
-        List<ApproveProcess> accountExpenses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getApproveType, 2));
+        List<ApproveProcess> accountExpenses = exportList(2);
         ExcelUtil<ApproveProcess> util = new ExcelUtil<ApproveProcess>(ApproveProcess.class);
         util.exportExcel(response, accountExpenses, "璇峰亣绠$悊瀵煎嚭");
     }
 
-    @ApiOperation(value = "鍑哄樊绠$悊瀵煎嚭")
+    @ApiOperation(value = "閿�鍞悎鍚屽鎵瑰鍑�")
     @PostMapping("/exportThree")
     public void exportThree(HttpServletResponse response) {
-        List<ApproveProcess> accountExpenses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getApproveType, 3));
+        List<ApproveProcess> accountExpenses = exportList(3);
         ExcelUtil<ApproveProcess> util = new ExcelUtil<ApproveProcess>(ApproveProcess.class);
-        util.exportExcel(response, accountExpenses, "鍑哄樊绠$悊瀵煎嚭");
+        util.exportExcel(response, accountExpenses, "閿�鍞悎鍚屽鎵硅〃");
     }
 
     @ApiOperation(value = "鎶ラ攢绠$悊瀵煎嚭")
     @PostMapping("/exportFour")
     public void exportFour(HttpServletResponse response) {
-        List<ApproveProcess> accountExpenses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getApproveType, 4));
+        List<ApproveProcess> accountExpenses = exportList(4);
         ExcelUtil<ApproveProcess> util = new ExcelUtil<ApproveProcess>(ApproveProcess.class);
         util.exportExcel(response, accountExpenses, "鎶ラ攢绠$悊瀵煎嚭");
     }
@@ -166,20 +156,37 @@
     @ApiOperation(value = "閲囪喘鐢宠瀵煎嚭")
     @PostMapping("/exportFive")
     public void exportFive(HttpServletResponse response) {
-        List<ApproveProcess> accountExpenses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getApproveType, 5));
+        List<ApproveProcess> accountExpenses = exportList(5);
         ExcelUtil<ApproveProcess> util = new ExcelUtil<ApproveProcess>(ApproveProcess.class);
-        util.exportExcel(response, accountExpenses, "閲囪喘鐢宠瀵煎嚭");
+        util.exportExcel(response, accountExpenses, "閲囪喘璁″垝瀹℃壒琛�");
     }
 
     @ApiOperation(value = "鍗忓悓瀹℃壒瀵煎嚭")
     @PostMapping("/exportZero")
     public void exportZero(HttpServletResponse response) {
-        List<ApproveProcess> accountExpenses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
-                        .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getApproveType, 0));
+        List<ApproveProcess> accountExpenses = exportList(1);
         ExcelUtil<ApproveProcess> util = new ExcelUtil<ApproveProcess>(ApproveProcess.class);
-        util.exportExcel(response, accountExpenses, "鍗忓悓瀹℃壒瀵煎嚭");
+        util.exportExcel(response, accountExpenses, "鑷敱鍗忓悓瀹℃壒琛�");
+    }
+
+    @ApiOperation(value = "鎶ヤ环瀹℃壒瀵煎嚭")
+    @PostMapping("/exportSix")
+    public void exportSix(HttpServletResponse response) {
+        ExcelUtil<ApproveProcess> util = new ExcelUtil<>(ApproveProcess.class);
+        util.exportExcel(response, exportList(6), "鎶ヤ环瀹℃壒琛�");
+    }
+
+    @ApiOperation(value = "鍑哄簱瀹℃壒瀵煎嚭")
+    @PostMapping("/exportSeven")
+    public void exportSeven(HttpServletResponse response) {
+        ExcelUtil<ApproveProcess> util = new ExcelUtil<>(ApproveProcess.class);
+        util.exportExcel(response, exportList(7), "鍑哄簱瀹℃壒琛�");
+    }
+
+    private List<ApproveProcess> exportList(int type) {
+        return approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .eq(ApproveProcess::getApproveType, type)
+                .eq(ApproveProcess::getTenantId, SecurityUtils.getLoginUser().getTenantId()));
     }
 }
diff --git a/src/main/java/com/ruoyi/approve/enums/ApproveType.java b/src/main/java/com/ruoyi/approve/enums/ApproveType.java
new file mode 100644
index 0000000..af84828
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/enums/ApproveType.java
@@ -0,0 +1,34 @@
+package com.ruoyi.approve.enums;
+
+import java.util.Arrays;
+
+public enum ApproveType {
+    FREE_COLLABORATION(1, "鑷敱鍗忓悓瀹℃壒"),
+    LEAVE(2, "璇峰亣绠$悊"),
+    SALES_CONTRACT(3, "閿�鍞鎵�"),
+    REIMBURSEMENT(4, "鎶ラ攢瀹℃壒"),
+    PURCHASE_PLAN(5, "閲囪喘瀹℃壒"),
+    QUOTATION(6, "鎶ヤ环瀹℃壒"),
+    OUTBOUND(7, "鍑哄簱瀹℃壒");
+
+    private final int code;
+    private final String label;
+
+    ApproveType(int code, String label) {
+        this.code = code;
+        this.label = label;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public static ApproveType fromCode(Integer code) {
+        return Arrays.stream(values()).filter(item -> item.code == code).findFirst()
+                .orElseThrow(() -> new IllegalArgumentException("涓嶆敮鎸佺殑瀹℃壒绫诲瀷"));
+    }
+}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApproveFlowDefinitionMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApproveFlowDefinitionMapper.java
new file mode 100644
index 0000000..bafe8b1
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/mapper/ApproveFlowDefinitionMapper.java
@@ -0,0 +1,7 @@
+package com.ruoyi.approve.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.approve.pojo.ApproveFlowDefinition;
+
+public interface ApproveFlowDefinitionMapper extends BaseMapper<ApproveFlowDefinition> {
+}
diff --git a/src/main/java/com/ruoyi/approve/mapper/ApproveFlowNodeDefinitionMapper.java b/src/main/java/com/ruoyi/approve/mapper/ApproveFlowNodeDefinitionMapper.java
new file mode 100644
index 0000000..3277407
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/mapper/ApproveFlowNodeDefinitionMapper.java
@@ -0,0 +1,7 @@
+package com.ruoyi.approve.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.approve.pojo.ApproveFlowNodeDefinition;
+
+public interface ApproveFlowNodeDefinitionMapper extends BaseMapper<ApproveFlowNodeDefinition> {
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApproveFlowDefinition.java b/src/main/java/com/ruoyi/approve/pojo/ApproveFlowDefinition.java
new file mode 100644
index 0000000..1e23d92
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/pojo/ApproveFlowDefinition.java
@@ -0,0 +1,50 @@
+package com.ruoyi.approve.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("approve_flow_definition")
+public class ApproveFlowDefinition {
+    @ApiModelProperty(value = "娴佺▼瀹氫箟ID")
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "娴佺▼鍚嶇О")
+    private String flowName;
+
+    @ApiModelProperty(value = "瀹℃壒绫诲瀷")
+    private Integer approveType;
+
+    @ApiModelProperty(value = "鍚敤鐘舵�侊細0鍋滅敤锛�1鍚敤")
+    private Integer enabled;
+
+    @ApiModelProperty(value = "鏄惁榛樿娴佺▼锛�0鍚︼紝1鏄�")
+    private Integer isDefault;
+
+    @ApiModelProperty(value = "娴佺▼澶囨敞")
+    private String remark;
+
+    @ApiModelProperty(value = "绉熸埛ID")
+    private Long tenantId;
+
+    @ApiModelProperty(value = "鍒涘缓鐢ㄦ埛ID")
+    private Long createUser;
+
+    @ApiModelProperty(value = "鏇存柊鐢ㄦ埛ID")
+    private Long updateUser;
+
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "鍒犻櫎鏍囧織锛�0姝e父锛�1鍒犻櫎")
+    private Integer deleteFlag;
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApproveFlowNodeDefinition.java b/src/main/java/com/ruoyi/approve/pojo/ApproveFlowNodeDefinition.java
new file mode 100644
index 0000000..8f1c7bb
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/pojo/ApproveFlowNodeDefinition.java
@@ -0,0 +1,59 @@
+package com.ruoyi.approve.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("approve_flow_node_definition")
+public class ApproveFlowNodeDefinition {
+    @ApiModelProperty(value = "娴佺▼鑺傜偣瀹氫箟ID")
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "娴佺▼瀹氫箟ID")
+    private Long flowDefinitionId;
+
+    @ApiModelProperty(value = "鑺傜偣椤哄簭")
+    private Integer nodeOrder;
+
+    @ApiModelProperty(value = "鑺傜偣鍚嶇О")
+    private String nodeName;
+
+    @ApiModelProperty(value = "瀹℃壒浜虹被鍨�")
+    private String approverType;
+
+    @ApiModelProperty(value = "瀹℃壒浜洪厤缃��")
+    private String approverValue;
+
+    @ApiModelProperty(value = "鏉′欢瀛楁")
+    private String conditionField;
+
+    @ApiModelProperty(value = "鏉′欢鎿嶄綔绗�")
+    private String conditionOperator;
+
+    @ApiModelProperty(value = "鏉′欢鍊�")
+    private String conditionValue;
+
+    @ApiModelProperty(value = "绉熸埛ID")
+    private Long tenantId;
+
+    @ApiModelProperty(value = "鍒涘缓鐢ㄦ埛ID")
+    private Long createUser;
+
+    @ApiModelProperty(value = "鏇存柊鐢ㄦ埛ID")
+    private Long updateUser;
+
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "鍒犻櫎鏍囧織锛�0姝e父锛�1鍒犻櫎")
+    private Integer deleteFlag;
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApproveLog.java b/src/main/java/com/ruoyi/approve/pojo/ApproveLog.java
index 8952e0d..4975df4 100644
--- a/src/main/java/com/ruoyi/approve/pojo/ApproveLog.java
+++ b/src/main/java/com/ruoyi/approve/pojo/ApproveLog.java
@@ -4,6 +4,7 @@
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
@@ -20,38 +21,57 @@
     /**
      *
      */
+    @ApiModelProperty(value = "涓婚敭ID")
     @TableId(type = IdType.AUTO)
     private Long id;
 
     /**
      * 瀹℃壒id
      */
+    @ApiModelProperty(value = "瀹℃壒鏃ュ織涓氬姟ID")
     private Long approveId;
+
+    @ApiModelProperty(value = "瀹℃壒娴佺▼涓婚敭")
+    private Long approveProcessId;
+
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣涓婚敭")
+    private Long approveNodeId;
 
     /**
      * 瀹℃壒鑺傜偣椤哄簭
      */
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣椤哄簭")
     private Integer approveNodeOrder;
 
     /**
      * 瀹℃壒浜篿d
      */
+    @ApiModelProperty(value = "瀹℃壒鐢ㄦ埛ID")
     private Long approveUser;
+
+    @ApiModelProperty(value = "瀹℃壒鐢ㄦ埛鍚嶇О")
+    private String approveUserName;
 
     /**
      * 瀹℃壒鏃堕棿
      */
+    @ApiModelProperty(value = "瀹℃壒鏃堕棿")
     @JsonFormat(pattern = "yyyy-MM-dd")
     private Date approveTime;
 
     /**
      * 瀹℃壒鐘舵��
      */
+    @ApiModelProperty(value = "瀹℃壒鐘舵��")
     private Integer approveStatus;
 
     /**
      * 瀹℃壒澶囨敞
      */
+    @ApiModelProperty(value = "瀹℃壒澶囨敞")
     private String approveRemark;
 
-}
\ No newline at end of file
+    @ApiModelProperty(value = "绉熸埛ID")
+    private Long tenantId;
+
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApproveNode.java b/src/main/java/com/ruoyi/approve/pojo/ApproveNode.java
index 2ea7dd5..f4ba654 100644
--- a/src/main/java/com/ruoyi/approve/pojo/ApproveNode.java
+++ b/src/main/java/com/ruoyi/approve/pojo/ApproveNode.java
@@ -35,39 +35,47 @@
     /**
      * 
      */
+    @ApiModelProperty(value = "涓婚敭ID")
     private Long id;
 
     /**
      * 瀹℃壒缂栧彿
      */
+    @ApiModelProperty(value = "瀹℃壒娴佺▼缂栧彿")
     private String approveProcessId;
 
     /**
      * 瀹℃壒鑺傜偣椤哄簭
      */
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣椤哄簭")
     private Integer approveNodeOrder;
 
     /**
      * 瀹℃壒鑺傜偣鐢ㄦ埛鍚嶅瓧
      */
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣鐢ㄦ埛鍚嶇О")
     private String approveNodeUser;
 
     /**
      * 瀹℃壒鑺傜偣鐢ㄦ埛id
      */
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣鐢ㄦ埛ID")
     private Long approveNodeUserId;
 
     /**
      * 瀹℃壒鑺傜偣鏃堕棿
      */
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣鏃堕棿")
     @JsonFormat(pattern = "yyyy-MM-dd")
     private Date approveNodeTime;
 
     /**
      * 瀹℃壒鑺傜偣鐘舵��:1鍚屾剰锛�2鎷掔粷锛�0灏氭湭瀹℃牳锛堥粯璁や负0锛�
      */
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣鐘舵�侊細0灏氭湭瀹℃牳锛�1鍚屾剰锛�2鎷掔粷")
     private Integer approveNodeStatus;
 
+    @ApiModelProperty(value = "鏄惁涓虹涓�涓妭鐐�")
     @TableField(exist = false)
     private Boolean isFirst;
 
@@ -75,12 +83,14 @@
     /**
      * 鏄惁涓烘渶鍚庝竴姝�
      */
+    @ApiModelProperty(value = "鏄惁涓烘渶鍚庝竴涓妭鐐�")
     @TableField(exist = false)
     private Boolean isLast;
 
     /**
      * 鏄惁涓哄綋鍓嶅鏍歌妭鐐�
      */
+    @ApiModelProperty(value = "褰撳墠鐢ㄦ埛鏄惁鍙鏍�")
     @TableField(exist = false)
     private Boolean isShen = false;
 
@@ -88,44 +98,67 @@
      * 绉熸埛id
      */
 //    @TableField(fill = FieldFill.INSERT)
+    @ApiModelProperty(value = "绉熸埛ID")
     private Long tenantId;
 
     /**
      * 鍒犻櫎鏍囪:0姝e父锛�1鍒犻櫎
      */
+    @ApiModelProperty(value = "鍒犻櫎鏍囧織锛�0姝e父锛�1鍒犻櫎")
     private Integer deleteFlag;
 
     /**
      * 鍏ュ簱鐢ㄦ埛id
      */
+    @ApiModelProperty(value = "鍒涘缓鐢ㄦ埛ID")
     private Long createUser;
 
     /**
      * 鍏ュ簱鏃堕棿
      */
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
     private LocalDateTime createTime;
 
     /**
      * 淇敼鑰�
      */
+    @ApiModelProperty(value = "鏇存柊鐢ㄦ埛ID")
     private Long updateUser;
 
     /**
      * 淇敼鏃堕棿
      */
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
     private LocalDateTime updateTime;
 
     /**
      * 瀹℃壒鑺傜偣鎷掔粷鍘熷洜
      */
+    @ApiModelProperty(value = "瀹℃壒澶勭悊鍘熷洜")
     private String approveNodeReason;
 
     /**
      * 瀹℃壒鑺傜偣澶囨敞
      */
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣澶囨敞")
     private String approveNodeRemark;
+
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣鍚嶇О")
+    private String approveNodeName;
+
+    @ApiModelProperty(value = "鏉′欢瀛楁")
+    private String conditionField;
+
+    @ApiModelProperty(value = "鏉′欢鎿嶄綔绗�")
+    private String conditionOperator;
+
+    @ApiModelProperty(value = "鏉′欢鍊�")
+    private String conditionValue;
+
+    @ApiModelProperty(value = "鏄惁涓哄綋鍓嶈妭鐐癸細0鍚︼紝1鏄�")
+    private Integer isCurrent;
 
     private static final long serialVersionUID = 1L;
 
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java b/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
index c1114bd..db80da3 100644
--- a/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
+++ b/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
@@ -4,6 +4,7 @@
 import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
+import java.math.BigDecimal;
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -24,9 +25,11 @@
     /**
      * 
      */
+    @ApiModelProperty(value = "涓婚敭ID")
     @TableId(type = IdType.AUTO)
     private Long id;
 
+    @ApiModelProperty(value = "闄勪欢鍒楄〃")
     @TableField(exist = false)
     private List<CommonFile> commonFileList;
 
@@ -40,6 +43,7 @@
     /**
      * 鐢宠浜篿d
      */
+    @ApiModelProperty(value = "鐢宠浜篒D")
     private Long approveUser;
 
     /**
@@ -52,6 +56,7 @@
     /**
      * 鐢宠閮ㄩ棬id
      */
+    @ApiModelProperty(value = "鐢宠閮ㄩ棬ID")
     private Long approveDeptId;
 
     /**
@@ -64,11 +69,13 @@
     /**
      * 瀹℃壒鐢ㄦ埛ids
      */
+    @ApiModelProperty(value = "瀹℃壒鐢ㄦ埛ID鍒楄〃锛屽涓互閫楀彿鍒嗛殧")
     private String approveUserIds;
 
     /**
      * 瀹℃壒鐢ㄦ埛鍚嶇О
      */
+    @ApiModelProperty(value = "瀹℃壒鐢ㄦ埛鍚嶇О鍒楄〃")
     private String approveUserNames;
 
     /**
@@ -81,6 +88,7 @@
     /**
      * 褰撳墠瀹℃壒鐢ㄦ埛ID
      */
+    @ApiModelProperty(value = "褰撳墠瀹℃壒鐢ㄦ埛ID")
     private Long approveUserCurrentId;
 
     /**
@@ -116,17 +124,20 @@
     /**
      * 瀹℃壒鏄惁鍒犻櫎锛�0姝e父锛�1鍒犻櫎
      */
+    @ApiModelProperty(value = "鍒犻櫎鏍囧織锛�0姝e父锛�1鍒犻櫎")
     private Integer approveDelete;
 
     /**
      * 绉熸埛id
      */
 //    @TableField(fill = FieldFill.INSERT)
+    @ApiModelProperty(value = "绉熸埛ID")
     private Long tenantId;
 
     /**
      * 瀹℃壒绫诲瀷
      */
+    @ApiModelProperty(value = "瀹℃壒绫诲瀷锛�1鑷敱鍗忓悓锛�2璇峰亣锛�3閿�鍞紝4鎶ラ攢锛�5閲囪喘锛�6鎶ヤ环锛�7鍑哄簱")
     private Integer approveType;
 
     /**
@@ -135,12 +146,34 @@
     @ApiModelProperty(value = "瀹℃壒澶囨敞")
     private String approveRemark;
 
+    @ApiModelProperty(value = "鍏宠仈涓氬姟涓婚敭")
+    private Long businessId;
+
+    @ApiModelProperty(value = "涓氬姟缂栧彿")
+    private String businessNo;
+
+    @ApiModelProperty(value = "瀹℃壒涓氬姟鏍囬")
+    private String businessTitle;
+
+    @ApiModelProperty(value = "涓氬姟閲戦")
+    private BigDecimal amount;
+
+    @ApiModelProperty(value = "涓氬姟鏁版嵁JSON蹇収")
+    private String businessData;
+
+    @ApiModelProperty(value = "娴佺▼瀹氫箟ID")
+    private Long flowDefinitionId;
+
     /**
      * 鍒涘缓鏃堕棿
      */
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
     private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿")
+    private LocalDateTime updateTime;
 
     private static final long serialVersionUID = 1L;
 
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/ruoyi/approve/service/IApproveNodeService.java b/src/main/java/com/ruoyi/approve/service/IApproveNodeService.java
index 41c84ec..dc3944b 100644
--- a/src/main/java/com/ruoyi/approve/service/IApproveNodeService.java
+++ b/src/main/java/com/ruoyi/approve/service/IApproveNodeService.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.approve.pojo.ApproveNode;
+import com.ruoyi.approve.vo.ApproveNodeVO;
 
 import java.io.IOException;
 import java.util.List;
@@ -9,6 +10,7 @@
 public interface IApproveNodeService extends IService<ApproveNode> {
 
     void initApproveNodes(String approveUserIds,String approveID,Long tenantId);
+    void initApproveNodes(List<ApproveNodeVO> nodes, String approveID, Long tenantId);
     /**
      * 璇︽儏
      * @param id
@@ -17,5 +19,5 @@
 
     void updateApproveNode(ApproveNode approveNode) throws IOException;
 
-    void delApproveNodeByApproveId(Long id);
+    void delApproveNodeByApproveId(String id);
 }
diff --git a/src/main/java/com/ruoyi/approve/service/IApproveProcessService.java b/src/main/java/com/ruoyi/approve/service/IApproveProcessService.java
index 675c474..4c5f34f 100644
--- a/src/main/java/com/ruoyi/approve/service/IApproveProcessService.java
+++ b/src/main/java/com/ruoyi/approve/service/IApproveProcessService.java
@@ -27,7 +27,7 @@
 
     IPage<ApproveProcess> listAll(Page page, ApproveProcess approveProcess);
 
-    void delApprove(Long[] ids);
+    void delApprove(String[] ids);
 
     void updateByApproveId(ApproveGetAndUpdateVo approveGetAndUpdateVo) throws IOException;
 
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
index d0ff36a..39d93af 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -3,11 +3,14 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.approve.mapper.ApproveLogMapper;
 import com.ruoyi.approve.mapper.ApproveNodeMapper;
 import com.ruoyi.approve.mapper.ApproveProcessMapper;
+import com.ruoyi.approve.pojo.ApproveLog;
 import com.ruoyi.approve.pojo.ApproveNode;
 import com.ruoyi.approve.pojo.ApproveProcess;
 import com.ruoyi.approve.service.IApproveNodeService;
+import com.ruoyi.approve.vo.ApproveNodeVO;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.other.service.impl.TempFileServiceImpl;
@@ -15,14 +18,16 @@
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.sales.mapper.CommonFileMapper;
 import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
 import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
 
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
@@ -30,142 +35,215 @@
 @Service
 @RequiredArgsConstructor
 public class ApproveNodeServiceImpl extends ServiceImpl<ApproveNodeMapper, ApproveNode> implements IApproveNodeService {
+    private final ApproveNodeMapper approveNodeMapper;
+    private final ApproveProcessMapper approveProcessMapper;
+    private final ApproveLogMapper approveLogMapper;
+    private final SysUserMapper sysUserMapper;
+    private final TempFileServiceImpl tempFileService;
+    private final CommonFileMapper fileMapper;
 
-    @Autowired
-    private  ApproveNodeMapper approveNodeMapper;
-    @Autowired
-    private ApproveProcessMapper approveProcessMapper;
-    @Autowired
-    private SysUserMapper sysUserMapper;
-
-    @Autowired
-    private TempFileServiceImpl tempFileService;
-
-    @Autowired
-    private CommonFileMapper fileMapper;
-
-
-    public ApproveProcess getApproveById(String id) {
-        LambdaQueryWrapper<ApproveProcess> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(ApproveProcess::getApproveId, id);
-        queryWrapper.eq(ApproveProcess::getApproveDelete, 0);
-        queryWrapper.eq(ApproveProcess::getTenantId, SecurityUtils.getLoginUser().getTenantId());
-        queryWrapper.last("limit 1");
-        ApproveProcess one = approveProcessMapper.selectOne(queryWrapper);
-        return one;
+    private ApproveProcess getApproveById(String code) {
+        ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getApproveId, code)
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .eq(ApproveProcess::getTenantId, tenantId())
+                .last("limit 1"));
+        if (process == null) throw new RuntimeException("瀹℃壒涓嶅瓨鍦�");
+        return process;
     }
 
     @Override
-    public void initApproveNodes(String approveUserIds,String approveID,Long tenantId) {
-        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
-        ApproveProcess approve = getApproveById(approveID);
-        String[] names = approveUserIds.split(",");
-        String approveId = approve.getApproveId();
-        for (int i = 0; i < names.length; i++) {
-            SysUser sysUser = sysUserMapper.selectUserById(Long.parseLong(names[i]));
-            if (sysUser == null) continue;
-            ApproveNode approveNode = new ApproveNode();
-            approveNode.setApproveProcessId(approveId);
-            approveNode.setApproveNodeOrder(i +1);
-            approveNode.setApproveNodeUser(sysUser.getNickName());
-            approveNode.setApproveNodeUserId(sysUser.getUserId());
-            approveNode.setApproveNodeTime(new Date());
-            approveNode.setApproveNodeStatus(0);
-            approveNode.setTenantId(tenantId);
-            approveNode.setDeleteFlag(0);
-            approveNode.setCreateUser(userId);
-            approveNode.setUpdateUser(userId);
-            approveNode.setCreateTime(LocalDateTime.now());
-            approveNode.setUpdateTime(LocalDateTime.now());
-            approveNodeMapper.insert(approveNode);
+    public void initApproveNodes(String approveUserIds, String approveID, Long tenantId) {
+        if (!StringUtils.hasText(approveUserIds)) throw new RuntimeException("璇烽�夋嫨瀹℃壒浜�");
+        List<ApproveNodeVO> nodes = new ArrayList<>();
+        for (String id : approveUserIds.split(",")) {
+            ApproveNodeVO node = new ApproveNodeVO();
+            node.setUserId(Long.parseLong(id.trim()));
+            node.setConditionOperator("ALWAYS");
+            nodes.add(node);
         }
+        initApproveNodes(nodes, approveID, tenantId);
+    }
+
+    @Override
+    public void initApproveNodes(List<ApproveNodeVO> nodes, String approveID, Long ignoredTenantId) {
+        if (CollectionUtils.isEmpty(nodes)) throw new RuntimeException("瀹℃壒娴佺▼鑷冲皯鍖呭惈涓�涓妭鐐�");
+        Long tenantId = tenantId();
+        Long currentUserId = SecurityUtils.getUserId();
+        ApproveProcess process = getApproveById(approveID);
+        int order = 1;
+        ApproveNode first = null;
+        Long previousUserId = null;
+        for (ApproveNodeVO request : nodes) {
+            if (request.getUserId() == null) throw new RuntimeException("瀹℃壒浜轰笉鑳戒负绌�");
+            if (request.getUserId().equals(previousUserId)) throw new RuntimeException("鐩搁偦瀹℃壒鑺傜偣涓嶈兘閫夋嫨鍚屼竴瀹℃壒浜�");
+            previousUserId = request.getUserId();
+            if (!matchesCondition(process.getAmount(), request)) continue;
+            SysUser user = sysUserMapper.selectUserById(request.getUserId());
+            if (user == null || !tenantId.equals(user.getTenantId())) throw new RuntimeException("瀹℃壒浜轰笉瀛樺湪鎴栦笉灞炰簬褰撳墠绉熸埛");
+            ApproveNode node = new ApproveNode();
+            node.setApproveProcessId(process.getApproveId());
+            node.setApproveNodeOrder(order++);
+            node.setApproveNodeName(StringUtils.hasText(request.getNodeName()) ? request.getNodeName() : "瀹℃壒");
+            node.setApproveNodeUser(user.getNickName());
+            node.setApproveNodeUserId(user.getUserId());
+            node.setApproveNodeStatus(0);
+            node.setConditionField(request.getConditionField());
+            node.setConditionOperator(StringUtils.hasText(request.getConditionOperator()) ? request.getConditionOperator() : "ALWAYS");
+            node.setConditionValue(request.getConditionValue());
+            node.setIsCurrent(first == null ? 1 : 0);
+            node.setTenantId(tenantId);
+            node.setDeleteFlag(0);
+            node.setCreateUser(currentUserId);
+            node.setUpdateUser(currentUserId);
+            node.setCreateTime(LocalDateTime.now());
+            node.setUpdateTime(LocalDateTime.now());
+            approveNodeMapper.insert(node);
+            if (first == null) first = node;
+        }
+        if (first == null) throw new RuntimeException("娌℃湁婊¤冻鏉′欢鐨勫鎵硅妭鐐�");
+        process.setApproveUserCurrentId(first.getApproveNodeUserId());
+        process.setApproveUserCurrentName(first.getApproveNodeUser());
+        process.setUpdateTime(LocalDateTime.now());
+        approveProcessMapper.updateById(process);
+    }
+
+    private boolean matchesCondition(BigDecimal amount, ApproveNodeVO node) {
+        String operator = node.getConditionOperator();
+        if (!StringUtils.hasText(operator) || "ALWAYS".equalsIgnoreCase(operator)) return true;
+        if (!"amount".equals(node.getConditionField())) throw new RuntimeException("瀹℃壒鏉′欢浠呮敮鎸侀噾棰濆瓧娈�");
+        if (amount == null || !StringUtils.hasText(node.getConditionValue())) return false;
+        try {
+            if ("BETWEEN".equalsIgnoreCase(operator)) {
+                String[] values = node.getConditionValue().replace("[", "").replace("]", "").split(",");
+                if (values.length != 2) throw new RuntimeException("閲戦鍖洪棿鏍煎紡涓嶆纭�");
+                return amount.compareTo(new BigDecimal(values[0].trim())) >= 0
+                        && amount.compareTo(new BigDecimal(values[1].trim())) <= 0;
+            }
+            int compared = amount.compareTo(new BigDecimal(node.getConditionValue()));
+            if ("GT".equalsIgnoreCase(operator)) return compared > 0;
+            if ("GTE".equalsIgnoreCase(operator)) return compared >= 0;
+            if ("LT".equalsIgnoreCase(operator)) return compared < 0;
+            if ("LTE".equalsIgnoreCase(operator)) return compared <= 0;
+            if ("EQ".equalsIgnoreCase(operator)) return compared == 0;
+        } catch (NumberFormatException ex) {
+            throw new RuntimeException("瀹℃壒鏉′欢閲戦鏍煎紡涓嶆纭�");
+        }
+        throw new RuntimeException("涓嶆敮鎸佺殑瀹℃壒鏉′欢鎿嶄綔绗�");
     }
 
     @Override
     public List<ApproveNode> details(String id) {
-        LambdaQueryWrapper<ApproveNode> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(ApproveNode::getApproveProcessId, id);
-        queryWrapper.eq(ApproveNode::getDeleteFlag, 0);
-        queryWrapper.eq(ApproveNode::getTenantId, SecurityUtils.getLoginUser().getTenantId());
-        List<ApproveNode> list = list(queryWrapper);
-        // 鎸夌収 approveNodeOrder 瀛楁鍗囧簭鎺掑簭
-        list.sort(Comparator.comparingInt(ApproveNode::getApproveNodeOrder));
-        LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveId, id)
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getTenantId, SecurityUtils.getLoginUser().getTenantId())
-                .last("limit 1");
-        ApproveProcess approveProcess = approveProcessMapper.selectOne(approveProcessLambdaQueryWrapper);
-        if(approveProcess != null && approveProcess.getApproveStatus() == 3){
-            return list;
-        }
-        for (ApproveNode approveNode : list) {
-            List<CommonFile> commonFiles = fileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
-                    .eq(CommonFile::getCommonId, approveNode.getId())
-                    .eq(CommonFile::getType, FileNameType.ApproveNode.getValue()));
-            if(!CollectionUtils.isEmpty(commonFiles)){
-                approveNode.setUrl(commonFiles.get(0).getUrl());
-            }
-            if(approveNode.getApproveNodeStatus() == 1){
-                continue;
-            }
-            approveNode.setIsShen(true);
-            break;
-        }
-        return list;
-    }
-
-    public void updateApproveProcessStatus(ApproveNode approveNode,Integer status) throws IOException {
-        LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveId, approveNode.getApproveProcessId())
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .eq(ApproveProcess::getTenantId, SecurityUtils.getLoginUser().getTenantId())
-                .last("limit 1");
-        ApproveProcess approveProcess = approveProcessMapper.selectOne(approveProcessLambdaQueryWrapper);
-        if(approveProcess == null) throw new RuntimeException("瀹℃壒涓嶅瓨鍦�");
-        LambdaQueryWrapper<ApproveNode> approveNodeLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        approveNodeLambdaQueryWrapper.eq(ApproveNode::getApproveProcessId, approveNode.getApproveProcessId())
-                .eq(ApproveNode::getApproveNodeOrder, approveNode.getApproveNodeOrder() + 1)
+        getApproveById(id);
+        List<ApproveNode> nodes = approveNodeMapper.selectList(new LambdaQueryWrapper<ApproveNode>()
+                .eq(ApproveNode::getApproveProcessId, id)
                 .eq(ApproveNode::getDeleteFlag, 0)
-                .eq(ApproveNode::getTenantId, SecurityUtils.getLoginUser().getTenantId())
-                .last("limit 1");
-        ApproveNode approveNode1 = approveNodeMapper.selectOne(approveNodeLambdaQueryWrapper);
-        approveProcess.setApproveStatus(status);
-        if(approveNode1 != null){
-            approveProcess.setApproveUserCurrentId(approveNode1.getApproveNodeUserId());
-            approveProcess.setApproveUserCurrentName(approveNode1.getApproveNodeUser());
+                .eq(ApproveNode::getTenantId, tenantId())
+                .orderByAsc(ApproveNode::getApproveNodeOrder));
+        for (ApproveNode node : nodes) {
+            List<CommonFile> files = fileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
+                    .eq(CommonFile::getCommonId, node.getId())
+                    .eq(CommonFile::getType, FileNameType.ApproveNode.getValue()));
+            if (!CollectionUtils.isEmpty(files)) node.setUrl(files.get(0).getUrl());
+            node.setIsShen(Integer.valueOf(1).equals(node.getIsCurrent())
+                    && node.getApproveNodeUserId().equals(SecurityUtils.getUserId()));
         }
-        approveProcessMapper.updateById(approveProcess);
+        nodes.sort(Comparator.comparingInt(ApproveNode::getApproveNodeOrder));
+        return nodes;
+    }
 
-        // 缁戝畾闄勪欢
-        if(!CollectionUtils.isEmpty(approveNode.getTempFileIds()) && approveNode.getApproveNodeStatus() == 1){
-            tempFileService.migrateTempFilesToFormal(approveNode.getId(), approveNode.getTempFileIds(), FileNameType.ApproveNode.getValue());
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateApproveNode(ApproveNode request) throws IOException {
+        if (request == null || request.getId() == null) throw new RuntimeException("瀹℃壒鑺傜偣涓嶈兘涓虹┖");
+        if (request.getApproveNodeStatus() == null || (request.getApproveNodeStatus() != 1 && request.getApproveNodeStatus() != 2)) {
+            throw new RuntimeException("瀹℃壒缁撴灉涓嶆纭�");
+        }
+        if (!StringUtils.hasText(request.getApproveNodeReason())) throw new RuntimeException("瀹℃壒鎰忚涓嶈兘涓虹┖");
+        Long tenantId = tenantId();
+        ApproveNode node = approveNodeMapper.selectOne(new LambdaQueryWrapper<ApproveNode>()
+                .eq(ApproveNode::getId, request.getId())
+                .eq(ApproveNode::getTenantId, tenantId)
+                .eq(ApproveNode::getDeleteFlag, 0));
+        if (node == null) throw new RuntimeException("瀹℃壒鑺傜偣涓嶅瓨鍦�");
+        if (!Integer.valueOf(0).equals(node.getApproveNodeStatus()) || !Integer.valueOf(1).equals(node.getIsCurrent())) {
+            throw new RuntimeException("璇ヨ妭鐐瑰凡缁忓鐞嗘垨涓嶆槸褰撳墠瀹℃壒鑺傜偣");
+        }
+        if (!SecurityUtils.getUserId().equals(node.getApproveNodeUserId())) throw new RuntimeException("褰撳墠鐢ㄦ埛鏃犳潈瀹℃壒姝よ妭鐐�");
+
+        ApproveProcess process = getApproveById(node.getApproveProcessId());
+        if (Integer.valueOf(2).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus())) {
+            throw new RuntimeException("瀹℃壒娴佺▼宸茬粡缁撴潫");
+        }
+        node.setApproveNodeStatus(request.getApproveNodeStatus());
+        node.setApproveNodeReason(request.getApproveNodeReason().trim());
+        node.setApproveNodeRemark(request.getApproveNodeRemark());
+        node.setApproveNodeTime(new Date());
+        node.setIsCurrent(0);
+        node.setUpdateUser(SecurityUtils.getUserId());
+        node.setUpdateTime(LocalDateTime.now());
+        approveNodeMapper.updateById(node);
+
+        if (node.getApproveNodeStatus() == 2) {
+            process.setApproveStatus(3);
+            process.setApproveUserCurrentId(null);
+            process.setApproveUserCurrentName(null);
+            process.setApproveOverTime(new Date());
+        } else {
+            ApproveNode next = approveNodeMapper.selectOne(new LambdaQueryWrapper<ApproveNode>()
+                    .eq(ApproveNode::getApproveProcessId, node.getApproveProcessId())
+                    .eq(ApproveNode::getTenantId, tenantId)
+                    .eq(ApproveNode::getDeleteFlag, 0)
+                    .eq(ApproveNode::getApproveNodeStatus, 0)
+                    .gt(ApproveNode::getApproveNodeOrder, node.getApproveNodeOrder())
+                    .orderByAsc(ApproveNode::getApproveNodeOrder)
+                    .last("limit 1"));
+            if (next == null) {
+                process.setApproveStatus(2);
+                process.setApproveOverTime(new Date());
+                process.setApproveUserCurrentId(null);
+                process.setApproveUserCurrentName(null);
+            } else {
+                next.setIsCurrent(1);
+                next.setUpdateTime(LocalDateTime.now());
+                approveNodeMapper.updateById(next);
+                process.setApproveStatus(1);
+                process.setApproveUserCurrentId(next.getApproveNodeUserId());
+                process.setApproveUserCurrentName(next.getApproveNodeUser());
+            }
+        }
+        process.setUpdateTime(LocalDateTime.now());
+        approveProcessMapper.updateById(process);
+
+        ApproveLog log = new ApproveLog();
+        log.setApproveId(process.getId());
+        log.setApproveProcessId(process.getId());
+        log.setApproveNodeId(node.getId());
+        log.setApproveNodeOrder(node.getApproveNodeOrder());
+        log.setApproveUser(SecurityUtils.getUserId());
+        log.setApproveUserName(node.getApproveNodeUser());
+        log.setApproveTime(new Date());
+        log.setApproveStatus(node.getApproveNodeStatus());
+        log.setApproveRemark(node.getApproveNodeReason());
+        log.setTenantId(tenantId);
+        approveLogMapper.insert(log);
+
+        if (!CollectionUtils.isEmpty(request.getTempFileIds()) && node.getApproveNodeStatus() == 1) {
+            tempFileService.migrateTempFilesToFormal(node.getId(), request.getTempFileIds(), FileNameType.ApproveNode.getValue());
         }
     }
 
     @Override
-    public void updateApproveNode(ApproveNode approveNode) throws IOException {
-        // 瀹℃壒鑺傜偣鐘舵��:1鍚屾剰锛�2鎷掔粷锛�0灏氭湭瀹℃牳
-        switch (approveNode.getApproveNodeStatus()){
-            case 1:
-                updateApproveProcessStatus(approveNode, Boolean.TRUE.equals(approveNode.getIsLast()) ? 2 : 1);
-                break;
-            case 2:
-                updateApproveProcessStatus(approveNode, 3);
-                break;
-            default:
-                break;
-        }
-        approveNode.setApproveNodeTime(new Date());
-        approveNodeMapper.updateById(approveNode);
+    public void delApproveNodeByApproveId(String id) {
+        UpdateWrapper<ApproveNode> wrapper = new UpdateWrapper<>();
+        wrapper.lambda().set(ApproveNode::getDeleteFlag, 1)
+                .set(ApproveNode::getIsCurrent, 0)
+                .eq(ApproveNode::getApproveProcessId, id)
+                .eq(ApproveNode::getTenantId, tenantId());
+        update(wrapper);
     }
 
-    @Override
-    public void delApproveNodeByApproveId(Long id) {
-        UpdateWrapper<ApproveNode> queryWrapper = new UpdateWrapper<>();
-        queryWrapper.lambda().set(ApproveNode::getDeleteFlag, 1)
-                .eq(ApproveNode::getApproveProcessId, id);
-        update(queryWrapper);
+    private Long tenantId() {
+        return SecurityUtils.getLoginUser().getTenantId();
     }
-
 }
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
index e866bbf..938414b 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -5,14 +5,22 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.approve.enums.ApproveType;
+import com.ruoyi.approve.mapper.ApproveFlowDefinitionMapper;
+import com.ruoyi.approve.mapper.ApproveFlowNodeDefinitionMapper;
 import com.ruoyi.approve.mapper.ApproveNodeMapper;
 import com.ruoyi.approve.mapper.ApproveProcessMapper;
+import com.ruoyi.approve.pojo.ApproveFlowDefinition;
+import com.ruoyi.approve.pojo.ApproveFlowNodeDefinition;
 import com.ruoyi.approve.pojo.ApproveNode;
 import com.ruoyi.approve.pojo.ApproveProcess;
 import com.ruoyi.approve.service.IApproveNodeService;
 import com.ruoyi.approve.service.IApproveProcessService;
 import com.ruoyi.approve.utils.DailyRedisCounter;
 import com.ruoyi.approve.vo.ApproveGetAndUpdateVo;
+import com.ruoyi.approve.vo.ApproveNodeVO;
 import com.ruoyi.approve.vo.ApproveProcessVO;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -22,12 +30,10 @@
 import com.ruoyi.project.system.mapper.SysDeptMapper;
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.sales.mapper.CommonFileMapper;
+import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.pojo.CommonFile;
-import lombok.AllArgsConstructor;
+import com.ruoyi.sales.pojo.SalesLedger;
 import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
@@ -41,7 +47,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @Service
@@ -49,174 +57,270 @@
 public class ApproveProcessServiceImpl extends ServiceImpl<ApproveProcessMapper, ApproveProcess> implements IApproveProcessService {
     private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
 
-    private final StringRedisTemplate redisTemplate;
-
     private final DailyRedisCounter dailyRedisCounter;
-
     private final SysDeptMapper sysDeptMapper;
     private final IApproveNodeService approveNodeService;
     private final SysUserMapper sysUserMapper;
     private final ApproveProcessMapper approveProcessMapper;
+    private final ApproveNodeMapper approveNodeMapper;
     private final TempFileServiceImpl tempFileService;
     private final CommonFileMapper commonFileMapper;
+    private final SalesLedgerMapper salesLedgerMapper;
+    private final ApproveFlowDefinitionMapper flowDefinitionMapper;
+    private final ApproveFlowNodeDefinitionMapper flowNodeDefinitionMapper;
+    private final ObjectMapper objectMapper;
 
     @Override
-    public void addApprove(ApproveProcessVO approveProcessVO) throws  Exception {
-        SysUser sysUser = sysUserMapper.selectUserById(approveProcessVO.getApproveUser());
-        SysDept sysDept = sysDeptMapper.selectDeptById(approveProcessVO.getApproveDeptId());
-        String[] split = approveProcessVO.getApproveUserIds().split(",");
-        List<Long> longList = Arrays.stream(split)
-                .map(Long::valueOf)  // 灏嗘瘡涓� String 杞崲涓� Long
-                .collect(Collectors.toList());
-        List<SysUser> sysUsers = sysUserMapper.selectUserByIds(longList);
-        if(CollectionUtils.isEmpty(sysUsers)) throw new RuntimeException("瀹℃牳鐢ㄦ埛涓嶅瓨鍦�");
-        if(sysDept == null) throw new RuntimeException("閮ㄩ棬涓嶅瓨鍦�");
-        if(sysUser == null) throw new RuntimeException("鐢宠浜轰笉瀛樺湪");
-        String today = LocalDate.now().format(DATE_FORMAT);
-        Long approveId = dailyRedisCounter.incrementAndGetByDb();
-        String formattedCount = String.format("%03d", approveId);
-        //娴佺▼ ID
-        String approveID = today + formattedCount;
-        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
-        ApproveProcess approveProcess = new ApproveProcess();
-        approveProcess.setApproveId(approveID);
-        approveProcess.setApproveUser(approveProcessVO.getApproveUser());
-        approveProcess.setApproveUserName(sysUser.getNickName());
-        approveProcess.setApproveDeptId(approveProcessVO.getApproveDeptId());
-        approveProcess.setApproveDeptName(sysDept.getDeptName());
-        approveProcess.setApproveUserNames(sysUsers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
-        approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? null : dateFormat.parse(approveProcessVO.getApproveTime()));
-        approveProcess.setApproveReason(approveProcessVO.getApproveReason());
-        approveProcess.setApproveOverTime(null);
-        approveProcess.setApproveStatus(0);
-        approveProcess.setApproveDelete(0);
-        approveProcess.setApproveType(approveProcessVO.getApproveType());
-        approveProcess.setCreateTime(LocalDateTime.now());
-        approveProcess.setTenantId(approveProcessVO.getApproveDeptId());
-        approveProcess.setApproveUserIds(approveProcessVO.getApproveUserIds());
-        approveProcess.setApproveUserCurrentId(longList.get(0));
-        approveProcess.setApproveUserCurrentName(sysUsers
-                .stream()
-                .filter(SysUser -> SysUser.getUserId().equals(longList.get(0)))
-                .collect(Collectors.toList())
-                .get(0)
-                .getNickName());
-        // 璁剧疆鐘舵�佷负閲嶆柊鎻愪氦
-        if(approveProcessVO.getId() != null){
-            ApproveProcess approveProcess1 = approveProcessMapper.selectById(approveProcessVO.getId());
-            approveProcess1.setApproveStatus(4);
-            approveProcessMapper.updateById(approveProcess1);
+    public void addApprove(ApproveProcessVO request) throws Exception {
+        if (request == null || request.getApproveType() == null) throw new RuntimeException("瀹℃壒绫诲瀷涓嶈兘涓虹┖");
+        ApproveType type = ApproveType.fromCode(request.getApproveType());
+        Long tenantId = tenantId();
+        SysUser applicant = SecurityUtils.getLoginUser().getUser();
+        Long deptId = resolveDeptId(request.getApproveDeptId());
+        SysDept dept = sysDeptMapper.selectDeptById(deptId);
+        if (dept == null) throw new RuntimeException("鐢宠閮ㄩ棬涓嶅瓨鍦�");
+
+        List<ApproveNodeVO> nodes = resolveNodes(request, tenantId);
+        List<SysUser> approvers = validateApprovers(nodes, tenantId);
+        prepareBusinessData(request, type, tenantId);
+
+        String approveCode = LocalDate.now().format(DATE_FORMAT)
+                + String.format("%03d", dailyRedisCounter.incrementAndGetByDb());
+        ApproveProcess process = new ApproveProcess();
+        process.setApproveId(approveCode);
+        process.setApproveUser(applicant.getUserId());
+        process.setApproveUserName(applicant.getNickName());
+        process.setApproveDeptId(deptId);
+        process.setApproveDeptName(dept.getDeptName());
+        process.setApproveUserIds(nodes.stream().map(item -> String.valueOf(item.getUserId())).collect(Collectors.joining(",")));
+        process.setApproveUserNames(approvers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
+        process.setApproveTime(parseDate(request.getApproveTime()));
+        process.setApproveReason(request.getApproveReason());
+        process.setApproveStatus(0);
+        process.setApproveDelete(0);
+        process.setApproveType(type.getCode());
+        process.setTenantId(tenantId);
+        process.setBusinessId(request.getBusinessId());
+        process.setBusinessNo(request.getBusinessNo());
+        process.setBusinessTitle(request.getBusinessTitle());
+        process.setAmount(request.getAmount());
+        process.setBusinessData(request.getBusinessData());
+        process.setFlowDefinitionId(request.getFlowDefinitionId());
+        process.setCreateTime(LocalDateTime.now());
+        process.setUpdateTime(LocalDateTime.now());
+        approveProcessMapper.insert(process);
+        approveNodeService.initApproveNodes(nodes, approveCode, tenantId);
+        tempFileService.migrateTempFilesToFormal(process.getId(), request.getTempFileIds(), FileNameType.ApproveProcess.getValue());
+    }
+
+    private void prepareBusinessData(ApproveProcessVO request, ApproveType type, Long tenantId) throws JsonProcessingException {
+        if (type == ApproveType.SALES_CONTRACT) {
+            if (request.getBusinessId() == null) throw new RuntimeException("璇烽�夋嫨閿�鍞悎鍚�");
+            SalesLedger ledger = salesLedgerMapper.selectById(request.getBusinessId());
+            if (ledger == null || !tenantId.equals(ledger.getTenantId())) throw new RuntimeException("閿�鍞悎鍚屼笉瀛樺湪鎴栦笉灞炰簬褰撳墠绉熸埛");
+            Long duplicate = approveProcessMapper.selectCount(new LambdaQueryWrapper<ApproveProcess>()
+                    .eq(ApproveProcess::getTenantId, tenantId)
+                    .eq(ApproveProcess::getApproveType, ApproveType.SALES_CONTRACT.getCode())
+                    .eq(ApproveProcess::getBusinessId, ledger.getId())
+                    .in(ApproveProcess::getApproveStatus, Arrays.asList(0, 1))
+                    .eq(ApproveProcess::getApproveDelete, 0));
+            if (duplicate != null && duplicate > 0) throw new RuntimeException("璇ラ攢鍞悎鍚屽凡鏈夊緟瀹℃祦绋�");
+            Map<String, Object> snapshot = new LinkedHashMap<>();
+            snapshot.put("salesLedgerId", ledger.getId());
+            snapshot.put("salesContractNo", ledger.getSalesContractNo());
+            snapshot.put("customerContractNo", ledger.getCustomerContractNo());
+            snapshot.put("customerName", ledger.getCustomerName());
+            snapshot.put("projectName", ledger.getProjectName());
+            snapshot.put("salesman", ledger.getSalesman());
+            snapshot.put("contractAmount", ledger.getContractAmount());
+            snapshot.put("executionDate", ledger.getExecutionDate());
+            snapshot.put("paymentMethod", ledger.getPaymentMethod());
+            snapshot.put("remarks", ledger.getRemarks());
+            request.setBusinessNo(ledger.getSalesContractNo());
+            request.setBusinessTitle(StringUtils.hasText(request.getBusinessTitle())
+                    ? request.getBusinessTitle() : "閿�鍞悎鍚屽鎵�-" + ledger.getSalesContractNo());
+            request.setAmount(ledger.getContractAmount());
+            request.setBusinessData(objectMapper.writeValueAsString(snapshot));
+        } else if (type == ApproveType.PURCHASE_PLAN || type == ApproveType.FREE_COLLABORATION) {
+            if (!StringUtils.hasText(request.getBusinessTitle())) throw new RuntimeException("瀹℃壒鏍囬涓嶈兘涓虹┖");
+            if (type == ApproveType.PURCHASE_PLAN && request.getAmount() == null) throw new RuntimeException("閲囪喘棰勭畻閲戦涓嶈兘涓虹┖");
+            if (!StringUtils.hasText(request.getBusinessNo())) {
+                String prefix = type == ApproveType.PURCHASE_PLAN ? "CG" : "XT";
+                request.setBusinessNo(prefix + LocalDate.now().format(DATE_FORMAT)
+                        + String.format("%03d", dailyRedisCounter.incrementAndGetByDb()));
+            }
         }
-        save(approveProcess);
-        //鍒濆鍖栧鎵硅妭鐐�
-        approveNodeService.initApproveNodes(approveProcessVO.getApproveUserIds(),approveID,approveProcessVO.getApproveDeptId());
-        // 闄勪欢缁戝畾
-        tempFileService.migrateTempFilesToFormal(approveProcess.getId(), approveProcessVO.getTempFileIds(), FileNameType.ApproveProcess.getValue());
+    }
+
+    private List<ApproveNodeVO> resolveNodes(ApproveProcessVO request, Long tenantId) {
+        if (!CollectionUtils.isEmpty(request.getNodes())) return request.getNodes();
+        if (request.getFlowDefinitionId() != null) {
+            ApproveFlowDefinition definition = flowDefinitionMapper.selectOne(new LambdaQueryWrapper<ApproveFlowDefinition>()
+                    .eq(ApproveFlowDefinition::getId, request.getFlowDefinitionId())
+                    .eq(ApproveFlowDefinition::getTenantId, tenantId)
+                    .eq(ApproveFlowDefinition::getApproveType, request.getApproveType())
+                    .eq(ApproveFlowDefinition::getEnabled, 1)
+                    .eq(ApproveFlowDefinition::getDeleteFlag, 0));
+            if (definition == null) throw new RuntimeException("瀹℃壒娴佺▼瀹氫箟涓嶅瓨鍦ㄦ垨宸插仠鐢�");
+            List<ApproveFlowNodeDefinition> definitions = flowNodeDefinitionMapper.selectList(
+                    new LambdaQueryWrapper<ApproveFlowNodeDefinition>()
+                            .eq(ApproveFlowNodeDefinition::getFlowDefinitionId, definition.getId())
+                            .eq(ApproveFlowNodeDefinition::getTenantId, tenantId)
+                            .eq(ApproveFlowNodeDefinition::getDeleteFlag, 0)
+                            .orderByAsc(ApproveFlowNodeDefinition::getNodeOrder));
+            List<ApproveNodeVO> result = new ArrayList<>();
+            for (ApproveFlowNodeDefinition item : definitions) {
+                if (!"USER".equals(item.getApproverType()) || !StringUtils.hasText(item.getApproverValue())) {
+                    throw new RuntimeException("褰撳墠棰勮娴佺▼鍖呭惈灏氭湭鎸囧畾鐨勫鎵逛汉");
+                }
+                ApproveNodeVO node = new ApproveNodeVO();
+                node.setUserId(Long.valueOf(item.getApproverValue().split(",")[0].trim()));
+                node.setNodeName(item.getNodeName());
+                node.setConditionField(item.getConditionField());
+                node.setConditionOperator(item.getConditionOperator());
+                node.setConditionValue(item.getConditionValue());
+                result.add(node);
+            }
+            if (!result.isEmpty()) return result;
+        }
+        if (!StringUtils.hasText(request.getApproveUserIds())) throw new RuntimeException("璇烽�夋嫨瀹℃壒浜�");
+        List<ApproveNodeVO> result = new ArrayList<>();
+        for (String id : request.getApproveUserIds().split(",")) {
+            ApproveNodeVO node = new ApproveNodeVO();
+            node.setUserId(Long.valueOf(id.trim()));
+            node.setConditionOperator("ALWAYS");
+            result.add(node);
+        }
+        return result;
+    }
+
+    private List<SysUser> validateApprovers(List<ApproveNodeVO> nodes, Long tenantId) {
+        List<SysUser> users = new ArrayList<>();
+        for (ApproveNodeVO node : nodes) {
+            SysUser user = sysUserMapper.selectUserById(node.getUserId());
+            if (user == null || !tenantId.equals(user.getTenantId())) throw new RuntimeException("瀹℃壒浜轰笉瀛樺湪鎴栦笉灞炰簬褰撳墠绉熸埛");
+            users.add(user);
+        }
+        return users;
     }
 
     @Override
     public List<SysDept> selectDeptListByDeptIds(Long[] deptIds) {
-        List<SysDept> sysDeptList =new ArrayList<SysDept>();
+        List<SysDept> departments = new ArrayList<>();
+        if (deptIds == null) return departments;
         for (Long deptId : deptIds) {
-            SysDept sysDept = sysDeptMapper.selectDeptById(deptId);
-            sysDeptList.add(sysDept);
+            SysDept dept = sysDeptMapper.selectDeptById(deptId);
+            if (dept != null) departments.add(dept);
         }
-        return sysDeptList;
+        return departments;
     }
 
     @Override
-    public IPage<ApproveProcess> listAll(Page page,ApproveProcess approveProcess) {
-        IPage<ApproveProcess> approveProcessIPage = approveProcessMapper.listPage(page,approveProcess);
-        List<ApproveProcess> records = approveProcessIPage.getRecords();
-        for (ApproveProcess record : records) {
-            List<CommonFile> commonFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
-                    .eq(CommonFile::getCommonId, record.getId())
-                    .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue()));
-            record.setCommonFileList(commonFiles);
-        }
-        return approveProcessIPage;
+    public IPage<ApproveProcess> listAll(Page page, ApproveProcess request) {
+        request.setTenantId(tenantId());
+        IPage<ApproveProcess> result = approveProcessMapper.listPage(page, request);
+        result.getRecords().forEach(record -> record.setCommonFileList(commonFileMapper.selectList(
+                new LambdaQueryWrapper<CommonFile>()
+                        .eq(CommonFile::getCommonId, record.getId())
+                        .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue()))));
+        return result;
     }
 
     @Override
-    public void delApprove(Long[] ids) {
-        for (Long id : ids) {
-            UpdateWrapper<ApproveProcess> queryWrapper = new UpdateWrapper<>();
-            queryWrapper.lambda().set(ApproveProcess::getApproveDelete, 1)
-                    .eq(ApproveProcess::getApproveId, id);
-            update(queryWrapper);
-            // 鍒犻櫎鍏宠仈鐨勫鎵硅妭鐐�
-            approveNodeService.delApproveNodeByApproveId(id);
+    public void delApprove(String[] ids) {
+        if (ids == null) return;
+        for (String code : ids) {
+            ApproveProcess process = findOwnedByCode(code);
+            if (!SecurityUtils.getUserId().equals(process.getApproveUser())) throw new RuntimeException("鍙兘鍒犻櫎鏈汉鐢宠");
+            if (!(Integer.valueOf(0).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus()))) {
+                throw new RuntimeException("瀹℃牳涓殑娴佺▼涓嶈兘鍒犻櫎");
+            }
+            UpdateWrapper<ApproveProcess> wrapper = new UpdateWrapper<>();
+            wrapper.lambda().set(ApproveProcess::getApproveDelete, 1)
+                    .set(ApproveProcess::getUpdateTime, LocalDateTime.now())
+                    .eq(ApproveProcess::getApproveId, code)
+                    .eq(ApproveProcess::getTenantId, tenantId());
+            update(wrapper);
+            approveNodeService.delApproveNodeByApproveId(code);
         }
-
-
     }
 
     @Override
     public ApproveProcess getApproveById(String id) {
-        LambdaQueryWrapper<ApproveProcess> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(ApproveProcess::getApproveId, id);
-        queryWrapper.eq(ApproveProcess::getApproveDelete, 0);
-        queryWrapper.eq(ApproveProcess::getTenantId, SecurityUtils.getLoginUser().getTenantId());
-        queryWrapper.last("limit 1");
-        ApproveProcess one = getOne(queryWrapper);
-        one.setCommonFileList(commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
-                .eq(CommonFile::getCommonId, one.getId())
+        ApproveProcess process = findOwnedByCode(id);
+        process.setCommonFileList(commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
+                .eq(CommonFile::getCommonId, process.getId())
                 .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue())));
-        return one;
+        return process;
     }
-
-    private final ApproveNodeMapper approveNodeMapper;
-
 
     @Override
-    public void updateByApproveId(ApproveGetAndUpdateVo approveGetAndUpdateVo) throws IOException {
-        ApproveProcess approve = approveProcessMapper.selectById(approveGetAndUpdateVo.getId());
-        approve.setApproveUserIds(approveGetAndUpdateVo.getApproveUserIds());
-        approve.setApproveReason(approveGetAndUpdateVo.getApproveReason());
-        SysUser sysUser = sysUserMapper.selectUserById(approveGetAndUpdateVo.getApproveUser());
-        String[] split = approveGetAndUpdateVo.getApproveUserIds().split(",");
-        if(split.length == 0){
-            throw new RuntimeException("璇烽�夋嫨瀹℃壒浜�");
+    public void updateByApproveId(ApproveGetAndUpdateVo request) throws IOException {
+        ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getId, request.getId())
+                .eq(ApproveProcess::getTenantId, tenantId())
+                .eq(ApproveProcess::getApproveDelete, 0));
+        if (process == null) throw new RuntimeException("瀹℃壒涓嶅瓨鍦�");
+        if (!SecurityUtils.getUserId().equals(process.getApproveUser())) throw new RuntimeException("鍙兘缂栬緫鏈汉鐢宠");
+        if (!(Integer.valueOf(0).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus()))) {
+            throw new RuntimeException("褰撳墠瀹℃壒鐘舵�佷笉鍏佽缂栬緫");
         }
-        List<SysUser> sysUsers = sysUserMapper.selectUserByIds(Arrays.asList(split).stream().map(Long::parseLong).collect(Collectors.toList()));
-        if(CollectionUtils.isEmpty(sysUsers)) throw new RuntimeException("璇烽�夋嫨瀹℃壒浜�");
-        if(sysUser == null) throw new RuntimeException("鐢宠浜轰笉瀛樺湪");
-        approve.setApproveUserName(sysUser.getNickName());
-        approve.setApproveUser(sysUser.getUserId());
-        //瀹℃牳涓笉鍙互缂栬緫瀹℃牳浜�
-        if(approve.getApproveStatus() != 1){
-            approve.setApproveUserCurrentId(Long.parseLong(split[0]));
-            approve.setApproveUserCurrentName(sysUsers.stream().filter(user -> user.getUserId().equals(Long.parseLong(split[0]))).collect(Collectors.toList()).get(0).getNickName());
-        }
-        updateById(approve);
-        //淇敼瀹℃壒浜�
-        // 鍏堝垹闄� 鍚庢柊澧�
-        LambdaQueryWrapper<ApproveNode> approveNodeLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        approveNodeLambdaQueryWrapper.eq(ApproveNode::getApproveProcessId, approve.getApproveId())
-                .eq(ApproveNode::getDeleteFlag, 0)
-                .eq(ApproveNode::getTenantId, SecurityUtils.getLoginUser().getTenantId())
-                .orderByAsc(ApproveNode::getApproveNodeOrder);
-        approveNodeMapper.delete(approveNodeLambdaQueryWrapper);
-        approveNodeService.initApproveNodes(approveGetAndUpdateVo.getApproveUserIds(),approve.getApproveId(),approve.getTenantId());
+        process.setApproveReason(request.getApproveReason());
+        process.setBusinessTitle(request.getBusinessTitle());
+        process.setAmount(request.getAmount());
+        process.setBusinessData(request.getBusinessData());
+        process.setUpdateTime(LocalDateTime.now());
+        process.setApproveStatus(0);
+        process.setApproveOverTime(null);
+        approveProcessMapper.updateById(process);
 
-//        int i = 0;
-//        for (ApproveNode approveNode : list) {
-//            int finalI = i;
-//            if(i >= split.length){
-//                approveNode.setDeleteFlag(1);
-//            }else{
-//                List<SysUser> collect = sysUsers.stream().filter(user -> user.getUserId().equals(Long.parseLong(split[finalI]))).collect(Collectors.toList());
-//                if(CollectionUtils.isEmpty(collect)){
-//                    throw new RuntimeException("璇烽�夋嫨姝g‘鐨勫鎵逛汉");
-//                }
-//                approveNode.setApproveNodeUserId(collect.get(0).getUserId());
-//                approveNode.setApproveNodeUser(collect.get(0).getNickName());
-//            }
-//            approveNodeMapper.updateById(approveNode);
-//            i++;
-//        }
-        tempFileService.migrateTempFilesToFormal(approve.getId(), approveGetAndUpdateVo.getTempFileIds(), FileNameType.ApproveProcess.getValue());
+        List<ApproveNodeVO> nodes = request.getNodes();
+        if (CollectionUtils.isEmpty(nodes) && StringUtils.hasText(request.getApproveUserIds())) {
+            nodes = new ArrayList<>();
+            for (String id : request.getApproveUserIds().split(",")) {
+                ApproveNodeVO node = new ApproveNodeVO();
+                node.setUserId(Long.valueOf(id.trim()));
+                node.setConditionOperator("ALWAYS");
+                nodes.add(node);
+            }
+        }
+        if (!CollectionUtils.isEmpty(nodes)) {
+            validateApprovers(nodes, tenantId());
+            UpdateWrapper<ApproveNode> oldNodes = new UpdateWrapper<>();
+            oldNodes.lambda().set(ApproveNode::getDeleteFlag, 1)
+                    .set(ApproveNode::getIsCurrent, 0)
+                    .eq(ApproveNode::getApproveProcessId, process.getApproveId())
+                    .eq(ApproveNode::getTenantId, tenantId());
+            approveNodeMapper.update(null, oldNodes);
+            approveNodeService.initApproveNodes(nodes, process.getApproveId(), tenantId());
+        }
+        tempFileService.migrateTempFilesToFormal(process.getId(), request.getTempFileIds(), FileNameType.ApproveProcess.getValue());
     }
 
+    private ApproveProcess findOwnedByCode(String code) {
+        ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
+                .eq(ApproveProcess::getApproveId, code)
+                .eq(ApproveProcess::getApproveDelete, 0)
+                .eq(ApproveProcess::getTenantId, tenantId())
+                .last("limit 1"));
+        if (process == null) throw new RuntimeException("瀹℃壒涓嶅瓨鍦�");
+        return process;
+    }
 
+    private Long resolveDeptId(Long requested) {
+        Long[] allowed = SecurityUtils.getDeptId();
+        if (requested == null) return SecurityUtils.getLoginUser().getCurrentDeptId();
+        if (allowed != null && Arrays.asList(allowed).contains(requested)) return requested;
+        Long current = SecurityUtils.getLoginUser().getCurrentDeptId();
+        if (requested.equals(current)) return requested;
+        throw new RuntimeException("鏃犳潈浣跨敤璇ョ敵璇烽儴闂�");
+    }
+
+    private Date parseDate(String value) throws ParseException {
+        return StringUtils.hasText(value) ? new SimpleDateFormat("yyyy-MM-dd").parse(value) : new Date();
+    }
+
+    private Long tenantId() {
+        return SecurityUtils.getLoginUser().getTenantId();
+    }
 }
diff --git a/src/main/java/com/ruoyi/approve/vo/ApproveFlowDefinitionVO.java b/src/main/java/com/ruoyi/approve/vo/ApproveFlowDefinitionVO.java
new file mode 100644
index 0000000..adfb747
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/vo/ApproveFlowDefinitionVO.java
@@ -0,0 +1,17 @@
+package com.ruoyi.approve.vo;
+
+import com.ruoyi.approve.pojo.ApproveFlowDefinition;
+import com.ruoyi.approve.pojo.ApproveFlowNodeDefinition;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ApproveFlowDefinitionVO {
+    @ApiModelProperty(value = "娴佺▼瀹氫箟")
+    private ApproveFlowDefinition definition;
+
+    @ApiModelProperty(value = "娴佺▼鑺傜偣瀹氫箟鍒楄〃")
+    private List<ApproveFlowNodeDefinition> nodes;
+}
diff --git a/src/main/java/com/ruoyi/approve/vo/ApproveGetAndUpdateVo.java b/src/main/java/com/ruoyi/approve/vo/ApproveGetAndUpdateVo.java
index 69d5dea..86c8c0d 100644
--- a/src/main/java/com/ruoyi/approve/vo/ApproveGetAndUpdateVo.java
+++ b/src/main/java/com/ruoyi/approve/vo/ApproveGetAndUpdateVo.java
@@ -1,31 +1,61 @@
 package com.ruoyi.approve.vo;
 
-import com.ruoyi.sales.pojo.CommonFile;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
+import java.math.BigDecimal;
 import java.util.List;
 
 @Data
 public class ApproveGetAndUpdateVo {
 
+    @ApiModelProperty(value = "涓存椂闄勪欢ID鍒楄〃")
     private List<String> tempFileIds;
-    //瀹℃壒id
+
+    @ApiModelProperty(value = "瀹℃壒娴佺▼缂栧彿")
     @NotBlank(message = "娴佺▼缂栧彿涓嶈兘涓虹┖")
     private String id;
-    //鐢宠浜嬬敱
+
+    @ApiModelProperty(value = "鐢宠浜嬬敱")
     @NotBlank(message = "鐢宠浜嬬敱涓嶈兘涓虹┖")
     private String approveReason;
 
+    @ApiModelProperty(value = "瀹℃壒鐢ㄦ埛ID鍒楄〃锛屽涓互閫楀彿鍒嗛殧")
     private String approveUserIds;
 
+    @ApiModelProperty(value = "鐢宠鐢ㄦ埛ID")
     private Long approveUser;
 
+    @ApiModelProperty(value = "鐢宠鏃ユ湡锛屾牸寮忥細yyyy-MM-dd")
     private String approveTime;
 
+    @ApiModelProperty(value = "瀹℃壒鐘舵�侊細0寰呭鏍革紝1瀹℃牳涓紝2瀹℃牳瀹屾垚锛�3瀹℃牳鏈�氳繃锛�4宸查噸鏂版彁浜�")
     private Integer approveStatus;
     /**
      * 瀹℃壒绫诲瀷
      */
+    @ApiModelProperty(value = "瀹℃壒绫诲瀷锛�1鑷敱鍗忓悓锛�2璇峰亣锛�3閿�鍞紝4鎶ラ攢锛�5閲囪喘锛�6鎶ヤ环锛�7鍑哄簱")
     private Integer approveType;
+
+    @ApiModelProperty(value = "鍏宠仈涓氬姟涓婚敭")
+    private Long businessId;
+
+    @ApiModelProperty(value = "涓氬姟缂栧彿")
+    private String businessNo;
+
+    @ApiModelProperty(value = "瀹℃壒涓氬姟鏍囬")
+    private String businessTitle;
+
+    @ApiModelProperty(value = "涓氬姟閲戦")
+    private BigDecimal amount;
+
+    @ApiModelProperty(value = "涓氬姟鏁版嵁JSON蹇収")
+    private String businessData;
+
+    @ApiModelProperty(value = "娴佺▼瀹氫箟ID")
+    private Long flowDefinitionId;
+
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣鍒楄〃")
+    private List<ApproveNodeVO> nodes;
 }
diff --git a/src/main/java/com/ruoyi/approve/vo/ApproveNodeVO.java b/src/main/java/com/ruoyi/approve/vo/ApproveNodeVO.java
new file mode 100644
index 0000000..51566c5
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/vo/ApproveNodeVO.java
@@ -0,0 +1,25 @@
+package com.ruoyi.approve.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class ApproveNodeVO {
+    @ApiModelProperty(value = "瀹℃壒鐢ㄦ埛ID")
+    @NotNull(message = "瀹℃壒浜轰笉鑳戒负绌�")
+    private Long userId;
+
+    @ApiModelProperty(value = "瀹℃壒鑺傜偣鍚嶇О")
+    private String nodeName;
+
+    @ApiModelProperty(value = "鏉′欢瀛楁")
+    private String conditionField;
+
+    @ApiModelProperty(value = "鏉′欢鎿嶄綔绗�")
+    private String conditionOperator;
+
+    @ApiModelProperty(value = "鏉′欢鍊�")
+    private String conditionValue;
+}
diff --git a/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java b/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java
index 1fb353e..1a344d7 100644
--- a/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java
+++ b/src/main/java/com/ruoyi/approve/vo/ApproveProcessVO.java
@@ -1,33 +1,61 @@
 package com.ruoyi.approve.vo;
 
-import com.ruoyi.sales.pojo.CommonFile;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
+import java.math.BigDecimal;
 import java.util.List;
 
 @Data
 public class ApproveProcessVO {
 
+    @ApiModelProperty(value = "涓存椂闄勪欢ID鍒楄〃")
     private List<String> tempFileIds;
 
+    @ApiModelProperty(value = "瀹℃壒娴佺▼涓婚敭")
     private Long id;
 
-
+    @ApiModelProperty(value = "鐢宠閮ㄩ棬ID")
     private Long approveDeptId;
 
+    @ApiModelProperty(value = "鐢宠鏃ユ湡锛屾牸寮忥細yyyy-MM-dd")
     private String approveTime;
 
-    // 鐢宠浜�
+    @ApiModelProperty(value = "鐢宠鐢ㄦ埛ID")
     private Long approveUser;
 
-    // 瀹℃壒浜�
+    @ApiModelProperty(value = "瀹℃壒鐢ㄦ埛ID鍒楄〃锛屽涓互閫楀彿鍒嗛殧")
     private String approveUserIds;
 
+    @ApiModelProperty(value = "鐢宠浜嬬敱")
     private String approveReason;
 
     /**
      * 瀹℃壒绫诲瀷
      */
+    @ApiModelProperty(value = "瀹℃壒绫诲瀷锛�1鑷敱鍗忓悓锛�2璇峰亣锛�3閿�鍞紝4鎶ラ攢锛�5閲囪喘锛�6鎶ヤ环锛�7鍑哄簱")
     private Integer approveType;
+
+    @ApiModelProperty(value = "鍏宠仈涓氬姟涓婚敭")
+    private Long businessId;
+
+    @ApiModelProperty(value = "涓氬姟缂栧彿")
+    private String businessNo;
+
+    @ApiModelProperty(value = "瀹℃壒涓氬姟鏍囬")
+    @NotBlank(message = "瀹℃壒鏍囬涓嶈兘涓虹┖")
+    private String businessTitle;
+
+    @ApiModelProperty(value = "涓氬姟閲戦")
+    private BigDecimal amount;
+
+    @ApiModelProperty(value = "涓氬姟鏁版嵁JSON蹇収")
+    private String businessData;
+
+    @ApiModelProperty(value = "娴佺▼瀹氫箟ID")
+    private Long flowDefinitionId;
+
+    @ApiModelProperty(value = "鑷畾涔夊鎵硅妭鐐瑰垪琛�")
+    private List<ApproveNodeVO> nodes;
 }
diff --git a/src/main/resources/mapper/approve/ApproveLogMapper.xml b/src/main/resources/mapper/approve/ApproveLogMapper.xml
index e47dbbc..1ea3242 100644
--- a/src/main/resources/mapper/approve/ApproveLogMapper.xml
+++ b/src/main/resources/mapper/approve/ApproveLogMapper.xml
@@ -7,15 +7,19 @@
     <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApproveLog">
             <id property="id" column="id" />
             <result property="approveId" column="approve_id" />
+            <result property="approveProcessId" column="approve_process_id" />
+            <result property="approveNodeId" column="approve_node_id" />
             <result property="approveNodeOrder" column="approve_node_order" />
             <result property="approveUser" column="approve_user" />
+            <result property="approveUserName" column="approve_user_name" />
             <result property="approveTime" column="approve_time" />
             <result property="approveStatus" column="approve_status" />
             <result property="approveRemark" column="approve_remark" />
+            <result property="tenantId" column="tenant_id" />
     </resultMap>
 
     <sql id="Base_Column_List">
-        id,approve_id,approve_node_order,approve_user,approve_time,approve_status,
-        approve_remark
+        id,approve_id,approve_process_id,approve_node_id,approve_node_order,approve_user,
+        approve_user_name,approve_time,approve_status,approve_remark,tenant_id
     </sql>
 </mapper>
diff --git a/src/main/resources/mapper/approve/ApproveNodeMapper.xml b/src/main/resources/mapper/approve/ApproveNodeMapper.xml
index d5863ed..d057216 100644
--- a/src/main/resources/mapper/approve/ApproveNodeMapper.xml
+++ b/src/main/resources/mapper/approve/ApproveNodeMapper.xml
@@ -9,16 +9,24 @@
             <result property="approveProcessId" column="approve_process_id" />
             <result property="approveNodeOrder" column="approve_node_order" />
             <result property="approveNodeUser" column="approve_node_user" />
+            <result property="approveNodeUserId" column="approve_node_user_id" />
             <result property="approveNodeTime" column="approve_node_time" />
             <result property="approveNodeStatus" column="approve_node_status" />
             <result property="tenantId" column="tenant_id" />
             <result property="deleteFlag" column="delete_flag" />
             <result property="approveNodeReason" column="approve_node_reason" />
             <result property="approveNodeRemark" column="approve_node_remark" />
+            <result property="approveNodeName" column="approve_node_name" />
+            <result property="conditionField" column="condition_field" />
+            <result property="conditionOperator" column="condition_operator" />
+            <result property="conditionValue" column="condition_value" />
+            <result property="isCurrent" column="is_current" />
     </resultMap>
 
     <sql id="Base_Column_List">
         id,approve_process_id,approve_node_order,approve_node_user,approve_node_time,approve_node_status,
-        tenant_id,delete_flag,approve_node_reason,approve_node_remark
+        tenant_id,delete_flag,approve_node_reason,approve_node_remark,approve_node_user_id,
+        approve_node_name,condition_field,condition_operator,condition_value,is_current,
+        create_user,create_time,update_user,update_time
     </sql>
 </mapper>
diff --git a/src/main/resources/mapper/approve/ApproveProcessMapper.xml b/src/main/resources/mapper/approve/ApproveProcessMapper.xml
index 33b29a9..cdbdaa1 100644
--- a/src/main/resources/mapper/approve/ApproveProcessMapper.xml
+++ b/src/main/resources/mapper/approve/ApproveProcessMapper.xml
@@ -20,12 +20,19 @@
             <result property="tenantId" column="tenant_id" />
             <result property="approveType" column="approve_type" />
             <result property="approveRemark" column="approve_remark" />
+            <result property="businessId" column="business_id" />
+            <result property="businessNo" column="business_no" />
+            <result property="businessTitle" column="business_title" />
+            <result property="amount" column="amount" />
+            <result property="businessData" column="business_data" />
+            <result property="flowDefinitionId" column="flow_definition_id" />
     </resultMap>
 
     <sql id="Base_Column_List">
         id,approve_id,approve_user,approve_dept_id,approve_dept_name,approve_user_ids,
         approve_user_names,approve_reason,approve_time,approve_over_time,approve_status,
-        approve_delete,tenant_id,approve_type,approve_remark
+        approve_delete,tenant_id,approve_type,approve_remark,business_id,business_no,
+        business_title,amount,business_data,flow_definition_id,create_time,update_time
     </sql>
     <select id="listPage" resultType="com.ruoyi.approve.pojo.ApproveProcess">
         select * from approve_process where approve_delete = 0
@@ -38,5 +45,13 @@
         <if test="req.approveType != null ">
             and approve_type = #{req.approveType}
         </if>
+        <if test="req.tenantId != null">
+            and tenant_id = #{req.tenantId}
+        </if>
+        <if test="req.businessNo != null and req.businessNo != ''">
+            and (business_no like concat('%',#{req.businessNo},'%')
+                 or business_title like concat('%',#{req.businessNo},'%'))
+        </if>
+        order by create_time desc, id desc
     </select>
 </mapper>

--
Gitblit v1.9.3