liyong
7 天以前 79cceefe43f14643781b76def9b980398990d458
feat(approve): 添加审批实例相关DTO、VO类及审批流程工具类

- 新增ApprovalInstanceDto和ApprovalInstanceVo类用于审批实例数据传输
- 新增ApprovalTemplateNodeApproverDto和Vo用于审批模板节点审批人数据
- 新增ApprovalTemplateNodeDto和Vo用于审批模板节点数据
- 新增ApprovalTemplateVo用于审批模板数据传输
- 实现ApproveProcessConfigNodeUtils审批流程节点工具类
- 修改ProductionOrderRoutingController使用正确的服务方法
- 在采购、销售模块中集成新的审批实例功能
- 添加TypeEnums枚举类定义各种业务类型
- 新增ApprovalInstance实体类定义审批实例表结构
- 添加ApprovalInstanceController提供审批实例相关接口
已添加55个文件
已修改11个文件
3194 ■■■■■ 文件已修改
src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeApproverDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeApproverVo.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeVo.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateVo.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApprovalInstanceNodeController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApprovalRecordController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApprovalTaskController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApprovalTemplateController.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeApproverController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceMapper.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceNodeMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/ApprovalRecordMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/ApprovalTaskMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateMapper.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeApproverMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApprovalInstance.java 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApprovalInstanceNode.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApprovalRecord.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApprovalTask.java 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApprovalTemplate.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNode.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNodeApprover.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalInstanceNodeService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalRecordService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalTaskService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeApproverService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeService.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceNodeServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java 507 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalRecordServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalTaskServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeApproverServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeServiceImpl.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java 251 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/utils/ApproveProcessConfigNodeUtils.java 363 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/ApprovalStatusEnum.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/SalesQuotationStatusEnum.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/ShippingStatusEnum.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/TypeEnums.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesQuotationDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/approve/ApprovalInstanceMapper.xml 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/approve/ApprovalInstanceNodeMapper.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/approve/ApprovalRecordMapper.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/approve/ApprovalTaskMapper.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/approve/ApprovalTemplateMapper.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/approve/ApprovalTemplateNodeApproverMapper.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/approve/ApprovalTemplateNodeMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.ruoyi.approve.bean.dto;
import com.ruoyi.approve.pojo.ApprovalInstance;
import lombok.Data;
@Data
public class ApprovalInstanceDto extends ApprovalInstance {
    private String approveAction;
    private String approveComment;
}
src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.ruoyi.approve.bean.dto;
import com.ruoyi.approve.pojo.ApprovalTemplate;
import lombok.Data;
import java.util.List;
@Data
public class ApprovalTemplateDto  extends ApprovalTemplate {
    private List<ApprovalTemplateNodeDto> nodes;
}
src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeApproverDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.approve.bean.dto;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import lombok.Data;
@Data
public class ApprovalTemplateNodeApproverDto extends ApprovalTemplateNodeApprover {
}
src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.ruoyi.approve.bean.dto;
import com.ruoyi.approve.pojo.ApprovalTemplateNode;
import lombok.Data;
import java.util.List;
@Data
public class ApprovalTemplateNodeDto extends ApprovalTemplateNode {
    private List<ApprovalTemplateNodeApproverDto> approvers;
}
src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.ruoyi.approve.bean.vo;
import com.ruoyi.approve.pojo.ApprovalInstance;
import com.ruoyi.approve.pojo.ApprovalRecord;
import com.ruoyi.approve.pojo.ApprovalTask;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class ApprovalInstanceVo extends ApprovalInstance {
    //当前用户是否可以审批
    @Schema(description = "当前用户是否可以审批")
    private Boolean isApprove;
    //审批流程
    private List<ApprovalTask> tasks;
    //审批记录
    private List<ApprovalRecord>  records;
    @Schema(description = "业务名称")
    private String businessName;
}
src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeApproverVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.ruoyi.approve.bean.vo;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import lombok.Data;
@Data
public class ApprovalTemplateNodeApproverVo extends ApprovalTemplateNodeApprover {
}
src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.ruoyi.approve.bean.vo;
import com.ruoyi.approve.pojo.ApprovalTemplateNode;
import lombok.Data;
import java.util.List;
@Data
public class ApprovalTemplateNodeVo extends ApprovalTemplateNode {
    private List<ApprovalTemplateNodeApproverVo> approvers;
}
src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.ruoyi.approve.bean.vo;
import com.ruoyi.approve.pojo.ApprovalTemplate;
import lombok.Data;
import java.util.List;
@Data
public class ApprovalTemplateVo extends ApprovalTemplate {
    private List<ApprovalTemplateNodeVo> nodes;
    private String createdUserName;
}
src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
package com.ruoyi.approve.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * <p>
 * å®¡æ‰¹å®žä¾‹è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:46
 */
@RestController
@RequestMapping("/approvalInstance")
@Tag(name = "审批实例表")
@AllArgsConstructor
public class ApprovalInstanceController {
    private final ApprovalInstanceService approvalInstanceService;
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
        return approvalInstanceService.listPage(page, approvalInstanceDto);
    }
    @PostMapping("/save")
    @Operation(summary = "保存")
    public R save(@RequestBody ApprovalInstanceDto approvalInstanceDto) {
        return approvalInstanceService.add(approvalInstanceDto) ? R.ok() : R.fail();
    }
    @PutMapping("/update")
    @Operation(summary = "更新")
    public R update(@RequestBody ApprovalInstanceDto approvalInstanceDto) {
        return approvalInstanceService.updateById(approvalInstanceDto) ? R.ok() : R.fail();
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除")
    public R delete(@RequestBody List<Long> ids) {
        return approvalInstanceService.delete(ids) ? R.ok() : R.fail();
    }
    @Operation(summary = "审批")
    @PostMapping("/approve")
    public R approve(@RequestBody ApprovalInstanceDto approvalInstanceDto) {
        return approvalInstanceService.approve(approvalInstanceDto);
    }
}
src/main/java/com/ruoyi/approve/controller/ApprovalInstanceNodeController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * å®¡æ‰¹èŠ‚ç‚¹å®žä¾‹è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:54
 */
@RestController
@RequestMapping("/approvalInstanceNode")
public class ApprovalInstanceNodeController {
}
src/main/java/com/ruoyi/approve/controller/ApprovalRecordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * å®¡æ‰¹è®°å½•表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:28:21
 */
@RestController
@RequestMapping("/approvalRecord")
public class ApprovalRecordController {
}
src/main/java/com/ruoyi/approve/controller/ApprovalTaskController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * å®¡æ‰¹ä»»åŠ¡è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:32:37
 */
@RestController
@RequestMapping("/approvalTask")
public class ApprovalTaskController {
}
src/main/java/com/ruoyi/approve/controller/ApprovalTemplateController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package com.ruoyi.approve.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
import com.ruoyi.approve.service.ApprovalTemplateService;
import com.ruoyi.framework.web.domain.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ‹é“è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:08
 */
@RestController
@RequestMapping("/approvalTemplate")
@Tag(name = "审批模板表")
@AllArgsConstructor
public class ApprovalTemplateController {
    private final ApprovalTemplateService approvalTemplateService;
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public R listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto) {
        return R.ok(approvalTemplateService.listPage(page, approvalTemplateDto));
    }
    @PostMapping("/add")
    @Operation(summary = "添加")
    public R add(@RequestBody ApprovalTemplateDto approvalTemplateDto) {
        return R.ok(approvalTemplateService.saveApprovalTemplateDto(approvalTemplateDto));
    }
    @PutMapping("/update")
    @Operation(summary = "修改")
    public R update(@RequestBody ApprovalTemplateDto approvalTemplateDto) {
        return R.ok(approvalTemplateService.updateApprovalTemplateDto(approvalTemplateDto));
    }
    @PostMapping("/delete")
    @Operation(summary = "删除")
    public R delete(@RequestBody List<Long> ids) {
        return R.ok(approvalTemplateService.delete(ids));
    }
    @GetMapping("/list/{type}")
    @Operation(summary = "查询所有审批模板")
    public R list(@PathVariable("type") Integer type) {
        return R.ok(approvalTemplateService.listApprovalTemplateVo(type));
    }
    @GetMapping("/detail/{id}")
    @Operation(summary = "查询审批模板详情")
    public R detail(@PathVariable("id") Long id) {
        return R.ok(approvalTemplateService.getApprovalTemplateVoById(id));
    }
}
src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeApproverController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹å®¡æ‰¹äººè¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:30
 */
@RestController
@RequestMapping("/approvalTemplateNodeApprover")
public class ApprovalTemplateNodeApproverController {
}
src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:19
 */
@RestController
@RequestMapping("/approvalTemplateNode")
public class ApprovalTemplateNodeController {
}
src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.approve.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
import com.ruoyi.approve.pojo.ApprovalInstance;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 * å®¡æ‰¹å®žä¾‹è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:46
 */
@Mapper
public interface ApprovalInstanceMapper extends BaseMapper<ApprovalInstance> {
    IPage<ApprovalInstanceVo> listPage(Page<ApprovalInstanceVo> page,@Param("ew") ApprovalInstanceDto approvalInstanceDto);
}
src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceNodeMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.approve.pojo.ApprovalInstanceNode;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * å®¡æ‰¹èŠ‚ç‚¹å®žä¾‹è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:54
 */
@Mapper
public interface ApprovalInstanceNodeMapper extends BaseMapper<ApprovalInstanceNode> {
}
src/main/java/com/ruoyi/approve/mapper/ApprovalRecordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.approve.pojo.ApprovalRecord;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * å®¡æ‰¹è®°å½•表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:28:21
 */
@Mapper
public interface ApprovalRecordMapper extends BaseMapper<ApprovalRecord> {
}
src/main/java/com/ruoyi/approve/mapper/ApprovalTaskMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.approve.pojo.ApprovalTask;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * å®¡æ‰¹ä»»åŠ¡è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:32:37
 */
@Mapper
public interface ApprovalTaskMapper extends BaseMapper<ApprovalTask> {
}
src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.approve.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
import com.ruoyi.approve.pojo.ApprovalTemplate;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:08
 */
@Mapper
public interface ApprovalTemplateMapper extends BaseMapper<ApprovalTemplate> {
    IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page,@Param("ew") ApprovalTemplateDto approvalTemplateDto);
}
src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeApproverMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹å®¡æ‰¹äººè¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:30
 */
@Mapper
public interface ApprovalTemplateNodeApproverMapper extends BaseMapper<ApprovalTemplateNodeApprover> {
}
src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.approve.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.approve.pojo.ApprovalTemplateNode;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:19
 */
@Mapper
public interface ApprovalTemplateNodeMapper extends BaseMapper<ApprovalTemplateNode> {
}
src/main/java/com/ruoyi/approve/pojo/ApprovalInstance.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,148 @@
package com.ruoyi.approve.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * å®¡æ‰¹å®žä¾‹è¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:46
 */
