From 2c18c7b8d1708fd028b8e5093d5f5832c389ed0e Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期五, 22 五月 2026 09:29:22 +0800
Subject: [PATCH] feat(approve): 完善审批实例管理功能并新增报销单模块

---
 src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java                                |  210 +++++++
 src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java                |    2 
 src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java                  |   18 
 src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java                         |   21 
 src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java                  |    4 
 src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.java          |   18 
 src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java                          |  162 +++++
 src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java                |   60 ++
 src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java             |  157 ++++
 src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java             |  537 ++++++++++++++++++
 src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java                |   16 
 src/main/java/com/ruoyi/approve/service/FinReimbursementService.java                      |   31 +
 src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml                        |   29 +
 src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java                          |  157 +++++
 src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml                        |   29 +
 src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java                    |    5 
 src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java |   14 
 src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java                         |    5 
 src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java                |   16 
 src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.java          |   18 
 src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java                           |    3 
 src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java       |   20 
 src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java       |   20 
 src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java                           |   34 +
 src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java             |    1 
 src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java                  |   18 
 src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java                      |    2 
 src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.java                        |   24 
 src/main/resources/mapper/approve/FinReimbursementMapper.xml                              |   57 +
 src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java                                   |    2 
 30 files changed, 1,671 insertions(+), 19 deletions(-)

diff --git a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java b/src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java
index 17e4921..a2df482 100644
--- a/src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java
+++ b/src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java
@@ -1,7 +1,10 @@
 package com.ruoyi.approve.bean.dto;
 
 import com.ruoyi.approve.pojo.ApprovalInstance;
+import com.ruoyi.basic.dto.StorageBlobDTO;
 import lombok.Data;
+
+import java.util.List;
 
 @Data
 public class ApprovalInstanceDto extends ApprovalInstance {
@@ -13,4 +16,6 @@
     private String createTimeEnd;
 
     private String createTimeStart;
+
+    private List<StorageBlobDTO> storageBlobDTOs;
 }
diff --git a/src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java b/src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java
new file mode 100644
index 0000000..2f14376
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java
@@ -0,0 +1,21 @@
+package com.ruoyi.approve.bean.dto;
+
+import com.ruoyi.approve.pojo.FinReimbursement;
+import com.ruoyi.approve.pojo.FinReimbursementDetail;
+import com.ruoyi.approve.pojo.FinReimbursementTravel;
+import com.ruoyi.basic.dto.StorageBlobDTO;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FinReimbursementDto extends FinReimbursement {
+
+    private String createTimeStart;
+    private String createTimeEnd;
+
+    private FinReimbursementTravel  travel;
+    private List<FinReimbursementDetail> details;
+    private List<ApprovalTemplateNodeDto> nodes;
+    private List<StorageBlobDTO> storageBlobDTOs;
+}
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java b/src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java
index f37c068..552ed0a 100644
--- a/src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java
+++ b/src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java
@@ -3,6 +3,7 @@
 import com.ruoyi.approve.pojo.ApprovalInstance;
 import com.ruoyi.approve.pojo.ApprovalRecord;
 import com.ruoyi.approve.pojo.ApprovalTask;
+import com.ruoyi.basic.dto.StorageBlobVO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -22,4 +23,6 @@
 
     @Schema(description = "涓氬姟鍚嶇О")
     private String businessName;
+
+    private List<StorageBlobVO> storageBlobVOList;
 }
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java b/src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java
new file mode 100644
index 0000000..5706ff3
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java
@@ -0,0 +1,34 @@
+package com.ruoyi.approve.bean.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.approve.pojo.*;
+import com.ruoyi.basic.dto.StorageBlobVO;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+public class FinReimbursementVo extends FinReimbursement {
+
+
+    private String createTimeStart;
+    private String createTimeEnd;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+
+    private FinReimbursementTravel travel;
+    private List<FinReimbursementDetail> details;
+    //瀹℃壒娴佺▼
+    private List<ApprovalTask> tasks;
+
+    //瀹℃壒璁板綍
+    private List<ApprovalRecord>  records;
+    private List<StorageBlobVO> storageBlobVOList;
+}
diff --git a/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java b/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java
index f13e1b3..0a32725 100644
--- a/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java
+++ b/src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java
@@ -43,7 +43,7 @@
     @PutMapping("/update")
     @Operation(summary = "鏇存柊")
     public R update(@RequestBody ApprovalInstanceDto approvalInstanceDto) {
-        return approvalInstanceService.updateById(approvalInstanceDto) ? R.ok() : R.fail();
+        return approvalInstanceService.update(approvalInstanceDto) ? R.ok() : R.fail();
     }
 
     @DeleteMapping("/delete")
