Эх сурвалжийг харах

feat(system): 优化公司服务新增逻辑并重构客户部门结构

- 新增公司时自动创建对应根部门功能
- 重构CustomerDept实体移除冗余字段
- 新增客户部门树形结构查询接口
- 优化CustomerDeptService实现类的新增和查询逻辑
- 调整CustomerDeptBo和CustomerDeptVo的字段映射
- 新增订单模块中客户名称的远程调用查询
- 更新数据权限拦截器中的表名配置
- 添加客户API依赖到各相关模块的pom文件
hurx 3 сар өмнө
parent
commit
d4dd812c9f
60 өөрчлөгдсөн 3306 нэмэгдсэн , 258 устгасан
  1. 5 4
      pom.xml
  2. 2 1
      ruoyi-api/pom.xml
  3. 5 0
      ruoyi-api/ruoyi-api-bom/pom.xml
  4. 28 0
      ruoyi-api/ruoyi-api-customer/pom.xml
  5. 10 0
      ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/RemoteCustomerService.java
  6. 21 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java
  7. 6 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteDeptVo.java
  8. 21 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/SysPlatformYesNo.java
  9. 2 0
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlatformDataScopeInterceptor.java
  10. 8 0
      ruoyi-modules/ruoyi-customer/pom.xml
  11. 7 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/CustomerDeptController.java
  12. 2 44
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/CustomerDept.java
  13. 1 5
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/bo/CustomerDeptBo.java
  14. 27 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/CustomerDeptTreeVo.java
  15. 2 9
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/CustomerDeptVo.java
  16. 25 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/dubbo/RemoteCustomerServiceImpl.java
  17. 4 2
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ICustomerDeptService.java
  18. 4 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ICustomerInfoService.java
  19. 137 70
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerDeptServiceImpl.java
  20. 113 87
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerInfoServiceImpl.java
  21. 4 0
      ruoyi-modules/ruoyi-order/pom.xml
  22. 106 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderRevenueDetailController.java
  23. 116 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderRevenueHeaderController.java
  24. 103 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderRevenueDetail.java
  25. 113 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderRevenueHeader.java
  26. 5 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderMainBo.java
  27. 95 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderRevenueDetailBo.java
  28. 112 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderRevenueHeaderBo.java
  29. 4 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderMainVo.java
  30. 118 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderRevenueDetailVo.java
  31. 138 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderRevenueHeaderVo.java
  32. 21 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderRevenueDetailMapper.java
  33. 15 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderRevenueHeaderMapper.java
  34. 70 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderRevenueDetailService.java
  35. 75 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderRevenueHeaderService.java
  36. 18 2
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java
  37. 145 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderRevenueDetailServiceImpl.java
  38. 293 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderRevenueHeaderServiceImpl.java
  39. 14 0
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderRevenueDetailMapper.xml
  40. 7 0
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderRevenueHeaderMapper.xml
  41. 36 23
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseServiceImpl.java
  42. 117 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/ComCurrencyController.java
  43. 118 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/ComRevenueExpenseController.java
  44. 67 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/ComCurrency.java
  45. 77 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/ComRevenueExpense.java
  46. 60 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/ComCurrencyBo.java
  47. 72 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/ComRevenueExpenseBo.java
  48. 76 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ComCurrencyVo.java
  49. 90 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ComRevenueExpenseVo.java
  50. 26 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java
  51. 15 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/ComCurrencyMapper.java
  52. 15 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/ComRevenueExpenseMapper.java
  53. 76 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IComCurrencyService.java
  54. 76 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IComRevenueExpenseService.java
  55. 40 8
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComCompanyServiceImpl.java
  56. 158 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComCurrencyServiceImpl.java
  57. 160 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComRevenueExpenseServiceImpl.java
  58. 11 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
  59. 7 0
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/ComCurrencyMapper.xml
  60. 7 0
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/ComRevenueExpenseMapper.xml

+ 5 - 4
pom.xml

@@ -91,6 +91,10 @@
                 <nacos.password>nacos</nacos.password>
                 <logstash.address>127.0.0.1:4560</logstash.address>
             </properties>
+            <activation>
+                <!-- 默认环境 -->
+                <activeByDefault>true</activeByDefault>
+            </activation>
         </profile>
         <profile>
             <id>xiaolu</id>
@@ -104,10 +108,7 @@
                 <nacos.password>nacos</nacos.password>
                 <logstash.address>127.0.0.1:4560</logstash.address>
             </properties>
-            <activation>
-                <!-- 默认环境 -->
-                <activeByDefault>true</activeByDefault>
-            </activation>
+
         </profile>
         <profile>
             <id>prod</id>

+ 2 - 1
ruoyi-api/pom.xml

@@ -15,7 +15,8 @@
         <module>ruoyi-api-workflow</module>
         <module>ruoyi-api-product</module>
         <module>ruoyi-api-external</module>
-	    <module>ruoyi-api-order</module>
+        <module>ruoyi-api-order</module>
+        <module>ruoyi-api-customer</module>
     </modules>
 
     <artifactId>ruoyi-api</artifactId>

+ 5 - 0
ruoyi-api/ruoyi-api-bom/pom.xml

@@ -57,6 +57,11 @@
                 <artifactId>ruoyi-api-order</artifactId>
                 <version>${revision}</version>
             </dependency>
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-api-customer</artifactId>
+                <version>${revision}</version>
+            </dependency>
 
         </dependencies>
     </dependencyManagement>

+ 28 - 0
ruoyi-api/ruoyi-api-customer/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-api</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-api-customer</artifactId>
+
+    <description>
+        ruoyi-api-customer 客户模块接口模块
+    </description>
+
+    <dependencies>
+
+        <!-- RuoYi Common Core-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+
+    </dependencies>
+
+</project>

+ 10 - 0
ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/RemoteCustomerService.java

@@ -0,0 +1,10 @@
+package org.dromara.customer.api;
+
+import java.util.Map;
+import java.util.Set;
+
+public interface RemoteCustomerService {
+
+    /*根据ids查询客户名称*/
+    Map<Long, String> selectCustomerNameByIds(Set<Long> ids);
+}

+ 21 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java

@@ -1,5 +1,6 @@
 package org.dromara.system.api;
 
+import cn.hutool.core.lang.tree.Tree;
 import org.dromara.system.api.domain.vo.RemoteDeptVo;
 
 import java.util.List;
@@ -19,6 +20,8 @@ public interface RemoteDeptService {
      */
     String selectDeptNameByIds(String deptIds);
 
+    RemoteDeptVo selectDeptById(Long deptId);
+
     /**
      * 根据部门ID查询部门负责人
      *
@@ -38,4 +41,22 @@ public interface RemoteDeptService {
 
     RemoteDeptVo insertDept(RemoteDeptVo vo);
 
+    List<RemoteDeptVo> selectDeptByIds(List<Long> deptIds);
+
+    /**
+     * 查询部门树结构信息
+     *
+     * @param dept 部门信息
+     * @return 部门树信息集合
+     */
+    List<Tree<Long>> selectDeptTreeList(RemoteDeptVo dept);
+
+    /**
+     * 构建前端所需要下拉树结构
+     *
+     * @param depts 部门列表
+     * @return 下拉树结构列表
+     */
+    List<Tree<Long>> buildDeptTreeSelect(List<RemoteDeptVo> depts);
+
 }

+ 6 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteDeptVo.java