@Getter
@Setter
@ToString
@TableName("approval_instance")
@ApiModel(value = "ApprovalInstance对象", description = "审批实例表")
public class ApprovalInstance implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * å®¡æ‰¹å®žä¾‹ID
     */
    @Schema(description ="审批实例ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å®¡æ‰¹ç¼–号
     */
    @Schema(description ="审批编号")
    private String instanceNo;
    /**
     * æ¨¡æ¿ID
     */
    @Schema(description ="模板ID")
    private Long templateId;
    /**
     * æ¨¡æ¿åç§°
     */
    @Schema(description ="模板名称")
    private String templateName;
    /**
     * ä¸šåŠ¡ID
     */
    @Schema(description ="业务ID")
    private Long businessId;
    /**
     * ä¸šåŠ¡ç±»åž‹
     */
    @Schema(description ="业务类型")
    private Long businessType;
    /**
     * å®¡æ‰¹æ ‡é¢˜
     */
    @Schema(description ="审批标题")
    private String title;
    /**
     * å®¡æ‰¹çŠ¶æ€
     */
    @Schema(description ="审批状态 PENDING - å¾…审批/进行中  APPROVED - å·²é€šè¿‡/已完成  REJECTED - å·²é©³å›ž")
    private String status;
    /**
     * å½“前审批级别
     */
    @Schema(description ="当前审批级别")
    private Integer currentLevel;
    /**
     * ç”³è¯·äººID
     */
    @Schema(description ="申请人ID")
    private Long applicantId;
    /**
     * ç”³è¯·äººåç§°
     */
    @Schema(description ="申请人名称")
    private String applicantName;
    /**
     * ç”³è¯·æ—¶é—´
     */
    @Schema(description ="申请时间")
    private LocalDateTime applyTime;
    /**
     * å®Œæˆæ—¶é—´
     */
    @Schema(description ="完成时间")
    private LocalDateTime finishTime;
    /**
     * åˆ›å»ºäºº
     */
    @Schema(description ="创建人")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @Schema(description ="创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /**
     * æ›´æ–°äºº
     */
    @Schema(description ="更新人")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    /**
     * æ›´æ–°æ—¶é—´
     */
    @Schema(description ="更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    /**
     * é€»è¾‘删除
     */
    @Schema(description ="逻辑删除")
    private Byte deleted;
    @Schema(description = "表单数据")
    private String formConfig;
}
src/main/java/com/ruoyi/approve/pojo/ApprovalInstanceNode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,106 @@
package com.ruoyi.approve.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * å®¡æ‰¹èŠ‚ç‚¹å®žä¾‹è¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:54
 */
@Getter
@Setter
@ToString
@TableName("approval_instance_node")
@ApiModel(value = "ApprovalInstanceNode对象", description = "审批节点实例表")
public class ApprovalInstanceNode implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * èŠ‚ç‚¹å®žä¾‹ID
     */
    @Schema(description ="节点实例ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å®¡æ‰¹å®žä¾‹ID
     */
    @Schema(description ="审批实例ID")
    private Long instanceId;
    /**
     * å®¡æ‰¹çº§åˆ«
     */
    @Schema(description ="审批级别")
    private Integer levelNo;
    /**
     * å®¡æ‰¹ç±»åž‹
     */
    @Schema(description ="审批类型")
    private String approveType;
    /**
     * èŠ‚ç‚¹çŠ¶æ€
     */
    @Schema(description ="节点状态 PENDING - å¾…处理 APPROVED - å·²é€šè¿‡ REJECTED - å·²é©³å›ž")
    private String status;
    /**
     * å¼€å§‹æ—¶é—´
     */
    @Schema(description ="开始时间")
    private LocalDateTime startTime;
    /**
     * å®Œæˆæ—¶é—´
     */
    @Schema(description ="完成时间")
    private LocalDateTime finishTime;
    /**
     * åˆ›å»ºäºº
     */
    @Schema(description ="创建人")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @Schema(description ="创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /**
     * æ›´æ–°äºº
     */
    @Schema(description ="更新人")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    /**
     * æ›´æ–°æ—¶é—´
     */
    @Schema(description ="更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    /**
     * é€»è¾‘删除
     */
    @Schema(description ="逻辑删除")
    private Byte deleted;
}
src/main/java/com/ruoyi/approve/pojo/ApprovalRecord.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
package com.ruoyi.approve.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * å®¡æ‰¹è®°å½•表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:28:21
 */
@Getter
@Setter
@ToString
@TableName("approval_record")
@ApiModel(value = "ApprovalRecord对象", description = "审批记录表")
public class ApprovalRecord implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * å®¡æ‰¹è®°å½•ID
     */
    @Schema(description ="审批记录ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å®¡æ‰¹å®žä¾‹ID
     */
    @Schema(description ="审批实例ID")
    private Long instanceId;
    /**
     * èŠ‚ç‚¹å®žä¾‹ID
     */
    @Schema(description ="节点实例ID")
    private Long nodeId;
    /**
     * å®¡æ‰¹ä»»åŠ¡ID
     */
    @Schema(description ="审批任务ID")
    private Long taskId;
    /**
     * æ“ä½œäººID
     */
    @Schema(description ="操作人ID")
    private Long operatorId;
    /**
     * æ“ä½œäººåç§°
     */
    @Schema(description ="操作人名称")
    private String operatorName;
    /**
     * æ“ä½œç±»åž‹
     */
    @Schema(description ="操作类型")
    private String action;
    /**
     * å®¡æ‰¹æ„è§
     */
    @Schema(description ="审批意见")
    private String comment;
    /**
     * åˆ›å»ºäºº
     */
    @Schema(description ="创建人")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @Schema(description ="创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /**
     * é€»è¾‘删除
     */
    @Schema(description ="逻辑删除")
    private Byte deleted;
}
src/main/java/com/ruoyi/approve/pojo/ApprovalTask.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,128 @@
package com.ruoyi.approve.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * å®¡æ‰¹ä»»åŠ¡è¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:32:37
 */
@Getter
@Setter
@ToString
@TableName("approval_task")
@ApiModel(value = "ApprovalTask对象", description = "审批任务表")
public class ApprovalTask implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * å®¡æ‰¹ä»»åŠ¡ID
     */
    @Schema(description ="审批任务ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å®¡æ‰¹å®žä¾‹ID
     */
    @Schema(description ="审批实例ID")
    private Long instanceId;
    /**
     * èŠ‚ç‚¹å®žä¾‹ID
     */
    @Schema(description ="节点实例ID")
    private Long nodeId;
    /**
     * å®¡æ‰¹çº§åˆ«
     */
    @Schema(description ="审批级别")
    private Integer levelNo;
    /**
     * å®¡æ‰¹äººID
     */
    @Schema(description ="审批人ID")
    private Long approverId;
    /**
     * å®¡æ‰¹äººåç§°
     */
    @Schema(description ="审批人名称")
    private String approverName;
    /**
     * ä»»åŠ¡çŠ¶æ€
     */
    @Schema(description ="任务状态 PENDING - å¾…审批 APPROVED - å·²åŒæ„  REJECTED - å·²æ‹’绝")
    private String taskStatus;
    /**
     * å®¡æ‰¹æ—¶é—´
     */
    @Schema(description ="审批时间")
    private LocalDateTime approveTime;
    /**
     * å®¡æ‰¹æ„è§
     */
    @Schema(description ="审批意见")
    private String comment;
    /**
     * æ˜¯å¦å·²è¯»
     */
    @Schema(description ="是否已读")
    private Byte isRead;
    /**
     * åˆ›å»ºäºº
     */
    @Schema(description ="创建人")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @Schema(description ="创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /**
     * æ›´æ–°äºº
     */
    @Schema(description ="更新人")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    /**
     * æ›´æ–°æ—¶é—´
     */
    @Schema(description ="更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    /**
     * é€»è¾‘删除
     */
    @Schema(description ="逻辑删除")
    private Byte deleted;
    @Schema(description ="部门ID")
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/approve/pojo/ApprovalTemplate.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
package com.ruoyi.approve.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿è¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:08
 */
@Getter
@Setter
@ToString
@TableName("approval_template")
@ApiModel(value = "ApprovalTemplate对象", description = "审批模板表")
public class ApprovalTemplate implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * æ¨¡æ¿ID
     */
    @Schema(description ="模板ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * æ¨¡æ¿åç§°
     */
    @Schema(description ="模板名称")
    private String templateName;
    /**
     * å¯ç”¨çŠ¶æ€ï¼š1启用,0停用
     */
    @Schema(description ="启用状态:1启用,0停用")
    private Byte enabled;
    /**
     * æ¨¡æ¿è¯´æ˜Ž
     */
    @Schema(description ="模板说明")
    private String description;
    /**
     * åˆ›å»ºäºº
     */
    @Schema(description ="创建人")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @Schema(description ="创建时间")
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    /**
     * æ›´æ–°äºº
     */
    @Schema(description ="更新人")
    @TableField(fill = FieldFill.UPDATE)
    private Long updateUser;
    /**
     * æ›´æ–°æ—¶é—´
     */
    @Schema(description ="更新时间")
    @TableField(fill = FieldFill.UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    /**
     * é€»è¾‘删除:0否,1是
     */
    @Schema(description ="逻辑删除:0否,1是")
    private Integer deleted;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @Schema(description = "表单配置")
    private String formConfig;
    @Schema(description = "模板类型:0系统内置,1自定义")
    private Integer templateType;
    @Schema(description = "业务类型")
    private Long businessType;
}
src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package com.ruoyi.approve.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹è¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:19
 */
@Getter
@Setter
@ToString
@TableName("approval_template_node")
@ApiModel(value = "ApprovalTemplateNode对象", description = "审批模板节点表")
public class ApprovalTemplateNode implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * èŠ‚ç‚¹ID
     */
    @Schema(description ="节点ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å®¡æ‰¹æ¨¡æ¿ID
     */
    @Schema(description ="审批模板ID")
    private Long templateId;
    /**
     * å®¡æ‰¹çº§åˆ«ï¼Œä»Ž1开始
     */
    @Schema(description ="审批级别,从1开始")
    private Integer levelNo;
    /**
     * å®¡æ‰¹æ–¹å¼ï¼šAND会签,OR或签
     */
    @Schema(description ="审批方式:AND会签,OR或签")
    private String approveType;
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNodeApprover.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package com.ruoyi.approve.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹å®¡æ‰¹äººè¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:30
 */
@Getter
@Setter
@ToString
@TableName("approval_template_node_approver")
@ApiModel(value = "ApprovalTemplateNodeApprover对象", description = "审批模板节点审批人表")
public class ApprovalTemplateNodeApprover implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®ID
     */
    @Schema(description = "主键ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å®¡æ‰¹èŠ‚ç‚¹ID
     */
    @Schema(description ="审批节点ID")
    private Long nodeId;
    /**
     * å®¡æ‰¹æ¨¡æ¿ID
     */
    @Schema(description ="审批模板ID")
    private Long templateId;
    /**
     * å®¡æ‰¹äººID
     */
    @Schema(description ="审批人ID")
    private Long approverId;
    /**
     * å®¡æ‰¹äººåç§°å†—ä½™
     */
    @Schema(description ="审批人名称冗余")
    private String approverName;
    /**
     * å®¡æ‰¹äººæŽ’序
     */
    @Schema(description ="审批人排序")
    private Integer sortNo;
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @TableField(fill = FieldFill.INSERT)
    private Long deleted ;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/approve/service/ApprovalInstanceNodeService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.ruoyi.approve.service;
import com.ruoyi.approve.pojo.ApprovalInstanceNode;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * å®¡æ‰¹èŠ‚ç‚¹å®žä¾‹è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:54
 */
public interface ApprovalInstanceNodeService extends IService<ApprovalInstanceNode> {
}
src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.ruoyi.approve.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
import com.ruoyi.approve.pojo.ApprovalInstance;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.R;
import java.util.List;
/**
 * <p>
 * å®¡æ‰¹å®žä¾‹è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:46
 */
public interface ApprovalInstanceService extends IService<ApprovalInstance> {
    R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto);
    Boolean add(ApprovalInstanceDto approvalInstanceDto);
    Boolean delete(List<Long> ids);
    R approve(ApprovalInstanceDto approvalInstanceDto);
}
src/main/java/com/ruoyi/approve/service/ApprovalRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.ruoyi.approve.service;
import com.ruoyi.approve.pojo.ApprovalRecord;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * å®¡æ‰¹è®°å½•表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:28:21
 */
public interface ApprovalRecordService extends IService<ApprovalRecord> {
}
src/main/java/com/ruoyi/approve/service/ApprovalTaskService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.ruoyi.approve.service;
import com.ruoyi.approve.pojo.ApprovalTask;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * å®¡æ‰¹ä»»åŠ¡è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:32:37
 */
public interface ApprovalTaskService extends IService<ApprovalTask> {
}
src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeApproverService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.ruoyi.approve.service;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹å®¡æ‰¹äººè¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:30
 */
public interface ApprovalTemplateNodeApproverService extends IService<ApprovalTemplateNodeApprover> {
}
src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.approve.service;
import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto;
import com.ruoyi.approve.pojo.ApprovalTemplateNode;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:19
 */
public interface ApprovalTemplateNodeService extends IService<ApprovalTemplateNode> {
    Boolean saveApprovalTemplateNode(Long id, List<ApprovalTemplateNodeDto> nodes);
}
src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package com.ruoyi.approve.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
import com.ruoyi.approve.pojo.ApprovalTemplate;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:08
 */
public interface ApprovalTemplateService extends IService<ApprovalTemplate> {
    IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto);
    Boolean saveApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto);
    Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto);
    Boolean delete(List<Long> ids);
    List<ApprovalTemplateVo> listApprovalTemplateVo(Integer type);
    ApprovalTemplateVo getApprovalTemplateVoById(Long id);
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceNodeServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.approve.service.impl;
import com.ruoyi.approve.pojo.ApprovalInstanceNode;
import com.ruoyi.approve.mapper.ApprovalInstanceNodeMapper;
import com.ruoyi.approve.service.ApprovalInstanceNodeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * å®¡æ‰¹èŠ‚ç‚¹å®žä¾‹è¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:27:54
 */
@Service
public class ApprovalInstanceNodeServiceImpl extends ServiceImpl<ApprovalInstanceNodeMapper, ApprovalInstanceNode> implements ApprovalInstanceNodeService {
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,507 @@
package com.ruoyi.approve.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
import com.ruoyi.approve.pojo.*;
import com.ruoyi.approve.service.*;
import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
import com.ruoyi.common.enums.*;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.project.system.service.ISysNoticeService;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.mapper.QualityInspectParamMapper;
import com.ruoyi.quality.mapper.QualityTestStandardMapper;
import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
import com.ruoyi.quality.utils.QualityInspectHelper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.SalesQuotationMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.SalesQuotation;
import com.ruoyi.sales.pojo.ShippingInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
 * å®¡æ‰¹å®žä¾‹æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @since 2026-05-18 03:27:46
 */
@Service
@RequiredArgsConstructor
public class ApprovalInstanceServiceImpl extends ServiceImpl<ApprovalInstanceMapper, ApprovalInstance> implements ApprovalInstanceService {
    private final ApprovalInstanceMapper approvalInstanceMapper;
    private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils;
    private final ApprovalInstanceNodeService approvalInstanceNodeService;
    private final ApprovalTaskService approvalTaskService;
    private final ApprovalRecordService approvalRecordService;
    private final ApprovalTemplateNodeService approvalTemplateNodeService;
    private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService;
    private final ISysNoticeService sysNoticeService;
    private final PurchaseLedgerMapper purchaseLedgerMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final StockUtils stockUtils;
    private final QualityInspectMapper qualityInspectMapper;
    private final QualityTestStandardMapper qualityTestStandardMapper;
    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
    private final QualityInspectParamMapper qualityInspectParamMapper;
    private final SalesQuotationMapper salesQuotationMapper;
    private final ShippingInfoMapper shippingInfoMapper;
    private final ApprovalTemplateMapper approvalTemplateMapper;
    private final QualityInspectHelper qualityInspectHelper;
    @Override
    public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
        IPage<ApprovalInstanceVo> approvalInstanceVoIPage = approvalInstanceMapper.listPage(page, approvalInstanceDto);
        List<ApprovalInstanceVo> records = approvalInstanceVoIPage.getRecords();
        if (records == null || records.isEmpty()) {
            return R.ok(approvalInstanceVoIPage);
        }
        records.forEach(vo -> {
            vo.setBusinessName(TypeEnums.getLabelByValue(vo.getBusinessType()));
        });
        Long currentUserId = SecurityUtils.getUserId();
        List<Long> instanceIds = records.stream()
                .map(ApprovalInstanceVo::getId)
                .filter(id -> id != null)
                .distinct()
                .collect(Collectors.toList());
        if (!instanceIds.isEmpty()) {
            Map<Long, List<ApprovalRecord>> recordMap = approvalRecordService.list(
                    Wrappers.<ApprovalRecord>lambdaQuery()
                            .in(ApprovalRecord::getInstanceId, instanceIds)
                            .eq(ApprovalRecord::getDeleted, 0)
            ).stream().collect(Collectors.groupingBy(ApprovalRecord::getInstanceId));
            Map<Long, List<ApprovalTask>> taskMap = approvalTaskService.list(
                    Wrappers.<ApprovalTask>lambdaQuery()
                            .in(ApprovalTask::getInstanceId, instanceIds)
                            .eq(ApprovalTask::getDeleted, 0)
            ).stream().collect(Collectors.groupingBy(ApprovalTask::getInstanceId));
            for (ApprovalInstanceVo vo : records) {
                vo.setIsApprove(approveProcessConfigNodeUtils.isCurrentApprover(vo.getId(), currentUserId));
                vo.setRecords(recordMap.getOrDefault(vo.getId(), new ArrayList<>()));
                vo.setTasks(taskMap.getOrDefault(vo.getId(), new ArrayList<>()));
            }
        }
        return R.ok(approvalInstanceVoIPage);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(ApprovalInstanceDto approvalInstanceDto) {
        String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no");
        approvalInstanceDto.setInstanceNo(instanceNo);
        approvalInstanceDto.setStatus("PENDING");
        approvalInstanceDto.setCurrentLevel(1);
        boolean saved = this.save(approvalInstanceDto);
        if (!saved) {
            return false;
        }
        approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstanceDto);
        sendApproveNotice(approvalInstanceDto, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        int instanceRows = approvalInstanceMapper.update(
                null,
                Wrappers.<ApprovalInstance>lambdaUpdate()
                        .in(ApprovalInstance::getId, ids)
                        .eq(ApprovalInstance::getDeleted, 0)
                        .set(ApprovalInstance::getDeleted, (byte) 1)
        );
        LambdaUpdateWrapper<ApprovalInstanceNode> nodeUpdateWrapper = Wrappers.lambdaUpdate();
        nodeUpdateWrapper.in(ApprovalInstanceNode::getInstanceId, ids)
                .eq(ApprovalInstanceNode::getDeleted, 0)
                .set(ApprovalInstanceNode::getDeleted, (byte) 1);
        approvalInstanceNodeService.update(nodeUpdateWrapper);
        LambdaUpdateWrapper<ApprovalTask> taskUpdateWrapper = Wrappers.lambdaUpdate();
        taskUpdateWrapper.in(ApprovalTask::getInstanceId, ids)
                .eq(ApprovalTask::getDeleted, 0)
                .set(ApprovalTask::getDeleted, (byte) 1);
        approvalTaskService.update(taskUpdateWrapper);
        LambdaUpdateWrapper<ApprovalRecord> recordUpdateWrapper = Wrappers.lambdaUpdate();
        recordUpdateWrapper.in(ApprovalRecord::getInstanceId, ids)
                .eq(ApprovalRecord::getDeleted, 0)
                .set(ApprovalRecord::getDeleted, (byte) 1);
        approvalRecordService.update(recordUpdateWrapper);
        return instanceRows > 0;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R approve(ApprovalInstanceDto approvalInstanceDto) {
        if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) {
            return R.fail("审批实例 ID ä¸èƒ½ä¸ºç©º");
        }
        String approveAction = normalizeApproveAction(approvalInstanceDto.getApproveAction());
        if (approveAction == null) {
            return R.fail("审批动作只支持 APPROVED æˆ– REJECTED");
        }
        ApprovalInstance instance = getPendingApprovalInstance(approvalInstanceDto.getId());
        if (instance == null) {
            return R.fail("审批实例不存在");
        }
        ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(instance.getId());
        if (currentNode == null) {
            return R.fail("当前没有待处理的审批节点");
        }
        Long currentUserId = SecurityUtils.getUserId();
        ApprovalTask currentTask = approveProcessConfigNodeUtils.getCurrentUserTask(instance.getId(), currentUserId);
        if (currentTask == null) {
            return R.fail("当前用户没有可审批任务");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String operatorName = loginUser.getUser() != null ? loginUser.getUser().getNickName() : SecurityUtils.getUsername();
        LocalDateTime now = LocalDateTime.now();
        if (!updateCurrentTask(approvalInstanceDto, approveAction, currentTask, now)) {
            return R.fail("当前任务已被处理,请刷新后重试");
        }
        saveApprovalRecord(
                instance.getId(),
                currentNode.getId(),
                currentTask.getId(),
                currentUserId,
                operatorName,
                approveAction,
                approvalInstanceDto.getApproveComment()
        );
        if ("REJECTED".equals(approveAction)) {
            return rejectCurrentNode(instance, currentNode, now);
        }
        if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) {
            return R.ok("审批成功,等待其他审批人处理");
        }
        return approveAndMoveNext(instance, currentNode, approvalInstanceDto, now);
    }
    private String normalizeApproveAction(String approveAction) {
        if (!StringUtils.hasText(approveAction)) {
            return null;
        }
        String normalizedAction = approveAction.trim().toUpperCase(Locale.ROOT);
        return "APPROVED".equals(normalizedAction) || "REJECTED".equals(normalizedAction)
                ? normalizedAction
                : null;
    }
    private ApprovalInstance getPendingApprovalInstance(Long instanceId) {
        return this.getOne(
                new LambdaQueryWrapper<ApprovalInstance>()
                        .eq(ApprovalInstance::getId, instanceId)
                        .eq(ApprovalInstance::getDeleted, 0)
                        .last("LIMIT 1")
        );
    }
    private boolean updateCurrentTask(ApprovalInstanceDto approvalInstanceDto,
                                      String approveAction,
                                      ApprovalTask currentTask,
                                      LocalDateTime now) {
        // ä»…允许待审批任务被成功处理一次,避免并发下重复审批成功。
        return approvalTaskService.update(
                Wrappers.<ApprovalTask>lambdaUpdate()
                        .eq(ApprovalTask::getId, currentTask.getId())
                        .eq(ApprovalTask::getTaskStatus, "PENDING")
                        .eq(ApprovalTask::getDeleted, 0)
                        .set(ApprovalTask::getTaskStatus, approveAction)
                        .set(ApprovalTask::getComment, approvalInstanceDto.getApproveComment())
                        .set(ApprovalTask::getApproveTime, now)
                        .set(ApprovalTask::getIsRead, (byte) 1)
        );
    }
    private R rejectCurrentNode(ApprovalInstance instance, ApprovalInstanceNode currentNode, LocalDateTime now) {
        if (!updateCurrentNodeStatus(currentNode.getId(), "REJECTED", now)) {
            return R.ok("当前节点已处理完成");
        }
        closePendingTasks(instance.getId(), currentNode.getId());
        instance.setStatus("REJECTED");
        instance.setFinishTime(now);
        this.updateById(instance);
        return R.ok("审批已驳回");
    }
    private R approveAndMoveNext(ApprovalInstance instance,
                                 ApprovalInstanceNode currentNode,
                                 ApprovalInstanceDto approvalInstanceDto,
                                 LocalDateTime now) {
        if (!updateCurrentNodeStatus(currentNode.getId(), "APPROVED", now)) {
            return R.ok("当前节点已处理完成");
        }
        closePendingTasks(instance.getId(), currentNode.getId());
        int nextLevel = currentNode.getLevelNo() + 1;
        ApprovalTemplateNode nextTemplateNode = approvalTemplateNodeService.getOne(
                new LambdaQueryWrapper<ApprovalTemplateNode>()
                        .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId())
                        .eq(ApprovalTemplateNode::getLevelNo, nextLevel)
                        .orderByAsc(ApprovalTemplateNode::getId)
                        .last("LIMIT 1")
        );
        if (nextTemplateNode == null) {
            instance.setStatus("APPROVED");
            instance.setFinishTime(now);
            this.updateById(instance);
            handleBusinessAfterApprovalFinished(instance);
            return R.ok("审批已完成");
        }
        instance.setCurrentLevel(nextLevel);
        instance.setStatus("PENDING");
        this.updateById(instance);
        approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false);
        sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
        return R.ok("审批成功,已流转到下一节点");
    }
    private boolean updateCurrentNodeStatus(Long nodeId, String targetStatus, LocalDateTime now) {
        // ä»…允许一个请求将当前节点从待处理推进到目标状态,避免重复流转。
        return approvalInstanceNodeService.update(
                Wrappers.<ApprovalInstanceNode>lambdaUpdate()
                        .eq(ApprovalInstanceNode::getId, nodeId)
                        .eq(ApprovalInstanceNode::getStatus, "PENDING")
                        .eq(ApprovalInstanceNode::getDeleted, 0)
                        .set(ApprovalInstanceNode::getStatus, targetStatus)
                        .set(ApprovalInstanceNode::getFinishTime, now)
        );
    }
    private void handleBusinessAfterApprovalFinished(ApprovalInstance instance) {
        String status = instance.getStatus();
        Long businessType = instance.getBusinessType();
        if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(businessType)) {
            handlePurchaseApprovalFinished(instance, status);
            return;
        }
        if (TypeEnums.QUOTATION_APPROVAL.getCode().equals(businessType)) {
            handleSalesQuotationApprovalFinished(instance, status);
            return;
        }
        if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(businessType)) {
            handleShippingApprovalFinished(instance, status);
        }
    }
    private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) {
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(
                new LambdaQueryWrapper<PurchaseLedger>()
                        .eq(PurchaseLedger::getPurchaseContractNumber, instance.getTitle())
                        .last("limit 1")
        );
        if (purchaseLedger == null) {
            return;
        }
        if ("APPROVED".equals(status)) {
            purchaseLedger.setApprovalStatus(ApprovalStatusEnum.APPROVED.getCode());
            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(
                    new QueryWrapper<SalesLedgerProduct>().lambda()
                            .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
                            .eq(SalesLedgerProduct::getType, 2)
            );
            for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
                if (salesLedgerProduct.getIsChecked()) {
                    qualityInspectHelper.addQualityInspect(purchaseLedger, salesLedgerProduct);
                } else {
                    stockUtils.addStockWithBatchNo(
                            salesLedgerProduct.getProductModelId(),
                            salesLedgerProduct.getQuantity(),
                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
                            purchaseLedger.getId(),
                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId()
                    );
                }
            }
        } else if ("REJECTED".equals(status)) {
            purchaseLedger.setApprovalStatus(ApprovalStatusEnum.REJECTED.getCode());
        } else if ("PENDING".equals(status)) {
            purchaseLedger.setApprovalStatus(ApprovalStatusEnum.IN_PROGRESS.getCode());
        }
        purchaseLedgerMapper.updateById(purchaseLedger);
    }
    private void handleSalesQuotationApprovalFinished(ApprovalInstance instance, String status) {
        SalesQuotation salesQuote = salesQuotationMapper.selectOne(
                new LambdaQueryWrapper<SalesQuotation>()
                        .eq(SalesQuotation::getQuotationNo, instance.getTitle())
                        .last("limit 1")
        );
        if (salesQuote == null) {
            return;
        }
        if ("APPROVED".equals(status)) {
            salesQuote.setStatus(SalesQuotationStatusEnum.APPROVED.getCode());
        } else if ("REJECTED".equals(status)) {
            salesQuote.setStatus(SalesQuotationStatusEnum.REJECTED.getCode());
        } else if ("PENDING".equals(status)) {
            salesQuote.setStatus(SalesQuotationStatusEnum.IN_PROGRESS.getCode());
        }
        salesQuotationMapper.updateById(salesQuote);
    }
    private void handleShippingApprovalFinished(ApprovalInstance instance, String status) {
        ShippingInfo shippingInfo = shippingInfoMapper.selectOne(
                new LambdaQueryWrapper<ShippingInfo>()
                        .eq(ShippingInfo::getShippingNo, instance.getTitle())
                        .orderByDesc(ShippingInfo::getCreateTime)
                        .last("limit 1")
        );
        if (shippingInfo == null) {
            return;
        }
        if ("APPROVED".equals(status)) {
            shippingInfo.setStatus(ShippingStatusEnum.APPROVED.getCode());
            shippingInfo.setShippingDate(new Date());
            stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
        } else if ("REJECTED".equals(status)) {
            stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
            shippingInfo.setStatus(ShippingStatusEnum.REJECTED.getCode());
        } else if ("PENDING".equals(status)) {
            shippingInfo.setStatus(ShippingStatusEnum.IN_PROGRESS.getCode());
        }
        shippingInfoMapper.updateById(shippingInfo);
    }
    private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverService.list(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                        .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId())
                        .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId())
                        .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
                        .orderByAsc(ApprovalTemplateNodeApprover::getSortNo)
        );
        if (approvers == null || approvers.isEmpty()) {
            throw new RuntimeException("下一审批节点未配置审批人");
        }
        ApprovalInstanceNode instanceNode = new ApprovalInstanceNode();
        instanceNode.setInstanceId(instance.getId());
        instanceNode.setLevelNo(templateNode.getLevelNo());
        instanceNode.setApproveType(templateNode.getApproveType());
        instanceNode.setStatus("PENDING");
        instanceNode.setStartTime(LocalDateTime.now());
        instanceNode.setDeleted((byte) 0);
        approvalInstanceNodeService.save(instanceNode);
        List<ApprovalTask> taskList = new ArrayList<>(approvers.size());
        for (ApprovalTemplateNodeApprover approver : approvers) {
            ApprovalTask task = new ApprovalTask();
            task.setInstanceId(instance.getId());
            task.setNodeId(instanceNode.getId());
            task.setLevelNo(instanceNode.getLevelNo());
            task.setApproverId(approver.getApproverId());
            task.setApproverName(approver.getApproverName());
            task.setTaskStatus("PENDING");
            task.setIsRead((byte) 0);
            task.setDeleted((byte) 0);
            taskList.add(task);
        }
        approvalTaskService.saveBatch(taskList);
        return taskList;
    }
    private void sendApproveNotice(ApprovalInstance instance, List<ApprovalTask> tasks) {
        if (instance == null || tasks == null || tasks.isEmpty()) {
            return;
        }
        List<Long> approverIds = tasks.stream()
                .map(ApprovalTask::getApproverId)
                .filter(id -> id != null && id > 0)
                .distinct()
                .collect(Collectors.toList());
        if (approverIds.isEmpty()) {
            return;
        }
        String title = StringUtils.hasText(instance.getTemplateName()) ? instance.getTemplateName() : "审批提醒";
        String message = "审批单号 " + instance.getInstanceNo() + " éœ€è¦æ‚¨å®¡æ‰¹";
        String jumpPath = "/approvalInstance?id=" + instance.getId();
        sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
    }
    private void closePendingTasks(Long instanceId, Long nodeId) {
        LambdaUpdateWrapper<ApprovalTask> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(ApprovalTask::getInstanceId, instanceId)
                .eq(ApprovalTask::getNodeId, nodeId)
                .eq(ApprovalTask::getTaskStatus, "PENDING")
                .eq(ApprovalTask::getDeleted, 0)
                .set(ApprovalTask::getDeleted, (byte) 1);
        approvalTaskService.update(updateWrapper);
    }
    private void saveApprovalRecord(Long instanceId,
                                    Long nodeId,
                                    Long taskId,
                                    Long operatorId,
                                    String operatorName,
                                    String action,
                                    String comment) {
        ApprovalRecord record = new ApprovalRecord();
        record.setInstanceId(instanceId);
        record.setNodeId(nodeId);
        record.setTaskId(taskId);
        record.setOperatorId(operatorId);
        record.setOperatorName(operatorName);
        record.setAction(action);
        record.setComment(comment);
        record.setDeleted((byte) 0);
        approvalRecordService.save(record);
    }
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.approve.service.impl;
import com.ruoyi.approve.pojo.ApprovalRecord;
import com.ruoyi.approve.mapper.ApprovalRecordMapper;
import com.ruoyi.approve.service.ApprovalRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * å®¡æ‰¹è®°å½•表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:28:21
 */
@Service
public class ApprovalRecordServiceImpl extends ServiceImpl<ApprovalRecordMapper, ApprovalRecord> implements ApprovalRecordService {
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalTaskServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.approve.service.impl;
import com.ruoyi.approve.pojo.ApprovalTask;
import com.ruoyi.approve.mapper.ApprovalTaskMapper;
import com.ruoyi.approve.service.ApprovalTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * å®¡æ‰¹ä»»åŠ¡è¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 03:32:37
 */
@Service
public class ApprovalTaskServiceImpl extends ServiceImpl<ApprovalTaskMapper, ApprovalTask> implements ApprovalTaskService {
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeApproverServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.approve.service.impl;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper;
import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹å®¡æ‰¹äººè¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:30
 */
@Service
public class ApprovalTemplateNodeApproverServiceImpl extends ServiceImpl<ApprovalTemplateNodeApproverMapper, ApprovalTemplateNodeApprover> implements ApprovalTemplateNodeApproverService {
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package com.ruoyi.approve.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeApproverDto;
import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto;
import com.ruoyi.approve.mapper.ApprovalTemplateNodeMapper;
import com.ruoyi.approve.pojo.ApprovalTemplateNode;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService;
import com.ruoyi.approve.service.ApprovalTemplateNodeService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿èŠ‚ç‚¹è¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-18 11:20:19
 */
@Service
@RequiredArgsConstructor
public class ApprovalTemplateNodeServiceImpl extends ServiceImpl<ApprovalTemplateNodeMapper, ApprovalTemplateNode> implements ApprovalTemplateNodeService {
    private final ApprovalTemplateNodeMapper approvalTemplateNodeMapper;
    private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService;
    @Override
    public Boolean saveApprovalTemplateNode(Long templateId, List<ApprovalTemplateNodeDto> nodes) {
        if (nodes == null || nodes.isEmpty()) {
            throw new RuntimeException("节点列表不能为空");
        }
        List<ApprovalTemplateNodeApprover> approverList = new ArrayList<>();
        for (ApprovalTemplateNodeDto nodeDto : nodes) {
            ApprovalTemplateNode node = new ApprovalTemplateNode();
            BeanUtils.copyProperties(nodeDto, node);
            node.setTemplateId(templateId);
            approvalTemplateNodeMapper.insert(node);
            List<ApprovalTemplateNodeApproverDto> approvers = nodeDto.getApprovers();
            if (approvers == null || approvers.isEmpty()) {
                throw new RuntimeException("节点审批人不能为空");
            }
            for (ApprovalTemplateNodeApproverDto approverDto : approvers) {
                ApprovalTemplateNodeApprover approver = new ApprovalTemplateNodeApprover();
                BeanUtils.copyProperties(approverDto, approver);
                approver.setNodeId(node.getId());
                approver.setTemplateId(templateId);
                approver.setDeleted(0L);
                approverList.add(approver);
            }
        }
        approvalTemplateNodeApproverService.saveBatch(approverList);
        return true;
    }
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,251 @@
package com.ruoyi.approve.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.bean.dto.ApprovalTemplateDto;
import com.ruoyi.approve.bean.vo.ApprovalTemplateNodeApproverVo;
import com.ruoyi.approve.bean.vo.ApprovalTemplateNodeVo;
import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper;
import com.ruoyi.approve.pojo.ApprovalTemplate;
import com.ruoyi.approve.pojo.ApprovalTemplateNode;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import com.ruoyi.approve.service.ApprovalTemplateNodeService;
import com.ruoyi.approve.service.ApprovalTemplateService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * <p>
 * å®¡æ‰¹æ¨¡æ¿æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @since 2026-05-18 11:20:08
 */
@Service
@RequiredArgsConstructor
public class ApprovalTemplateServiceImpl extends ServiceImpl<ApprovalTemplateMapper, ApprovalTemplate> implements ApprovalTemplateService {
    private final ApprovalTemplateMapper approvalTemplateMapper;
    private final ApprovalTemplateNodeService approvalTemplateNodeService;
    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
    @Override
    public IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto) {
        IPage<ApprovalTemplateVo> approvalTemplateVoIPage = approvalTemplateMapper.listPage(page, approvalTemplateDto);
        fillTemplateVoNodes(approvalTemplateVoIPage.getRecords());
        return approvalTemplateVoIPage;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) {
        approvalTemplateMapper.insert(approvalTemplateDto);
        approvalTemplateNodeService.remove(
                new LambdaQueryWrapper<ApprovalTemplateNode>()
                        .eq(ApprovalTemplateNode::getTemplateId, approvalTemplateDto.getId())
        );
        approvalTemplateNodeApproverMapper.delete(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                        .eq(ApprovalTemplateNodeApprover::getTemplateId, approvalTemplateDto.getId())
        );
        return approvalTemplateNodeService.saveApprovalTemplateNode(
                approvalTemplateDto.getId(),
                approvalTemplateDto.getNodes()
        );
    }
    @Override
    public Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) {
        approvalTemplateMapper.updateById(approvalTemplateDto);
        approvalTemplateNodeService.remove(
                new LambdaQueryWrapper<ApprovalTemplateNode>()
                        .eq(ApprovalTemplateNode::getTemplateId, approvalTemplateDto.getId())
        );
        approvalTemplateNodeApproverMapper.delete(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                        .eq(ApprovalTemplateNodeApprover::getTemplateId, approvalTemplateDto.getId())
        );
        return approvalTemplateNodeService.saveApprovalTemplateNode(
                approvalTemplateDto.getId(),
                approvalTemplateDto.getNodes()
        );
    }
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        ApprovalTemplate updateEntity = new ApprovalTemplate();
        updateEntity.setDeleted(1);
        LambdaUpdateWrapper<ApprovalTemplate> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.in(ApprovalTemplate::getId, ids)
                .eq(ApprovalTemplate::getDeleted, 0);
        int rows = approvalTemplateMapper.update(updateEntity, updateWrapper);
        return rows == ids.size();
    }
    @Override
    public List<ApprovalTemplateVo> listApprovalTemplateVo(Integer type) {
        List<ApprovalTemplate> templateList = this.list(
                new LambdaQueryWrapper<ApprovalTemplate>()
                        .eq(ApprovalTemplate::getDeleted, 0)
                        .eq(ApprovalTemplate::getEnabled, 1)
                        .eq(type != null, ApprovalTemplate::getTemplateType, type)
                        .orderByDesc(ApprovalTemplate::getTemplateType)
                        .orderByDesc(ApprovalTemplate::getId)
        );
        if (CollUtil.isEmpty(templateList)) {
            return Collections.emptyList();
        }
        List<ApprovalTemplateVo> templateVos = templateList.stream()
                .map(template -> {
                    ApprovalTemplateVo templateVo = new ApprovalTemplateVo();
                    BeanUtils.copyProperties(template, templateVo);
                    return templateVo;
                })
                .collect(Collectors.toList());
        fillTemplateVoNodes(templateVos);
        return templateVos;
    }
    @Override
    public ApprovalTemplateVo getApprovalTemplateVoById(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("参数 id ä¸èƒ½ä¸ºç©º");
        }
        ApprovalTemplate template = this.getOne(
                new LambdaQueryWrapper<ApprovalTemplate>()
                        .eq(ApprovalTemplate::getId, id)
                        .eq(ApprovalTemplate::getDeleted, 0)
        );
        if (template == null) {
            throw new IllegalArgumentException("模板不存在");
        }
        List<ApprovalTemplateNode> nodeList = approvalTemplateNodeService.list(
                new LambdaQueryWrapper<ApprovalTemplateNode>()
                        .eq(ApprovalTemplateNode::getTemplateId, id)
                        .orderByAsc(ApprovalTemplateNode::getLevelNo)
        );
        List<ApprovalTemplateNodeApprover> approverList = approvalTemplateNodeApproverMapper.selectList(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                        .eq(ApprovalTemplateNodeApprover::getTemplateId, id)
                        .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
        );
        Map<Long, List<ApprovalTemplateNode>> nodeMap = nodeList.stream()
                .collect(Collectors.groupingBy(ApprovalTemplateNode::getTemplateId));
        Map<Long, List<ApprovalTemplateNodeApprover>> approverMap = approverList.stream()
                .collect(Collectors.groupingBy(ApprovalTemplateNodeApprover::getNodeId));
        return buildTemplateVo(template, nodeMap, approverMap);
    }
    /**
     * æ‰¹é‡å¡«å……模板节点及节点审批人,避免循环查库。
     */
    private void fillTemplateVoNodes(List<ApprovalTemplateVo> templateVos) {
        if (CollUtil.isEmpty(templateVos)) {
            return;
        }
        List<Long> templateIds = templateVos.stream()
                .map(ApprovalTemplateVo::getId)
                .collect(Collectors.toList());
        List<ApprovalTemplateNode> nodeList = approvalTemplateNodeService.list(
                new LambdaQueryWrapper<ApprovalTemplateNode>()
                        .in(ApprovalTemplateNode::getTemplateId, templateIds)
                        .orderByAsc(ApprovalTemplateNode::getLevelNo)
        );
        List<ApprovalTemplateNodeApprover> approverList = approvalTemplateNodeApproverMapper.selectList(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                        .in(ApprovalTemplateNodeApprover::getTemplateId, templateIds)
                        .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
        );
        Map<Long, List<ApprovalTemplateNode>> nodeMap = nodeList.stream()
                .collect(Collectors.groupingBy(ApprovalTemplateNode::getTemplateId));
        Map<Long, List<ApprovalTemplateNodeApprover>> approverMap = approverList.stream()
                .collect(Collectors.groupingBy(ApprovalTemplateNodeApprover::getNodeId));
        templateVos.forEach(templateVo -> templateVo.setNodes(
                nodeMap.getOrDefault(templateVo.getId(), Collections.emptyList())
                        .stream()
                        .sorted(Comparator.comparing(
                                ApprovalTemplateNode::getLevelNo,
                                Comparator.nullsLast(Integer::compareTo)
                        ))
                        .map(node ->  buildNodeVo(node, approverMap))
                        .collect(Collectors.toList())
        ));
    }
    private ApprovalTemplateVo buildTemplateVo(ApprovalTemplate template,
                                               Map<Long, List<ApprovalTemplateNode>> nodeMap,
                                               Map<Long, List<ApprovalTemplateNodeApprover>> approverMap) {
        ApprovalTemplateVo templateVo = new ApprovalTemplateVo();
        BeanUtils.copyProperties(template, templateVo);
        List<ApprovalTemplateNodeVo> nodeVos = nodeMap
                .getOrDefault(template.getId(), Collections.emptyList())
                .stream()
                .sorted(Comparator.comparing(
                        ApprovalTemplateNode::getLevelNo,
                        Comparator.nullsLast(Integer::compareTo)
                ))
                .map(node -> buildNodeVo(node, approverMap))
                .collect(Collectors.toList());
        templateVo.setNodes(nodeVos);
        return templateVo;
    }
    private ApprovalTemplateNodeVo buildNodeVo(ApprovalTemplateNode node,
                                               Map<Long, List<ApprovalTemplateNodeApprover>> approverMap) {
        ApprovalTemplateNodeVo nodeVo = new ApprovalTemplateNodeVo();
        BeanUtils.copyProperties(node, nodeVo);
        List<ApprovalTemplateNodeApproverVo> approverVos = approverMap
                .getOrDefault(node.getId(), Collections.emptyList())
                .stream()
                .sorted(Comparator.comparing(
                        ApprovalTemplateNodeApprover::getSortNo,
                        Comparator.nullsLast(Integer::compareTo)
                ))
                .map(this::buildApproverVo)
                .collect(Collectors.toList());
        nodeVo.setApprovers(approverVos);
        return nodeVo;
    }
    private ApprovalTemplateNodeApproverVo buildApproverVo(ApprovalTemplateNodeApprover approver) {
        ApprovalTemplateNodeApproverVo approverVo = new ApprovalTemplateNodeApproverVo();
        BeanUtils.copyProperties(approver, approverVo);
        return approverVo;
    }
}
src/main/java/com/ruoyi/approve/utils/ApproveProcessConfigNodeUtils.java
@@ -1,9 +1,370 @@
package com.ruoyi.approve.utils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.approve.pojo.ApprovalInstance;
import com.ruoyi.approve.pojo.ApprovalInstanceNode;
import com.ruoyi.approve.pojo.ApprovalRecord;
import com.ruoyi.approve.pojo.ApprovalTask;
import com.ruoyi.approve.pojo.ApprovalTemplateNode;
import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover;
import com.ruoyi.approve.service.ApprovalInstanceNodeService;
import com.ruoyi.approve.service.ApprovalRecordService;
import com.ruoyi.approve.service.ApprovalTaskService;
import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService;
import com.ruoyi.approve.service.ApprovalTemplateNodeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
 * å®¡æ‰¹æµç¨‹èŠ‚ç‚¹å·¥å…·ç±»
 */
@Component
@RequiredArgsConstructor
public class ApproveProcessConfigNodeUtils {
    private final ApprovalInstanceNodeService instanceNodeService;
    private final ApprovalTaskService approvalTaskService;
    private final ApprovalRecordService approvalRecordService;
    private final ApprovalTemplateNodeService approvalTemplateNodeService;
    private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService;
}
    /**
     * æŒ‰å½“前层级创建审批节点和审批任务。
     * è¯¥é‡è½½ä¼šåŒæ—¶å†™å…¥ä¸€æ¡å‘起审批记录。
     */
    @Transactional(rollbackFor = Exception.class)
    public ApprovalInstanceNode createCurrentNodeAndTasks(ApprovalInstance instance) {
        return createCurrentNodeAndTasks(instance, true);
    }
    /**
     * æŒ‰å½“前层级创建审批节点和审批任务。
     *
     * @param instance å®¡æ‰¹å®žä¾‹
     * @param createSubmitRecord æ˜¯å¦åˆ›å»ºå‘起审批记录
     * @return åˆ›å»ºå‡ºçš„当前节点实例
     */
    @Transactional(rollbackFor = Exception.class)
    public ApprovalInstanceNode createCurrentNodeAndTasks(ApprovalInstance instance, boolean createSubmitRecord) {
        if (instance == null || instance.getId() == null) {
            throw new RuntimeException("审批实例不能为空");
        }
        if (instance.getTemplateId() == null) {
            throw new RuntimeException("审批模板不能为空");
        }
        Integer currentLevel = instance.getCurrentLevel() == null ? 1 : instance.getCurrentLevel();
        ApprovalInstanceNode existsNode = instanceNodeService.getOne(
                new LambdaQueryWrapper<ApprovalInstanceNode>()
                        .eq(ApprovalInstanceNode::getInstanceId, instance.getId())
                        .eq(ApprovalInstanceNode::getLevelNo, currentLevel)
                        .eq(ApprovalInstanceNode::getDeleted, 0)
                        .last("LIMIT 1")
        );
        if (existsNode != null) {
            return existsNode;
        }
        ApprovalTemplateNode templateNode = approvalTemplateNodeService.getOne(
                new LambdaQueryWrapper<ApprovalTemplateNode>()
                        .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId())
                        .eq(ApprovalTemplateNode::getLevelNo, currentLevel)
                        .orderByAsc(ApprovalTemplateNode::getId)
                        .last("LIMIT 1")
        );
        if (templateNode == null) {
            throw new RuntimeException("未找到当前层级对应的审批模板节点");
        }
        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverService.list(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                        .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId())
                        .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId())
                        .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
                        .orderByAsc(ApprovalTemplateNodeApprover::getSortNo)
        );
        if (approvers == null || approvers.isEmpty()) {
            throw new RuntimeException("当前审批节点未配置审批人");
        }
        ApprovalInstanceNode instanceNode = new ApprovalInstanceNode();
        instanceNode.setInstanceId(instance.getId());
        instanceNode.setLevelNo(templateNode.getLevelNo());
        instanceNode.setApproveType(templateNode.getApproveType());
        instanceNode.setStatus("PENDING");
        instanceNode.setStartTime(LocalDateTime.now());
        instanceNode.setDeleted((byte) 0);
        instanceNodeService.save(instanceNode);
        List<ApprovalTask> taskList = new ArrayList<>(approvers.size());
        for (ApprovalTemplateNodeApprover approver : approvers) {
            ApprovalTask task = new ApprovalTask();
            task.setInstanceId(instance.getId());
            task.setNodeId(instanceNode.getId());
            task.setLevelNo(instanceNode.getLevelNo());
            task.setApproverId(approver.getApproverId());
            task.setApproverName(approver.getApproverName());
            task.setTaskStatus("PENDING");
            task.setIsRead((byte) 0);
            task.setDeleted((byte) 0);
            taskList.add(task);
        }
        approvalTaskService.saveBatch(taskList);
        if (createSubmitRecord) {
            ApprovalRecord record = new ApprovalRecord();
            record.setInstanceId(instance.getId());
            record.setNodeId(instanceNode.getId());
            record.setOperatorId(instance.getApplicantId());
            record.setOperatorName(instance.getApplicantName());
            record.setAction("SUBMIT");
            record.setComment("发起审批");
            record.setDeleted((byte) 0);
            approvalRecordService.save(record);
        }
        return instanceNode;
    }
    /**
     * æŸ¥è¯¢å½“前待处理节点。
     */
    public ApprovalInstanceNode getCurrentNode(Long instanceId) {
        if (instanceId == null) {
            return null;
        }
        return instanceNodeService.getOne(
                new LambdaQueryWrapper<ApprovalInstanceNode>()
                        .eq(ApprovalInstanceNode::getInstanceId, instanceId)
                        .eq(ApprovalInstanceNode::getStatus, "PENDING")
                        .eq(ApprovalInstanceNode::getDeleted, 0)
                        .orderByAsc(ApprovalInstanceNode::getLevelNo)
                        .last("LIMIT 1")
        );
    }
    /**
     * æŸ¥è¯¢å½“前审批层级。
     */
    public Integer getCurrentLevel(Long instanceId) {
        ApprovalInstanceNode currentNode = getCurrentNode(instanceId);
        return currentNode != null ? currentNode.getLevelNo() : null;
    }
    /**
     * æŸ¥è¯¢å½“前节点下的待审批任务。
     */
    public List<ApprovalTask> getCurrentPendingTasks(Long instanceId) {
        if (instanceId == null) {
            return List.of();
        }
        ApprovalInstanceNode currentNode = getCurrentNode(instanceId);
        if (currentNode == null) {
            return List.of();
        }
        return approvalTaskService.list(
                new LambdaQueryWrapper<ApprovalTask>()
                        .eq(ApprovalTask::getInstanceId, instanceId)
                        .eq(ApprovalTask::getNodeId, currentNode.getId())
                        .eq(ApprovalTask::getTaskStatus, "PENDING")
                        .eq(ApprovalTask::getDeleted, 0)
                        .orderByAsc(ApprovalTask::getLevelNo)
        );
    }
    /**
     * æŸ¥è¯¢å½“前用户在当前节点上的待审批任务。
     */
    public ApprovalTask getCurrentUserTask(Long instanceId, Long userId) {
        if (instanceId == null || userId == null) {
            return null;
        }
        ApprovalInstanceNode currentNode = getCurrentNode(instanceId);
        if (currentNode == null) {
            return null;
        }
        return approvalTaskService.getOne(
                new LambdaQueryWrapper<ApprovalTask>()
                        .eq(ApprovalTask::getInstanceId, instanceId)
                        .eq(ApprovalTask::getNodeId, currentNode.getId())
                        .eq(ApprovalTask::getApproverId, userId)
                        .eq(ApprovalTask::getTaskStatus, "PENDING")
                        .eq(ApprovalTask::getDeleted, 0)
                        .last("LIMIT 1")
        );
    }
    /**
     * åˆ¤æ–­å½“前用户是否是当前审批人。
     */
    public boolean isCurrentApprover(Long instanceId, Long userId) {
        return getCurrentUserTask(instanceId, userId) != null;
    }
    /**
     * æŸ¥è¯¢å½“前节点的审批人 ID åˆ—表。
     */
    public List<Long> getCurrentNodeApproverIds(Long instanceId) {
        return getCurrentPendingTasks(instanceId).stream()
                .map(ApprovalTask::getApproverId)
                .distinct()
                .collect(Collectors.toList());
    }
    /**
     * æŸ¥è¯¢å½“前节点剩余待审批人数。
     */
    public int getRemainingApproverCount(Long instanceId) {
        return getCurrentPendingTasks(instanceId).size();
    }
    /**
     * æŸ¥è¯¢å½“前节点已同意人数。
     */
    public int getApprovedCount(Long instanceId) {
        if (instanceId == null) {
            return 0;
        }
        ApprovalInstanceNode currentNode = getCurrentNode(instanceId);
        if (currentNode == null) {
            return 0;
        }
        return Math.toIntExact(approvalTaskService.count(
                new LambdaQueryWrapper<ApprovalTask>()
                        .eq(ApprovalTask::getInstanceId, instanceId)
                        .eq(ApprovalTask::getNodeId, currentNode.getId())
                        .eq(ApprovalTask::getTaskStatus, "APPROVED")
                        .eq(ApprovalTask::getDeleted, 0)
        ));
    }
    /**
     * æŸ¥è¯¢å½“前节点已拒绝人数。
     */
    public int getRejectedCount(Long instanceId) {
        if (instanceId == null) {
            return 0;
        }
        ApprovalInstanceNode currentNode = getCurrentNode(instanceId);
        if (currentNode == null) {
            return 0;
        }
        return Math.toIntExact(approvalTaskService.count(
                new LambdaQueryWrapper<ApprovalTask>()
                        .eq(ApprovalTask::getInstanceId, instanceId)
                        .eq(ApprovalTask::getNodeId, currentNode.getId())
                        .eq(ApprovalTask::getTaskStatus, "REJECTED")
                        .eq(ApprovalTask::getDeleted, 0)
        ));
    }
    /**
     * åˆ¤æ–­å½“前节点是否可以流转到下一层。
     */
    public boolean canProceedToNextLevel(Long instanceId, String approveType) {
        if (instanceId == null || approveType == null) {
            return false;
        }
        if (getRejectedCount(instanceId) > 0) {
            return false;
        }
        int totalApproverCount = getCurrentPendingTasks(instanceId).size() + getApprovedCount(instanceId);
        int approvedCount = getApprovedCount(instanceId);
        if ("AND".equalsIgnoreCase(approveType)) {
            return approvedCount > 0 && approvedCount == totalApproverCount;
        }
        if ("OR".equalsIgnoreCase(approveType)) {
            return approvedCount > 0;
        }
        return false;
    }
    /**
     * æŸ¥è¯¢å½“前用户在当前节点上的任务状态。
     */
    public String getUserTaskStatus(Long instanceId, Long userId) {
        if (instanceId == null || userId == null) {
            return null;
        }
        ApprovalInstanceNode currentNode = getCurrentNode(instanceId);
        if (currentNode == null) {
            return null;
        }
        ApprovalTask task = approvalTaskService.getOne(
                new LambdaQueryWrapper<ApprovalTask>()
                        .eq(ApprovalTask::getInstanceId, instanceId)
                        .eq(ApprovalTask::getNodeId, currentNode.getId())
                        .eq(ApprovalTask::getApproverId, userId)
                        .eq(ApprovalTask::getDeleted, 0)
                        .last("LIMIT 1")
        );
        return task != null ? task.getTaskStatus() : null;
    }
    /**
     * æŸ¥è¯¢æŒ‡å®šç”¨æˆ·çš„全部待审批任务。
     */
    public List<ApprovalTask> getUserAllPendingTasks(Long userId) {
        if (userId == null) {
            return List.of();
        }
        return approvalTaskService.list(
                new LambdaQueryWrapper<ApprovalTask>()
                        .eq(ApprovalTask::getApproverId, userId)
                        .eq(ApprovalTask::getTaskStatus, "PENDING")
                        .eq(ApprovalTask::getDeleted, 0)
                        .orderByDesc(ApprovalTask::getCreateTime)
        );
    }
    /**
     * æŸ¥è¯¢å®¡æ‰¹å®žä¾‹çš„进度摘要。
     */
    public String getApprovalProgress(Long instanceId) {
        if (instanceId == null) {
            return "无效的审批实例";
        }
        ApprovalInstanceNode currentNode = getCurrentNode(instanceId);
        if (currentNode == null) {
            return "审批已完成或尚未开始";
        }
        int approvedCount = getApprovedCount(instanceId);
        int rejectedCount = getRejectedCount(instanceId);
        int pendingCount = getRemainingApproverCount(instanceId);
        int totalCount = approvedCount + rejectedCount + pendingCount;
        return String.format(
                "第%d级审批:总人数=%d,已同意=%d,已拒绝=%d,待审批=%d",
                currentNode.getLevelNo(),
                totalCount,
                approvedCount,
                rejectedCount,
                pendingCount
        );
    }
}
src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
@@ -205,7 +205,9 @@
    SALES_RECEIPT_RETURN("sales_receipt_return"),
    ACCOUNT_EXPENSE("account_expense"),
    FIN_VOUCHER("fin_voucher"),
    ACCOUNT_FILE("account_file");
    ACCOUNT_FILE("account_file"),
    APPROVAL_INSTANCE("approval_instance");
    private final String type;
    RecordTypeEnum(String type) { this.type = type; }