diff --git a/src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java b/src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java
new file mode 100644
index 0000000..a2eecdb
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java
@@ -0,0 +1,60 @@
+package com.ruoyi.approve.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.approve.bean.dto.FinReimbursementDto;
+import com.ruoyi.approve.bean.vo.FinReimbursementVo;
+import com.ruoyi.approve.service.FinReimbursementService;
+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-21 09:56:15
+ */
+@RestController
+@RequestMapping("/finReimbursement")
+@Tag(name = "鎶ラ攢鍗曚富琛�", description = "鎶ラ攢鍗曚富琛�")
+@AllArgsConstructor
+public class FinReimbursementController {
+
+    private final FinReimbursementService finReimbursementService;
+
+    @GetMapping("/listPage")
+    @Operation(summary = "鍒嗛〉鏌ヨ")
+    public R listPage(Page<FinReimbursementVo> page, FinReimbursementDto finReimbursementDto) {
+        return R.ok(finReimbursementService.listPage(finReimbursementDto, page));
+    }
+
+    @PostMapping("/save")
+    @Operation(summary = "淇濆瓨")
+    public R save(@RequestBody FinReimbursementDto finReimbursementDto) {
+        return R.ok(finReimbursementService.add(finReimbursementDto));
+    }
+
+    @GetMapping("/detail")
+    @Operation(summary = "璇︽儏")
+    public R detail(Long id) {
+        return R.ok(finReimbursementService.detail(id));
+    }
+
+    @PostMapping("/update")
+    @Operation(summary = "淇敼")
+    public R update(@RequestBody FinReimbursementDto finReimbursementDto) {
+        return R.ok(finReimbursementService.update(finReimbursementDto));
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "鍒犻櫎")
+    public R delete(@RequestBody List<Long> ids) {
+        return R.ok(finReimbursementService.delete(ids));
+    }
+}
diff --git a/src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.java b/src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.java
new file mode 100644
index 0000000..18e4f73
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.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-21 09:56:38
+ */
+@RestController
+@RequestMapping("/finReimbursementDetail")
+public class FinReimbursementDetailController {
+
+}
diff --git a/src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.java b/src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.java
new file mode 100644
index 0000000..0e67feb
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.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-21 09:56:47
+ */
+@RestController
+@RequestMapping("/finReimbursementTravel")
+public class FinReimbursementTravelController {
+
+}
diff --git a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java
new file mode 100644
index 0000000..edc039a
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.approve.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.approve.pojo.FinReimbursementDetail;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曟槑缁嗚〃 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:38
+ */
+@Mapper
+public interface FinReimbursementDetailMapper extends BaseMapper<FinReimbursementDetail> {
+
+}
diff --git a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.java b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.java
new file mode 100644
index 0000000..19ac354
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.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.FinReimbursementDto;
+import com.ruoyi.approve.bean.vo.FinReimbursementVo;
+import com.ruoyi.approve.pojo.FinReimbursement;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曚富琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:15
+ */
+@Mapper
+public interface FinReimbursementMapper extends BaseMapper<FinReimbursement> {
+
+    IPage<FinReimbursementVo> listPage(@Param("ew") FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page);
+}
diff --git a/src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java
new file mode 100644
index 0000000..bc5e1b8
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.approve.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.approve.pojo.FinReimbursementTravel;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 宸梾鎶ラ攢鎵╁睍琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:47
+ */
+@Mapper
+public interface FinReimbursementTravelMapper extends BaseMapper<FinReimbursementTravel> {
+
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java b/src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java
new file mode 100644
index 0000000..7d5ad9c
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java
@@ -0,0 +1,210 @@
+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.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曚富琛�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:15
+ */
+@Getter
+@Setter
+@ToString
+@TableName("fin_reimbursement")
+@ApiModel(value = "FinReimbursement瀵硅薄", description = "鎶ラ攢鍗曚富琛�")
+public class FinReimbursement 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 billNo;
+
+    /**
+     * 鎶ラ攢绫诲瀷锛�1-宸梾鎶ラ攢锛�2-璐圭敤鎶ラ攢
+     */
+    @Schema(description = "鎶ラ攢绫诲瀷锛�1-宸梾鎶ラ攢锛�2-璐圭敤鎶ラ攢")
+    private Byte reimbursementType;
+
+    /**
+     * 璐圭敤绫诲瀷锛氬樊鏃呰垂/鍔炲叕閲囪喘/涓氬姟鎷涘緟/浜ら�氳垂/閫氳璐�/鍏朵粬
+     */
+    @Schema(description = "璐圭敤绫诲瀷锛氬樊鏃呰垂/鍔炲叕閲囪喘/涓氬姟鎷涘緟/浜ら�氳垂/閫氳璐�/鍏朵粬")
+    private String expenseType;
+
+    /**
+     * 鐢宠浜篒D
+     */
+    @Schema(description = "鐢宠浜篒D")
+    private Long applicantId;
+
+    /**
+     * 鍛樺伐缂栧彿
+     */
+    @Schema(description = "鍛樺伐缂栧彿")
+    private String applicantCode;
+
+    /**
+     * 鍛樺伐濮撳悕
+     */
+    @Schema(description = "鍛樺伐濮撳悕")
+    private String applicantName;
+
+    /**
+     * 鐢宠閮ㄩ棬ID
+     */
+    @Schema(description = "鐢宠閮ㄩ棬ID")
+    private Long applicantDeptId;
+
+    /**
+     * 鐢宠閮ㄩ棬鍚嶇О
+     */
+    @Schema(description = "鐢宠閮ㄩ棬鍚嶇О")
+    private String applicantDeptName;
+
+    /**
+     * 鎶ラ攢鍘熷洜
+     */
+    @Schema(description = "鎶ラ攢鍘熷洜")
+    private String reason;
+
+    /**
+     * 鐢宠閲戦
+     */
+    @Schema(description = "鐢宠閲戦")
+    private BigDecimal applyAmount;
+
+    /**
+     * 鏄庣粏姹囨�婚噾棰�
+     */
+    @Schema(description = "鏄庣粏姹囨�婚噾棰�")
+    private BigDecimal detailTotalAmount;
+
+    /**
+     * 鏀舵浜�
+     */
+    @Schema(description = "鏀舵浜�")
+    private String payeeName;
+
+    /**
+     * 鏀舵璐﹀彿
+     */
+    @Schema(description = "鏀舵璐﹀彿")
+    private String payeeAccount;
+
+    /**
+     * 寮�鎴锋敮琛�
+     */
+    @Schema(description = "寮�鎴锋敮琛�")
+    private String payeeBank;
+
+    /**
+     * 瀹℃壒瀹炰緥ID锛屽搴� approval_instance.id
+     */
+    @Schema(description = "瀹℃壒瀹炰緥ID锛屽搴� approval_instance.id")
+    private Long approvalInstanceId;
+
+    /**
+     * 瀹℃壒娴佺▼ID锛屽搴� approve_process.id
+     */
+    @Schema(description = "瀹℃壒娴佺▼ID锛屽搴� approve_process.id")
+    private Long approveProcessId;
+
+    /**
+     * 鍗曟嵁鐘舵�侊細DRAFT-鑽夌锛孖N_APPROVAL-瀹℃壒涓紝APPROVED-瀹℃壒閫氳繃锛孯EJECTED-瀹℃壒椹冲洖锛學ITHDRAWN-宸叉挙鍥烇紝PAID-宸蹭粯娆�
+     */
+    @Schema(description = "鍗曟嵁鐘舵�侊細DRAFT-鑽夌锛孖N_APPROVAL-瀹℃壒涓紝APPROVED-瀹℃壒閫氳繃锛孯EJECTED-瀹℃壒椹冲洖锛學ITHDRAWN-宸叉挙鍥烇紝PAID-宸蹭粯娆�")
+    private String billStatus;
+
+    /**
+     * 瀹℃壒閫氳繃鏃堕棿
+     */
+    @Schema(description = "瀹℃壒閫氳繃鏃堕棿")
+    private LocalDateTime approvedTime;
+
+    /**
+     * 浠樻鏃堕棿
+     */
+    @Schema(description = "浠樻鏃堕棿")
+    private LocalDateTime paidTime;
+
+    /**
+     * 鐢熸垚鐨勮储鍔℃敮鍑鸿褰旾D锛屽搴� account_expense.id
+     */
+    @Schema(description = "鐢熸垚鐨勮储鍔℃敮鍑鸿褰旾D锛屽搴� account_expense.id")
+    private Long accountExpenseId;
+
+    /**
+     * 澶囨敞
+     */
+    @Schema(description = "澶囨敞")
+    private String remark;
+
+    /**
+     * 绉熸埛ID
+     */
+    @Schema(description = "绉熸埛ID")
+    private Long tenantId;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @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;
+
+    /**
+     * 褰掑睘閮ㄩ棬ID
+     */
+    @Schema(description = "褰掑睘閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�
+     */
+    @Schema(description = "閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�")
+    private Byte deleted;
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java b/src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java
new file mode 100644
index 0000000..5d0220e
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java
@@ -0,0 +1,157 @@
+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.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曟槑缁嗚〃
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:38
+ */
+@Getter
+@Setter
+@ToString
+@TableName("fin_reimbursement_detail")
+@ApiModel(value = "FinReimbursementDetail瀵硅薄", description = "鎶ラ攢鍗曟槑缁嗚〃")
+public class FinReimbursementDetail implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭ID
+     */
+    @Schema(description = "涓婚敭ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id
+     */
+    @Schema(description = "鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id")
+    private Long reimbursementId;
+
+    /**
+     * 鏄庣粏琛屽彿
+     */
+    @Schema(description = "鏄庣粏琛屽彿")
+    private Integer rowNo;
+
+    /**
+     * 鍙戠エ鏃ユ湡
+     */
+    @Schema(description = "鍙戠エ鏃ユ湡")
+    private LocalDate invoiceDate;
+
+    /**
+     * 璐圭敤绉戠洰
+     */
+    @Schema(description = "璐圭敤绉戠洰")
+    private String expenseCategory;
+
+    /**
+     * 閲戦
+     */
+    @Schema(description = "閲戦")
+    private BigDecimal amount;
+
+    /**
+     * 鎻忚堪
+     */
+    @Schema(description = "鎻忚堪")
+    private String description;
+
+    /**
+     * 鍙戠エ鍙风爜
+     */
+    @Schema(description = "鍙戠エ鍙风爜")
+    private String invoiceNo;
+
+    /**
+     * 鍙戠エ绫诲瀷
+     */
+    @Schema(description = "鍙戠エ绫诲瀷")
+    private String invoiceType;
+
+    /**
+     * 绁ㄩ潰閲戦
+     */
+    @Schema(description = "绁ㄩ潰閲戦")
+    private BigDecimal invoiceAmount;
+
+    /**
+     * 绋庣巼
+     */
+    @Schema(description = "绋庣巼")
+    private BigDecimal taxRate;
+
+    /**
+     * 绋庨
+     */
+    @Schema(description = "绋庨")
+    private BigDecimal taxAmount;
+
+    /**
+     * 澶囨敞
+     */
+    @Schema(description = "澶囨敞")
+    private String remark;
+
+    /**
+     * 绉熸埛ID
+     */
+    @Schema(description = "绉熸埛ID")
+    private Long tenantId;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @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;
+
+    /**
+     * 褰掑睘閮ㄩ棬ID
+     */
+    @Schema(description = "褰掑睘閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+
+    /**
+     * 閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�
+     */
+    @Schema(description = "閫昏緫鍒犻櫎锛�0-鍚︼紝1-鏄�")
+    private Byte deleted;
+}
diff --git a/src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java b/src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java
new file mode 100644
index 0000000..10c607c
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java
@@ -0,0 +1,162 @@
+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.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 宸梾鎶ラ攢鎵╁睍琛�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:47
+ */
+@Getter
+@Setter
+@ToString
+@TableName("fin_reimbursement_travel")
+@ApiModel(value = "FinReimbursementTravel瀵硅薄", description = "宸梾鎶ラ攢鎵╁睍琛�")
+public class FinReimbursementTravel implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭ID
+     */
+    @Schema(description = "涓婚敭ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id
+     */
+    @Schema(description = "鎶ラ攢鍗旾D锛屽搴� fin_reimbursement.id")
+    private Long reimbursementId;
+
+    /**
+     * 鍑哄樊寮�濮嬫椂闂�
+     */
+    @Schema(description = "鍑哄樊寮�濮嬫椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+
+    /**
+     * 鍑哄樊缁撴潫鏃堕棿
+     */
+    @Schema(description = "鍑哄樊缁撴潫鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+
+    /**
+     * 鍑哄樊澶╂暟
+     */
+    @Schema(description = "鍑哄樊澶╂暟")
+    private BigDecimal travelDays;
+
+    /**
+     * 鍑哄樊鍦�/鍑哄彂鍩庡競
+     */
+    @Schema(description = "鍑哄樊鍦�/鍑哄彂鍩庡競")
+    private String departureCity;
+
+    /**
+     * 鐩殑鍦�/鐩殑鍩庡競
+     */
+    @Schema(description = "鐩殑鍦�/鐩殑鍩庡競")
+    private String destinationCity;
+
+    /**
+     * 閰掑簵鏍囧噯
+     */
+    @Schema(description = "閰掑簵鏍囧噯")
+    private BigDecimal hotelStandard;
+
+    /**
+     * 浣忓澶╂暟
+     */
+    @Schema(description = "浣忓澶╂暟")
+    private BigDecimal lodgingDays;
+
+    /**
+     * 鐢熸椿琛ヨ创
+     */
+    @Schema(description = "鐢熸椿琛ヨ创")
+    private BigDecimal mealAllowance;
+
+    /**
+     * 浜ら�氳ˉ璐�
+     */
+    @Schema(description = "浜ら�氳ˉ璐�")
+    private BigDecimal transportAllowance;
+
+    /**
+     * 浣忓闄愰
+     */
+    @Schema(description = "浣忓闄愰")
+    private BigDecimal lodgingLimit;
+
+    /**
+     * 鐗规壒鏍囪鏂囨湰锛屽鍦ㄦ爣鍑嗚寖鍥村唴/瓒呮爣鐗规壒
+     */
+    @Schema(description = "鐗规壒鏍囪鏂囨湰锛屽鍦ㄦ爣鍑嗚寖鍥村唴/瓒呮爣鐗规壒")
+    private String standardTag;
+
+    /**
+     * 鏄惁鍦ㄦ爣鍑嗗唴锛�1-鏄紝0-鍚�
+     */
+    @Schema(description = "鏄惁鍦ㄦ爣鍑嗗唴锛�1-鏄紝0-鍚�")
+    private Byte withinStandard;
+
+    /**
+     * 绉熸埛ID
+     */
+    @Schema(description = "绉熸埛ID")
+    private Long tenantId;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @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;
+
+    /**
+     * 褰掑睘閮ㄩ棬ID
+     */
+    @Schema(description = "褰掑睘閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+}
diff --git a/src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java b/src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java
index fe24839..dfb9517 100644
--- a/src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java
+++ b/src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java
@@ -23,6 +23,8 @@
 
     Boolean add(ApprovalInstanceDto approvalInstanceDto);
 
+    Boolean update(ApprovalInstanceDto approvalInstanceDto);
+
     Boolean delete(List<Long> ids);
 
     R approve(ApprovalInstanceDto approvalInstanceDto);
diff --git a/src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java b/src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java
new file mode 100644
index 0000000..0279c25
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.approve.service;
+
+import com.ruoyi.approve.pojo.FinReimbursementDetail;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曟槑缁嗚〃 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:38
+ */
+public interface FinReimbursementDetailService extends IService<FinReimbursementDetail> {
+
+}
diff --git a/src/main/java/com/ruoyi/approve/service/FinReimbursementService.java b/src/main/java/com/ruoyi/approve/service/FinReimbursementService.java
new file mode 100644
index 0000000..c14b943
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/FinReimbursementService.java
@@ -0,0 +1,31 @@
+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.FinReimbursementDto;
+import com.ruoyi.approve.bean.vo.FinReimbursementVo;
+import com.ruoyi.approve.pojo.FinReimbursement;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曚富琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:15
+ */
+public interface FinReimbursementService extends IService<FinReimbursement> {
+
+    IPage<FinReimbursementVo> listPage(FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page);
+
+    Boolean add(FinReimbursementDto finReimbursementDto);
+
+    FinReimbursementVo detail(Long id);
+
+    Boolean update(FinReimbursementDto finReimbursementDto);
+
+    Boolean delete(List<Long> ids);
+}
diff --git a/src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java b/src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java
new file mode 100644
index 0000000..0733d1b
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.approve.service;
+
+import com.ruoyi.approve.pojo.FinReimbursementTravel;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 宸梾鎶ラ攢鎵╁睍琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:47
+ */
+public interface FinReimbursementTravelService extends IService<FinReimbursementTravel> {
+
+}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
index c15ccb7..3e710a8 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -10,15 +10,20 @@
 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.ApprovalTemplateNodeApproverMapper;
+import com.ruoyi.approve.mapper.FinReimbursementMapper;
 import com.ruoyi.approve.pojo.*;
 import com.ruoyi.approve.service.*;
 import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
+import com.ruoyi.basic.enums.RecordTypeEnum;
+import com.ruoyi.basic.utils.FileUtil;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper;
 import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
 import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
 import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeDeptService;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeUserService;
-import com.ruoyi.collaborativeApproval.service.EnterpriseNewsService;
 import com.ruoyi.common.enums.*;
 import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -40,6 +45,8 @@
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.pojo.SalesQuotation;
 import com.ruoyi.sales.pojo.ShippingInfo;
+import com.ruoyi.staff.mapper.HolidayApplicationMapper;
+import com.ruoyi.staff.pojo.HolidayApplication;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -69,7 +76,8 @@
     private final ApprovalTaskService approvalTaskService;
     private final ApprovalRecordService approvalRecordService;
     private final ApprovalTemplateNodeService approvalTemplateNodeService;
-    private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService;
+    private final FinReimbursementMapper finReimbursementMapper;
+    private final FileUtil fileUtil;
     private final ISysNoticeService sysNoticeService;
     private final PurchaseLedgerMapper purchaseLedgerMapper;
     private final SalesLedgerProductMapper salesLedgerProductMapper;
@@ -77,12 +85,14 @@
     private final SalesQuotationMapper salesQuotationMapper;
     private final ShippingInfoMapper shippingInfoMapper;
     private final QualityInspectHelper qualityInspectHelper;
-    private final EnterpriseNewsService enterpriseNewsService;
-    private final EnterpriseNewsScopeDeptService enterpriseNewsScopeDeptService;
-    private final EnterpriseNewsScopeUserService enterpriseNewsScopeUserService;
+    private final EnterpriseNewsScopeUserMapper enterpriseNewsScopeUserMapper;
     private final SysUserMapper sysUserMapper;
     private final SysUserDeptMapper sysUserDeptMapper;
     private final SysDeptMapper sysDeptMapper;
+    private final HolidayApplicationMapper holidayApplicationMapper;
+    private final EnterpriseNewsMapper enterpriseNewsMapper;
+    private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper;
+    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
 
     @Override
     public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
@@ -119,6 +129,7 @@
                 vo.setIsApprove(approveProcessConfigNodeUtils.isCurrentApprover(vo.getId(), currentUserId));
                 vo.setRecords(recordMap.getOrDefault(vo.getId(), new ArrayList<>()));
                 vo.setTasks(taskMap.getOrDefault(vo.getId(), new ArrayList<>()));
+                vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.APPROVAL_INSTANCE, vo.getId()));
             }
 
         }
@@ -137,7 +148,22 @@
             return false;
         }
         approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstanceDto);
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
         sendApproveNotice(approvalInstanceDto, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(ApprovalInstanceDto approvalInstanceDto) {
+        if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) {
+            return false;
+        }
+        boolean updated = this.updateById(approvalInstanceDto);
+        if (!updated) {
+            return false;
+        }
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
         return true;
     }
 
@@ -147,6 +173,7 @@
         if (ids == null || ids.isEmpty()) {
             return false;
         }
+        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, ids);
 
         int instanceRows = approvalInstanceMapper.update(
                 null,
@@ -221,11 +248,10 @@
                 approveAction,
                 approvalInstanceDto.getApproveComment()
         );