@@ -36,6 +36,12 @@ public class RemoteDeptVo implements Serializable {
 
     private Long customerId;
 
+    private String status;
+
+    private Integer orderNum;
+
+    private Long companyId;
+
 
     private String platformCode;
 

+ 21 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/SysPlatformYesNo.java

@@ -0,0 +1,21 @@
+package org.dromara.common.core.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum SysPlatformYesNo {
+
+    /**
+     * 是
+     */
+    YES("0", "是"),
+    /**
+     * 否
+     */
+    NO("1", "否");
+
+    private final String code;
+    private final String info;
+}

+ 2 - 0
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlatformDataScopeInterceptor.java

@@ -42,6 +42,7 @@ public class PlatformDataScopeInterceptor implements Interceptor {
         "sys_user_post",
         "sys_config",
         "sys_dict",
+        "sys_dept",
         "sys_dict_type",
         "sys_dict_data",
         "sys_oss",
@@ -57,6 +58,7 @@ public class PlatformDataScopeInterceptor implements Interceptor {
         "customer_info_tag",
         "invoice_type",
         "customer_info",
+        "customer_dept",
         "com_bank",
         "settlement_level",
         "settlement_method",

+ 8 - 0
ruoyi-modules/ruoyi-customer/pom.xml

@@ -108,6 +108,14 @@
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-api-workflow</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-customer</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-customer</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 7 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/CustomerDeptController.java

@@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.customer.domain.vo.CustomerDeptTreeVo;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -45,6 +46,12 @@ public class CustomerDeptController extends BaseController {
         return R.ok(list);
     }
 
+    @GetMapping("/tree")
+    public R<List<CustomerDeptTreeVo>> getCustomerDeptTree(@RequestParam Long customerId) {
+        List<CustomerDeptTreeVo> list = customerDeptService.getCustomerDeptTree(customerId);
+        return R.ok(list);
+    }
+
     /**
      * 导出客户部门信息列表
      */

+ 2 - 44
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/CustomerDept.java

@@ -25,39 +25,14 @@ public class CustomerDept extends TenantEntity {
     /**
      * ID
      */
-    @TableId(value = "id")
-    private Long id;
-
-    /**
-     * 部门编号
-     */
-    private String deptNo;
-
-    /**
-     * 部门名称
-     */
-    private String deptName;
-
-    /**
-     * 父部门id
-     */
-    private Long parentId;
-
-    /**
-     * 祖级列表
-     */
-    private String ancestors;
+    @TableId(value = "dept_id")
+    private Long deptId;
 
     /**
      * 客户编号
      */
     private Long customerId;
 
-    /**
-     * 部门层级(如1级、2级等)
-     */
-    private Long departmentLevel;
-
     /**
      * 年度预算
      */
@@ -118,21 +93,4 @@ public class CustomerDept extends TenantEntity {
      */
     private Long recharge;
 
-    /**
-     * 状态(0正常 1停用)
-     */
-    private String status;
-
-    /**
-     * 删除标志(0代表存在 2代表删除)
-     */
-    @TableLogic
-    private String delFlag;
-
-    /**
-     * 备注
-     */
-    private String remark;
-
-
 }

+ 1 - 5
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/bo/CustomerDeptBo.java

@@ -25,7 +25,7 @@ public class CustomerDeptBo extends BaseEntity {
     /**
      * ID
      */
-    private Long id;
+    private Long deptId;
 
     /**
      * 部门编号
@@ -35,7 +35,6 @@ public class CustomerDeptBo extends BaseEntity {
     /**
      * 部门名称
      */
-    @NotBlank(message = "部门名称不能为空", groups = {AddGroup.class, EditGroup.class})
     private String deptName;
 
     /**
@@ -61,19 +60,16 @@ public class CustomerDeptBo extends BaseEntity {
     /**
      * 年度预算
      */
-    @NotNull(message = "年度预算不能为空", groups = {AddGroup.class, EditGroup.class})
     private BigDecimal yearlyBudget;
 
     /**
      * 已使用预算
      */
-    @NotNull(message = "已使用预算不能为空", groups = {AddGroup.class, EditGroup.class})
     private BigDecimal usedBudget;
 
     /**
      * 月度限额
      */
-    @NotNull(message = "月度限额不能为空", groups = {AddGroup.class, EditGroup.class})
     private BigDecimal monthLimit;
 
     /**

+ 27 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/CustomerDeptTreeVo.java

@@ -0,0 +1,27 @@
+package org.dromara.customer.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class CustomerDeptTreeVo implements Serializable {
+
+    private Long deptId;            // = dept_id
+    private Long parentId;      // 来自 sys_dept
+    private String deptName;    // 来自 sys_dept
+    private Integer orderNum;   // 排序
+
+    // 业务字段(来自 customer_dept)
+    private BigDecimal yearlyBudget;
+    private BigDecimal usedBudget;
+    private BigDecimal monthLimit;
+    private String bindAddress;
+    private String bindStatus;
+    private String status;      // 来自 sys_dept(启用/停用)
+
+    // 可选:是否叶子节点(前端有时需要)
+    private Boolean hasChildren = false;
+
+}

+ 2 - 9
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/CustomerDeptVo.java

@@ -31,8 +31,8 @@ public class CustomerDeptVo implements Serializable {
     /**
      * ID
      */
-    @ExcelProperty(value = "ID")
-    private Long id;
+    @ExcelProperty(value = "dept_id")
+    private Long deptId;
 
     /**
      * 部门编号
@@ -64,13 +64,6 @@ public class CustomerDeptVo implements Serializable {
     @ExcelProperty(value = "客户编号")
     private Long customerId;
 
-    /**
-     * 部门层级(如1级、2级等)
-     */
-    @ExcelProperty(value = "部门层级", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "如=1级、2级等")
-    private BigDecimal departmentLevel;
-
     /**
      * 年度预算
      */

+ 25 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/dubbo/RemoteCustomerServiceImpl.java

@@ -0,0 +1,25 @@
+package org.dromara.customer.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.customer.api.RemoteCustomerService;
+import org.dromara.customer.service.ICustomerInfoService;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+import java.util.Set;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@DubboService
+public class RemoteCustomerServiceImpl implements RemoteCustomerService {
+
+    private final ICustomerInfoService customerInfoService;
+
+    @Override
+    public Map<Long, String> selectCustomerNameByIds(Set<Long> ids) {
+        return customerInfoService.selectCustomerNameByIds(ids);
+    }
+}

+ 4 - 2
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ICustomerDeptService.java

@@ -2,6 +2,7 @@ package org.dromara.customer.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.dromara.customer.domain.CustomerDept;
+import org.dromara.customer.domain.vo.CustomerDeptTreeVo;
 import org.dromara.customer.domain.vo.CustomerDeptVo;
 import org.dromara.customer.domain.bo.CustomerDeptBo;
 
@@ -14,7 +15,7 @@ import java.util.List;
  * @author LionLi
  * @date 2025-12-18
  */
-public interface ICustomerDeptService extends IService<CustomerDept>{
+public interface ICustomerDeptService extends IService<CustomerDept> {
 
     /**
      * 查询客户部门信息
@@ -24,7 +25,6 @@ public interface ICustomerDeptService extends IService<CustomerDept>{
      */
     CustomerDeptVo queryById(Long id);
 
-
     /**
      * 查询符合条件的客户部门信息列表
      *
@@ -33,6 +33,8 @@ public interface ICustomerDeptService extends IService<CustomerDept>{
      */
     List<CustomerDeptVo> queryList(CustomerDeptBo bo);
 
+    List<CustomerDeptTreeVo> getCustomerDeptTree(Long customerId);
+
     /**
      * 新增客户部门信息
      *

+ 4 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ICustomerInfoService.java

@@ -11,6 +11,8 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import java.math.BigDecimal;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * 客户信息Service接口
@@ -82,6 +84,8 @@ public interface ICustomerInfoService extends IService<CustomerInfo> {
     /*设置客户标签*/
     int setCustomerInfoTag(List<Long> customerIds, List<Long> tagIds);
 
+    Map<Long, String> selectCustomerNameByIds(Set<Long> ids);
+
     /**
      * 校验并批量删除客户信息信息
      *

+ 137 - 70
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerDeptServiceImpl.java

@@ -1,27 +1,33 @@
 package org.dromara.customer.service.impl;
 
-import cn.hutool.core.util.ObjectUtil;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.dromara.common.core.constant.SystemConstants;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.StringUtils;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.tree.Tree;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.dromara.common.redis.utils.SequenceUtils;
-import org.springframework.stereotype.Service;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.context.PlatformContext;
+import org.dromara.common.core.enums.IsDefault;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.customer.domain.CustomerDept;
+import org.dromara.customer.domain.CustomerInfo;
 import org.dromara.customer.domain.bo.CustomerDeptBo;
+import org.dromara.customer.domain.vo.CustomerDeptTreeVo;
 import org.dromara.customer.domain.vo.CustomerDeptVo;
-import org.dromara.customer.domain.CustomerDept;
 import org.dromara.customer.mapper.CustomerDeptMapper;
 import org.dromara.customer.service.ICustomerDeptService;
+import org.dromara.system.api.RemoteDeptService;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
-import java.time.Duration;
-import java.util.List;
-import java.util.Map;
-import java.util.Collection;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 客户部门信息Service业务层处理
@@ -34,6 +40,9 @@ import java.util.Collection;
 @Service
 public class CustomerDeptServiceImpl extends ServiceImpl<CustomerDeptMapper, CustomerDept> implements ICustomerDeptService {
 
+    @DubboReference
+    private RemoteDeptService remoteDeptService;
+
     private static final String DEPT_NO_KEY = "customer_dept:dept_no";
 
     private final CustomerDeptMapper baseMapper;
@@ -62,16 +71,64 @@ public class CustomerDeptServiceImpl extends ServiceImpl<CustomerDeptMapper, Cus
         return baseMapper.selectVoList(lqw);
     }
 
+    @Override
+    public List<CustomerDeptTreeVo> getCustomerDeptTree(Long customerId) {
+        if (customerId == null) {
+            return Collections.emptyList();
+        }
+
+        // 1. 查 customer_dept
+        List<CustomerDept> customerDepts = baseMapper.selectList(
+            new LambdaQueryWrapper<CustomerDept>()
+                .eq(CustomerDept::getCustomerId, customerId)
+        );
+
+        if (CollUtil.isEmpty(customerDepts)) {
+            return Collections.emptyList();
+        }
+
+        // 2. 查 sys_dept
+        List<Long> deptIds = customerDepts.stream()
+            .map(CustomerDept::getDeptId)
+            .collect(Collectors.toList());
+
+        List<RemoteDeptVo> sysDepts = remoteDeptService.selectDeptByIds(deptIds);
+
+        Map<Long, RemoteDeptVo> deptMap = sysDepts.stream()
+            .collect(Collectors.toMap(RemoteDeptVo::getDeptId, d -> d));
+
+        // 3. 合并 + 安全排序
+        return customerDepts.stream()
+            .filter(cd -> deptMap.containsKey(cd.getDeptId()))
+            .map(cd -> {
+                RemoteDeptVo sys = deptMap.get(cd.getDeptId());
+                CustomerDeptTreeVo vo = new CustomerDeptTreeVo();
+                vo.setDeptId(sys.getDeptId());
+                vo.setParentId(sys.getParentId());
+                vo.setDeptName(sys.getDeptName());
+                vo.setOrderNum(sys.getOrderNum()); // 可能为 null!
+                vo.setStatus(sys.getStatus());
+
+                vo.setYearlyBudget(cd.getYearlyBudget());
+                vo.setUsedBudget(cd.getUsedBudget());
+                vo.setMonthLimit(cd.getMonthLimit());
+                vo.setBindAddress(cd.getBindAddress());
+                vo.setBindStatus(cd.getBindStatus());
+
+                return vo;
+            })
+            .sorted(Comparator.comparing(
+                CustomerDeptTreeVo::getOrderNum,
+                Comparator.nullsLast(Comparator.naturalOrder()) // ✅ 安全处理 null
+            ))
+            .collect(Collectors.toList());
+    }
+
     private LambdaQueryWrapper<CustomerDept> buildQueryWrapper(CustomerDeptBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<CustomerDept> lqw = Wrappers.lambdaQuery();
-        lqw.orderByAsc(CustomerDept::getId);
-        lqw.eq(StringUtils.isNotBlank(bo.getDeptNo()), CustomerDept::getDeptNo, bo.getDeptNo());
-        lqw.like(StringUtils.isNotBlank(bo.getDeptName()), CustomerDept::getDeptName, bo.getDeptName());
-        lqw.eq(bo.getParentId() != null, CustomerDept::getParentId, bo.getParentId());
+        lqw.orderByAsc(CustomerDept::getDeptId);
         lqw.eq(bo.getCustomerId() != null, CustomerDept::getCustomerId, bo.getCustomerId());
-        lqw.eq(StringUtils.isNotBlank(bo.getAncestors()), CustomerDept::getAncestors, bo.getAncestors());
-        lqw.eq(bo.getDepartmentLevel() != null, CustomerDept::getDepartmentLevel, bo.getDepartmentLevel());
         lqw.eq(bo.getYearlyBudget() != null, CustomerDept::getYearlyBudget, bo.getYearlyBudget());
         lqw.eq(bo.getUsedBudget() != null, CustomerDept::getUsedBudget, bo.getUsedBudget());
         lqw.eq(bo.getMonthLimit() != null, CustomerDept::getMonthLimit, bo.getMonthLimit());
@@ -81,74 +138,84 @@ public class CustomerDeptServiceImpl extends ServiceImpl<CustomerDeptMapper, Cus
         lqw.eq(StringUtils.isNotBlank(bo.getDeptManage()), CustomerDept::getDeptManage, bo.getDeptManage());
         lqw.eq(StringUtils.isNotBlank(bo.getIsLimit()), CustomerDept::getIsLimit, bo.getIsLimit());
         lqw.eq(StringUtils.isNotBlank(bo.getSelectYear()), CustomerDept::getSelectYear, bo.getSelectYear());
-        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), CustomerDept::getStatus, bo.getStatus());
         lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), CustomerDept::getPlatformCode, bo.getPlatformCode());
         return lqw;
     }
 
-    /**
-     * 新增客户部门信息
-     *
-     * @param bo 客户部门信息
-     * @return 是否新增成功
-     */
+
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Boolean insertByBo(CustomerDeptBo bo) {
-        bo.setDeptNo(SequenceUtils.nextPaddedIdStr(DEPT_NO_KEY, Duration.ofDays(3650), 5));
+        try {
+            // 1. 参数校验
+            if (bo == null || bo.getCustomerId() == null) {
+                throw new IllegalArgumentException("客户ID不能为空");
+            }
 
-        CustomerDept info = baseMapper.selectById(bo.getParentId());
-        // 如果父节点不为正常状态,则不允许新增子节点
-        if (!SystemConstants.NORMAL.equals(info.getStatus())) {
-            throw new ServiceException("部门停用,不允许新增");
-        }
+            // 2. 构建并插入 sys_dept 部门结构
+            RemoteDeptVo remoteDeptVo = new RemoteDeptVo();
+            remoteDeptVo.setParentId(bo.getParentId());
+            remoteDeptVo.setDeptName(bo.getDeptName());
+            remoteDeptVo.setPlatformCode(PlatformContext.getPlatform());
+
+
+            RemoteDeptVo deptVo = remoteDeptService.insertDept(remoteDeptVo);
+
+            // 3. 校验 deptId 是否回填成功
+            if (deptVo == null || deptVo.getDeptId() == null) {
+                log.error("创建部门失败:未返回有效部门ID");
+            }
 
-        CustomerDept dept = MapstructUtils.convert(bo, CustomerDept.class);
-        dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId());
-        validEntityBeforeSave(dept);
-        boolean flag = baseMapper.insert(dept) > 0;
-        if (flag) {
-            bo.setId(dept.getId());
+            // 4. 插入 customer_dept 业务数据
+            CustomerDept dept = new CustomerDept();
+            dept.setDeptId(deptVo.getDeptId());
+            dept.setCustomerId(bo.getCustomerId());
+            dept.setYearlyBudget(bo.getYearlyBudget());
+            dept.setMonthLimit(bo.getMonthLimit());
+            dept.setUsedBudget(bo.getUsedBudget());
+            dept.setBindStatus(bo.getBindStatus());
+            dept.setBindAddress(bo.getBindAddress());
+
+            boolean success = baseMapper.insert(dept) > 0;
+            if (!success) {
+                log.error("创建部门失败:插入业务数据失败");
+            }
+            return success;
+        } catch (IllegalArgumentException e) {
+            log.error("创建部门失败:{}", e.getMessage());
+            throw new RuntimeException(e);
         }
-        return flag;
     }
 
-    /**
-     * 修改客户部门信息
-     *
-     * @param bo 客户部门信息
-     * @return 是否修改成功
-     */
     @Override
     public Boolean updateByBo(CustomerDeptBo bo) {
-        CustomerDept update = MapstructUtils.convert(bo, CustomerDept.class);
-        validEntityBeforeSave(update);
-        return baseMapper.updateById(update) > 0;
-    }
 
-    /**
-     * 保存前的数据校验
-     */
-    private boolean validEntityBeforeSave(CustomerDept dept) {
-        boolean exist = baseMapper.exists(new LambdaQueryWrapper<CustomerDept>()
-            .eq(CustomerDept::getDeptName, dept.getDeptName())
-            .eq(CustomerDept::getParentId, dept.getParentId())
-            .eq(CustomerDept::getPlatformCode, dept.getPlatformCode())
-            .ne(ObjectUtil.isNotNull(dept.getId()), CustomerDept::getId, dept.getId()));
-        return !exist;
+        if (bo == null || bo.getDeptId() == null || bo.getDeptId() <= 0) {
+            return false;
+        }
+        RemoteDeptVo remoteDeptVo = remoteDeptService.selectDeptById(bo.getDeptId());
+        if (remoteDeptVo == null) {
+            return false;
+        }
+
+        MapstructUtils.convert(bo, CustomerInfo.class);
+
+
+        // 1. 更新主表
+        CustomerInfo entity = MapstructUtils.convert(bo, CustomerInfo.class);
+//        boolean mainUpdated = baseMapper.updateById(entity) > 0;
+//        if (!mainUpdated) {
+//            return false;
+//        }
+//
+//        Long customerId = bo.getId();
+
+
+        return true;
     }
 
-    /**
-     * 校验并批量删除客户部门信息信息
-     *
-     * @param ids     待删除的主键集合
-     * @param isValid 是否进行有效性校验
-     * @return 是否删除成功
-     */
     @Override
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
-        if (isValid) {
-            //TODO 做一些业务上的校验,判断是否需要校验
-        }
-        return baseMapper.deleteByIds(ids) > 0;
+        return null;
     }
 }

+ 113 - 87
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerInfoServiceImpl.java

@@ -41,7 +41,8 @@ import java.util.stream.Collectors;
 @RequiredArgsConstructor
 @Service
 public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, CustomerInfo> implements ICustomerInfoService {
-
+    @DubboReference
+    private RemoteDeptService remoteDeptService;
     @DubboReference
     private RemoteComPostService remoteComPostService;
     @DubboReference
@@ -437,104 +438,105 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean insertByBo(CustomerInfoBo bo) {
-        if (bo == null) {
-            return false;
-        }
-        String platform = PlatformContext.getPlatform();
-//        RemoteDeptVo deptVo = remoteDeptService.selectParentDeptByPlatformCode(platform);
+        try {
+            if (bo == null) {
+                return false;
+            }
+            String platform = PlatformContext.getPlatform();
 
-        boolean isNew = bo.getId() == null || bo.getId() <= 0;
+            boolean isNew = bo.getId() == null || bo.getId() <= 0;
 
-        // 1. 处理主表 CustomerInfo
-        CustomerInfo entity = MapstructUtils.convert(bo, CustomerInfo.class);
-        validEntityBeforeSave(entity);
+            // 1. 处理主表 CustomerInfo
+            CustomerInfo entity = MapstructUtils.convert(bo, CustomerInfo.class);
+            validEntityBeforeSave(entity);
 
-        boolean success;
-        if (isNew) {
-            success = baseMapper.insert(entity) > 0;
-            if (success) {
-                bo.setId(entity.getId()); // 回填ID
+            boolean success;
+            if (isNew) {
+                success = baseMapper.insert(entity) > 0;
+                if (success) {
+                    bo.setId(entity.getId()); // 回填ID
+                }
+            } else {
+                success = baseMapper.updateById(entity) > 0;
             }
-        } else {
-            success = baseMapper.updateById(entity) > 0;
-        }
 
-        if (!success) {
-            return false;
-        }
+            if (!success) {
+                return false;
+            }
 
-        Long customerId = entity.getId();
-
-        /*新增客户时给每个客户创建自己的组织架构*/
-//        RemoteDeptVo remoteDeptVo = new RemoteDeptVo();
-//        remoteDeptVo.setParentId(deptVo.getDeptId());
-//        remoteDeptVo.setCustomerId(customerId);
-//        remoteDeptVo.setDeptName(bo.getCustomerName());
-//        remoteDeptVo.setPlatformCode(platform);
-//        remoteDeptService.insertDept(remoteDeptVo);
-        CustomerDept dept = new CustomerDept();
-        dept.setCustomerId(customerId);
-        dept.setDeptName(bo.getCustomerName());
-        dept.setParentId(0L);
-        dept.setYearlyBudget(BigDecimal.ZERO);
-        dept.setYearlyBudget(BigDecimal.ZERO);
-        dept.setMonthLimit(BigDecimal.ZERO);
-        dept.setUsedBudget(BigDecimal.ZERO);
-        dept.setStatus(IsDefault.No.getCode());
-        dept.setBindStatus(IsDefault.No.getCode());
-        customerDeptMapper.insert(dept);
-
-
-        // 2. 获取各子对象
-        CustomerBusinessInfoBo businessBo = bo.getCustomerBusinessBo();
-        CustomerSalesInfoBo salesBo = bo.getCustomerSalesInfoBo();
-        List<CustomerContactBo> contactList = bo.getCustomerContactBoList();
-        List<CustomerInvoiceInfoBo> invoiceList = bo.getCustomerInvoiceInfoBoList();
-
-        // 3. 如果是更新,先删除旧的关联数据
-        if (!isNew) {
-            // 删除业务信息(一对一)
-            customerBusinessInfoMapper.deleteByCustomerId(customerId);
-            // 删除销售信息(一对一)
-            customerSalesInfoMapper.deleteByCustomerId(customerId);
-            // 删除发票信息(一对多)
-            customerInvoiceInfoMapper.deleteByCustomerId(customerId);
-        }
-
-        // 4. 插入新的关联数据(即使为空也安全处理)
-        // 业务信息
-        if (businessBo != null) {
-            CustomerBusinessInfo businessEntity = MapstructUtils.convert(businessBo, CustomerBusinessInfo.class);
-            businessEntity.setCustomerId(customerId);
-            customerBusinessInfoMapper.insert(businessEntity);
-        }
+            Long customerId = entity.getId();
+
+            /*新增客户时给每个客户创建自己的组织架构*/
+            RemoteDeptVo remoteDeptVo = new RemoteDeptVo();
+            remoteDeptVo.setParentId(100L);
+            remoteDeptVo.setDeptName(bo.getCustomerName());
+            remoteDeptVo.setPlatformCode(platform);
+            RemoteDeptVo deptVo = remoteDeptService.insertDept(remoteDeptVo);
+
+            CustomerDept dept = new CustomerDept();
+            dept.setDeptId(deptVo.getDeptId());
+            dept.setCustomerId(customerId);
+            dept.setYearlyBudget(BigDecimal.ZERO);
+            dept.setMonthLimit(BigDecimal.ZERO);
+            dept.setUsedBudget(BigDecimal.ZERO);
+            dept.setBindStatus(IsDefault.No.getCode());
+            customerDeptMapper.insert(dept);
+
+
+            // 2. 获取各子对象
+            CustomerBusinessInfoBo businessBo = bo.getCustomerBusinessBo();
+            CustomerSalesInfoBo salesBo = bo.getCustomerSalesInfoBo();
+            List<CustomerContactBo> contactList = bo.getCustomerContactBoList();
+            List<CustomerInvoiceInfoBo> invoiceList = bo.getCustomerInvoiceInfoBoList();
+
+            // 3. 如果是更新,先删除旧的关联数据
+            if (!isNew) {
+                // 删除业务信息(一对一)
+                customerBusinessInfoMapper.deleteByCustomerId(customerId);
+                // 删除销售信息(一对一)
+                customerSalesInfoMapper.deleteByCustomerId(customerId);
+                // 删除发票信息(一对多)
+                customerInvoiceInfoMapper.deleteByCustomerId(customerId);
+            }
 
-        // 销售信息
-        if (salesBo != null) {
-            CustomerSalesInfo salesEntity = MapstructUtils.convert(salesBo, CustomerSalesInfo.class);
-            salesEntity.setCustomerId(customerId);
-            customerSalesInfoMapper.insert(salesEntity);
-        }
+            // 4. 插入新的关联数据(即使为空也安全处理)
+            // 业务信息
+            if (businessBo != null) {
+                CustomerBusinessInfo businessEntity = MapstructUtils.convert(businessBo, CustomerBusinessInfo.class);
+                businessEntity.setCustomerId(customerId);
+                customerBusinessInfoMapper.insert(businessEntity);
+            }
 
-        // 联系人列表
-        if (contactList != null && !contactList.isEmpty()) {
-            for (CustomerContactBo contactBo : contactList) {
-                CustomerContact contact = MapstructUtils.convert(contactBo, CustomerContact.class);
-                contact.setCustomerId(customerId);
-                customerContactMapper.insert(contact);
+            // 销售信息
+            if (salesBo != null) {
+                CustomerSalesInfo salesEntity = MapstructUtils.convert(salesBo, CustomerSalesInfo.class);
+                salesEntity.setCustomerId(customerId);
+                customerSalesInfoMapper.insert(salesEntity);
             }
-        }
 
-        // 发票信息列表
-        if (invoiceList != null && !invoiceList.isEmpty()) {
-            for (CustomerInvoiceInfoBo invoiceBo : invoiceList) {
-                CustomerInvoiceInfo invoice = MapstructUtils.convert(invoiceBo, CustomerInvoiceInfo.class);
-                invoice.setCustomerId(customerId);
-                customerInvoiceInfoMapper.insert(invoice);
+            // 联系人列表
+            if (contactList != null && !contactList.isEmpty()) {
+                for (CustomerContactBo contactBo : contactList) {
+                    CustomerContact contact = MapstructUtils.convert(contactBo, CustomerContact.class);
+                    contact.setCustomerId(customerId);
+                    customerContactMapper.insert(contact);
+                }
             }
-        }
 
-        return true;
+            // 发票信息列表
+            if (invoiceList != null && !invoiceList.isEmpty()) {
+                for (CustomerInvoiceInfoBo invoiceBo : invoiceList) {
+                    CustomerInvoiceInfo invoice = MapstructUtils.convert(invoiceBo, CustomerInvoiceInfo.class);
+                    invoice.setCustomerId(customerId);
+                    customerInvoiceInfoMapper.insert(invoice);
+                }
+            }
+            log.info("新增客户信息成功:{}", bo);
+            return true;
+        } catch (Exception e) {
+            log.error("新增客户信息失败:{}", e.getMessage());
+            throw new RuntimeException(e);
+        }
     }
 
     /**
@@ -687,6 +689,30 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         }
     }
 
+    public Map<Long, String> selectCustomerNameByIds(Set<Long> ids) {
+        if (ids == null || ids.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        // 限制批量大小
+        if (ids.size() > 1000) {
+            throw new IllegalArgumentException("Batch size exceeds limit: " + ids.size());
+        }
+
+        List<CustomerInfo> customerInfoList = baseMapper.selectByIds(ids);
+        Map<Long, String> resultMap = new HashMap<>(ids.size());
+
+        // 初始化所有请求的 ID 为 null
+        ids.forEach(id -> resultMap.put(id, null));
+
+        if (customerInfoList != null) {
+            customerInfoList.stream()
+                .filter(dept -> dept.getId() != null && dept.getCustomerName() != null)
+                .forEach(dept -> resultMap.put(dept.getId(), dept.getCustomerName()));
+        }
+
+        return resultMap;
+    }
 
     /**
      * 保存前的数据校验

+ 4 - 0
ruoyi-modules/ruoyi-order/pom.xml

@@ -112,6 +112,10 @@
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-api-order</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-customer</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 106 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderRevenueDetailController.java

@@ -0,0 +1,106 @@
+package org.dromara.order.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.order.domain.vo.OrderRevenueDetailVo;
+import org.dromara.order.domain.bo.OrderRevenueDetailBo;
+import org.dromara.order.service.IOrderRevenueDetailService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 收入单明细
+ * 前端访问路由地址为:/system/revenueDetail
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/revenueDetail")
+public class OrderRevenueDetailController extends BaseController {
+
+    private final IOrderRevenueDetailService orderRevenueDetailService;
+
+    /**
+     * 查询收入单明细列表
+     */
+//    @SaCheckPermission("order:revenueDetail:list")
+    @GetMapping("/list")
+    public TableDataInfo<OrderRevenueDetailVo> list(OrderRevenueDetailBo bo, PageQuery pageQuery) {
+        return orderRevenueDetailService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出收入单明细列表
+     */
+//    @SaCheckPermission("order:revenueDetail:export")
+    @Log(title = "收入单明细", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(OrderRevenueDetailBo bo, HttpServletResponse response) {
+        List<OrderRevenueDetailVo> list = orderRevenueDetailService.queryList(bo);
+        ExcelUtil.exportExcel(list, "收入单明细", OrderRevenueDetailVo.class, response);
+    }
+
+    /**
+     * 获取收入单明细详细信息
+     *
+     * @param id 主键
+     */
+//    @SaCheckPermission("order:revenueDetail:query")
+    @GetMapping("/{id}")
+    public R<OrderRevenueDetailVo> getInfo(@NotNull(message = "主键不能为空")
+                                           @PathVariable("id") Long id) {
+        return R.ok(orderRevenueDetailService.queryById(id));
+    }
+
+    /**
+     * 新增收入单明细
+     */
+//    @SaCheckPermission("order:revenueDetail:add")
+    @Log(title = "收入单明细", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody OrderRevenueDetailBo bo) {
+        return toAjax(orderRevenueDetailService.insertByBo(bo));
+    }
+
+    /**
+     * 修改收入单明细
+     */
+//    @SaCheckPermission("order:revenueDetail:edit")
+    @Log(title = "收入单明细", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody OrderRevenueDetailBo bo) {
+        return toAjax(orderRevenueDetailService.updateByBo(bo));
+    }
+
+    /**
+     * 删除收入单明细
+     *
+     * @param ids 主键串
+     */
+//    @SaCheckPermission("order:revenueDetail:remove")
+    @Log(title = "收入单明细", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(orderRevenueDetailService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 116 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderRevenueHeaderController.java

@@ -0,0 +1,116 @@
+package org.dromara.order.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.order.domain.vo.OrderRevenueHeaderVo;
+import org.dromara.order.domain.bo.OrderRevenueHeaderBo;
+import org.dromara.order.service.IOrderRevenueHeaderService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 收入单主
+ * 前端访问路由地址为:/system/revenueHeader
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/revenueHeader")
+public class OrderRevenueHeaderController extends BaseController {
+
+    private final IOrderRevenueHeaderService orderRevenueHeaderService;
+
+    /**
+     * 查询收入单主列表
+     */
+//    @SaCheckPermission("order:revenueHeader:list")
+    @GetMapping("/list")
+    public TableDataInfo<OrderRevenueHeaderVo> list(OrderRevenueHeaderBo bo, PageQuery pageQuery) {
+        return orderRevenueHeaderService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出收入单主列表
+     */
+//    @SaCheckPermission("order:revenueHeader:export")
+    @Log(title = "收入单主", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(OrderRevenueHeaderBo bo, HttpServletResponse response) {
+        List<OrderRevenueHeaderVo> list = orderRevenueHeaderService.queryList(bo);
+        ExcelUtil.exportExcel(list, "收入单主", OrderRevenueHeaderVo.class, response);
+    }
+
+    /**
+     * 获取收入单主详细信息
+     *
+     * @param id 主键
+     */
+//    @SaCheckPermission("order:revenueHeader:query")
+    @GetMapping("/{id}")
+    public R<OrderRevenueHeaderVo> getInfo(@NotNull(message = "主键不能为空")
+                                           @PathVariable("id") Long id) {
+        return R.ok(orderRevenueHeaderService.queryById(id));
+    }
+
+    /**
+     * 新增收入单主
+     */
+//    @SaCheckPermission("order:revenueHeader:add")
+    @Log(title = "收入单主", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody OrderRevenueHeaderBo bo) {
+        return toAjax(orderRevenueHeaderService.insertByBo(bo));
+    }
+
+    /**
+     * 修改收入单主
+     */
+//    @SaCheckPermission("order:revenueHeader:edit")
+    @Log(title = "收入单主", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody OrderRevenueHeaderBo bo) {
+        return toAjax(orderRevenueHeaderService.updateByBo(bo));
+    }
+
+    /**
+     * 删除收入单主
+     *
+     * @param ids 主键串
+     */
+//    @SaCheckPermission("order:revenueHeader:remove")
+    @Log(title = "收入单主", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(orderRevenueHeaderService.deleteWithValidByIds(List.of(ids), true));
+    }
+
+    /**
+     * 状态修改
+     */
+//    @SaCheckPermission("order:revenueHeader:edit")
+    @Log(title = "收入单主", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody OrderRevenueHeaderBo bo) {
+        return toAjax(orderRevenueHeaderService.updateStatus(bo));
+    }
+}

+ 103 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderRevenueDetail.java

@@ -0,0 +1,103 @@
+package org.dromara.order.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.math.BigDecimal;
+
+import java.io.Serial;
+
+/**
+ * 收入单明细对象 order_revenue_detail
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("order_revenue_detail")
+public class OrderRevenueDetail extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 关联的收入单id
+     */
+    private Long orderRevenueId;
+
+    /**
+     * 收入类型ID
+     */
+    private Long revenueId;
+
+    /**
+     * 收入明细编号
+     */
+    private String revenueCode;
+
+    /**
+     * 税率编码
+     */
+    private String taxRateCode;
+
+    /**
+     * 总金额
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 单价
+     */
+    private BigDecimal unitPrice;
+
+    /**
+     * 数量
+     */
+    private Long quantity;
+
+    /**
+     * 平台分账金额
+     */
+    private Long platformAmount;
+
+    /**
+     * 平台单价
+     */
+    private BigDecimal platformPrice;
+
+    /**
+     * 订单类型
+     */
+    private String orderType;
+
+    /**
+     * 明细附件文件路径
+     */
+    private String revFile;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 113 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderRevenueHeader.java

@@ -0,0 +1,113 @@
+package org.dromara.order.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 收入单主对象 order_revenue_header
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("order_revenue_header")
+public class OrderRevenueHeader extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 收入大类
+     */
+    private String revenueType;
+
+    /**
+     * 收入单号
+     */
+    private String orderRevenueCode;
+
+    /**
+     * 关联的主订单号
+     */
+    private String incomeOrderCode;
+
+    /**
+     * 其他收入子类型
+     */
+    private String otherRevenueType;
+
+    /**
+     * 客户id
+     */
+    private Long customerId;
+
+    private String customerName;
+
+    /*客户编号*/
+    private String customerCode;
+
+    private String supplierName;
+
+    private String companyName;
+
+    private String businessDept;
+
+    private String businessStaff;
+
+    private String customerService;
+
+
+    /**
+     * 供应商id
+     */
+    private Long supplierId;
+
+    /**
+     * 是否含税
+     */
+    private String isPrwTax;
+
+    /**
+     * 币种
+     */
+    private Long currencyId;
+
+    /**
+     * 推送状态
+     */
+    private String pushStatus;
+
+    /**
+     * 附件文件路径或URL
+     */
+    private String orderFile;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 5 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderMainBo.java

@@ -269,6 +269,11 @@ public class OrderMainBo extends BaseEntity {
      */
     private String remark;
 
+    /**
+     * 订单状态
+     */
+    private String orderStatuses;
+
     List<OrderProductBo> orderProductBos;
 
 

+ 95 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderRevenueDetailBo.java

@@ -0,0 +1,95 @@
+package org.dromara.order.domain.bo;
+
+import org.dromara.order.domain.OrderRevenueDetail;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.math.BigDecimal;
+
+/**
+ * 收入单明细业务对象 order_revenue_detail
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = OrderRevenueDetail.class, reverseConvertGenerate = false)
+public class OrderRevenueDetailBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 关联的收入单id
+     */
+    private Long orderRevenueId;
+
+    /**
+     * 收入类型ID
+     */
+    private Long revenueId;
+
+    /**
+     * 收入明细编号
+     */
+    private String revenueCode;
+
+    /**
+     * 税率编码
+     */
+    private String taxRateCode;
+
+    /**
+     * 总金额
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 单价
+     */
+    private BigDecimal unitPrice;
+
+    /**
+     * 数量
+     */
+    private Long quantity;
+
+    /**
+     * 平台分账金额
+     */
+    private Long platformAmount;
+
+    /**
+     * 平台单价
+     */
+    private BigDecimal platformPrice;
+
+    /**
+     * 订单类型
+     */
+    private String orderType;
+
+    /**
+     * 明细附件文件路径
+     */
+    private String revFile;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 112 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderRevenueHeaderBo.java

@@ -0,0 +1,112 @@
+package org.dromara.order.domain.bo;
+
+import org.dromara.order.domain.OrderRevenueDetail;
+import org.dromara.order.domain.OrderRevenueHeader;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+import java.util.List;
+
+/**
+ * 收入单主业务对象 order_revenue_header
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = OrderRevenueHeader.class, reverseConvertGenerate = false)
+public class OrderRevenueHeaderBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 收入大类
+     */
+    private String revenueType;
+
+    /**
+     * 收入单号
+     */
+    private String orderRevenueCode;
+
+    /**
+     * 关联的主订单号
+     */
+    private String incomeOrderCode;
+
+    /**
+     * 其他收入子类型
+     */
+    private String otherRevenueType;
+
+    /**
+     * 客户id
+     */
+    private Long customerId;
+
+    /**
+     * 客户名称
+     */
+    private String customerName;
+
+    /**
+     * 供应商id
+     */
+    private Long supplierId;
+
+    /**
+     * 是否含税
+     */
+    private String isPrwTax;
+
+    /**
+     * 币种
+     */
+    private Long currencyId;
+
+    /**
+     * 推送状态
+     */
+    private String pushStatus;
+
+    /**
+     * 附件文件路径或URL
+     */
+    private String orderFile;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /*客户编号*/
+    private String customerCode;
+
+    private String supplierName;
+
+    private String companyName;
+
+    private String businessDept;
+
+    private String businessStaff;
+
+    private String customerService;
+
+    private List<OrderRevenueDetailBo> orderRevenueDetails;
+
+
+}

+ 4 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderMainVo.java

@@ -325,6 +325,10 @@ public class OrderMainVo implements Serializable {
 
     private String dataSource;
 
+    private String createTime;
+
+    private String customerName;
+
     private List<OrderProductVo> orderProductList;
 
     private List<OrderDeliverProductVo> deliverProductList;

+ 118 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderRevenueDetailVo.java

@@ -0,0 +1,118 @@
+package org.dromara.order.domain.vo;
+
+import java.math.BigDecimal;
+import org.dromara.order.domain.OrderRevenueDetail;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 收入单明细视图对象 order_revenue_detail
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = OrderRevenueDetail.class)
+public class OrderRevenueDetailVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 关联的收入单id
+     */
+    @ExcelProperty(value = "关联的收入单id")
+    private Long orderRevenueId;
+
+    /**
+     * 收入类型ID
+     */
+    @ExcelProperty(value = "收入类型ID")
+    private Long revenueId;
+
+    /**
+     * 收入明细编号
+     */
+    @ExcelProperty(value = "收入明细编号")
+    private String revenueCode;
+
+    /**
+     * 税率编码
+     */
+    @ExcelProperty(value = "税率编码")
+    private String taxRateCode;
+
+    /**
+     * 总金额
+     */
+    @ExcelProperty(value = "总金额")
+    private BigDecimal totalAmount;
+
+    /**
+     * 单价
+     */
+    @ExcelProperty(value = "单价")
+    private BigDecimal unitPrice;
+
+    /**
+     * 数量
+     */
+    @ExcelProperty(value = "数量")
+    private Long quantity;
+
+    /**
+     * 平台分账金额
+     */
+    @ExcelProperty(value = "平台分账金额")
+    private Long platformAmount;
+
+    /**
+     * 平台单价
+     */
+    @ExcelProperty(value = "平台单价")
+    private BigDecimal platformPrice;
+
+    /**
+     * 订单类型
+     */
+    @ExcelProperty(value = "订单类型")
+    private String orderType;
+
+    /**
+     * 明细附件文件路径
+     */
+    @ExcelProperty(value = "明细附件文件路径")
+    private String revFile;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

+ 138 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderRevenueHeaderVo.java

@@ -0,0 +1,138 @@
+package org.dromara.order.domain.vo;
+
+import org.dromara.order.domain.OrderRevenueDetail;
+import org.dromara.order.domain.OrderRevenueHeader;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 收入单主视图对象 order_revenue_header
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = OrderRevenueHeader.class)
+public class OrderRevenueHeaderVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 收入大类
+     */
+    @ExcelProperty(value = "收入大类")
+    private String revenueType;
+
+    /**
+     * 收入单号
+     */
+    @ExcelProperty(value = "收入单号")
+    private String orderRevenueCode;
+
+    /**
+     * 关联的主订单号
+     */
+    @ExcelProperty(value = "关联的主订单号")
+    private String incomeOrderCode;
+
+    /**
+     * 其他收入子类型
+     */
+    @ExcelProperty(value = "其他收入子类型")
+    private String otherRevenueType;
+
+    /**
+     * 客户id
+     */
+    @ExcelProperty(value = "客户id")
+    private Long customerId;
+
+    /**
+     * 客户名称
+     */
+    private String customerName;
+
+    /**
+     * 供应商id
+     */
+    @ExcelProperty(value = "供应商id")
+    private Long supplierId;
+
+    /**
+     * 是否含税
+     */
+    @ExcelProperty(value = "是否含税", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_platform_yes_no")
+    private String isPrwTax;
+
+    /**
+     * 币种
+     */
+    @ExcelProperty(value = "币种")
+    private Long currencyId;
+
+    /**
+     * 推送状态
+     */
+    @ExcelProperty(value = "推送状态")
+    private String pushStatus;
+
+    /**
+     * 附件文件路径或URL
+     */
+    @ExcelProperty(value = "附件文件路径或URL")
+    private String orderFile;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+    private Date createTime;
+
+    /*客户编号*/
+    private String customerCode;
+
+    private String supplierName;
+
+    private String companyName;
+
+    private String businessDept;
+
+    private String businessStaff;
+
+    private String customerService;
+
+    private BigDecimal totalAmount;
+
+    private List<OrderRevenueDetailVo> orderRevenueDetailList;
+
+
+}

+ 21 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderRevenueDetailMapper.java

@@ -0,0 +1,21 @@
+package org.dromara.order.mapper;
+
+import org.apache.dubbo.remoting.http12.rest.Param;
+import org.dromara.order.domain.OrderRevenueDetail;
+import org.dromara.order.domain.vo.OrderDeliverProductVo;
+import org.dromara.order.domain.vo.OrderRevenueDetailVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+import java.util.List;
+
+/**
+ * 收入单明细Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface OrderRevenueDetailMapper extends BaseMapperPlus<OrderRevenueDetail, OrderRevenueDetailVo> {
+
+    void deleteByRevenueHeadId(@Param("orderRevenueId") Long orderRevenueId);
+
+}

+ 15 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderRevenueHeaderMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.order.mapper;
+
+import org.dromara.order.domain.OrderRevenueHeader;
+import org.dromara.order.domain.vo.OrderRevenueHeaderVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 收入单主Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface OrderRevenueHeaderMapper extends BaseMapperPlus<OrderRevenueHeader, OrderRevenueHeaderVo> {
+
+}

+ 70 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderRevenueDetailService.java

@@ -0,0 +1,70 @@
+package org.dromara.order.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.order.domain.OrderRevenueDetail;
+import org.dromara.order.domain.vo.OrderRevenueDetailVo;
+import org.dromara.order.domain.bo.OrderRevenueDetailBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 收入单明细Service接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface IOrderRevenueDetailService extends IService<OrderRevenueDetail>{
+
+    /**
+     * 查询收入单明细
+     *
+     * @param id 主键
+     * @return 收入单明细
+     */
+    OrderRevenueDetailVo queryById(Long id);
+
+    /**
+     * 分页查询收入单明细列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 收入单明细分页列表
+     */
+    TableDataInfo<OrderRevenueDetailVo> queryPageList(OrderRevenueDetailBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的收入单明细列表
+     *
+     * @param bo 查询条件
+     * @return 收入单明细列表
+     */
+    List<OrderRevenueDetailVo> queryList(OrderRevenueDetailBo bo);
+
+    /**
+     * 新增收入单明细
+     *
+     * @param bo 收入单明细
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(OrderRevenueDetailBo bo);
+
+    /**
+     * 修改收入单明细
+     *
+     * @param bo 收入单明细
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(OrderRevenueDetailBo bo);
+
+    /**
+     * 校验并批量删除收入单明细信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 75 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderRevenueHeaderService.java

@@ -0,0 +1,75 @@
+package org.dromara.order.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.order.domain.OrderRevenueHeader;
+import org.dromara.order.domain.vo.OrderRevenueHeaderVo;
+import org.dromara.order.domain.bo.OrderRevenueHeaderBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 收入单主Service接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface IOrderRevenueHeaderService extends IService<OrderRevenueHeader> {
+
+    /**
+     * 查询收入单主
+     *
+     * @param id 主键
+     * @return 收入单主
+     */
+    OrderRevenueHeaderVo queryById(Long id);
+
+    /**
+     * 分页查询收入单主列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 收入单主分页列表
+     */
+    TableDataInfo<OrderRevenueHeaderVo> queryPageList(OrderRevenueHeaderBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的收入单主列表
+     *
+     * @param bo 查询条件
+     * @return 收入单主列表
+     */
+    List<OrderRevenueHeaderVo> queryList(OrderRevenueHeaderBo bo);
+
+    /**
+     * 新增收入单主
+     *
+     * @param bo 收入单主
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(OrderRevenueHeaderBo bo);
+
+    /**
+     * 修改收入单主
+     *
+     * @param bo 收入单主
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(OrderRevenueHeaderBo bo);
+
+    /**
+     * 修改状态
+     */
+    int updateStatus(OrderRevenueHeaderBo bo);
+
+    /**
+     * 校验并批量删除收入单主信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 18 - 2
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java

@@ -7,11 +7,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.redis.utils.SequenceUtils;
+import org.dromara.customer.api.RemoteCustomerService;
 import org.dromara.order.domain.OrderMain;
 import org.dromara.order.domain.OrderProduct;
 import org.dromara.order.domain.bo.OrderMainBo;
@@ -30,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -43,6 +46,9 @@ import java.util.stream.Collectors;
 @Service
 public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain> implements IOrderMainService {
 
+    @DubboReference
+    private RemoteCustomerService remoteCustomerService;
+
     private final OrderMainMapper baseMapper;
 
     private final OrderProductMapper orderProductMapper;
@@ -91,6 +97,11 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         Page<OrderMainVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
         List<OrderMainVo> records = result.getRecords();
 
+        if (CollUtil.isNotEmpty(records)) {
+            Set<Long> customerIds = records.stream().map(OrderMainVo::getCustomerId).collect(Collectors.toSet());
+            Map<Long, String> customerMap = remoteCustomerService.selectCustomerNameByIds(customerIds);
+            records.forEach(orderMainVo -> orderMainVo.setCustomerName(customerMap.get(orderMainVo.getCustomerId())));
+        }
         return TableDataInfo.build(result);
     }
 
@@ -150,15 +161,20 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         lqw.eq(bo.getSignedQuantity() != null, OrderMain::getSignedQuantity, bo.getSignedQuantity());
         lqw.eq(bo.getAfterSaleCompleted() != null, OrderMain::getAfterSaleCompleted, bo.getAfterSaleCompleted());
         lqw.eq(bo.getAfterSalePending() != null, OrderMain::getAfterSalePending, bo.getAfterSalePending());
-        lqw.eq(StringUtils.isNotBlank(bo.getDeliveryDesc()), OrderMain::getDeliveryDesc, bo.getDeliveryDesc());
         lqw.eq(StringUtils.isNotBlank(bo.getPushStatus()), OrderMain::getPushStatus, bo.getPushStatus());
         lqw.eq(StringUtils.isNotBlank(bo.getAttachmentPath()), OrderMain::getAttachmentPath, bo.getAttachmentPath());
         lqw.eq(StringUtils.isNotBlank(bo.getDeliveryType()), OrderMain::getDeliveryType, bo.getDeliveryType());
         lqw.eq(StringUtils.isNotBlank(bo.getOrderCategory()), OrderMain::getOrderCategory, bo.getOrderCategory());
         lqw.eq(StringUtils.isNotBlank(bo.getProductCode()), OrderMain::getProductCode, bo.getProductCode());
-        lqw.eq(StringUtils.isNotBlank(bo.getCancelReason()), OrderMain::getCancelReason, bo.getCancelReason());
         lqw.eq(StringUtils.isNotBlank(bo.getExpenseType()), OrderMain::getExpenseType, bo.getExpenseType());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), OrderMain::getStatus, bo.getStatus());
+        if (params != null) {
+            lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
+                OrderMain::getCreateTime, params.get("beginTime"), params.get("endTime"));
+        }
+        if (null != bo.getOrderStatuses() && bo.getOrderStatuses().contains(",")) {
+            lqw.in(OrderMain::getOrderStatus, bo.getOrderStatuses().split(","));
+        }
         return lqw;
     }
 

+ 145 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderRevenueDetailServiceImpl.java

@@ -0,0 +1,145 @@
+package org.dromara.order.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.dromara.order.domain.bo.OrderRevenueDetailBo;
+import org.dromara.order.domain.vo.OrderRevenueDetailVo;
+import org.dromara.order.domain.OrderRevenueDetail;
+import org.dromara.order.mapper.OrderRevenueDetailMapper;
+import org.dromara.order.service.IOrderRevenueDetailService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 收入单明细Service业务层处理
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class OrderRevenueDetailServiceImpl  extends ServiceImpl<OrderRevenueDetailMapper, OrderRevenueDetail> implements IOrderRevenueDetailService {
+
+    private final OrderRevenueDetailMapper baseMapper;
+
+    /**
+     * 查询收入单明细
+     *
+     * @param id 主键
+     * @return 收入单明细
+     */
+    @Override
+    public OrderRevenueDetailVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询收入单明细列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 收入单明细分页列表
+     */
+    @Override
+    public TableDataInfo<OrderRevenueDetailVo> queryPageList(OrderRevenueDetailBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<OrderRevenueDetail> lqw = buildQueryWrapper(bo);
+        Page<OrderRevenueDetailVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的收入单明细列表
+     *
+     * @param bo 查询条件
+     * @return 收入单明细列表
+     */
+    @Override
+    public List<OrderRevenueDetailVo> queryList(OrderRevenueDetailBo bo) {
+        LambdaQueryWrapper<OrderRevenueDetail> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<OrderRevenueDetail> buildQueryWrapper(OrderRevenueDetailBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<OrderRevenueDetail> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(OrderRevenueDetail::getId);
+        lqw.eq(bo.getOrderRevenueId() != null, OrderRevenueDetail::getOrderRevenueId, bo.getOrderRevenueId());
+        lqw.eq(bo.getRevenueId() != null, OrderRevenueDetail::getRevenueId, bo.getRevenueId());
+        lqw.eq(StringUtils.isNotBlank(bo.getRevenueCode()), OrderRevenueDetail::getRevenueCode, bo.getRevenueCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getTaxRateCode()), OrderRevenueDetail::getTaxRateCode, bo.getTaxRateCode());
+        lqw.eq(bo.getTotalAmount() != null, OrderRevenueDetail::getTotalAmount, bo.getTotalAmount());
+        lqw.eq(bo.getUnitPrice() != null, OrderRevenueDetail::getUnitPrice, bo.getUnitPrice());
+        lqw.eq(bo.getQuantity() != null, OrderRevenueDetail::getQuantity, bo.getQuantity());
+        lqw.eq(bo.getPlatformAmount() != null, OrderRevenueDetail::getPlatformAmount, bo.getPlatformAmount());
+        lqw.eq(bo.getPlatformPrice() != null, OrderRevenueDetail::getPlatformPrice, bo.getPlatformPrice());
+        lqw.eq(StringUtils.isNotBlank(bo.getOrderType()), OrderRevenueDetail::getOrderType, bo.getOrderType());
+        lqw.eq(StringUtils.isNotBlank(bo.getRevFile()), OrderRevenueDetail::getRevFile, bo.getRevFile());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), OrderRevenueDetail::getStatus, bo.getStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), OrderRevenueDetail::getPlatformCode, bo.getPlatformCode());
+        return lqw;
+    }
+
+    /**
+     * 新增收入单明细
+     *
+     * @param bo 收入单明细
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(OrderRevenueDetailBo bo) {
+        OrderRevenueDetail add = MapstructUtils.convert(bo, OrderRevenueDetail.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改收入单明细
+     *
+     * @param bo 收入单明细
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(OrderRevenueDetailBo bo) {
+        OrderRevenueDetail update = MapstructUtils.convert(bo, OrderRevenueDetail.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(OrderRevenueDetail entity){
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除收入单明细信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 293 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderRevenueHeaderServiceImpl.java

@@ -0,0 +1,293 @@
+package org.dromara.order.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.SequenceUtils;
+import org.dromara.customer.api.RemoteCustomerService;
+import org.dromara.order.domain.OrderDeliverProduct;
+import org.dromara.order.domain.OrderRevenueDetail;
+import org.dromara.order.domain.OrderRevenueHeader;
+import org.dromara.order.domain.bo.OrderDeliverProductBo;
+import org.dromara.order.domain.bo.OrderRevenueDetailBo;
+import org.dromara.order.domain.bo.OrderRevenueHeaderBo;
+import org.dromara.order.domain.vo.OrderRevenueDetailVo;
+import org.dromara.order.domain.vo.OrderRevenueHeaderVo;
+import org.dromara.order.mapper.OrderRevenueDetailMapper;
+import org.dromara.order.mapper.OrderRevenueHeaderMapper;
+import org.dromara.order.service.IOrderRevenueHeaderService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 收入单主Service业务层处理
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class OrderRevenueHeaderServiceImpl extends ServiceImpl<OrderRevenueHeaderMapper, OrderRevenueHeader> implements IOrderRevenueHeaderService {
+
+    @DubboReference
+    private RemoteCustomerService remoteCustomerService;
+
+    private final OrderRevenueHeaderMapper baseMapper;
+
+    private final OrderRevenueDetailMapper orderRevenueDetailMapper;
+
+    /**
+     * 查询收入单主
+     *
+     * @param id 主键
+     * @return 收入单主
+     */
+    @Override
+    public OrderRevenueHeaderVo queryById(Long id) {
+        OrderRevenueHeaderVo orderRevenueHeaderVo = baseMapper.selectVoById(id);
+        orderRevenueHeaderVo.setOrderRevenueDetailList(orderRevenueDetailMapper.selectVoList(new LambdaQueryWrapper<OrderRevenueDetail>()
+            .eq(OrderRevenueDetail::getOrderRevenueId, id)));
+        return orderRevenueHeaderVo;
+    }
+
+    /**
+     * 分页查询收入单主列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 收入单主分页列表
+     */
+    @Override
+    public TableDataInfo<OrderRevenueHeaderVo> queryPageList(OrderRevenueHeaderBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<OrderRevenueHeader> lqw = buildQueryWrapper(bo);
+        Page<OrderRevenueHeaderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        List<OrderRevenueHeaderVo> records = result.getRecords();
+        if (CollUtil.isNotEmpty(records)) {
+            // 1. 提取所有主单 ID
+            List<Long> headerIds = records.stream()
+                .map(OrderRevenueHeaderVo::getId)
+                .collect(Collectors.toList());
+
+            // 2. 一次性查询所有相关明细(IN 查询)
+            List<OrderRevenueDetailVo> detailVos = orderRevenueDetailMapper.selectVoList(
+                new LambdaQueryWrapper<OrderRevenueDetail>()
+                    .in(OrderRevenueDetail::getOrderRevenueId, headerIds)
+            );
+
+            // 3. 按主单 ID 分组:Map<Long, List<OrderRevenueDetailVo>>
+            Map<Long, List<OrderRevenueDetailVo>> detailGroupMap = detailVos.stream()
+                .collect(Collectors.groupingBy(OrderRevenueDetailVo::getOrderRevenueId));
+
+            // 4. 为每个主单设置 totalAmount
+            for (OrderRevenueHeaderVo record : records) {
+                List<OrderRevenueDetailVo> details = detailGroupMap.get(record.getId());
+                if (CollUtil.isNotEmpty(details)) {
+                    BigDecimal total = details.stream()
+                        .map(OrderRevenueDetailVo::getTotalAmount)
+                        .filter(Objects::nonNull) // 防止空值导致 NPE
+                        .reduce(BigDecimal.ZERO, BigDecimal::add);
+                    record.setTotalAmount(total);
+                } else {
+                    record.setTotalAmount(BigDecimal.ZERO); // 无明细时设为 0
+                }
+            }
+        }
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的收入单主列表
+     *
+     * @param bo 查询条件
+     * @return 收入单主列表
+     */
+    @Override
+    public List<OrderRevenueHeaderVo> queryList(OrderRevenueHeaderBo bo) {
+        LambdaQueryWrapper<OrderRevenueHeader> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<OrderRevenueHeader> buildQueryWrapper(OrderRevenueHeaderBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<OrderRevenueHeader> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(OrderRevenueHeader::getId);
+        lqw.eq(StringUtils.isNotBlank(bo.getRevenueType()), OrderRevenueHeader::getRevenueType, bo.getRevenueType());
+        lqw.eq(StringUtils.isNotBlank(bo.getOrderRevenueCode()), OrderRevenueHeader::getOrderRevenueCode, bo.getOrderRevenueCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getIncomeOrderCode()), OrderRevenueHeader::getIncomeOrderCode, bo.getIncomeOrderCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getOtherRevenueType()), OrderRevenueHeader::getOtherRevenueType, bo.getOtherRevenueType());
+        lqw.like(StringUtils.isNotBlank(bo.getBusinessStaff()), OrderRevenueHeader::getBusinessStaff, bo.getBusinessStaff());
+        lqw.like(StringUtils.isNotBlank(bo.getCustomerService()), OrderRevenueHeader::getCustomerService, bo.getCustomerService());
+        lqw.eq(bo.getCustomerId() != null, OrderRevenueHeader::getCustomerId, bo.getCustomerId());
+        lqw.eq(bo.getSupplierId() != null, OrderRevenueHeader::getSupplierId, bo.getSupplierId());
+        lqw.eq(StringUtils.isNotBlank(bo.getIsPrwTax()), OrderRevenueHeader::getIsPrwTax, bo.getIsPrwTax());
+        lqw.eq(bo.getCurrencyId() != null, OrderRevenueHeader::getCurrencyId, bo.getCurrencyId());
+        lqw.eq(StringUtils.isNotBlank(bo.getPushStatus()), OrderRevenueHeader::getPushStatus, bo.getPushStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getOrderFile()), OrderRevenueHeader::getOrderFile, bo.getOrderFile());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), OrderRevenueHeader::getStatus, bo.getStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), OrderRevenueHeader::getPlatformCode, bo.getPlatformCode());
+        if (null != bo.getSearchValue()) {
+            String keyword = bo.getSearchValue().trim();
+            lqw.and(wrapper -> wrapper
+                .like(OrderRevenueHeader::getCustomerName, keyword)
+                .or()
+                .like(OrderRevenueHeader::getOrderRevenueCode, keyword)
+                .or()
+                .like(OrderRevenueHeader::getIncomeOrderCode, keyword)
+                .or()
+                .like(OrderRevenueHeader::getSupplierName, keyword)
+            );
+        }
+        return lqw;
+    }
+
+    /**
+     * 新增收入单主
+     *
+     * @param bo 收入单主
+     * @return 是否新增成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertByBo(OrderRevenueHeaderBo bo) {
+        if (bo == null) {
+            log.warn("新增收入单失败:入参为空");
+            return false;
+        }
+
+        // 生成单号
+        bo.setOrderRevenueCode(SequenceUtils.generateOrderCode("OR"));
+
+        // 转换并校验
+        OrderRevenueHeader entity = MapstructUtils.convert(bo, OrderRevenueHeader.class);
+        validEntityBeforeSave(entity);
+
+        // 插入主表
+        boolean inserted = baseMapper.insert(entity) > 0;
+        if (!inserted) {
+            log.warn("插入收入单主表失败");
+            return false;
+        }
+
+        // 保存明细
+        saveOrderRevenueDetails(entity.getId(), bo.getOrderRevenueDetails(), false);
+
+        log.info("新增收入单成功,单号: {}", entity.getOrderRevenueCode());
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateByBo(OrderRevenueHeaderBo bo) {
+        if (bo == null || bo.getId() == null) {
+            log.warn("修改收入单失败:BO 或 ID 为空");
+            return false;
+        }
+
+        // 检查主表记录是否存在
+        if (baseMapper.selectById(bo.getId()) == null) {
+            log.warn("修改收入单失败:主表记录不存在,ID={}", bo.getId());
+            return false;
+        }
+
+        // 转换并校验
+        OrderRevenueHeader entity = MapstructUtils.convert(bo, OrderRevenueHeader.class);
+        validEntityBeforeSave(entity);
+
+        // 更新主表
+        boolean updated = baseMapper.updateById(entity) > 0;
+        if (!updated) {
+            log.warn("更新收入单主表失败,ID={}", bo.getId());
+            return false;
+        }
+
+        // 先删后插明细
+        saveOrderRevenueDetails(bo.getId(), bo.getOrderRevenueDetails(), true);
+
+        log.info("修改收入单成功,ID: {}", bo.getId());
+        return true;
+    }
+
+    /**
+     * 保存收入单明细
+     *
+     * @param orderRevenueId 主表ID
+     * @param detailList     明细列表
+     * @param deleteFirst    是否先删除已有明细(true=编辑模式)
+     */
+    private void saveOrderRevenueDetails(Long orderRevenueId, List<OrderRevenueDetailBo> detailList, boolean deleteFirst) {
+        if (orderRevenueId == null) {
+            return;
+        }
+
+        if (deleteFirst) {
+            orderRevenueDetailMapper.deleteByRevenueHeadId(orderRevenueId);
+        }
+
+        if (detailList == null || detailList.isEmpty()) {
+            return;
+        }
+
+        List<OrderRevenueDetail> details = detailList.stream()
+            .filter(Objects::nonNull) // 防止空元素
+            .map(bo -> {
+                OrderRevenueDetail detail = MapstructUtils.convert(bo, OrderRevenueDetail.class);
+                detail.setOrderRevenueId(orderRevenueId);
+                return detail;
+            })
+            .collect(Collectors.toList());
+
+        if (!details.isEmpty()) {
+            orderRevenueDetailMapper.insertBatch(details);
+        }
+    }
+
+    /**
+     * 修改状态
+     *
+     * @param bo 信息
+     * @return 结果
+     */
+    @Override
+    public int updateStatus(OrderRevenueHeaderBo bo) {
+        OrderRevenueHeader header = new OrderRevenueHeader();
+        header.setId(bo.getId());
+        header.setStatus(bo.getStatus());
+        return baseMapper.updateById(header);
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(OrderRevenueHeader entity) {
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除收入单主信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 14 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderRevenueDetailMapper.xml

@@ -0,0 +1,14 @@
+<?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="org.dromara.order.mapper.OrderRevenueDetailMapper">
+
+    <delete id="deleteByRevenueId" parameterType="java.lang.Long">
+        DELETE
+        FROM order_revenue_detail
+        WHERE order_revenue_id = #{orderRevenueId}
+    </delete>
+
+
+</mapper>

+ 7 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderRevenueHeaderMapper.xml

@@ -0,0 +1,7 @@
+<?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="org.dromara.order.mapper.OrderRevenueHeaderMapper">
+
+</mapper>

+ 36 - 23
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseServiceImpl.java

@@ -30,8 +30,10 @@ import org.dromara.product.service.IProductBaseService;
 import java.util.List;
 import java.util.Map;
 import java.util.Collection;
+
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.core.type.TypeReference;
+
 import java.math.BigDecimal;
 
 /**
@@ -43,7 +45,7 @@ import java.math.BigDecimal;
 @Slf4j
 @RequiredArgsConstructor
 @Service
-public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, ProductBase> implements IProductBaseService {
+public class ProductBaseServiceImpl extends ServiceImpl<ProductBaseMapper, ProductBase> implements IProductBaseService {
 
     //产品基础信息Mapper
     private final ProductBaseMapper baseMapper;
@@ -70,7 +72,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
      * @return 产品基础信息
      */
     @Override
-    public ProductBaseVo queryById(Long id){
+    public ProductBaseVo queryById(Long id) {
         // 1. 查询基础信息
         ProductBaseVo vo = baseMapper.selectVoById(id);
         if (vo == null) {
@@ -78,17 +80,17 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
         //获取分类信息
         ProductCategory productCategory = categoryMapper.selectById(vo.getBottomCategoryId());
-        if (ObjectUtil.isNotEmpty(productCategory)){
+        if (ObjectUtil.isNotEmpty(productCategory)) {
             vo.setCategoryName(productCategory.getCategoryName());
         }
         //获取品牌信息
         ProductBrand productBrand = brandMapper.selectById(vo.getBrandId());
-        if (ObjectUtil.isNotEmpty(productBrand)){
+        if (ObjectUtil.isNotEmpty(productBrand)) {
             vo.setBrandName(productBrand.getBrandName());
         }
         //获取单位信息
         ProductUnit productUnit = unitMapper.selectById(vo.getUnitId());
-        if (ObjectUtil.isNotEmpty(productUnit)){
+        if (ObjectUtil.isNotEmpty(productUnit)) {
             vo.setUnitName(productUnit.getUnitName());
         }
         // 2. 查询并填充扩展信息(product_extend表)
@@ -210,7 +212,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<ProductBase> lqw = Wrappers.lambdaQuery();
         lqw.orderByAsc(ProductBase::getId);
-        lqw.in(StringUtils.isNotBlank(bo.getProductIds()), ProductBase::getId, bo.getProductIds().split( ","));
+        // lqw.in(StringUtils.isNotBlank(bo.getProductIds()), ProductBase::getId, bo.getProductIds().split( ","));
         lqw.eq(StringUtils.isNotBlank(bo.getProductNo()), ProductBase::getProductNo, bo.getProductNo());
         lqw.like(StringUtils.isNotBlank(bo.getItemName()), ProductBase::getItemName, bo.getItemName());
         lqw.eq(bo.getBrandId() != null, ProductBase::getBrandId, bo.getBrandId());
@@ -374,7 +376,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         extend.setVolumeUnit(bo.getVolumeUnit());
         extend.setAfterSalesService(bo.getAfterSalesService());
         extend.setReferenceLink(bo.getReferenceLink());
-        extend.setIsCustomize(bo.getCustomizable()?"1":"0");
+        extend.setIsCustomize(bo.getCustomizable() ? "1" : "0");
         extend.setCustomDescription(bo.getCustomDescription());
         // 直接使用前端传递的服务保障ID列表(逗号分隔)
         extend.setServiceGuarantee(bo.getServiceGuarantee());
@@ -474,7 +476,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     /**
      * 保存前的数据校验
      */
-    private void validEntityBeforeSave(ProductBase entity){
+    private void validEntityBeforeSave(ProductBase entity) {
         // 校验产品编号唯一性(新增时)
         if (entity.getId() == null && StringUtils.isNotBlank(entity.getProductNo())) {
             LambdaQueryWrapper<ProductBase> wrapper = Wrappers.lambdaQuery();
@@ -522,7 +524,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
-        if(isValid){
+        if (isValid) {
             // 校验是否有关联的订单或其他业务数据
             for (Long id : ids) {
                 ProductBase product = baseMapper.selectById(id);
@@ -584,7 +586,8 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
                 // 解析JSON数组为List<Map>
                 List<Map<String, Object>> customDetailsList = objectMapper.readValue(
                     bo.getCustomDetailsJson(),
-                    new TypeReference<List<Map<String, Object>>>() {}
+                    new TypeReference<List<Map<String, Object>>>() {
+                    }
                 );
 
                 // 遍历每条定制详情,保存为独立记录
@@ -639,10 +642,14 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     private String mapDecorationMethodToValue(String decorationMethod) {
         if (decorationMethod == null) return null;
         switch (decorationMethod) {
-            case "包装定制": return "0";
-            case "商品定制": return "1";
-            case "开模定制": return "2";
-            default: return decorationMethod;
+            case "包装定制":
+                return "0";
+            case "商品定制":
+                return "1";
+            case "开模定制":
+                return "2";
+            default:
+                return decorationMethod;
         }
     }
 
@@ -652,12 +659,18 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     private String mapCraftToValue(String craft) {
         if (craft == null) return null;
         switch (craft) {
-            case "丝印": return "0";
-            case "热转印": return "1";
-            case "激光": return "2";
-            case "烤花": return "3";
-            case "压印": return "4";
-            default: return craft;
+            case "丝印":
+                return "0";
+            case "热转印":
+                return "1";
+            case "激光":
+                return "2";
+            case "烤花":
+                return "3";
+            case "压印":
+                return "4";
+            default:
+                return craft;
         }
     }
 
@@ -692,15 +705,15 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     /**
      * 修改商品上架状态
      *
-     * @param productId  商品id
+     * @param productId 商品id
      */
     @Override
     public ProductBaseVo updateProductShelfState(Long productId) {
         ProductBaseVo productBase = baseMapper.selectVoById(productId);
 
-        if(productBase.getProductStatus().equals("1")){
+        if (productBase.getProductStatus().equals("1")) {
             productBase.setProductStatus("0");
-        }else{
+        } else {
             productBase.setProductStatus("1");
         }
         baseMapper.update(Wrappers.lambdaUpdate(ProductBase.class)

+ 117 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/ComCurrencyController.java

@@ -0,0 +1,117 @@
+package org.dromara.system.controller.system;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.system.domain.bo.OrderPaySetBo;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.system.domain.vo.ComCurrencyVo;
+import org.dromara.system.domain.bo.ComCurrencyBo;
+import org.dromara.system.service.IComCurrencyService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 交易币别配置
+ * 前端访问路由地址为:/system/comCurrency
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/comCurrency")
+public class ComCurrencyController extends BaseController {
+
+    private final IComCurrencyService comCurrencyService;
+
+    /**
+     * 查询交易币别配置列表
+     */
+//    @SaCheckPermission("system:comCurrency:list")
+    @GetMapping("/list")
+    public TableDataInfo<ComCurrencyVo> list(ComCurrencyBo bo, PageQuery pageQuery) {
+        return comCurrencyService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出交易币别配置列表
+     */
+//    @SaCheckPermission("system:comCurrency:export")
+    @Log(title = "交易币别配置", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(ComCurrencyBo bo, HttpServletResponse response) {
+        List<ComCurrencyVo> list = comCurrencyService.queryList(bo);
+        ExcelUtil.exportExcel(list, "交易币别配置", ComCurrencyVo.class, response);
+    }
+
+    /**
+     * 获取交易币别配置详细信息
+     *
+     * @param id 主键
+     */
+//    @SaCheckPermission("system:comCurrency:query")
+    @GetMapping("/{id}")
+    public R<ComCurrencyVo> getInfo(@NotNull(message = "主键不能为空")
+                                    @PathVariable("id") Long id) {
+        return R.ok(comCurrencyService.queryById(id));
+    }
+
+    /**
+     * 新增交易币别配置
+     */
+    @SaCheckPermission("system:comCurrency:add")
+    @Log(title = "交易币别配置", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody ComCurrencyBo bo) {
+        return toAjax(comCurrencyService.insertByBo(bo));
+    }
+
+    /**
+     * 修改交易币别配置
+     */
+    @SaCheckPermission("system:comCurrency:edit")
+    @Log(title = "交易币别配置", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ComCurrencyBo bo) {
+        return toAjax(comCurrencyService.updateByBo(bo));
+    }
+
+    /**
+     * 删除交易币别配置
+     *
+     * @param ids 主键串
+     */
+    @SaCheckPermission("system:comCurrency:remove")
+    @Log(title = "交易币别配置", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(comCurrencyService.deleteWithValidByIds(List.of(ids), true));
+    }
+
+    /**
+     * 状态修改
+     */
+    @SaCheckPermission("system:comCurrency:edit")
+    @Log(title = "交易币别配置", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody ComCurrencyBo bo) {
+        return toAjax(comCurrencyService.updateStatus(bo));
+    }
+}

+ 118 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/ComRevenueExpenseController.java

@@ -0,0 +1,118 @@
+package org.dromara.system.controller.system;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.system.domain.bo.ComCurrencyBo;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.system.domain.vo.ComRevenueExpenseVo;
+import org.dromara.system.domain.bo.ComRevenueExpenseBo;
+import org.dromara.system.service.IComRevenueExpenseService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 收入费用设定
+ * 前端访问路由地址为:/system/revenueExpense
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/revenueExpense")
+public class ComRevenueExpenseController extends BaseController {
+
+    private final IComRevenueExpenseService comRevenueExpenseService;
+
+    /**
+     * 查询收入费用设定列表
+     */
+//    @SaCheckPermission("system:revenueExpense:list")
+    @GetMapping("/list")
+    public TableDataInfo<ComRevenueExpenseVo> list(ComRevenueExpenseBo bo, PageQuery pageQuery) {
+        return comRevenueExpenseService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出收入费用设定列表
+     */
+    @SaCheckPermission("system:revenueExpense:export")
+    @Log(title = "收入费用设定", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(ComRevenueExpenseBo bo, HttpServletResponse response) {
+        List<ComRevenueExpenseVo> list = comRevenueExpenseService.queryList(bo);
+        ExcelUtil.exportExcel(list, "收入费用设定", ComRevenueExpenseVo.class, response);
+    }
+
+    /**
+     * 获取收入费用设定详细信息
+     *
+     * @param id 主键
+     */
+    @SaCheckPermission("system:revenueExpense:query")
+    @GetMapping("/{id}")
+    public R<ComRevenueExpenseVo> getInfo(@NotNull(message = "主键不能为空")
+                                          @PathVariable("id") Long id) {
+        return R.ok(comRevenueExpenseService.queryById(id));
+    }
+
+    /**
+     * 新增收入费用设定
+     */
+    @SaCheckPermission("system:revenueExpense:add")
+    @Log(title = "收入费用设定", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody ComRevenueExpenseBo bo) {
+        return toAjax(comRevenueExpenseService.insertByBo(bo));
+    }
+
+    /**
+     * 修改收入费用设定
+     */
+    @SaCheckPermission("system:revenueExpense:edit")
+    @Log(title = "收入费用设定", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ComRevenueExpenseBo bo) {
+        return toAjax(comRevenueExpenseService.updateByBo(bo));
+    }
+
+    /**
+     * 删除收入费用设定
+     *
+     * @param ids 主键串
+     */
+    @SaCheckPermission("system:revenueExpense:remove")
+    @Log(title = "收入费用设定", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(comRevenueExpenseService.deleteWithValidByIds(List.of(ids), true));
+    }
+
+
+    /**
+     * 状态修改
+     */
+    @SaCheckPermission("system:revenueExpense:edit")
+    @Log(title = "收入费用设定", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody ComCurrencyBo bo) {
+        return toAjax(comRevenueExpenseService.updateStatus(bo));
+    }
+}

+ 67 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/ComCurrency.java

@@ -0,0 +1,67 @@
+package org.dromara.system.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 交易币别配置对象 com_currency
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("com_currency")
+public class ComCurrency extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 货币编码
+     */
+    private String currencyCode;
+
+    /**
+     * 货币名称
+     */
+    private String currencyName;
+
+    /**
+     * 是否显示(0-显示,1-不显示)
+     */
+    private String isShow;
+
+    /**
+     * 数据来源
+     */
+    private String dataSource;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 77 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/ComRevenueExpense.java

@@ -0,0 +1,77 @@
+package org.dromara.system.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 收入费用设定对象 com_revenue_expense
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("com_revenue_expense")
+public class ComRevenueExpense extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 编码
+     */
+    private String revenueCode;
+
+    /**
+     * 费用名称
+     */
+    private String revenueName;
+
+    /**
+     * 费用类(0 是  1否)
+     */
+    private String expenseFlag;
+
+    /**
+     * 收入类(0 是  1否)
+     */
+    private String revenueFlag;
+
+    /**
+     * 是否显示(0-显示,1-不显示)
+     */
+    private String isShow;
+
+    /**
+     * 数据来源
+     */
+    private String dataSource;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 60 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/ComCurrencyBo.java

@@ -0,0 +1,60 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.system.domain.ComCurrency;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 交易币别配置业务对象 com_currency
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ComCurrency.class, reverseConvertGenerate = false)
+public class ComCurrencyBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 货币编码
+     */
+    private String currencyCode;
+
+    /**
+     * 货币名称
+     */
+    @NotBlank(message = "货币名称不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String currencyName;
+
+    /**
+     * 是否显示(0-显示,1-不显示)
+     */
+    private String isShow;
+
+    /**
+     * 数据来源
+     */
+    private String dataSource;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 72 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/ComRevenueExpenseBo.java

@@ -0,0 +1,72 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.system.domain.ComRevenueExpense;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 收入费用设定业务对象 com_revenue_expense
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ComRevenueExpense.class, reverseConvertGenerate = false)
+public class ComRevenueExpenseBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 编码
+     */
+    private String revenueCode;
+
+    /**
+     * 费用名称
+     */
+    @NotBlank(message = "费用名称不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String revenueName;
+
+    /**
+     * 费用类(0 是  1否)
+     */
+    @NotBlank(message = "费用类(0 是  1否)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String expenseFlag;
+
+    /**
+     * 收入类(0 是  1否)
+     */
+    @NotBlank(message = "收入类(0 是  1否)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String revenueFlag;
+
+    /**
+     * 是否显示(0-显示,1-不显示)
+     */
+    private String isShow;
+
+    /**
+     * 数据来源
+     */
+    private String dataSource;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 76 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ComCurrencyVo.java

@@ -0,0 +1,76 @@
+package org.dromara.system.domain.vo;
+
+import org.dromara.system.domain.ComCurrency;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 交易币别配置视图对象 com_currency
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ComCurrency.class)
+public class ComCurrencyVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 货币编码
+     */
+    @ExcelProperty(value = "货币编码")
+    private String currencyCode;
+
+    /**
+     * 货币名称
+     */
+    @ExcelProperty(value = "货币名称")
+    private String currencyName;
+
+    /**
+     * 是否显示(0-显示,1-不显示)
+     */
+    @ExcelProperty(value = "是否显示", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_platform_yes_no")
+    private String isShow;
+
+    /**
+     * 数据来源
+     */
+    @ExcelProperty(value = "数据来源")
+    private String dataSource;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

+ 90 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ComRevenueExpenseVo.java

@@ -0,0 +1,90 @@
+package org.dromara.system.domain.vo;
+
+import org.dromara.system.domain.ComRevenueExpense;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 收入费用设定视图对象 com_revenue_expense
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ComRevenueExpense.class)
+public class ComRevenueExpenseVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 编码
+     */
+    @ExcelProperty(value = "编码")
+    private String revenueCode;
+
+    /**
+     * 费用名称
+     */
+    @ExcelProperty(value = "费用名称")
+    private String revenueName;
+
+    /**
+     * 费用类(0 是  1否)
+     */
+    @ExcelProperty(value = "费用类(0 是  1否)", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_platform_yes_no")
+    private String expenseFlag;
+
+    /**
+     * 收入类(0 是  1否)
+     */
+    @ExcelProperty(value = "收入类(0 是  1否)", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_platform_yes_no")
+    private String revenueFlag;
+
+    /**
+     * 是否显示(0-显示,1-不显示)
+     */
+    @ExcelProperty(value = "是否显示", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_platform_yes_no")
+    private String isShow;
+
+    /**
+     * 数据来源
+     */
+    @ExcelProperty(value = "数据来源")
+    private String dataSource;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

+ 26 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java

@@ -1,6 +1,7 @@
 package org.dromara.system.dubbo;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.lang.tree.Tree;
 import lombok.RequiredArgsConstructor;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.dromara.system.api.RemoteDeptService;
@@ -73,4 +74,29 @@ public class RemoteDeptServiceImpl implements RemoteDeptService {
         sysDeptService.insertDept(dept);
         return BeanUtil.copyProperties(dept, RemoteDeptVo.class);
     }
+
+    @Override
+    public List<RemoteDeptVo> selectDeptByIds(List<Long> deptIds) {
+        List<SysDeptVo> sysDeptVos = sysDeptService.selectDeptByIds(deptIds);
+        return BeanUtil.copyToList(sysDeptVos, RemoteDeptVo.class);
+    }
+
+    @Override
+    public List<Tree<Long>> selectDeptTreeList(RemoteDeptVo dept) {
+        SysDeptBo sysDeptBo = BeanUtil.copyProperties(dept, SysDeptBo.class);
+        List<Tree<Long>> trees = sysDeptService.selectDeptTreeList(sysDeptBo);
+        return trees;
+    }
+
+    @Override
+    public List<Tree<Long>> buildDeptTreeSelect(List<RemoteDeptVo> depts) {
+        List<Tree<Long>> trees = sysDeptService.buildDeptTreeSelect(BeanUtil.copyToList(depts, SysDeptVo.class));
+        return trees;
+    }
+
+    @Override
+    public RemoteDeptVo selectDeptById(Long deptId) {
+        SysDeptVo sysDeptVo = sysDeptService.selectDeptById(deptId);
+        return BeanUtil.copyProperties(sysDeptVo, RemoteDeptVo.class);
+    }
 }

+ 15 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/ComCurrencyMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.system.mapper;
+
+import org.dromara.system.domain.ComCurrency;
+import org.dromara.system.domain.vo.ComCurrencyVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 交易币别配置Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface ComCurrencyMapper extends BaseMapperPlus<ComCurrency, ComCurrencyVo> {
+
+}

+ 15 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/ComRevenueExpenseMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.system.mapper;
+
+import org.dromara.system.domain.ComRevenueExpense;
+import org.dromara.system.domain.vo.ComRevenueExpenseVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 收入费用设定Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface ComRevenueExpenseMapper extends BaseMapperPlus<ComRevenueExpense, ComRevenueExpenseVo> {
+
+}

+ 76 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IComCurrencyService.java

@@ -0,0 +1,76 @@
+package org.dromara.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.system.domain.ComCurrency;
+import org.dromara.system.domain.bo.OrderPaySetBo;
+import org.dromara.system.domain.vo.ComCurrencyVo;
+import org.dromara.system.domain.bo.ComCurrencyBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 交易币别配置Service接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface IComCurrencyService extends IService<ComCurrency> {
+
+    /**
+     * 查询交易币别配置
+     *
+     * @param id 主键
+     * @return 交易币别配置
+     */
+    ComCurrencyVo queryById(Long id);
+
+    /**
+     * 分页查询交易币别配置列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 交易币别配置分页列表
+     */
+    TableDataInfo<ComCurrencyVo> queryPageList(ComCurrencyBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的交易币别配置列表
+     *
+     * @param bo 查询条件
+     * @return 交易币别配置列表
+     */
+    List<ComCurrencyVo> queryList(ComCurrencyBo bo);
+
+    /**
+     * 新增交易币别配置
+     *
+     * @param bo 交易币别配置
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(ComCurrencyBo bo);
+
+    /**
+     * 修改交易币别配置
+     *
+     * @param bo 交易币别配置
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(ComCurrencyBo bo);
+
+    /**
+     * 修改状态
+     */
+    int updateStatus(ComCurrencyBo bo);
+
+    /**
+     * 校验并批量删除交易币别配置信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 76 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IComRevenueExpenseService.java

@@ -0,0 +1,76 @@
+package org.dromara.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.system.domain.ComRevenueExpense;
+import org.dromara.system.domain.bo.ComCurrencyBo;
+import org.dromara.system.domain.vo.ComRevenueExpenseVo;
+import org.dromara.system.domain.bo.ComRevenueExpenseBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 收入费用设定Service接口
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+public interface IComRevenueExpenseService extends IService<ComRevenueExpense> {
+
+    /**
+     * 查询收入费用设定
+     *
+     * @param id 主键
+     * @return 收入费用设定
+     */
+    ComRevenueExpenseVo queryById(Long id);
+
+    /**
+     * 分页查询收入费用设定列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 收入费用设定分页列表
+     */
+    TableDataInfo<ComRevenueExpenseVo> queryPageList(ComRevenueExpenseBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的收入费用设定列表
+     *
+     * @param bo 查询条件
+     * @return 收入费用设定列表
+     */
+    List<ComRevenueExpenseVo> queryList(ComRevenueExpenseBo bo);
+
+    /**
+     * 新增收入费用设定
+     *
+     * @param bo 收入费用设定
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(ComRevenueExpenseBo bo);
+
+    /**
+     * 修改收入费用设定
+     *
+     * @param bo 收入费用设定
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(ComRevenueExpenseBo bo);
+
+    /**
+     * 修改状态
+     */
+    int updateStatus(ComCurrencyBo bo);
+
+    /**
+     * 校验并批量删除收入费用设定信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 40 - 8
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComCompanyServiceImpl.java

@@ -6,18 +6,24 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.enums.SysPlatformYesNo;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.redis.utils.SequenceUtils;
 import org.dromara.system.domain.ComCompany;
+import org.dromara.system.domain.SysDept;
 import org.dromara.system.domain.bo.ComCompanyBo;
+import org.dromara.system.domain.bo.SysDeptBo;
 import org.dromara.system.domain.vo.ComCompanyVo;
 import org.dromara.system.mapper.ComCompanyMapper;
 import org.dromara.system.mapper.SysDeptMapper;
 import org.dromara.system.service.IComCompanyService;
+import org.dromara.system.service.ISysDeptService;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.time.Duration;
 import java.util.*;
@@ -33,12 +39,17 @@ import java.util.*;
 @Service
 public class ComCompanyServiceImpl extends ServiceImpl<ComCompanyMapper, ComCompany> implements IComCompanyService {
 
+    private static final String DEPT_NO_KEY = "sys_dept:dept_no";
     private static final String COMPANY_CODE_KEY = "com_company:company_code";
 
     private final ComCompanyMapper baseMapper;
 
     private final SysDeptMapper deptMapper;
 
+    private final ISysDeptService sysDeptService;
+    ;
+
+
     /**
      * 查询公司信息
      *
@@ -115,17 +126,38 @@ public class ComCompanyServiceImpl extends ServiceImpl<ComCompanyMapper, ComComp
      * @param bo 公司信息
      * @return 是否新增成功
      */
+    @Transactional(rollbackFor = Exception.class)
     @Override
     public Boolean insertByBo(ComCompanyBo bo) {
-
-        bo.setCompanyCode(SequenceUtils.nextPaddedIdStr(COMPANY_CODE_KEY, Duration.ofDays(3650), 4));
-        ComCompany add = MapstructUtils.convert(bo, ComCompany.class);
-        validEntityBeforeSave(add);
-        boolean flag = baseMapper.insert(add) > 0;
-        if (flag) {
-            bo.setId(add.getId());
+        try {
+            // 1. 生成公司编码
+            bo.setCompanyCode(SequenceUtils.nextPaddedIdStr(COMPANY_CODE_KEY, Duration.ofDays(3650), 4));
+
+            // 2. 转换并校验
+            ComCompany company = MapstructUtils.convert(bo, ComCompany.class);
+            validEntityBeforeSave(company);
+            int insert = baseMapper.insert(company);
+            if (insert > 0) {
+                bo.setId(company.getId());
+                log.info("新增公司信息成功:{}", company);
+            }
+
+            // 4. 创建根部门(以公司名为部门名)
+            SysDeptBo deptBo = new SysDeptBo();
+            deptBo.setDeptNo(SequenceUtils.nextPaddedIdStr(DEPT_NO_KEY, Duration.ofDays(3650), 4));
+            deptBo.setCompanyId(company.getId());
+            deptBo.setDeptName(company.getCompanyName());
+            deptBo.setParentId(100L); // 通常为 顶级部门的id
+            deptBo.setIsCompanyFlag(SysPlatformYesNo.YES.getCode());
+
+            // 5. 插入部门
+            sysDeptService.insertDept(deptBo);
+
+            return true; // 表示公司及根部门创建成功
+        } catch (Exception e) {
+            log.error("新增公司信息失败:{}", e.getMessage(), e);
+            throw new RuntimeException(e);
         }
-        return flag;
     }
 
     /**

+ 158 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComCurrencyServiceImpl.java

@@ -0,0 +1,158 @@
+package org.dromara.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.redis.utils.SequenceUtils;
+import org.dromara.system.domain.OrderPaySet;
+import org.dromara.system.domain.bo.OrderPaySetBo;
+import org.springframework.stereotype.Service;
+import org.dromara.system.domain.bo.ComCurrencyBo;
+import org.dromara.system.domain.vo.ComCurrencyVo;
+import org.dromara.system.domain.ComCurrency;
+import org.dromara.system.mapper.ComCurrencyMapper;
+import org.dromara.system.service.IComCurrencyService;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 交易币别配置Service业务层处理
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ComCurrencyServiceImpl extends ServiceImpl<ComCurrencyMapper, ComCurrency> implements IComCurrencyService {
+
+    private static final String CURRENCY_CODE_KEY = "com_currency:currency_code";
+
+    private final ComCurrencyMapper baseMapper;
+
+    /**
+     * 查询交易币别配置
+     *
+     * @param id 主键
+     * @return 交易币别配置
+     */
+    @Override
+    public ComCurrencyVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询交易币别配置列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 交易币别配置分页列表
+     */
+    @Override
+    public TableDataInfo<ComCurrencyVo> queryPageList(ComCurrencyBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<ComCurrency> lqw = buildQueryWrapper(bo);
+        Page<ComCurrencyVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的交易币别配置列表
+     *
+     * @param bo 查询条件
+     * @return 交易币别配置列表
+     */
+    @Override
+    public List<ComCurrencyVo> queryList(ComCurrencyBo bo) {
+        LambdaQueryWrapper<ComCurrency> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<ComCurrency> buildQueryWrapper(ComCurrencyBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<ComCurrency> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(ComCurrency::getId);
+        lqw.eq(StringUtils.isNotBlank(bo.getCurrencyCode()), ComCurrency::getCurrencyCode, bo.getCurrencyCode());
+        lqw.like(StringUtils.isNotBlank(bo.getCurrencyName()), ComCurrency::getCurrencyName, bo.getCurrencyName());
+        lqw.eq(StringUtils.isNotBlank(bo.getIsShow()), ComCurrency::getIsShow, bo.getIsShow());
+        lqw.eq(StringUtils.isNotBlank(bo.getDataSource()), ComCurrency::getDataSource, bo.getDataSource());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ComCurrency::getStatus, bo.getStatus());
+        return lqw;
+    }
+
+    /**
+     * 新增交易币别配置
+     *
+     * @param bo 交易币别配置
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(ComCurrencyBo bo) {
+        bo.setCurrencyCode(SequenceUtils.nextPaddedIdStr(CURRENCY_CODE_KEY, Duration.ofDays(3650), 4));
+        ComCurrency add = MapstructUtils.convert(bo, ComCurrency.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改状态
+     *
+     * @param bo 信息
+     * @return 结果
+     */
+    @Override
+    public int updateStatus(ComCurrencyBo bo) {
+        ComCurrency currency = new ComCurrency();
+        currency.setId(bo.getId());
+        currency.setIsShow(bo.getIsShow());
+        return baseMapper.updateById(currency);
+    }
+
+    /**
+     * 修改交易币别配置
+     *
+     * @param bo 交易币别配置
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(ComCurrencyBo bo) {
+        ComCurrency update = MapstructUtils.convert(bo, ComCurrency.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(ComCurrency entity) {
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除交易币别配置信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 160 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComRevenueExpenseServiceImpl.java

@@ -0,0 +1,160 @@
+package org.dromara.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.redis.utils.SequenceUtils;
+import org.dromara.system.domain.ComCurrency;
+import org.dromara.system.domain.bo.ComCurrencyBo;
+import org.springframework.stereotype.Service;
+import org.dromara.system.domain.bo.ComRevenueExpenseBo;
+import org.dromara.system.domain.vo.ComRevenueExpenseVo;
+import org.dromara.system.domain.ComRevenueExpense;
+import org.dromara.system.mapper.ComRevenueExpenseMapper;
+import org.dromara.system.service.IComRevenueExpenseService;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 收入费用设定Service业务层处理
+ *
+ * @author LionLi
+ * @date 2026-01-04
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ComRevenueExpenseServiceImpl extends ServiceImpl<ComRevenueExpenseMapper, ComRevenueExpense> implements IComRevenueExpenseService {
+
+    private static final String REVENUE_CODE_KEY = "com_revenue_expense:revenue_code";
+
+    private final ComRevenueExpenseMapper baseMapper;
+
+    /**
+     * 查询收入费用设定
+     *
+     * @param id 主键
+     * @return 收入费用设定
+     */
+    @Override
+    public ComRevenueExpenseVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询收入费用设定列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 收入费用设定分页列表
+     */
+    @Override
+    public TableDataInfo<ComRevenueExpenseVo> queryPageList(ComRevenueExpenseBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<ComRevenueExpense> lqw = buildQueryWrapper(bo);
+        Page<ComRevenueExpenseVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的收入费用设定列表
+     *
+     * @param bo 查询条件
+     * @return 收入费用设定列表
+     */
+    @Override
+    public List<ComRevenueExpenseVo> queryList(ComRevenueExpenseBo bo) {
+        LambdaQueryWrapper<ComRevenueExpense> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<ComRevenueExpense> buildQueryWrapper(ComRevenueExpenseBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<ComRevenueExpense> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(ComRevenueExpense::getId);
+        lqw.eq(StringUtils.isNotBlank(bo.getRevenueCode()), ComRevenueExpense::getRevenueCode, bo.getRevenueCode());
+        lqw.like(StringUtils.isNotBlank(bo.getRevenueName()), ComRevenueExpense::getRevenueName, bo.getRevenueName());
+        lqw.eq(StringUtils.isNotBlank(bo.getExpenseFlag()), ComRevenueExpense::getExpenseFlag, bo.getExpenseFlag());
+        lqw.eq(StringUtils.isNotBlank(bo.getRevenueFlag()), ComRevenueExpense::getRevenueFlag, bo.getRevenueFlag());
+        lqw.eq(StringUtils.isNotBlank(bo.getIsShow()), ComRevenueExpense::getIsShow, bo.getIsShow());
+        lqw.eq(StringUtils.isNotBlank(bo.getDataSource()), ComRevenueExpense::getDataSource, bo.getDataSource());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ComRevenueExpense::getStatus, bo.getStatus());
+        return lqw;
+    }
+
+    /**
+     * 新增收入费用设定
+     *
+     * @param bo 收入费用设定
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(ComRevenueExpenseBo bo) {
+        bo.setRevenueCode(SequenceUtils.nextPaddedIdStr(REVENUE_CODE_KEY, Duration.ofDays(3650), 4));
+        ComRevenueExpense add = MapstructUtils.convert(bo, ComRevenueExpense.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改收入费用设定
+     *
+     * @param bo 收入费用设定
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(ComRevenueExpenseBo bo) {
+        ComRevenueExpense update = MapstructUtils.convert(bo, ComRevenueExpense.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 修改状态
+     *
+     * @param bo 信息
+     * @return 结果
+     */
+    @Override
+    public int updateStatus(ComCurrencyBo bo) {
+        ComRevenueExpense revenueExpense = new ComRevenueExpense();
+        revenueExpense.setId(bo.getId());
+        revenueExpense.setIsShow(bo.getIsShow());
+        return baseMapper.updateById(revenueExpense);
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(ComRevenueExpense entity) {
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除收入费用设定信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 11 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java

@@ -98,7 +98,6 @@ public class SysDeptServiceImpl implements ISysDeptService {
         lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL);
         lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
         lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId());
-        lqw.eq(ObjectUtil.isNotNull(bo.getCustomerId()), SysDept::getCustomerId, bo.getCustomerId());
         lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
         lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptCategory, bo.getDeptCategory());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
@@ -185,7 +184,12 @@ public class SysDeptServiceImpl implements ISysDeptService {
     @Override
     public List<SysDeptVo> selectDeptByIds(List<Long> deptIds) {
         return baseMapper.selectDeptList(new LambdaQueryWrapper<SysDept>()
-            .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getLeader)
+            .select(SysDept::getDeptId,
+                SysDept::getDeptName,
+                SysDept::getLeader,
+                SysDept::getParentId,
+                SysDept::getOrderNum,
+                SysDept::getStatus)
             .eq(SysDept::getStatus, SystemConstants.NORMAL)
             .in(CollUtil.isNotEmpty(deptIds), SysDept::getDeptId, deptIds));
     }
@@ -317,7 +321,11 @@ public class SysDeptServiceImpl implements ISysDeptService {
         }
         //在 "main" 平台上下文中执行插入,并获取返回值
         Integer rows = PlatformContextUtil.executeWithPlatform(targetPlatform, () -> {
-            return baseMapper.insert(dept);
+            Integer i = baseMapper.insert(dept);
+            if (i > 0) {
+                bo.setDeptId(dept.getDeptId());
+            }
+            return i;
         });
         return rows;
     }

+ 7 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/ComCurrencyMapper.xml

@@ -0,0 +1,7 @@
+<?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="org.dromara.system.mapper.ComCurrencyMapper">
+
+</mapper>

+ 7 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/ComRevenueExpenseMapper.xml

@@ -0,0 +1,7 @@
+<?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="org.dromara.system.mapper.ComRevenueExpenseMapper">
+
+</mapper>