src/main/java/com/ruoyi/common/enums/ApprovalStatusEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * å®¡æ‰¹çŠ¶æ€æžšä¸¾
 */
@Getter
@AllArgsConstructor
public enum ApprovalStatusEnum implements BaseEnum<Integer> {
    DRAFT(0, "草稿"),
    PENDING(1, "待审批"),
    IN_PROGRESS(2, "审批中"),
    APPROVED(3, "已通过"),
    REJECTED(4, "已驳回");
    private final Integer value;
    private final String label;
    @Override
    public Integer getCode() {
        return value;
    }
    @Override
    public String getValue() {
        return label;
    }
    public static ApprovalStatusEnum fromValue(Integer value) {
        if (value == null) {
            return null;
        }
        for (ApprovalStatusEnum status : values()) {
            if (status.getCode().equals(value)) {
                return status;
            }
        }
        return null;
    }
    public static String getLabelByValue(Integer value) {
        ApprovalStatusEnum statusEnum = fromValue(value);
        return statusEnum != null ? statusEnum.getValue() : "未知状态";
    }
}
src/main/java/com/ruoyi/common/enums/SalesQuotationStatusEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * é”€å”®æŠ¥ä»·çŠ¶æ€æžšä¸¾
 */
@Getter
@AllArgsConstructor
public enum SalesQuotationStatusEnum implements BaseEnum<String> {
    DRAFT("草稿", "草稿"),
    PENDING("待审批", "待审批"),
    IN_PROGRESS("审核中", "审核中"),
    APPROVED("通过", "通过"),
    REJECTED("拒绝", "拒绝");
    private final String value;
    private final String label;
    @Override
    public String getCode() {
        return value;
    }
    @Override
    public String getValue() {
        return label;
    }
    public static SalesQuotationStatusEnum fromValue(String value) {
        if (value == null) {
            return null;
        }
        for (SalesQuotationStatusEnum status : values()) {
            if (status.getCode().equals(value)) {
                return status;
            }
        }
        return null;
    }
}
src/main/java/com/ruoyi/common/enums/ShippingStatusEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * å‘货审批状态枚举
 */