-
+        //瀹℃壒鎷掔粷鐨勫鐞�
         if ("REJECTED".equals(approveAction)) {
             return rejectCurrentNode(instance, currentNode, now);
         }
-
         if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) {
             return R.ok("瀹℃壒鎴愬姛锛岀瓑寰呭叾浠栧鎵逛汉澶勭悊");
         }
@@ -278,6 +304,20 @@
         instance.setStatus("REJECTED");
         instance.setFinishTime(now);
         this.updateById(instance);
+        // 椹冲洖瀵瑰簲鐨勪紒涓氭柊闂伙紝 宸梾鎶ラ攢
+        if (instance.getBusinessType().equals(TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode())) {
+            enterpriseNewsMapper.update(
+                    new LambdaUpdateWrapper<EnterpriseNews>()
+                            .eq(EnterpriseNews::getId, instance.getBusinessId())
+                            .set(EnterpriseNews::getStatus, "REJECTED")
+            );
+        }else if (instance.getBusinessType().equals(TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode())||instance.getBusinessType().equals(TypeEnums.EXPENSE_APPROVAL.getCode())) {
+            finReimbursementMapper.update(
+                    new LambdaUpdateWrapper<FinReimbursement>()
+                            .eq(FinReimbursement::getId, instance.getBusinessId())
+                            .set(FinReimbursement::getBillStatus, "REJECTED")
+            );
+        }
         return R.ok("瀹℃壒宸查┏鍥�");
     }
 