@Getter
@AllArgsConstructor
public enum ShippingStatusEnum implements BaseEnum<String> {
    PENDING("待确认", "待确认"),
    IN_PROGRESS("审核中", "审核中"),
    APPROVED("审核通过", "审核通过"),
    REJECTED("审核拒绝", "审核拒绝");
    private final String value;
    private final String label;
    @Override
    public String getCode() {
        return value;
    }
    @Override
    public String getValue() {
        return label;
    }
    public static ShippingStatusEnum fromValue(String value) {
        if (value == null) {
            return null;
        }
        for (ShippingStatusEnum status : values()) {
            if (status.getCode().equals(value)) {
                return status;
            }
        }
        return null;
    }
}
src/main/java/com/ruoyi/common/enums/TypeEnums.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum TypeEnums implements BaseEnum<Long> {
    PUBLIC_OUT(1L, "公出管理"),
    LEAVE(2L, "请假管理"),
    BUSINESS_TRIP(3L, "出差管理"),
    REIMBURSEMENT(4L, "报销管理"),
    PURCHASE_APPROVAL(5L, "采购审批"),
    QUOTATION_APPROVAL(6L, "报价审批"),
    SHIPPING_APPROVAL(7L, "发货审批"),
    DANGEROUS_OPERATION(8L, "危险作业审批"),
    OFFICE_SUPPLIES(9L, "办公用品审批"),
    REGULARIZATION_APPROVAL(10L, "转正审批"),
    TRANSFER_APPROVAL(11L, "调动审批"),
    RESIGNATION_APPROVAL(12L, "离职审批"),
    WORK_HANDOVER_APPROVAL(13L, "工作交接审批"),
    LEAVE_APPROVAL(14L, "请假审批"),
    OVERTIME_APPROVAL(15L, "加班审批"),
    TRAVEL_REIMBURSEMENT_APPROVAL(16L, "出差报销审批"),
    EXPENSE_APPROVAL(17L, "费用审批"),
    ENTERPRISE_NEWS_APPROVAL(18L, "企业新闻审批");
    private final Long value;
    private final String label;
    @Override
    public Long getCode() {
        return value;
    }
    @Override
    public String getValue() {
        return label;
    }
    /**
     * æ ¹æ®å€¼èŽ·å–å¯¹åº”çš„æžšä¸¾
     * @param value ä¸šåŠ¡ç±»åž‹å€¼
     * @return å¯¹åº”的枚举,未匹配返回null
     */
    public static TypeEnums fromValue(Long value) {
        if (value == null) {
            return null;
        }
        for (TypeEnums type : values()) {
            if (type.getCode().equals(value)) {
                return type;
            }
        }
        return null;
    }
    /**
     * æ ¹æ®å€¼èŽ·å–æè¿°
     * @param value ä¸šåŠ¡ç±»åž‹å€¼
     * @return ä¸šåŠ¡ç±»åž‹æè¿°ï¼ŒæœªåŒ¹é…è¿”å›ž"自定义审批"
     */
    public static String getLabelByValue(Long value) {
        TypeEnums typeEnum = fromValue(value);
        return typeEnum != null ? typeEnum.getValue() : "自定义审批";
    }
}
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
@@ -39,7 +39,7 @@
    @PostMapping("/updateRouteItem")
    @Operation(summary = "修改生产订单的工艺路线详情")
    public R updateRouteItem(@RequestBody ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        return R.ok(productionOrderRoutingOperationService.updateById(productionOrderRoutingOperation));
        return R.ok(productionOrderRoutingOperationService.updateRouteItem(productionOrderRoutingOperation));
    }
    @DeleteMapping("/deleteRouteItem/{id}")
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
@@ -11,4 +11,6 @@
    R deleteRouteItem(Long id);
    int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
    Boolean updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
}
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
@@ -182,4 +182,11 @@
        }
        return 0;
    }
    @Override
    public Boolean updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        //根据是否生产判断是否需要删除对应的工单
        return null;
    }
}
src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
@@ -166,4 +166,7 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @Schema(description = "模板id")
    private Long templateId;
}
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -6,8 +6,12 @@
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApproveProcessVO;
import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
import com.ruoyi.approve.pojo.ApprovalInstance;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
import com.ruoyi.basic.enums.ApplicationTypeEnum;
import com.ruoyi.basic.enums.RecordTypeEnum;
@@ -112,6 +116,8 @@
    private final ApproveProcessServiceImpl approveProcessService;
    private final ProcurementRecordMapper procurementRecordStorageMapper;
    private final FileUtil fileUtil;
    private final ApprovalInstanceService approvalInstanceService;
    private final ApprovalTemplateMapper approvalTemplateMapper;
    @Override
    public List<PurchaseLedger> selectPurchaseLedgerList(PurchaseLedger purchaseLedger) {
@@ -162,7 +168,7 @@
        if (purchaseLedger.getId() == null) {
            purchaseLedgerMapper.insert(purchaseLedger);
        } else {
            // åˆ é™¤é‡‡è´­å®¡æ ¸ï¼Œé‡æ–°æäº¤
//            // åˆ é™¤é‡‡è´­å®¡æ ¸ï¼Œé‡æ–°æäº¤
            ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                    .eq(ApproveProcess::getApproveType, 5)
                    .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber())
@@ -172,8 +178,22 @@
                approveProcessService.delByIds(Collections.singletonList(one.getId()));
            }
            purchaseLedgerMapper.updateById(purchaseLedger);
            //删除新采购审批
            approvalInstanceService.remove(new LambdaQueryWrapper<ApprovalInstance>().eq(ApprovalInstance::getBusinessId, purchaseLedger.getId()).eq(ApprovalInstance::getBusinessType, 5));
        }
        //新采购审批
        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
        approvalInstanceDto.setTemplateId(purchaseLedger.getTemplateId());
        approvalInstanceDto.setBusinessId(purchaseLedger.getId());
        approvalInstanceDto.setBusinessType(5L);
        approvalInstanceDto.setTitle("采购合同号:" + purchaseLedger.getPurchaseContractNumber());
        approvalInstanceDto.setApplicantId(SecurityUtils.getUserId());
        approvalInstanceDto.setTemplateId(purchaseLedger.getTemplateId());
        approvalInstanceDto.setTemplateName(approvalTemplateMapper.selectById(purchaseLedger.getTemplateId()).getTemplateName());
        approvalInstanceDto.setApplicantName(SecurityUtils.getLoginUser().getNickName());
        approvalInstanceDto.setApplyTime(LocalDateTime.now());
        approvalInstanceService.add(approvalInstanceDto);
        // 4. å¤„理子表数据
        List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData();
        if (productList != null && !productList.isEmpty()) {
@@ -493,10 +513,29 @@
    @Override
    public IPage<PurchaseLedgerDto> selectPurchaseLedgerListPage(IPage ipage, PurchaseLedgerDto purchaseLedger) {
        IPage<PurchaseLedgerDto> purchaseLedgerDtoIPage = purchaseLedgerMapper.selectPurchaseLedgerListPage(ipage, purchaseLedger);
        purchaseLedgerDtoIPage.getRecords().forEach(purchaseLedgerDto -> {
            List<CommonFile> commonFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>().eq(CommonFile::getCommonId, purchaseLedgerDto.getId()).eq(CommonFile::getType, FileNameType.PURCHASE.getValue()));
            purchaseLedgerDto.setSalesLedgerFiles(commonFiles);
        });
        List<PurchaseLedgerDto> records = purchaseLedgerDtoIPage.getRecords();
        if (records == null || records.isEmpty()) {
            return purchaseLedgerDtoIPage;
        }
        // æ‰¹é‡æŸ¥è¯¢æ–‡ä»¶ï¼Œé¿å… N+1 é—®é¢˜
        List<Long> ledgerIds = records.stream()
                .map(PurchaseLedgerDto::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (!ledgerIds.isEmpty()) {
            List<CommonFile> allFiles = commonFileMapper.selectList(
                    new LambdaQueryWrapper<CommonFile>()
                            .in(CommonFile::getCommonId, ledgerIds)
                            .eq(CommonFile::getType, FileNameType.PURCHASE.getValue())
            );
            Map<Long, List<CommonFile>> fileMap = allFiles.stream()
                    .collect(Collectors.groupingBy(CommonFile::getCommonId));
            records.forEach(dto -> dto.setSalesLedgerFiles(fileMap.getOrDefault(dto.getId(), new ArrayList<>())));
        }
        return purchaseLedgerDtoIPage;
    }
@@ -642,9 +681,9 @@
            return AjaxResult.success("导入成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("PurchaseLedgerServiceImpl importData error", e);
            return AjaxResult.error("导入失败: " + e.getMessage());
        }
        return AjaxResult.success("导入失败");
    }
    @Override