@@ -292,6 +332,33 @@
         closePendingTasks(instance.getId(), currentNode.getId());
 
         int nextLevel = currentNode.getLevelNo() + 1;
+        ApprovalInstanceNode nextInstanceNode = approvalInstanceNodeService.getOne(
+                new LambdaQueryWrapper<ApprovalInstanceNode>()
+                        .eq(ApprovalInstanceNode::getInstanceId, instance.getId())
+                        .eq(ApprovalInstanceNode::getLevelNo, nextLevel)
+                        .eq(ApprovalInstanceNode::getDeleted, 0)
+                        .orderByAsc(ApprovalInstanceNode::getId)
+                        .last("LIMIT 1")
+        );
+
+        if (nextInstanceNode != null) {
+            if (!activateNextInstanceNode(nextInstanceNode.getId(), now)) {
+                return R.ok("涓嬩竴瀹℃壒鑺傜偣宸茶婵�娲伙紝璇峰埛鏂板悗閲嶈瘯");
+            }
+            instance.setCurrentLevel(nextLevel);
+            instance.setStatus("PENDING");
+            this.updateById(instance);
+            List<ApprovalTask> nextTasks = approvalTaskService.list(
+                    Wrappers.<ApprovalTask>lambdaQuery()
+                            .eq(ApprovalTask::getInstanceId, instance.getId())
+                            .eq(ApprovalTask::getNodeId, nextInstanceNode.getId())
+                            .eq(ApprovalTask::getTaskStatus, "PENDING")
+                            .eq(ApprovalTask::getDeleted, 0)
+            );
+            sendApproveNotice(instance, nextTasks);
+            return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
+        }
+
         ApprovalTemplateNode nextTemplateNode = approvalTemplateNodeService.getOne(
                 new LambdaQueryWrapper<ApprovalTemplateNode>()
                         .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId())
@@ -314,6 +381,17 @@
         approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false);
         sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
         return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
+    }
+
+    private boolean activateNextInstanceNode(Long nodeId, LocalDateTime now) {
+        return approvalInstanceNodeService.update(
+                Wrappers.<ApprovalInstanceNode>lambdaUpdate()
+                        .eq(ApprovalInstanceNode::getId, nodeId)
+                        .eq(ApprovalInstanceNode::getStatus, "WAITING")
+                        .eq(ApprovalInstanceNode::getDeleted, 0)
+                        .set(ApprovalInstanceNode::getStatus, "PENDING")
+                        .set(ApprovalInstanceNode::getStartTime, now)
+        );
     }
 
     private boolean updateCurrentNodeStatus(Long nodeId, String targetStatus, LocalDateTime now) {
@@ -343,9 +421,40 @@
             handleShippingApprovalFinished(instance, status);
             return;
         }
+        if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType)
+                || TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) {
+            handleReimbursementApprovalFinished(instance, status);
+            return;
+        }
+        // 椹冲洖瀵瑰簲鐨勪紒涓氭柊闂汇�佸姞鐝敵璇枫�佽鍋囩敵璇峰彲浠ラ噸鏂板啀鎻愪氦
+        if (TypeEnums.LEAVE_APPROVAL.getCode().equals(businessType)
+                || TypeEnums.OVERTIME_APPROVAL.getCode().equals(businessType)) {
+            handleHolidayApplicationApprovalFinished(instance, status);
+            return;
+        }
         if (TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode().equals(businessType)) {
             handleNewsApprovalFinished(instance, status);
         }
+    }
+
+    private void handleReimbursementApprovalFinished(ApprovalInstance instance, String status) {
+        if (instance == null || instance.getBusinessId() == null) {
+            return;
+        }
+
+        FinReimbursement reimbursement = new FinReimbursement();
+        reimbursement.setId(instance.getBusinessId());
+        if ("APPROVED".equals(status)) {
+            reimbursement.setBillStatus("APPROVED");
+            reimbursement.setApprovedTime(instance.getFinishTime());
+        } else if ("REJECTED".equals(status)) {
+            reimbursement.setBillStatus("REJECTED");
+        } else if ("PENDING".equals(status)) {
+            reimbursement.setBillStatus("IN_APPROVAL");
+        } else {
+            return;
+        }
+        finReimbursementMapper.updateById(reimbursement);
     }
 
     private void handleNewsApprovalFinished(ApprovalInstance instance, String status) {
@@ -356,14 +465,32 @@
         enterpriseNews.setId(instance.getBusinessId());
         if ("APPROVED".equals(status)) {
             enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_PUBLISHED);
-            enterpriseNewsService.updateById(enterpriseNews);
+            enterpriseNewsMapper.updateById(enterpriseNews);
             sendEnterpriseNewsNotice(instance.getBusinessId());
             return;
         }
         if ("REJECTED".equals(status)) {
             enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_REJECTED);
-            enterpriseNewsService.updateById(enterpriseNews);
+            enterpriseNewsMapper.updateById(enterpriseNews);
         }
+    }
+
+    private void handleHolidayApplicationApprovalFinished(ApprovalInstance instance, String status) {
+        if (instance == null || instance.getBusinessId() == null) {
+            return;
+        }
+        HolidayApplication holidayApplication = new HolidayApplication();
+        holidayApplication.setId(instance.getBusinessId());
+        if ("APPROVED".equals(status)) {
+            holidayApplication.setStatus("APPROVED");
+        } else if ("REJECTED".equals(status)) {
+            holidayApplication.setStatus("REJECTED");
+        } else if ("PENDING".equals(status)) {
+            holidayApplication.setStatus("PENDING");
+        } else {
+            return;
+        }
+        holidayApplicationMapper.updateById(holidayApplication);
     }
 
     private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) {
@@ -449,7 +576,7 @@
     }
 
     private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
-        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverService.list(
+        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList(
                 new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
                         .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId())
                         .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId())
@@ -507,7 +634,7 @@
     }
 
     private void sendEnterpriseNewsNotice(Long newsId) {
-        EnterpriseNews enterpriseNews = enterpriseNewsService.getById(newsId);
+        EnterpriseNews enterpriseNews = enterpriseNewsMapper.selectById(newsId);
         if (enterpriseNews == null) {
             return;
         }
@@ -537,7 +664,7 @@
                     .collect(Collectors.toList());
         }
         if ("dept".equals(readScope)) {
-            List<Long> deptIds = enterpriseNewsScopeDeptService.list(
+            List<Long> deptIds = enterpriseNewsScopeDeptMapper.selectList(
                             new LambdaQueryWrapper<EnterpriseNewsScopeDept>()
                                     .eq(EnterpriseNewsScopeDept::getNewsId, enterpriseNews.getId()))
                     .stream()
@@ -551,7 +678,7 @@
             return sysUserDeptMapper.selectDistinctUserIdsByDeptIds(collectDeptIdsWithChildren(deptIds));
         }
         if ("custom".equals(readScope)) {
-            return enterpriseNewsScopeUserService.list(
+            return enterpriseNewsScopeUserMapper.selectList(
                             new LambdaQueryWrapper<EnterpriseNewsScopeUser>()
                                     .eq(EnterpriseNewsScopeUser::getNewsId, enterpriseNews.getId()))
                     .stream()
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
index db1f378..af5a774 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
@@ -107,7 +107,6 @@
                 new LambdaQueryWrapper<ApprovalTemplate>()
                         .eq(ApprovalTemplate::getDeleted, 0)
                         .eq(ApprovalTemplate::getEnabled, 1)
-                        .eq(type != null, ApprovalTemplate::getTemplateType, type)
                         .orderByDesc(ApprovalTemplate::getTemplateType)
                         .orderByDesc(ApprovalTemplate::getId)
         );
diff --git a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java
new file mode 100644
index 0000000..1897440
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.approve.service.impl;
+
+import com.ruoyi.approve.pojo.FinReimbursementDetail;
+import com.ruoyi.approve.mapper.FinReimbursementDetailMapper;
+import com.ruoyi.approve.service.FinReimbursementDetailService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曟槑缁嗚〃 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:38
+ */
+@Service
+public class FinReimbursementDetailServiceImpl extends ServiceImpl<FinReimbursementDetailMapper, FinReimbursementDetail> implements FinReimbursementDetailService {
+
+}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java
new file mode 100644
index 0000000..a69bb76
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java
@@ -0,0 +1,537 @@
+package com.ruoyi.approve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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.dto.ApprovalTemplateNodeApproverDto;
+import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto;
+import com.ruoyi.approve.bean.dto.FinReimbursementDto;
+import com.ruoyi.approve.bean.vo.FinReimbursementVo;
+import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
+import com.ruoyi.approve.mapper.FinReimbursementDetailMapper;
+import com.ruoyi.approve.mapper.FinReimbursementMapper;
+import com.ruoyi.approve.mapper.FinReimbursementTravelMapper;
+import com.ruoyi.approve.pojo.*;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
+import com.ruoyi.basic.enums.RecordTypeEnum;
+import com.ruoyi.basic.utils.FileUtil;
+import com.ruoyi.approve.service.*;
+import com.ruoyi.common.enums.TypeEnums;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.OrderUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.project.system.service.ISysNoticeService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 鎶ラ攢鍗曚富琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:15
+ */
+@Service
+@RequiredArgsConstructor
+public class FinReimbursementServiceImpl extends ServiceImpl<FinReimbursementMapper, FinReimbursement> implements FinReimbursementService {
+
+    private static final String BILL_STATUS_DRAFT = "DRAFT";
+    private static final String BILL_STATUS_IN_APPROVAL = "IN_APPROVAL";
+    private static final String NODE_STATUS_WAITING = "WAITING";
+
+    private final ApprovalInstanceMapper approvalInstanceMapper;
+    private final ApprovalInstanceService approvalInstanceService;
+    private final ApprovalInstanceNodeService approvalInstanceNodeService;
+    private final ApprovalTaskService approvalTaskService;
+    private final ApprovalRecordService approvalRecordService;
+    private final FinReimbursementMapper finReimbursementMapper;
+    private final FinReimbursementTravelMapper finReimbursementTravelMapper;
+    private final FinReimbursementDetailMapper finReimbursementDetailMapper;
+    private final FileUtil fileUtil;
+    private final ISysNoticeService sysNoticeService;
+    @Override
+    public IPage<FinReimbursementVo> listPage(FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page) {
+        IPage<FinReimbursementVo> finReimbursementVoIPage = finReimbursementMapper.listPage(finReimbursementDto, page);
+        finReimbursementVoIPage.getRecords().forEach(vo -> {
+            vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT,  vo.getId()));
+        });
+
+        return finReimbursementVoIPage;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean add(FinReimbursementDto finReimbursementDto) {
+        String billStatus = validateAddParam(finReimbursementDto);
+
+        // 鐢熸垚鎶ラ攢鍗曞彿
+        String billNo = OrderUtils.countTodayByCreateTime(finReimbursementMapper, "BXD", "bill_no");
+        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
+        BigDecimal totalAmount = details.stream()
+                .map(FinReimbursementDetail::getAmount)
+                .filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        FinReimbursement reimbursement = buildReimbursement(finReimbursementDto, billNo, totalAmount, billStatus);
+        // 淇濆瓨鎶ラ攢鍗曚富琛�
+        boolean saved = this.save(reimbursement);
+        if (!saved || reimbursement.getId() == null) {
+            throw new ServiceException("鏂板鎶ラ攢鍗曞け璐�");
+        }
+        Long reimbursementId = reimbursement.getId();
+
+        // 淇濆瓨宸梾鎶ラ攢鎵╁睍淇℃伅锛堟姤閿�绫诲瀷涓哄樊鏃呮姤閿�鏃讹級
+        FinReimbursementTravel travel = finReimbursementDto.getTravel();
+        if (isTravelReimbursement(finReimbursementDto.getReimbursementType())) {
+            travel.setReimbursementId(reimbursementId);
+            int travelRows = finReimbursementTravelMapper.insert(travel);
+            if (travelRows != 1) {
+                throw new ServiceException("鏂板宸梾鎶ラ攢鎵╁睍淇℃伅澶辫触");
+            }
+        }
+
+        // 淇濆瓨鎶ラ攢鍗曟槑缁�
+        for (int i = 0; i < details.size(); i++) {
+            FinReimbursementDetail detail = details.get(i);
+            detail.setId(null);
+            detail.setReimbursementId(reimbursementId);
+            detail.setRowNo(i + 1);
+            int detailRows = finReimbursementDetailMapper.insert(detail);
+            if (detailRows != 1) {
+                throw new ServiceException("鏂板鎶ラ攢鍗曟槑缁嗗け璐�");
+            }
+        }
+
+        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
+            startApproval(reimbursement, finReimbursementDto);
+        }
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs());
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(FinReimbursementDto finReimbursementDto) {
+        String billStatus = validateUpdateParam(finReimbursementDto);
+
+        Long reimbursementId = finReimbursementDto.getId();
+        FinReimbursement existing = finReimbursementMapper.selectById(reimbursementId);
+        if (existing == null) {
+            throw new ServiceException("鎶ラ攢鍗曚笉瀛樺湪");
+        }
+
+        // 璁$畻鏄庣粏姹囨�婚噾棰�
+        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
+        BigDecimal totalAmount = details.stream()
+                .map(FinReimbursementDetail::getAmount)
+                .filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        // 鏇存柊涓昏〃
+        FinReimbursement reimbursement = buildReimbursement(
+                finReimbursementDto,
+                existing.getBillNo(),
+                totalAmount,
+                billStatus
+        );
+        reimbursement.setId(reimbursementId);
+        int mainRows = finReimbursementMapper.updateById(reimbursement);
+        if (mainRows != 1) {
+            throw new ServiceException("鏇存柊鎶ラ攢鍗曚富琛ㄥけ璐�");
+        }
+
+        // 鏌ヨ鏁版嵁搴撲腑宸叉湁鐨勬槑缁�
+        List<FinReimbursementDetail> existingDetails = finReimbursementDetailMapper.selectList(
+                new LambdaQueryWrapper<FinReimbursementDetail>()
+                        .eq(FinReimbursementDetail::getReimbursementId, reimbursementId));
+        Set<Long> existingDetailIds = existingDetails.stream()
+                .map(FinReimbursementDetail::getId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+
+        // 鏂版槑缁嗕腑鏈塈D鐨� 鈫� 鏇存柊锛涙棤ID鐨� 鈫� 鏂板
+        Set<Long> submittedDetailIds = new HashSet<>();
+        for (int i = 0; i < details.size(); i++) {
+            FinReimbursementDetail detail = details.get(i);
+            detail.setReimbursementId(reimbursementId);
+            detail.setRowNo(i + 1);
+            if (detail.getId() != null && existingDetailIds.contains(detail.getId())) {
+                finReimbursementDetailMapper.updateById(detail);
+                submittedDetailIds.add(detail.getId());
+            } else {
+                detail.setId(null);
+                finReimbursementDetailMapper.insert(detail);
+            }
+        }
+
+        // 鏁版嵁搴撲腑宸叉湁浣嗘柊鏄庣粏涓病鏈夌殑 鈫� 鍒犻櫎
+        for (Long existingId : existingDetailIds) {
+            if (!submittedDetailIds.contains(existingId)) {
+                finReimbursementDetailMapper.deleteById(existingId);
+            }
+        }
+
+        // 宸梾鎵╁睍锛氭湁鍒欐洿鏂帮紝鏃犲垯鏂板
+        FinReimbursementTravel existingTravel = finReimbursementTravelMapper.selectOne(
+                new LambdaQueryWrapper<FinReimbursementTravel>()
+                        .eq(FinReimbursementTravel::getReimbursementId, reimbursementId)
+                        .last("LIMIT 1"));
+        FinReimbursementTravel travel = finReimbursementDto.getTravel();
+        if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && travel != null) {
+            travel.setReimbursementId(reimbursementId);
+            if (existingTravel != null) {
+                travel.setId(existingTravel.getId());
+                finReimbursementTravelMapper.updateById(travel);
+            } else {
+                travel.setId(null);
+                finReimbursementTravelMapper.insert(travel);
+            }
+        }
+
+        resetApprovalFlow(existing.getApprovalInstanceId(), reimbursementId);
+        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
+            reimbursement.setApprovalInstanceId(null);
+            startApproval(reimbursement, finReimbursementDto);
+        }
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs());
+
+        return true;
+    }
+
+    @Override
+    public FinReimbursementVo detail(Long id) {
+        if (id == null ) {
+            throw new ServiceException("鎶ラ攢鍗旾D涓嶈兘涓虹┖");
+        }
+
+        FinReimbursement reimbursement = finReimbursementMapper.selectById(id);
+        if (reimbursement == null) {
+            throw new ServiceException("鎶ラ攢鍗曚笉瀛樺湪");
+        }
+
+        FinReimbursementVo vo = new FinReimbursementVo();
+        vo.setId(reimbursement.getId());
+        vo.setBillNo(reimbursement.getBillNo());
+        vo.setReimbursementType(reimbursement.getReimbursementType());
+        vo.setExpenseType(reimbursement.getExpenseType());
+        vo.setApplicantId(reimbursement.getApplicantId());
+        vo.setApplicantCode(reimbursement.getApplicantCode());
+        vo.setApplicantName(reimbursement.getApplicantName());
+        vo.setApplicantDeptId(reimbursement.getApplicantDeptId());
+        vo.setApplicantDeptName(reimbursement.getApplicantDeptName());
+        vo.setReason(reimbursement.getReason());
+        vo.setApplyAmount(reimbursement.getApplyAmount());
+        vo.setDetailTotalAmount(reimbursement.getDetailTotalAmount());
+        vo.setPayeeName(reimbursement.getPayeeName());
+        vo.setPayeeAccount(reimbursement.getPayeeAccount());
+        vo.setPayeeBank(reimbursement.getPayeeBank());
+        vo.setApprovalInstanceId(reimbursement.getApprovalInstanceId());
+        vo.setApproveProcessId(reimbursement.getApproveProcessId());
+        vo.setBillStatus(reimbursement.getBillStatus());
+        vo.setApprovedTime(reimbursement.getApprovedTime());
+        vo.setPaidTime(reimbursement.getPaidTime());
+        vo.setAccountExpenseId(reimbursement.getAccountExpenseId());
+        vo.setRemark(reimbursement.getRemark());
+        vo.setTenantId(reimbursement.getTenantId());
+        vo.setCreateUser(reimbursement.getCreateUser());
+        vo.setCreateTime(reimbursement.getCreateTime());
+        vo.setUpdateUser(reimbursement.getUpdateUser());
+        vo.setUpdateTime(reimbursement.getUpdateTime());
+        vo.setDeptId(reimbursement.getDeptId());
+        vo.setDeleted(reimbursement.getDeleted());
+
+        vo.setDetails(finReimbursementDetailMapper.selectList(
+                new LambdaQueryWrapper<FinReimbursementDetail>()
+                        .eq(FinReimbursementDetail::getReimbursementId, reimbursement.getId())
+                        .orderByAsc(FinReimbursementDetail::getRowNo)
+        ));
+
+        if (isTravelReimbursement(reimbursement.getReimbursementType())) {
+            vo.setTravel(finReimbursementTravelMapper.selectOne(
+                    new LambdaQueryWrapper<FinReimbursementTravel>()
+                            .eq(FinReimbursementTravel::getReimbursementId, reimbursement.getId())
+                            .last("LIMIT 1")
+            ));
+        }
+        vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT, reimbursement.getId()));
+        //瀹℃壒璁板綍杩斿洖
+        vo.setTasks(approvalTaskService.list(new LambdaQueryWrapper<ApprovalTask>().eq(ApprovalTask::getInstanceId, reimbursement.getApprovalInstanceId())));
+        vo.setRecords(approvalRecordService.list(new LambdaQueryWrapper<ApprovalRecord>().eq(ApprovalRecord::getInstanceId, reimbursement.getApprovalInstanceId())));
+        return vo;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean delete(List<Long> ids) {
+        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, ids);
+        //鍏堝垹闄ゆ槑缁�
+        finReimbursementDetailMapper.delete(new LambdaQueryWrapper<FinReimbursementDetail>().in(FinReimbursementDetail::getReimbursementId, ids));
+        //鍒犻櫎宸梾
+        finReimbursementTravelMapper.delete(new LambdaQueryWrapper<FinReimbursementTravel>().in(FinReimbursementTravel::getReimbursementId, ids));
+        //鍒犻櫎涓昏〃
+        int rows = finReimbursementMapper.delete(new LambdaQueryWrapper<FinReimbursement>().in(FinReimbursement::getId, ids));
+        return rows == ids.size();
+    }
+
+    private String validateUpdateParam(FinReimbursementDto finReimbursementDto) {
+        if (finReimbursementDto == null || finReimbursementDto.getId() == null) {
+            throw new ServiceException("鎶ラ攢鍗旾D涓嶈兘涓虹┖");
+        }
+        if (finReimbursementDto.getReimbursementType() == null) {
+            throw new ServiceException("鎶ラ攢绫诲瀷涓嶈兘涓虹┖");
+        }
+        String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus());
+        if (billStatus == null) {
+            throw new ServiceException("鍗曟嵁鐘舵�佸彧鏀寔 DRAFT 鎴� IN_APPROVAL");
+        }
+        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
+            validateApprovalNodes(finReimbursementDto.getNodes());
+        }
+        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
+        if (details == null || details.isEmpty()) {
+            throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
+        }
+        for (FinReimbursementDetail detail : details) {
+            if (detail == null) {
+                throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
+            }
+            if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
+                throw new ServiceException("鎶ラ攢鍗曟槑缁嗛噾棰濆繀椤诲ぇ浜�0");
+            }
+        }
+        if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) {
+            throw new ServiceException("宸梾鎶ラ攢蹇呴』濉啓宸梾鎵╁睍淇℃伅");
+        }
+        if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) {
+            throw new ServiceException("闈炲樊鏃呮姤閿�涓嶅厑璁稿~鍐欏樊鏃呮墿灞曚俊鎭�");
+        }
+        return billStatus;
+    }
+
+    private String validateAddParam(FinReimbursementDto finReimbursementDto) {
+        if (finReimbursementDto == null) {
+            throw new ServiceException("鎶ラ攢鍗曟暟鎹笉鑳戒负绌�");
+        }
+        if (finReimbursementDto.getReimbursementType() == null) {
+            throw new ServiceException("鎶ラ攢绫诲瀷涓嶈兘涓虹┖");
+        }
+        String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus());
+        if (billStatus == null) {
+            throw new ServiceException("鍗曟嵁鐘舵�佸彧鏀寔 DRAFT 鎴� IN_APPROVAL");
+        }
+        if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
+            validateApprovalNodes(finReimbursementDto.getNodes());
+        }
+        List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
+        if (details == null || details.isEmpty()) {
+            throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
+        }
+        for (FinReimbursementDetail detail : details) {
+            if (detail == null) {
+                throw new ServiceException("鎶ラ攢鍗曟槑缁嗕笉鑳戒负绌�");
+            }
+            if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
+                throw new ServiceException("鎶ラ攢鍗曟槑缁嗛噾棰濆繀椤诲ぇ浜�0");
+            }
+        }
+        if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) {
+            throw new ServiceException("宸梾鎶ラ攢蹇呴』濉啓宸梾鎵╁睍淇℃伅");
+        }
+        if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) {
+            throw new ServiceException("闈炲樊鏃呮姤閿�涓嶅厑璁稿~鍐欏樊鏃呮墿灞曚俊鎭�");
+        }
+        return billStatus;
+    }
+
+    private FinReimbursement buildReimbursement(FinReimbursementDto finReimbursementDto, String billNo, BigDecimal totalAmount, String billStatus) {
+        FinReimbursement reimbursement = new FinReimbursement();
+        reimbursement.setId(null);
+        reimbursement.setBillNo(billNo);
+        reimbursement.setReimbursementType(finReimbursementDto.getReimbursementType());
+        reimbursement.setExpenseType(finReimbursementDto.getExpenseType());
+        reimbursement.setApplicantId(finReimbursementDto.getApplicantId());
+        reimbursement.setApplicantCode(finReimbursementDto.getApplicantCode());
+        reimbursement.setApplicantName(finReimbursementDto.getApplicantName());
+        reimbursement.setApplicantDeptId(finReimbursementDto.getApplicantDeptId());
+        reimbursement.setApplicantDeptName(finReimbursementDto.getApplicantDeptName());
+        reimbursement.setReason(finReimbursementDto.getReason());
+        reimbursement.setApplyAmount(finReimbursementDto.getApplyAmount());
+        reimbursement.setDetailTotalAmount(totalAmount);
+        reimbursement.setPayeeName(finReimbursementDto.getPayeeName());
+        reimbursement.setPayeeAccount(finReimbursementDto.getPayeeAccount());
+        reimbursement.setPayeeBank(finReimbursementDto.getPayeeBank());
+        reimbursement.setRemark(finReimbursementDto.getRemark());
+        reimbursement.setTenantId(finReimbursementDto.getTenantId());
+        reimbursement.setApproveProcessId(null);
+        reimbursement.setBillStatus(billStatus);
+        return reimbursement;
+    }
+
+    private void startApproval(FinReimbursement reimbursement, FinReimbursementDto finReimbursementDto) {
+        Long businessType = resolveBusinessType(finReimbursementDto.getReimbursementType());
+        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
+        approvalInstanceDto.setInstanceNo(OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no"));
+        approvalInstanceDto.setBusinessId(reimbursement.getId());
+        approvalInstanceDto.setTemplateId(null);
+        approvalInstanceDto.setTemplateName(TypeEnums.getLabelByValue(businessType) + "瀹℃壒");
+        approvalInstanceDto.setBusinessType(businessType);
+        approvalInstanceDto.setTitle("鎶ラ攢鍗曞彿锛�" + reimbursement.getBillNo());
+        approvalInstanceDto.setApplicantId(reimbursement.getApplicantId() != null ? reimbursement.getApplicantId() : SecurityUtils.getUserId());
+        approvalInstanceDto.setApplicantName(reimbursement.getApplicantName() != null ? reimbursement.getApplicantName() : SecurityUtils.getLoginUser().getNickName());
+        approvalInstanceDto.setApplyTime(LocalDateTime.now());
+        approvalInstanceDto.setStatus("PENDING");
+        approvalInstanceDto.setCurrentLevel(1);
+
+        boolean approvalSaved = approvalInstanceService.save(approvalInstanceDto);
+        if (!approvalSaved || approvalInstanceDto.getId() == null) {
+            throw new ServiceException("鍙戣捣瀹℃壒澶辫触");
+        }
+        List<ApprovalTask> firstTasks = createApprovalNodes(approvalInstanceDto, finReimbursementDto.getNodes());
+        sendApproveNotice(approvalInstanceDto, firstTasks);
+
+        FinReimbursement update = new FinReimbursement();
+        update.setId(reimbursement.getId());
+        update.setApprovalInstanceId(approvalInstanceDto.getId());
+        update.setBillStatus(BILL_STATUS_IN_APPROVAL);
+        int rows = finReimbursementMapper.updateById(update);
+        if (rows != 1) {
+            throw new ServiceException("鍥炲~瀹℃壒瀹炰緥澶辫触");
+        }
+    }
+
+    private List<ApprovalTask> createApprovalNodes(ApprovalInstanceDto approvalInstanceDto, List<ApprovalTemplateNodeDto> nodes) {
+        List<ApprovalTask> firstTasks = Collections.emptyList();
+        for (int i = 0; i < nodes.size(); i++) {
+            ApprovalTemplateNodeDto nodeDto = nodes.get(i);
+            ApprovalInstanceNode instanceNode = new ApprovalInstanceNode();
+            instanceNode.setInstanceId(approvalInstanceDto.getId());
+            instanceNode.setLevelNo(nodeDto.getLevelNo());
+            instanceNode.setApproveType(nodeDto.getApproveType());
+            instanceNode.setStatus(i == 0 ? "PENDING" : NODE_STATUS_WAITING);
+            instanceNode.setStartTime(i == 0 ? LocalDateTime.now() : null);
+            instanceNode.setDeleted((byte) 0);
+            approvalInstanceNodeService.save(instanceNode);
+
+            List<ApprovalTask> tasks = nodeDto.getApprovers().stream().map(approver -> {
+                ApprovalTask task = new ApprovalTask();
+                task.setInstanceId(approvalInstanceDto.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);
+                return task;
+            }).collect(Collectors.toList());
+            approvalTaskService.saveBatch(tasks);
+
+            if (i == 0) {
+                firstTasks = tasks;
+                ApprovalRecord record = new ApprovalRecord();
+                record.setInstanceId(approvalInstanceDto.getId());
+                record.setNodeId(instanceNode.getId());
+                record.setOperatorId(approvalInstanceDto.getApplicantId());
+                record.setOperatorName(approvalInstanceDto.getApplicantName());
+                record.setAction("SUBMIT");
+                record.setComment("鍙戣捣瀹℃壒");
+                record.setDeleted((byte) 0);
+                approvalRecordService.save(record);
+            }
+        }
+        return firstTasks;
+    }
+
+    private void validateApprovalNodes(List<ApprovalTemplateNodeDto> nodes) {
+        if (nodes == null || nodes.isEmpty()) {
+            throw new ServiceException("鎻愪氦瀹℃壒鏃跺鎵硅妭鐐逛笉鑳戒负绌�");
+        }
+        for (int i = 0; i < nodes.size(); i++) {
+            ApprovalTemplateNodeDto node = nodes.get(i);
+            if (node == null) {
+                throw new ServiceException("瀹℃壒鑺傜偣涓嶈兘涓虹┖");
+            }
+            if (node.getLevelNo() == null) {
+                node.setLevelNo(i + 1);
+            }
+            if (!StringUtils.hasText(node.getApproveType())) {
+                throw new ServiceException("瀹℃壒鑺傜偣瀹℃壒鏂瑰紡涓嶈兘涓虹┖");
+            }
+            List<ApprovalTemplateNodeApproverDto> approvers = node.getApprovers();
+            if (approvers == null || approvers.isEmpty()) {
+                throw new ServiceException("瀹℃壒鑺傜偣瀹℃壒浜轰笉鑳戒负绌�");
+            }
+            for (ApprovalTemplateNodeApproverDto approver : approvers) {
+                if (approver == null || approver.getApproverId() == null) {
+                    throw new ServiceException("瀹℃壒浜轰笉鑳戒负绌�");
+                }
+            }
+        }
+    }
+
+    private void sendApproveNotice(ApprovalInstanceDto 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 = "鎶ラ攢瀹℃壒";
+        String message = "瀹℃壒鍗曞彿 " + instance.getInstanceNo() + " 闇�瑕佹偍瀹℃壒";
+        String jumpPath = "/approvalInstance?id=" + instance.getId();
+        sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
+    }
+
+    private void resetApprovalFlow(Long approvalInstanceId, Long reimbursementId) {
+        if (approvalInstanceId == null) {
+            return;
+        }
+        approvalInstanceService.delete(Collections.singletonList(approvalInstanceId));
+        int rows = finReimbursementMapper.update(
+                null,
+                Wrappers.<FinReimbursement>lambdaUpdate()
+                        .eq(FinReimbursement::getId, reimbursementId)
+                        .set(FinReimbursement::getApprovalInstanceId, null)
+        );
+        if (rows != 1) {
+            throw new ServiceException("閲嶇疆瀹℃壒娴佺▼澶辫触");
+        }
+    }
+
+    private Long resolveBusinessType(Byte reimbursementType) {
+        return isTravelReimbursement(reimbursementType)
+                ? TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode()
+                : TypeEnums.EXPENSE_APPROVAL.getCode();
+    }
+
+    private String normalizeBillStatus(String billStatus) {
+        if (billStatus == null) {
+            return BILL_STATUS_DRAFT;
+        }
+        String normalized = billStatus.trim().toUpperCase();
+        if (BILL_STATUS_DRAFT.equals(normalized) || BILL_STATUS_IN_APPROVAL.equals(normalized)) {
+            return normalized;
+        }
+        return null;
+    }
+
+    private boolean isTravelReimbursement(Byte reimbursementType) {
+        return Byte.valueOf((byte) 1).equals(reimbursementType);
+    }
+}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java
new file mode 100644
index 0000000..3329f9a
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.approve.service.impl;
+
+import com.ruoyi.approve.pojo.FinReimbursementTravel;
+import com.ruoyi.approve.mapper.FinReimbursementTravelMapper;
+import com.ruoyi.approve.service.FinReimbursementTravelService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 宸梾鎶ラ攢鎵╁睍琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-21 09:56:47
+ */
+@Service
+public class FinReimbursementTravelServiceImpl extends ServiceImpl<FinReimbursementTravelMapper, FinReimbursementTravel> implements FinReimbursementTravelService {
+
+}
diff --git a/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java b/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
index 073a798..6613d3e 100644
--- a/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
+++ b/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
@@ -204,8 +204,10 @@
     SALES_REFUND_AMOUNT_ORDER("sales_refund_amount_order"),
     SALES_RECEIPT_RETURN("sales_receipt_return"),
     ACCOUNT_EXPENSE("account_expense"),