src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
package com.ruoyi.quality.utils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.mapper.QualityInspectParamMapper;
import com.ruoyi.quality.mapper.QualityTestStandardMapper;
import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectParam;
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardParam;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
/**
 * è´¨æ£€å•创建工具类
 */
@Component
@RequiredArgsConstructor
public class QualityInspectHelper {
    private final QualityInspectMapper qualityInspectMapper;
    private final QualityTestStandardMapper qualityTestStandardMapper;
    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
    private final QualityInspectParamMapper qualityInspectParamMapper;
    /**
     * åˆ›å»ºè´¨æ£€å•
     * @param purchaseLedger é‡‡è´­å°è´¦
     * @param saleProduct é‡‡è´­äº§å“
     */
    public void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) {
        QualityInspect qualityInspect = new QualityInspect();
        qualityInspect.setInspectType(0);
        qualityInspect.setSupplier(purchaseLedger.getSupplierName());
        qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
        qualityInspect.setProductId(saleProduct.getProductId());
        qualityInspect.setProductName(saleProduct.getProductCategory());
        qualityInspect.setModel(saleProduct.getSpecificationModel());
        qualityInspect.setProductModelId(saleProduct.getProductModelId());
        qualityInspect.setUnit(saleProduct.getUnit());
        qualityInspect.setQuantity(saleProduct.getQuantity());
        qualityInspectMapper.insert(qualityInspect);
        List<QualityTestStandard> qualityTestStandardList = qualityTestStandardMapper
                .getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null);
        if (qualityTestStandardList.isEmpty()) {
            return;
        }
        QualityTestStandard firstStandard = qualityTestStandardList.get(0);
        qualityInspect.setTestStandardId(firstStandard.getId());
        qualityInspectMapper.updateById(qualityInspect);
        List<QualityTestStandardParam> standardParams = qualityTestStandardParamMapper.selectList(
                Wrappers.<QualityTestStandardParam>lambdaQuery()
                        .eq(QualityTestStandardParam::getTestStandardId, firstStandard.getId()));
        for (QualityTestStandardParam standardParam : standardParams) {
            QualityInspectParam param = new QualityInspectParam();
            BeanUtils.copyProperties(standardParam, param);
            param.setId(null);
            param.setInspectId(qualityInspect.getId());
            qualityInspectParamMapper.insert(param);
        }
    }
}
src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
@@ -2,7 +2,10 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApproveProcessVO;
import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
@@ -26,6 +29,7 @@
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
@@ -38,6 +42,8 @@
@AllArgsConstructor
public class ShippingInfoController extends BaseController {
    private final ApprovalTemplateMapper approvalTemplateMapper;
    private final ApprovalInstanceService approvalInstanceService;
    private ShippingInfoService shippingInfoService;
    private ApproveProcessServiceImpl approveProcessService;
    private ShippingInfoMapper shippingInfoMapper;
@@ -66,6 +72,19 @@
        approveProcessVO.setApproveUser(loginUser.getUserId());
        approveProcessVO.setApproveTime(LocalDate.now().toString());
        approveProcessService.addApprove(approveProcessVO);
        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
        approvalInstanceDto.setTemplateId(req.getTemplateId());
        approvalInstanceDto.setBusinessId(req.getId());
        approvalInstanceDto.setBusinessType(7L);
        approvalInstanceDto.setTitle("发货编号:" + sh);
        approvalInstanceDto.setApplicantId(SecurityUtils.getUserId());
        approvalInstanceDto.setTemplateId(req.getTemplateId());
        approvalInstanceDto.setTemplateName(approvalTemplateMapper.selectById(req.getTemplateId()).getTemplateName());
        approvalInstanceDto.setApplicantName(SecurityUtils.getLoginUser().getNickName());
        approvalInstanceDto.setApplyTime(LocalDateTime.now());
        approvalInstanceService.add(approvalInstanceDto);
        // æ·»åŠ å‘è´§æ¶ˆæ¯
        req.setShippingNo(sh);
        req.setStatus("待审核");
src/main/java/com/ruoyi/sales/dto/SalesQuotationDto.java
@@ -17,4 +17,6 @@
     */
    // å®¡æ‰¹äºº
    private String approveUserIds;
    private Long templateId;
}
src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java
@@ -47,5 +47,9 @@
    //发货数量
    private BigDecimal totalQuantity;
    private Long templateId;
    private String templateName;
}
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -7,10 +7,13 @@
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApproveGetAndUpdateVo;
import com.ruoyi.approve.bean.vo.ApproveProcessVO;
import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.common.enums.IsDeleteEnum;
@@ -30,8 +33,8 @@
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -44,6 +47,8 @@
    private final ApproveProcessServiceImpl approveProcessService;
    private final CustomerMapper customerMapper;
    private final ApprovalTemplateMapper approvalTemplateMapper;
    private final ApprovalInstanceService approvalInstanceService;
    @Override
    public IPage<SalesQuotationDto> listPage(Page page, SalesQuotationDto salesQuotationDto) {
@@ -51,10 +56,26 @@
        if(CollectionUtils.isEmpty(salesQuotationDtoIPage.getRecords())){
            return salesQuotationDtoIPage;
        }
        salesQuotationDtoIPage.getRecords().forEach(record -> {
            List<SalesQuotationProduct> products = salesQuotationProductMapper.selectBySalesQuotationId(record.getId());
            record.setProducts(products);
        });
        // æ‰¹é‡æŸ¥è¯¢äº§å“ï¼Œé¿å… N+1 é—®é¢˜
        List<Long> quotationIds = salesQuotationDtoIPage.getRecords().stream()
                .map(SalesQuotationDto::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (!quotationIds.isEmpty()) {
            List<SalesQuotationProduct> allProducts = salesQuotationProductMapper.selectList(
                    new LambdaQueryWrapper<SalesQuotationProduct>()
                            .in(SalesQuotationProduct::getSalesQuotationId, quotationIds)
            );
            Map<Long, List<SalesQuotationProduct>> productMap = allProducts.stream()
                    .collect(Collectors.groupingBy(SalesQuotationProduct::getSalesQuotationId));
            salesQuotationDtoIPage.getRecords().forEach(record ->
                    record.setProducts(productMap.getOrDefault(record.getId(), new ArrayList<>()))
            );
        }
        return salesQuotationDtoIPage;
    }
@@ -93,10 +114,21 @@
        approveProcessVO.setPrice(salesQuotationDto.getTotalAmount());
        try {
            approveProcessService.addApprove(approveProcessVO);
        }catch (Exception e){
            log.error("SalesQuotationServiceImpl error:{}", e);
            throw                                new RuntimeException("审批失败");
        } catch (Exception e) {
            log.error("SalesQuotationServiceImpl approve error for quotationNo: {}", e);
            throw new RuntimeException("审批失败: " + e.getMessage(), e);
        }
        // æŠ¥ä»·å®¡æ‰¹
        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
        approvalInstanceDto.setTemplateId(salesQuotationDto.getTemplateId());
        approvalInstanceDto.setBusinessId(salesQuotationDto.getId());
        approvalInstanceDto.setBusinessType(7L);
        approvalInstanceDto.setTitle("报价编号:" + quotationNo);
        approvalInstanceDto.setApplicantId(SecurityUtils.getUserId());
        approvalInstanceDto.setTemplateName(approvalTemplateMapper.selectById(salesQuotationDto.getTemplateId()).getTemplateName());
        approvalInstanceDto.setApplicantName(SecurityUtils.getLoginUser().getNickName());
        approvalInstanceDto.setApplyTime(LocalDateTime.now());
        approvalInstanceService.add(approvalInstanceDto);
        return true;
    }
    @Override