+    FIN_REIMBURSEMENT("fin_reimbursement"),
     FIN_VOUCHER("fin_voucher"),
     ACCOUNT_FILE("account_file"),
+    ENTERPRISE_NEWS("enterprise_news"),
     APPROVAL_INSTANCE("approval_instance");
 
 
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java b/src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java
index 3cde773..108cf66 100644
--- a/src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java
+++ b/src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java
@@ -1,5 +1,6 @@
 package com.ruoyi.collaborativeApproval.dto;
 
+import com.ruoyi.basic.dto.StorageBlobDTO;
 import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
 import lombok.Data;
 
@@ -19,4 +20,7 @@
 
     private String createTimeStart;
     private String createTimeEnd;
+
+    private List<StorageBlobDTO> storageBlobDTOs;
+
 }
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java b/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
index 2cf7fae..cb155fe 100644
--- a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
+++ b/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
@@ -10,6 +10,9 @@
 import com.ruoyi.approve.pojo.ApprovalTask;
 import com.ruoyi.approve.pojo.ApprovalTemplate;
 import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
+import com.ruoyi.basic.enums.RecordTypeEnum;
+import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto;
 import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper;
 import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
@@ -72,10 +75,15 @@
     private final ApprovalTemplateMapper approvalTemplateMapper;
     private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils;
     private final ISysNoticeService sysNoticeService;
+    private final FileUtil fileUtil;
 
     @Override
     public IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page, EnterpriseNewsDto enterpriseNewsDto) {
-        return enterpriseNewsMapper.listPage(page, enterpriseNewsDto);
+        IPage<EnterpriseNewsVo> enterpriseNewsVoIPage = enterpriseNewsMapper.listPage(page, enterpriseNewsDto);
+        enterpriseNewsVoIPage.getRecords().forEach(enterpriseNewsVo -> {
+            enterpriseNewsVo.setStorageBlobDTOs(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNewsVo.getId()));
+        });
+        return enterpriseNewsVoIPage;
     }
 
     @Override
@@ -107,6 +115,8 @@
         if (STATUS_PENDING.equals(enterpriseNews.getStatus())) {
             startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto);
         }
+        //娣诲姞闄勪欢
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs());
         return true;
     }
 
@@ -148,7 +158,7 @@
 
         clearReadScopeRelations(enterpriseNews.getId());
         saveReadScopeRelations(enterpriseNews.getId(), readScope, deptIds, userIds);
-
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs());
         if (STATUS_PENDING.equals(enterpriseNews.getStatus())) {
             startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto);
         }
diff --git a/src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java b/src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java
index ef40e65..66123b9 100644
--- a/src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java
+++ b/src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java
@@ -1,10 +1,15 @@
 package com.ruoyi.collaborativeApproval.vo;
 