src/main/resources/mapper/approve/ApprovalInstanceMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
<?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.ruoyi.approve.mapper.ApprovalInstanceMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalInstance">
        <id column="id" property="id" />
        <result column="instance_no" property="instanceNo" />
        <result column="template_id" property="templateId" />
        <result column="template_name" property="templateName" />
        <result column="business_id" property="businessId" />
        <result column="business_type" property="businessType" />
        <result column="title" property="title" />
        <result column="status" property="status" />
        <result column="current_level" property="currentLevel" />
        <result column="applicant_id" property="applicantId" />
        <result column="applicant_name" property="applicantName" />
        <result column="apply_time" property="applyTime" />
        <result column="finish_time" property="finishTime" />
        <result column="create_user" property="createUser" />
        <result column="create_time" property="createTime" />
        <result column="update_user" property="updateUser" />
        <result column="update_time" property="updateTime" />
        <result column="deleted" property="deleted" />
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.approve.bean.vo.ApprovalInstanceVo">
        select ai.*,su.nick_name as create_user_name  from
        approval_instance ai
        left join sys_user su on ai.create_user = su.user_id
        <where>
            deleted = 0
            <if test="ew.instanceNo != null">
                and instance_no like concat('%',#{ew.instanceNo},'%')
            </if>
            <if test="ew.templateName != null">
                and template_name like concat('%',#{ew.templateName},'%')
            </if>
        </where>
        order by ai.id desc
    </select>
</mapper>
src/main/resources/mapper/approve/ApprovalInstanceNodeMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
<?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.ruoyi.approve.mapper.ApprovalInstanceNodeMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalInstanceNode">
        <id column="id" property="id" />
        <result column="instance_id" property="instanceId" />
        <result column="level_no" property="levelNo" />
        <result column="approve_type" property="approveType" />
        <result column="status" property="status" />
        <result column="start_time" property="startTime" />
        <result column="finish_time" property="finishTime" />
        <result column="create_user" property="createUser" />
        <result column="create_time" property="createTime" />
        <result column="update_user" property="updateUser" />
        <result column="update_time" property="updateTime" />
        <result column="deleted" property="deleted" />
    </resultMap>
</mapper>
src/main/resources/mapper/approve/ApprovalRecordMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
<?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.ruoyi.approve.mapper.ApprovalRecordMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalRecord">
        <id column="id" property="id" />
        <result column="instance_id" property="instanceId" />
        <result column="node_id" property="nodeId" />
        <result column="task_id" property="taskId" />
        <result column="operator_id" property="operatorId" />
        <result column="operator_name" property="operatorName" />
        <result column="action" property="action" />
        <result column="comment" property="comment" />
        <result column="create_user" property="createUser" />
        <result column="create_time" property="createTime" />
        <result column="deleted" property="deleted" />
    </resultMap>
</mapper>
src/main/resources/mapper/approve/ApprovalTaskMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
<?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.ruoyi.approve.mapper.ApprovalTaskMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTask">
        <id column="id" property="id" />
        <result column="instance_id" property="instanceId" />
        <result column="node_id" property="nodeId" />
        <result column="level_no" property="levelNo" />
        <result column="approver_id" property="approverId" />
        <result column="approver_name" property="approverName" />
        <result column="task_status" property="taskStatus" />
        <result column="approve_time" property="approveTime" />
        <result column="comment" property="comment" />
        <result column="is_read" property="isRead" />
        <result column="create_user" property="createUser" />
        <result column="create_time" property="createTime" />
        <result column="update_user" property="updateUser" />
        <result column="update_time" property="updateTime" />
        <result column="deleted" property="deleted" />
    </resultMap>
</mapper>
src/main/resources/mapper/approve/ApprovalTemplateMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
<?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.ruoyi.approve.mapper.ApprovalTemplateMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplate">
        <id column="id" property="id" />
        <result column="template_name" property="templateName" />
        <result column="enabled" property="enabled" />
        <result column="description" property="description" />
        <result column="deleted" property="deleted" />
        <result column="dept_id" property="deptId" />
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.approve.bean.vo.ApprovalTemplateVo">
        select at.*,su.nick_name as create_user_name  from
        approval_template at
        left join sys_user su on at.create_user = su.user_id
        <where>
            deleted = 0
            <if test="ew.templateName != null">
                and template_name like concat('%',#{ew.templateName},'%')
            </if>
            <if test="ew.templateType != null">
                and template_type = #{ew.templateType}
            </if>
            <if test="ew.enabled != null">
                and enabled = #{ew.enabled}
            </if>
        </where>
        order by at.id desc
    </select>
</mapper>
src/main/resources/mapper/approve/ApprovalTemplateNodeApproverMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
<?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.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover">
        <id column="id" property="id" />
        <result column="node_id" property="nodeId" />
        <result column="template_id" property="templateId" />
        <result column="approver_id" property="approverId" />
        <result column="approver_name" property="approverName" />
        <result column="sort_no" property="sortNo" />
        <result column="created_time" property="createdTime" />
    </resultMap>
</mapper>
src/main/resources/mapper/approve/ApprovalTemplateNodeMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
<?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.ruoyi.approve.mapper.ApprovalTemplateNodeMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplateNode">
        <id column="id" property="id" />
        <result column="template_id" property="templateId" />
        <result column="level_no" property="levelNo" />
        <result column="approve_type" property="approveType" />
        <result column="created_time" property="createdTime" />
        <result column="updated_time" property="updatedTime" />
    </resultMap>
</mapper>