+import com.ruoyi.basic.dto.StorageBlobVO;
 import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
 import lombok.Data;
+
+import java.util.List;
 
 @Data
 public class EnterpriseNewsVo extends EnterpriseNews {
 
     private String createUserName;
+
+    private List<StorageBlobVO> storageBlobDTOs;
 }
diff --git a/src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml b/src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml
new file mode 100644
index 0000000..f8a67bb
--- /dev/null
+++ b/src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml
@@ -0,0 +1,29 @@
+<?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.FinReimbursementDetailMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursementDetail">
+        <id column="id" property="id" />
+        <result column="reimbursement_id" property="reimbursementId" />
+        <result column="row_no" property="rowNo" />
+        <result column="invoice_date" property="invoiceDate" />
+        <result column="expense_category" property="expenseCategory" />
+        <result column="amount" property="amount" />
+        <result column="description" property="description" />
+        <result column="invoice_no" property="invoiceNo" />
+        <result column="invoice_type" property="invoiceType" />
+        <result column="invoice_amount" property="invoiceAmount" />
+        <result column="tax_rate" property="taxRate" />
+        <result column="tax_amount" property="taxAmount" />
+        <result column="remark" property="remark" />
+        <result column="tenant_id" property="tenantId" />
+        <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="dept_id" property="deptId" />
+        <result column="deleted" property="deleted" />
+    </resultMap>
+
+</mapper>
diff --git a/src/main/resources/mapper/approve/FinReimbursementMapper.xml b/src/main/resources/mapper/approve/FinReimbursementMapper.xml
new file mode 100644
index 0000000..75ca038
--- /dev/null
+++ b/src/main/resources/mapper/approve/FinReimbursementMapper.xml
@@ -0,0 +1,57 @@
+<?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.FinReimbursementMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursement">
+        <id column="id" property="id" />
+        <result column="bill_no" property="billNo" />
+        <result column="reimbursement_type" property="reimbursementType" />
+        <result column="expense_type" property="expenseType" />
+        <result column="applicant_id" property="applicantId" />
+        <result column="applicant_code" property="applicantCode" />
+        <result column="applicant_name" property="applicantName" />
+        <result column="applicant_dept_id" property="applicantDeptId" />
+        <result column="applicant_dept_name" property="applicantDeptName" />
+        <result column="reason" property="reason" />
+        <result column="apply_amount" property="applyAmount" />
+        <result column="detail_total_amount" property="detailTotalAmount" />
+        <result column="payee_name" property="payeeName" />
+        <result column="payee_account" property="payeeAccount" />
+        <result column="payee_bank" property="payeeBank" />
+        <result column="approval_instance_id" property="approvalInstanceId" />
+        <result column="approve_process_id" property="approveProcessId" />
+        <result column="bill_status" property="billStatus" />
+        <result column="approved_time" property="approvedTime" />
+        <result column="paid_time" property="paidTime" />
+        <result column="account_expense_id" property="accountExpenseId" />
+        <result column="remark" property="remark" />
+        <result column="tenant_id" property="tenantId" />
+        <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="dept_id" property="deptId" />
+        <result column="deleted" property="deleted" />
+    </resultMap>
+    <select id="listPage" resultType="com.ruoyi.approve.bean.vo.FinReimbursementVo">
+        select fin_reimbursement.*,
+        fin_reimbursement_travel.start_time ,
+        fin_reimbursement_travel.end_time
+               from
+                fin_reimbursement
+            left join fin_reimbursement_travel on fin_reimbursement.id = fin_reimbursement_travel.reimbursement_id
+        <where>
+            <if test="ew.billNo != null and ew.billNo != ''">
+                bill_no like concat('%',#{ew.billNo},'%')
+            </if>
+            <if test="ew.applicantName != null and ew.applicantName != ''">
+                and applicant_name like concat('%',#{ew.applicantName},'%')
+            </if>
+            <if test="ew.createTimeStart != null and ew.createTimeStart !=''">
+                and create_time between to_date(#{ew.createTimeStart}) and to_date(#{ew.createTimeEnd})
+            </if>
+        </where>
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml b/src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml
new file mode 100644
index 0000000..dc42863
--- /dev/null
+++ b/src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml
@@ -0,0 +1,29 @@
+<?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.FinReimbursementTravelMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursementTravel">
+        <id column="id" property="id" />
+        <result column="reimbursement_id" property="reimbursementId" />
+        <result column="start_time" property="startTime" />
+        <result column="end_time" property="endTime" />
+        <result column="travel_days" property="travelDays" />
+        <result column="departure_city" property="departureCity" />
+        <result column="destination_city" property="destinationCity" />
+        <result column="hotel_standard" property="hotelStandard" />
+        <result column="lodging_days" property="lodgingDays" />
+        <result column="meal_allowance" property="mealAllowance" />
+        <result column="transport_allowance" property="transportAllowance" />
+        <result column="lodging_limit" property="lodgingLimit" />
+        <result column="standard_tag" property="standardTag" />
+        <result column="within_standard" property="withinStandard" />
+        <result column="tenant_id" property="tenantId" />
+        <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="dept_id" property="deptId" />
+    </resultMap>
+
+</mapper>

--
Gitblit v1.9.3