Преглед изворни кода

Merge remote-tracking branch 'origin/master' into master

肖路 пре 11 часа
родитељ
комит
aa58c8c1d4
39 измењених фајлова са 2036 додато и 158 уклоњено
  1. 5 0
      ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/RemoteCustomerService.java
  2. 36 0
      ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/RemoteOrderInfoService.java
  3. 26 0
      ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/HotProductRankingDto.java
  4. 39 0
      ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/LatestOrderDto.java
  5. 27 0
      ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/OrderAmountTrendDto.java
  6. 131 0
      ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/PartnerOrderIndexDto.java
  7. 5 0
      ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductService.java
  8. 4 0
      ruoyi-modules/ruoyi-customer/pom.xml
  9. 10 7
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/CustomerInfoController.java
  10. 41 17
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/PartnerInfoController.java
  11. 103 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/CustomerIndexDataVo.java
  12. 136 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/PartnerInfoIndexDataVo.java
  13. 82 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/PartnerManageIndexDataVo.java
  14. 4 2
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/dubbo/RemoteCustomerServiceImpl.java
  15. 5 6
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ICustomerInfoService.java
  16. 39 31
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/IPartnerInfoService.java
  17. 162 2
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerInfoServiceImpl.java
  18. 235 15
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/PartnerInfoServiceImpl.java
  19. 61 36
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SupplierContractServiceImpl.java
  20. 9 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderMainController.java
  21. 13 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/pc/PcOrderController.java
  22. 81 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/CustomerOrderTradeDataVo.java
  23. 137 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderIndexDataVo.java
  24. 265 17
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/dubbo/RemoteOrderInfoServiceImpl.java
  25. 5 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderMainService.java
  26. 238 1
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java
  27. 8 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductServiceImpl.java
  28. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/pc/IndexSystemController.java
  29. 5 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/ComStaff.java
  30. 4 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
  31. 5 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/ComStaffBo.java
  32. 5 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
  33. 5 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ComStaffVo.java
  34. 5 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
  35. 70 5
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComStaffServiceImpl.java
  36. 22 16
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysAdContentServiceImpl.java
  37. 1 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
  38. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysFloorAdvertManageServiceImpl.java
  39. 5 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

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

@@ -43,4 +43,9 @@ public interface RemoteCustomerService {
 
     CustomerAddressDTO addReceiverAddress(String provinceId, String cityId, String countyId, String address, String mobile);
 
+    /**
+     * 是否需要确认订单
+     */
+    Boolean isNeedAffirmOrder(Long customerId);
+
 }

+ 36 - 0
ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/RemoteOrderInfoService.java

@@ -1,6 +1,12 @@
 package org.dromara.product.api;
 
+import org.dromara.product.api.domain.dto.HotProductRankingDto;
+import org.dromara.product.api.domain.dto.LatestOrderDto;
+import org.dromara.product.api.domain.dto.OrderAmountTrendDto;
 import org.dromara.product.api.domain.dto.OrderStatusCountDto;
+import org.dromara.product.api.domain.dto.PartnerOrderIndexDto;
+
+import java.util.List;
 
 /**
  * @author
@@ -12,4 +18,34 @@ public interface RemoteOrderInfoService {
      * @param itemKey 项目key
     * */
     OrderStatusCountDto getOrderStatusCount(String itemKey);
+
+    /**
+     * 获取最新订单列表
+     * @param itemKey 项目key
+     * @param limit 查询条数
+     * @return 最新订单列表
+     */
+    List<LatestOrderDto> getLatestOrders(String itemKey, int limit);
+
+    /**
+     * 获取本月订单金额趋势(按天汇总)
+     * @param itemKey 项目key
+     * @return 每日订单金额列表
+     */
+    List<OrderAmountTrendDto> getOrderAmountTrend(String itemKey);
+
+    /**
+     * 获取热销商品排行榜
+     * @param itemKey 项目key
+     * @param limit 排行数量
+     * @return 热销商品排行列表
+     */
+    List<HotProductRankingDto> getHotProductRankings(String itemKey, int limit);
+
+    /**
+     * 获取伙伴商协同平台首页订单统计数据
+     * @param partnerId 伙伴商ID
+     * @return 订单统计数据
+     */
+    PartnerOrderIndexDto getPartnerOrderIndex(Long partnerId);
 }

+ 26 - 0
ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/HotProductRankingDto.java

@@ -0,0 +1,26 @@
+package org.dromara.product.api.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 热销商品排行DTO
+ *
+ * @date 2026-06-01
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class HotProductRankingDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 商品名称 */
+    private String productName;
+
+    /** 销量 */
+    private Long salesCount;
+}

+ 39 - 0
ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/LatestOrderDto.java

@@ -0,0 +1,39 @@
+package org.dromara.product.api.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 最新订单DTO
+ *
+ * @date 2026-06-01
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LatestOrderDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 订单编号 */
+    private String orderNo;
+
+    /** 客户名称 */
+    private String customerName;
+
+    /** 商品信息(第一个商品名称) */
+    private String productName;
+
+    /** 订单金额 */
+    private BigDecimal amount;
+
+    /** 订单状态 */
+    private String orderStatus;
+
+    /** 下单时间 */
+    private String orderTime;
+}

+ 27 - 0
ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/OrderAmountTrendDto.java

@@ -0,0 +1,27 @@
+package org.dromara.product.api.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 订单金额趋势DTO
+ *
+ * @date 2026-06-01
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class OrderAmountTrendDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 日期 */
+    private String date;
+
+    /** 金额 */
+    private BigDecimal amount;
+}

+ 131 - 0
ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/domain/dto/PartnerOrderIndexDto.java

@@ -0,0 +1,131 @@
+package org.dromara.product.api.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 伙伴商协同平台订单统计数据DTO
+ *
+ * @author LionLi
+ * @date 2026-06-01
+ */
+@Data
+public class PartnerOrderIndexDto implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 今日新增订单数
+     */
+    private Long todayOrders;
+
+    /**
+     * 本周销售总额
+     */
+    private BigDecimal weekRevenue;
+
+    /**
+     * 待发货数量
+     */
+    private Long pendingShipment;
+
+    /**
+     * 近7天发货量走势
+     */
+    private List<DayShipment> shipmentTrend;
+
+    /**
+     * 商品类型销售占比
+     */
+    private List<TypeSales> productTypeSales;
+
+    /**
+     * 最新发货动态
+     */
+    private List<ShipmentOrder> latestShipments;
+
+    /**
+     * 每日发货量
+     */
+    @Data
+    public static class DayShipment implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 日期,格式: "MM-dd"
+         */
+        private String date;
+
+        /**
+         * 发货量
+         */
+        private Long count;
+    }
+
+    /**
+     * 商品类型销售占比
+     */
+    @Data
+    public static class TypeSales implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 类型名称
+         */
+        private String name;
+
+        /**
+         * 销售数量/金额
+         */
+        private Long value;
+    }
+
+    /**
+     * 发货订单
+     */
+    @Data
+    public static class ShipmentOrder implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 订单编号
+         */
+        private String orderNo;
+
+        /**
+         * 商品名称
+         */
+        private String productName;
+
+        /**
+         * 订单金额
+         */
+        private BigDecimal amount;
+
+        /**
+         * 收货人
+         */
+        private String customer;
+
+        /**
+         * 发货状态
+         */
+        private String status;
+
+        /**
+         * 时间
+         */
+        private String date;
+    }
+}

+ 5 - 0
ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductService.java

@@ -125,5 +125,10 @@ public interface RemoteProductService {
      */
     Long getProductIdProductNo(String productNo);
 
+    /**
+     * 获取商品总数
+     * @return 商品总数
+     */
+    Long getTotalProductCount();
 
 }

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

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

+ 10 - 7
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/CustomerInfoController.java

@@ -17,17 +17,12 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.web.core.BaseController;
-import org.dromara.customer.domain.bo.CustomerClaimBo;
-import org.dromara.customer.domain.bo.CustomerInfoBo;
-import org.dromara.customer.domain.bo.CustomerListBo;
-import org.dromara.customer.domain.bo.CustomerSalesInfoBo;
-import org.dromara.customer.domain.bo.MessagePublishCustomerBo;
-import org.dromara.customer.domain.dto.SetCustomerInfoTagDto;
+import org.dromara.customer.domain.bo.*;
 import org.dromara.customer.domain.dto.ReleaseToPoolDto;
+import org.dromara.customer.domain.dto.SetCustomerInfoTagDto;
 import org.dromara.customer.domain.vo.*;
 import org.dromara.customer.listener.CustomerImportListener;
 import org.dromara.customer.service.ICustomerInfoService;
-import org.dromara.system.api.RemoteProductTaxrateService;
 import org.dromara.system.api.*;
 import org.dromara.system.api.domain.vo.RemoteComCompanyVo;
 import org.dromara.system.api.domain.vo.RemoteComCustomerLevelVo;
@@ -74,6 +69,14 @@ public class CustomerInfoController extends BaseController {
 
     private final ICustomerInfoService customerInfoService;
 
+    /**
+     * 客户首页数据
+     */
+    @GetMapping("/customerIndexData")
+    public R<CustomerIndexDataVo> customerIndexData() {
+        return customerInfoService.customerIndexData();
+    }
+
     /**
      * 查询客户信息列表
      */

+ 41 - 17
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/PartnerInfoController.java

@@ -1,28 +1,32 @@
 package org.dromara.customer.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.dromara.common.core.utils.StringUtils;
-import org.dromara.customer.domain.vo.CustomerInfoVo;
-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 cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
 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.customer.domain.vo.PartnerInfoVo;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
 import org.dromara.customer.domain.bo.PartnerInfoBo;
+import org.dromara.customer.domain.vo.PartnerInfoIndexDataVo;
+import org.dromara.customer.domain.vo.PartnerInfoVo;
+import org.dromara.customer.domain.vo.PartnerManageIndexDataVo;
 import org.dromara.customer.service.IPartnerInfoService;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 伙伴商基本信息
@@ -39,6 +43,26 @@ public class PartnerInfoController extends BaseController {
 
     private final IPartnerInfoService partnerInfoService;
 
+    /**
+     * 伙伴商管理平台首页数据
+     */
+    @GetMapping("/partnerManageIndexData")
+    public R<PartnerManageIndexDataVo> partnerManageIndexData() {
+        return partnerInfoService.partnerManageIndexData();
+    }
+
+    /**
+     * 伙伴商协同平台首页数据
+     */
+    @GetMapping("/partnerInfoIndexData")
+    public R<PartnerInfoIndexDataVo> partnerInfoIndexData() {
+        Long partnerId = LoginHelper.getLoginUser().getPartnerId();
+        if (ObjectUtil.isEmpty(partnerId)) {
+            return R.fail("未获取到当前伙伴商信息");
+        }
+        return partnerInfoService.partnerInfoIndexData(partnerId);
+    }
+
     /**
      * 查询伙伴商基本信息列表
      */
@@ -67,7 +91,7 @@ public class PartnerInfoController extends BaseController {
     @SaCheckPermission("customer:partnerInfo:query")
     @GetMapping("/{id}")
     public R<PartnerInfoVo> getInfo(@NotNull(message = "主键不能为空")
-                                     @PathVariable("id") Long id) {
+                                    @PathVariable("id") Long id) {
         return R.ok(partnerInfoService.queryById(id));
     }
 

+ 103 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/CustomerIndexDataVo.java

@@ -0,0 +1,103 @@
+package org.dromara.customer.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 客户首页数据看板VO
+ *
+ * @date 2026-06-01
+ */
+@Data
+public class CustomerIndexDataVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 总客户数 */
+    private Long totalCustomers;
+
+    /** 总订单数 */
+    private Long totalOrders;
+
+    /** 商品总量 */
+    private Long totalProducts;
+
+    /** 本月营收 */
+    private BigDecimal monthlyRevenue;
+
+    /** 最近七天客户趋势 */
+    private List<TrendItem> customerTrend;
+
+    /** 本月订单金额趋势 */
+    private List<TrendItem> orderAmountTrend;
+
+    /** 客户类型分布 */
+    private List<TypeDistribution> customerTypeDistribution;
+
+    /** 最新订单明细 */
+    private List<LatestOrder> latestOrders;
+
+    /** 热销商品排行榜 */
+    private List<HotProduct> hotProductRankings;
+
+    /**
+     * 趋势数据项
+     */
+    @Data
+    public static class TrendItem implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /** 日期 */
+        private String date;
+        /** 数量/金额 */
+        private BigDecimal value;
+    }
+
+    /**
+     * 类型分布
+     */
+    @Data
+    public static class TypeDistribution implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /** 类型名称 */
+        private String name;
+        /** 数量 */
+        private Long value;
+    }
+
+    /**
+     * 最新订单
+     */
+    @Data
+    public static class LatestOrder implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /** 订单编号 */
+        private String orderNo;
+        /** 客户名称 */
+        private String customer;
+        /** 商品信息 */
+        private String product;
+        /** 金额 */
+        private BigDecimal amount;
+        /** 状态 */
+        private String status;
+        /** 下单时间 */
+        private String date;
+    }
+
+    /**
+     * 热销商品
+     */
+    @Data
+    public static class HotProduct implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /** 商品名称 */
+        private String name;
+        /** 销量 */
+        private Long sales;
+        /** 百分比 */
+        private Integer percentage;
+    }
+}

+ 136 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/PartnerInfoIndexDataVo.java

@@ -0,0 +1,136 @@
+package org.dromara.customer.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 伙伴商协同平台首页数据视图对象
+ *
+ * @author LionLi
+ * @date 2026-06-01
+ */
+@Data
+public class PartnerInfoIndexDataVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 今日新增订单
+     */
+    private Long todayOrders;
+
+    /**
+     * 本周销售总额
+     */
+    private BigDecimal weekRevenue;
+
+    /**
+     * 待发货数量
+     */
+    private Long pendingShipment;
+
+    /**
+     * 在售商品数
+     */
+    private Long onSaleProducts;
+
+    /**
+     * 近期订单发货量走势
+     */
+    private List<ShipmentTrend> shipmentTrend;
+
+    /**
+     * 商品类型销售占比
+     */
+    private List<ProductTypeSales> productTypeSales;
+
+    /**
+     * 最新发货动态
+     */
+    private List<LatestShipment> latestShipments;
+
+    /**
+     * 发货量走势
+     */
+    @Data
+    public static class ShipmentTrend implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 日期,格式: "MM-dd"
+         */
+        private String date;
+
+        /**
+         * 发货量
+         */
+        private Long count;
+    }
+
+    /**
+     * 商品类型销售占比
+     */
+    @Data
+    public static class ProductTypeSales implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 类型名称
+         */
+        private String name;
+
+        /**
+         * 销售数量/金额
+         */
+        private Long value;
+    }
+
+    /**
+     * 最新发货订单
+     */
+    @Data
+    public static class LatestShipment implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 订单编号
+         */
+        private String orderNo;
+
+        /**
+         * 商品名称
+         */
+        private String productName;
+
+        /**
+         * 订单金额
+         */
+        private BigDecimal amount;
+
+        /**
+         * 收货人
+         */
+        private String customer;
+
+        /**
+         * 发货状态
+         */
+        private String status;
+
+        /**
+         * 时间
+         */
+        private String date;
+    }
+}

+ 82 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/PartnerManageIndexDataVo.java

@@ -0,0 +1,82 @@
+package org.dromara.customer.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 伙伴商管理平台首页数据
+ *
+ * @author LionLi
+ * @date 2026-06-01
+ */
+@Data
+public class PartnerManageIndexDataVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 伙伴商总数 */
+    private Long partnerTotal;
+
+    /** 本月新增入驻 */
+    private Long monthlyNew;
+
+    /** 季度新增入驻 */
+    private Long quarterlyNew;
+
+    /** 合作中项目数(PartnerContract中cooperationId去重) */
+    private Long cooperationProjectCount;
+
+    /** 近半年新增伙伴商趋势 */
+    private List<MonthTrend> monthlyTrend;
+
+    /** 伙伴合作型态分布 */
+    private List<TypeDistribution> typeDistribution;
+
+    /** 最新入驻伙伴商列表(最新8条) */
+    private List<LatestPartner> latestPartners;
+
+    /**
+     * 月度趋势
+     */
+    @Data
+    public static class MonthTrend implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /** 月份标签,如"5月" */
+        private String month;
+        /** 新增数量 */
+        private Long count;
+    }
+
+    /**
+     * 合作型态分布
+     */
+    @Data
+    public static class TypeDistribution implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /** 类型名称 */
+        private String name;
+        /** 数量 */
+        private Long value;
+    }
+
+    /**
+     * 最新入驻伙伴商
+     */
+    @Data
+    public static class LatestPartner implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /** 伙伴商名称 */
+        private String companyName;
+        /** 联系人 */
+        private String contact;
+        /** 联系电话 */
+        private String phone;
+        /** 合作型态 */
+        private Long partnerCooperateType;
+        /** 申请时间 */
+        private String joinTime;
+    }
+}

+ 4 - 2
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/dubbo/RemoteCustomerServiceImpl.java

@@ -2,7 +2,6 @@ package org.dromara.customer.dubbo;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
-import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -146,5 +145,8 @@ public class RemoteCustomerServiceImpl implements RemoteCustomerService {
         return customerAddressDTO;
     }
 
-
+    @Override
+    public Boolean isNeedAffirmOrder(Long customerId) {
+        return customerInfoService.isNeedAffirmOrder(customerId);
+    }
 }

+ 5 - 6
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ICustomerInfoService.java

@@ -1,14 +1,12 @@
 package org.dromara.customer.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.common.core.domain.R;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.customer.domain.CustomerInfo;
 import org.dromara.customer.domain.bo.*;
-import org.dromara.customer.domain.vo.ContractVo;
-import org.dromara.customer.domain.vo.CustomerInfoVo;
-import org.dromara.customer.domain.vo.CustomerListVo;
-import org.dromara.customer.domain.vo.MessagePublishCustomerVo;
+import org.dromara.customer.domain.vo.*;
 
 import java.math.BigDecimal;
 import java.util.Collection;
@@ -130,7 +128,7 @@ public interface ICustomerInfoService extends IService<CustomerInfo> {
      * 退回客户到公海
      *
      * @param customerIds 客户ID列表
-     * @param reason 退回原因
+     * @param reason      退回原因
      * @return 更新数量
      */
     int releaseToPool(List<Long> customerIds, String reason);
@@ -195,6 +193,7 @@ public interface ICustomerInfoService extends IService<CustomerInfo> {
      */
     CustomerInfoVo selectCustomerByName(String customerName);
 
+    R<CustomerIndexDataVo> customerIndexData();
 
-
+    Boolean isNeedAffirmOrder(Long customerId);
 }

+ 39 - 31
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/IPartnerInfoService.java

@@ -1,12 +1,14 @@
 package org.dromara.customer.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.customer.domain.PartnerInfo;
-import org.dromara.customer.domain.vo.CustomerInfoVo;
-import org.dromara.customer.domain.vo.PartnerInfoVo;
 import org.dromara.customer.domain.bo.PartnerInfoBo;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.customer.domain.vo.PartnerInfoIndexDataVo;
+import org.dromara.customer.domain.vo.PartnerInfoVo;
+import org.dromara.customer.domain.vo.PartnerManageIndexDataVo;
 
 import java.util.Collection;
 import java.util.List;
@@ -14,7 +16,7 @@ import java.util.Map;
 import java.util.Set;
 
 /**
- * 伙伴商基本信息Service接口
+ * 浼欎即鍟嗗熀鏈�俊鎭疭ervice鎺ュ彛
  *
  * @author LionLi
  * @date 2026-01-21
@@ -22,70 +24,76 @@ import java.util.Set;
 public interface IPartnerInfoService extends IService<PartnerInfo> {
 
     /**
-     * 查询伙伴商基本信息
+     * 鏌ヨ�浼欎即鍟嗗熀鏈�俊鎭?
      *
-     * @param id 主键
-     * @return 伙伴商基本信息
+     * @param id 涓婚敭
+     * @return 浼欎即鍟嗗熀鏈�俊鎭?
      */
     PartnerInfoVo queryById(Long id);
 
     /**
-     * 分页查询伙伴商基本信息列表
+     * 鍒嗛〉鏌ヨ�浼欎即鍟嗗熀鏈�俊鎭�垪琛?
      *
-     * @param bo        查询条件
-     * @param pageQuery 分页参数
-     * @return 伙伴商基本信息分页列表
+     * @param bo        鏌ヨ�鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 浼欎即鍟嗗熀鏈�俊鎭�垎椤靛垪琛?
      */
     TableDataInfo<PartnerInfoVo> queryPageList(PartnerInfoBo bo, PageQuery pageQuery);
 
     /**
-     * 查询符合条件的伙伴商基本信息列表
+     * 鏌ヨ�绗﹀悎鏉′欢鐨勪紮浼村晢鍩烘湰淇℃伅鍒楄〃
      *
-     * @param bo 查询条件
-     * @return 伙伴商基本信息列表
+     * @param bo 鏌ヨ�鏉′欢
+     * @return 浼欎即鍟嗗熀鏈�俊鎭�垪琛?
      */
     List<PartnerInfoVo> queryList(PartnerInfoBo bo);
 
     /**
-     * 新增伙伴商基本信息
+     * 鏂板�浼欎即鍟嗗熀鏈�俊鎭?
      *
-     * @param bo 伙伴商基本信息
-     * @return 是否新增成功
+     * @param bo 浼欎即鍟嗗熀鏈�俊鎭?
+     * @return 鏄�惁鏂板�鎴愬姛
      */
     Boolean insertByBo(PartnerInfoBo bo);
 
     /**
-     * 修改伙伴商基本信息
+     * 淇�敼浼欎即鍟嗗熀鏈�俊鎭?
      *
-     * @param bo 伙伴商基本信息
-     * @return 是否修改成功
+     * @param bo 浼欎即鍟嗗熀鏈�俊鎭?
+     * @return 鏄�惁淇�敼鎴愬姛
      */
     Boolean updateByBo(PartnerInfoBo bo);
 
     /**
-     * 校验并批量删除伙伴商基本信息信息
+     * 鏍¢獙骞舵壒閲忓垹闄や紮浼村晢鍩烘湰淇℃伅淇℃伅
      *
-     * @param ids     待删除的主键集合
-     * @param isValid 是否进行有效性校验
-     * @return 是否删除成功
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄�惁杩涜�鏈夋晥鎬ф牎楠?
+     * @return 鏄�惁鍒犻櫎鎴愬姛
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
     /**
-     * 获取当前登录用户的伙伴商信息
+     * 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛鐨勪紮浼村晢淇℃伅
      *
-     * @return 伙伴商基本信息
+     * @return 浼欎即鍟嗗熀鏈�俊鎭?
      */
     PartnerInfoVo queryCurrentPartnerInfo();
 
-    /*根据ids查询伙伴商名称*/
+    /**
+     * 根据ids查询伙伴商名称
+     */
     Map<Long, String> selectPartnerNameByIds(Set<Long> ids);
 
     /**
-     * 查询伙伴商名称查询伙伴商信息
+     * 鏌ヨ�浼欎即鍟嗗悕绉版煡璇�紮浼村晢淇℃伅
      *
-     * @param partnerName 主键
-     * @return 伙伴商信息
+     * @param partnerName 涓婚敭
+     * @return 浼欎即鍟嗕俊鎭?
      */
     List<PartnerInfoVo> selectByPartnerName(String partnerName);
+
+    R<PartnerManageIndexDataVo> partnerManageIndexData();
+
+    R<PartnerInfoIndexDataVo> partnerInfoIndexData(Long partnerId);
 }

+ 162 - 2
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerInfoServiceImpl.java

@@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.common.core.constant.GlobalConstants;
 import org.dromara.common.core.context.PlatformContext;
+import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.IsDefault;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.DateUtils;
@@ -31,6 +32,12 @@ import org.dromara.customer.mapper.*;
 import org.dromara.customer.service.ICustomerInfoService;
 import org.dromara.customer.utils.qcc.QccUtils;
 import org.dromara.customer.utils.qcc.domain.CompanyInfoResponse;
+import org.dromara.product.api.RemoteOrderInfoService;
+import org.dromara.product.api.RemoteProductService;
+import org.dromara.product.api.domain.dto.HotProductRankingDto;
+import org.dromara.product.api.domain.dto.LatestOrderDto;
+import org.dromara.product.api.domain.dto.OrderAmountTrendDto;
+import org.dromara.product.api.domain.dto.OrderStatusCountDto;
 import org.dromara.system.api.*;
 import org.dromara.system.api.domain.bo.RemoteUserBo;
 import org.dromara.system.api.domain.dto.AddressAreaDTO;
@@ -42,6 +49,8 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.time.Duration;
+import java.time.LocalDate;
+import java.time.ZoneId;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -89,6 +98,12 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
     @DubboReference
     private RemoteAddressAreaService remoteAddressAreaService;
 
+    @DubboReference
+    private RemoteOrderInfoService remoteOrderInfoService;
+
+    @DubboReference
+    private RemoteProductService remoteProductService;
+
     private static final String CUSTOMER_NO_KEY = "customer_info:customer_no";
     private static final String CONTACT_NO_KEY = "customer_contact:contact_no";
 
@@ -445,8 +460,8 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         }
 
         // === 远程调用获取名称 ===
-        Map<Long, String> comStaffMap = staffIds.isEmpty() ? Collections.emptyMap() : remoteComStaffService.selectStaffNameByIds(comStaffIds);
-        Map<Long, String> comDeptMap = deptIds.isEmpty() ? Collections.emptyMap() : remoteDeptService.selectDeptNameByIds(comDeptIds);
+        Map<Long, String> comStaffMap = comStaffIds.isEmpty() ? Collections.emptyMap() : remoteComStaffService.selectStaffNameByIds(comStaffIds);
+        Map<Long, String> comDeptMap = comDeptIds.isEmpty() ? Collections.emptyMap() : remoteDeptService.selectDeptNameByIds(comDeptIds);
         records.forEach(v -> {
             v.setSalesPersonName(comStaffMap.get(v.getSalesPersonId()));
             v.setServiceStaffName(comStaffMap.get(v.getServiceStaffId()));
@@ -1188,6 +1203,9 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
                 if (null == salesInfoVo.getCreditManagementId()) {
                     throw new ServiceException("ERP销售人员信用等级不能为空");
                 }
+                if (null == salesInfoVo.getOrderAudit()) {
+                    throw new ServiceException("ERP销售人员订单审核方式不能为空");
+                }
             }
         }
         return baseMapper.update(null,
@@ -1872,4 +1890,146 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
     public CustomerInfoVo selectCustomerByName(String customerName) {
         return baseMapper.selectVoOne(new LambdaQueryWrapper<CustomerInfo>().eq(CustomerInfo::getCustomerName, customerName));
     }
+
+    @Override
+    public R<CustomerIndexDataVo> customerIndexData() {
+        CustomerIndexDataVo vo = new CustomerIndexDataVo();
+
+        // 1. 总客户数
+        vo.setTotalCustomers(baseMapper.selectCount(null));
+
+        // 2. 订单统计
+        OrderStatusCountDto orderStatusCount = remoteOrderInfoService.getOrderStatusCount(null);
+        vo.setTotalOrders(orderStatusCount.getOrderCount());
+
+        // 3. 商品总量
+        vo.setTotalProducts(remoteProductService.getTotalProductCount());
+
+        // 4. 本月营收(从订单金额趋势汇总)
+        List<OrderAmountTrendDto> orderAmountTrend = remoteOrderInfoService.getOrderAmountTrend(null);
+        BigDecimal monthlyRevenue = orderAmountTrend.stream()
+            .map(OrderAmountTrendDto::getAmount)
+            .filter(Objects::nonNull)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        vo.setMonthlyRevenue(monthlyRevenue);
+
+        // 5. 最近七天客户趋势
+        LocalDate today = LocalDate.now();
+        LocalDate sevenDaysAgo = today.minusDays(6);
+        List<CustomerInfo> recentCustomers = baseMapper.selectList(
+            new LambdaQueryWrapper<CustomerInfo>()
+                .ge(CustomerInfo::getCreateTime, java.sql.Date.valueOf(sevenDaysAgo))
+                .le(CustomerInfo::getCreateTime, java.sql.Date.valueOf(today))
+        );
+        Map<LocalDate, Long> dailyCustomerMap = new LinkedHashMap<>();
+        LocalDate cursor = sevenDaysAgo;
+        while (!cursor.isAfter(today)) {
+            dailyCustomerMap.put(cursor, 0L);
+            cursor = cursor.plusDays(1);
+        }
+        for (CustomerInfo c : recentCustomers) {
+            if (c.getCreateTime() != null) {
+                LocalDate createDate = c.getCreateTime().toInstant()
+                    .atZone(ZoneId.systemDefault()).toLocalDate();
+                dailyCustomerMap.merge(createDate, 1L, Long::sum);
+            }
+        }
+        List<String> weekDayNames = Arrays.asList("周一", "周二", "周三", "周四", "周五", "周六", "周日");
+        List<CustomerIndexDataVo.TrendItem> customerTrend = new ArrayList<>();
+        int idx = 0;
+        for (Map.Entry<LocalDate, Long> entry : dailyCustomerMap.entrySet()) {
+            CustomerIndexDataVo.TrendItem item = new CustomerIndexDataVo.TrendItem();
+            // 使用星期几作为标签,与前端保持一致
+            item.setDate(weekDayNames.get(idx % 7));
+            item.setValue(BigDecimal.valueOf(entry.getValue()));
+            customerTrend.add(item);
+            idx++;
+        }
+        vo.setCustomerTrend(customerTrend);
+
+        // 6. 本月订单金额趋势(转换DTO->VO)
+        List<CustomerIndexDataVo.TrendItem> orderTrendItems = orderAmountTrend.stream().map(dto -> {
+            CustomerIndexDataVo.TrendItem item = new CustomerIndexDataVo.TrendItem();
+            item.setDate(dto.getDate());
+            item.setValue(dto.getAmount());
+            return item;
+        }).collect(Collectors.toList());
+        vo.setOrderAmountTrend(orderTrendItems);
+
+        // 7. 客户类型分布
+        List<CustomerInfo> allCustomers = baseMapper.selectList(
+            new LambdaQueryWrapper<CustomerInfo>()
+                .isNotNull(CustomerInfo::getCustomerTypeId)
+                .select(CustomerInfo::getCustomerTypeId)
+        );
+        Map<Long, Long> typeCountMap = allCustomers.stream()
+            .filter(c -> c.getCustomerTypeId() != null)
+            .collect(Collectors.groupingBy(CustomerInfo::getCustomerTypeId, Collectors.counting()));
+
+        // 查询字典获取类型名称
+        List<RemoteDictDataVo> enterpriseTypeDicts = remoteDictService.selectDictDataByType("Q0001");
+        Map<String, String> dictMap = CollUtil.emptyIfNull(enterpriseTypeDicts).stream()
+            .collect(Collectors.toMap(RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel, (k1, k2) -> k1));
+
+        List<CustomerIndexDataVo.TypeDistribution> typeDistributions = typeCountMap.entrySet().stream()
+            .map(entry -> {
+                CustomerIndexDataVo.TypeDistribution td = new CustomerIndexDataVo.TypeDistribution();
+                String typeName = dictMap.get(String.valueOf(entry.getKey()));
+                td.setName(typeName != null ? typeName : "其他");
+                td.setValue(entry.getValue());
+                return td;
+            }).collect(Collectors.toList());
+        vo.setCustomerTypeDistribution(typeDistributions);
+
+        // 8. 最新订单明细
+        List<LatestOrderDto> latestOrders = remoteOrderInfoService.getLatestOrders(null, 10);
+        List<CustomerIndexDataVo.LatestOrder> orderList = latestOrders.stream().map(dto -> {
+            CustomerIndexDataVo.LatestOrder order = new CustomerIndexDataVo.LatestOrder();
+            order.setOrderNo(dto.getOrderNo());
+            order.setCustomer(dto.getCustomerName());
+            order.setProduct(dto.getProductName());
+            order.setAmount(dto.getAmount());
+            order.setStatus(dto.getOrderStatus());
+            order.setDate(dto.getOrderTime());
+            return order;
+        }).collect(Collectors.toList());
+        vo.setLatestOrders(orderList);
+
+        // 9. 热销商品排行榜
+        List<HotProductRankingDto> hotProductRankings = remoteOrderInfoService.getHotProductRankings(null, 6);
+        // 计算最大销量用于百分比
+        long maxSales = hotProductRankings.stream()
+            .mapToLong(HotProductRankingDto::getSalesCount)
+            .max().orElse(1L);
+        List<CustomerIndexDataVo.HotProduct> hotProducts = hotProductRankings.stream().map(dto -> {
+            CustomerIndexDataVo.HotProduct hp = new CustomerIndexDataVo.HotProduct();
+            hp.setName(dto.getProductName());
+            hp.setSales(dto.getSalesCount());
+            // 百分比 = 当前销量 / 最大销量 * 100
+            int percentage = maxSales > 0
+                ? (int) Math.round(dto.getSalesCount() * 100.0 / maxSales)
+                : 0;
+            hp.setPercentage(percentage);
+            return hp;
+        }).collect(Collectors.toList());
+        vo.setHotProductRankings(hotProducts);
+
+        return R.ok(vo);
+    }
+
+    //是否需要确认订单
+    @Override
+    public Boolean isNeedAffirmOrder(Long customerId) {
+        boolean affirmFlag = false;
+        CustomerInfoVo customerInfoVo = baseMapper.selectVoById(customerId);
+        if (ObjectUtils.isNotEmpty(customerInfoVo)) {
+            CustomerSalesInfoVo salesInfoVo = customerSalesInfoMapper.selectVoOne(new LambdaQueryWrapper<CustomerSalesInfo>().eq(CustomerSalesInfo::getCustomerId, customerInfoVo.getId()).last("LIMIT 1"));
+            if (ObjectUtils.isNotEmpty(salesInfoVo) && ObjectUtils.isNotEmpty(salesInfoVo.getOrderAudit())) {
+                if ("1".equals(salesInfoVo.getOrderAudit())) {//下单后需要客服确认
+                    affirmFlag = true;
+                }
+            }
+        }
+        return affirmFlag;
+    }
 }

+ 235 - 15
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/PartnerInfoServiceImpl.java

@@ -1,29 +1,44 @@
 package org.dromara.customer.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 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.dromara.customer.domain.CustomerInfo;
-import org.dromara.customer.domain.SupplierInfo;
-import org.dromara.customer.domain.vo.CustomerInfoVo;
-import org.springframework.stereotype.Service;
-import org.dromara.customer.domain.bo.PartnerInfoBo;
-import org.dromara.customer.domain.vo.PartnerInfoVo;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.domain.R;
+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.satoken.utils.LoginHelper;
+import org.dromara.customer.domain.PartnerContacts;
+import org.dromara.customer.domain.PartnerContract;
 import org.dromara.customer.domain.PartnerInfo;
 import org.dromara.customer.domain.PartnerUser;
+import org.dromara.customer.domain.bo.PartnerInfoBo;
+import org.dromara.customer.domain.vo.PartnerInfoIndexDataVo;
+import org.dromara.customer.domain.vo.PartnerInfoVo;
+import org.dromara.customer.domain.vo.PartnerManageIndexDataVo;
+import org.dromara.customer.mapper.PartnerContactsMapper;
+import org.dromara.customer.mapper.PartnerContractMapper;
 import org.dromara.customer.mapper.PartnerInfoMapper;
 import org.dromara.customer.mapper.PartnerUserMapper;
 import org.dromara.customer.service.IPartnerInfoService;
-import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.product.api.RemoteOrderInfoService;
+import org.dromara.product.api.RemoteProductService;
+import org.dromara.product.api.domain.dto.PartnerOrderIndexDto;
+import org.dromara.system.api.RemoteDictService;
+import org.dromara.system.api.domain.vo.RemoteDictDataVo;
+import org.springframework.stereotype.Service;
 
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 伙伴商基本信息Service业务层处理
@@ -38,6 +53,17 @@ public class PartnerInfoServiceImpl extends ServiceImpl<PartnerInfoMapper, Partn
 
     private final PartnerInfoMapper baseMapper;
     private final PartnerUserMapper partnerUserMapper;
+    private final PartnerContractMapper partnerContractMapper;
+    private final PartnerContactsMapper partnerContactsMapper;
+
+    @DubboReference
+    private RemoteDictService remoteDictService;
+
+    @DubboReference
+    private RemoteOrderInfoService remoteOrderInfoService;
+
+    @DubboReference
+    private RemoteProductService remoteProductService;
 
     /**
      * 查询伙伴商基本信息
@@ -209,7 +235,7 @@ public class PartnerInfoServiceImpl extends ServiceImpl<PartnerInfoMapper, Partn
     private String generatePartnerNo() {
         // 获取当前年份
         String year = String.valueOf(java.time.LocalDate.now().getYear());
-        
+
         // 查询当年最大的编号
         LambdaQueryWrapper<PartnerInfo> lqw = Wrappers.lambdaQuery();
         lqw.select(PartnerInfo::getPartnerNo);
@@ -231,8 +257,202 @@ public class PartnerInfoServiceImpl extends ServiceImpl<PartnerInfoMapper, Partn
                 log.warn("解析伙伴商编号失败: {}", maxRecord.getPartnerNo());
             }
         }
-        
+
         // 格式化为 P + 年份 + 3位序号,如 P2026001
         return String.format("P%s%03d", year, nextNum);
     }
+
+    @Override
+    public R<PartnerManageIndexDataVo> partnerManageIndexData() {
+        PartnerManageIndexDataVo vo = new PartnerManageIndexDataVo();
+        LocalDate today = LocalDate.now();
+
+        // 1. 伙伴商总数
+        vo.setPartnerTotal(baseMapper.selectCount(null));
+
+        // 2. 本月新增入驻
+        LocalDate firstDayOfMonth = today.withDayOfMonth(1);
+        vo.setMonthlyNew(baseMapper.selectCount(new LambdaQueryWrapper<PartnerInfo>()
+            .ge(PartnerInfo::getCreateTime, java.sql.Date.valueOf(firstDayOfMonth))
+            .lt(PartnerInfo::getCreateTime, java.sql.Date.valueOf(today.plusDays(1)))
+        ));
+
+        // 3. 季度新增入驻
+        int quarterStartMonth = ((today.getMonthValue() - 1) / 3) * 3 + 1;
+        LocalDate firstDayOfQuarter = LocalDate.of(today.getYear(), quarterStartMonth, 1);
+        vo.setQuarterlyNew(baseMapper.selectCount(new LambdaQueryWrapper<PartnerInfo>()
+            .ge(PartnerInfo::getCreateTime, java.sql.Date.valueOf(firstDayOfQuarter))
+            .lt(PartnerInfo::getCreateTime, java.sql.Date.valueOf(today.plusDays(1)))
+        ));
+
+        // 4. 合作中项目数(PartnerContract中cooperationId去重)
+        List<PartnerContract> contracts = partnerContractMapper.selectList(
+            new LambdaQueryWrapper<PartnerContract>()
+                .isNotNull(PartnerContract::getCooperationId)
+                .select(PartnerContract::getCooperationId)
+        );
+        vo.setCooperationProjectCount(contracts.stream()
+            .map(PartnerContract::getCooperationId)
+            .filter(Objects::nonNull)
+            .distinct()
+            .count());
+
+        // 5. 近半年新增伙伴商趋势
+        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("M月");
+        List<PartnerManageIndexDataVo.MonthTrend> monthlyTrend = new ArrayList<>();
+        for (int i = 5; i >= 0; i--) {
+            LocalDate monthStart = today.minusMonths(i).withDayOfMonth(1);
+            LocalDate monthEnd = monthStart.plusMonths(1);
+
+            PartnerManageIndexDataVo.MonthTrend trend = new PartnerManageIndexDataVo.MonthTrend();
+            trend.setMonth(monthStart.format(monthFormatter));
+            trend.setCount(baseMapper.selectCount(new LambdaQueryWrapper<PartnerInfo>()
+                .ge(PartnerInfo::getCreateTime, java.sql.Date.valueOf(monthStart))
+                .lt(PartnerInfo::getCreateTime, java.sql.Date.valueOf(monthEnd))
+            ));
+            monthlyTrend.add(trend);
+        }
+        vo.setMonthlyTrend(monthlyTrend);
+
+        // 6. 伙伴合作型态分布
+        List<PartnerInfo> allPartners = baseMapper.selectList(
+            new LambdaQueryWrapper<PartnerInfo>()
+                .isNotNull(PartnerInfo::getPartnerCooperateType)
+                .select(PartnerInfo::getPartnerCooperateType)
+        );
+        Map<Long, Long> typeCountMap = allPartners.stream()
+            .filter(p -> p.getPartnerCooperateType() != null)
+            .collect(Collectors.groupingBy(PartnerInfo::getPartnerCooperateType, Collectors.counting()));
+
+        // 查询字典获取类型名称
+        List<RemoteDictDataVo> cooperateTypeDicts = remoteDictService.selectDictDataByType("cooperate_type");
+        Map<String, String> dictMap = CollUtil.emptyIfNull(cooperateTypeDicts).stream()
+            .collect(Collectors.toMap(RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel, (k1, k2) -> k1));
+
+        List<PartnerManageIndexDataVo.TypeDistribution> typeDistributions = typeCountMap.entrySet().stream()
+            .map(entry -> {
+                PartnerManageIndexDataVo.TypeDistribution td = new PartnerManageIndexDataVo.TypeDistribution();
+                String typeName = dictMap.get(String.valueOf(entry.getKey()));
+                td.setName(typeName != null ? typeName : "未知");
+                td.setValue(entry.getValue());
+                return td;
+            }).collect(Collectors.toList());
+        vo.setTypeDistribution(typeDistributions);
+
+        // 7. 最新入驻伙伴商列表(最新8条)
+        List<PartnerInfo> latestPartners = baseMapper.selectList(
+            new LambdaQueryWrapper<PartnerInfo>()
+                .orderByDesc(PartnerInfo::getCreateTime)
+                .last("LIMIT 8")
+        );
+
+        if (CollUtil.isNotEmpty(latestPartners)) {
+            Set<Long> partnerIds = latestPartners.stream()
+                .map(PartnerInfo::getId)
+                .collect(Collectors.toSet());
+
+            // 查询联系人,优先取contactType=1,没有则取contactType=2的任意一个
+            List<PartnerContacts> allContacts = partnerContactsMapper.selectList(
+                new LambdaQueryWrapper<PartnerContacts>()
+                    .in(PartnerContacts::getPartnerId, partnerIds)
+            );
+
+            Map<Long, PartnerContacts> contactMap = allContacts.stream()
+                .collect(Collectors.groupingBy(
+                    PartnerContacts::getPartnerId,
+                    Collectors.collectingAndThen(
+                        Collectors.toList(),
+                        list -> {
+                            // 先找type=1
+                            Optional<PartnerContacts> type1 = list.stream()
+                                .filter(c -> c.getContactType() != null && c.getContactType() == 1)
+                                .findFirst();
+                            if (type1.isPresent()) return type1.get();
+                            // 再找type=2
+                            Optional<PartnerContacts> type2 = list.stream()
+                                .filter(c -> c.getContactType() != null && c.getContactType() == 2)
+                                .findFirst();
+                            return type2.orElse(null);
+                        }
+                    )
+                ));
+
+            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            List<PartnerManageIndexDataVo.LatestPartner> partnerList = latestPartners.stream().map(p -> {
+                PartnerManageIndexDataVo.LatestPartner lp = new PartnerManageIndexDataVo.LatestPartner();
+                lp.setCompanyName(p.getPartnerName());
+                lp.setPartnerCooperateType(p.getPartnerCooperateType());
+
+                PartnerContacts contact = contactMap.get(p.getId());
+                if (contact != null) {
+                    lp.setContact(contact.getName());
+                    lp.setPhone(contact.getPhone());
+                }
+
+                if (p.getCreateTime() != null) {
+                    lp.setJoinTime(p.getCreateTime().toInstant()
+                        .atZone(ZoneId.systemDefault())
+                        .toLocalDateTime().format(dateTimeFormatter));
+                }
+                return lp;
+            }).collect(Collectors.toList());
+            vo.setLatestPartners(partnerList);
+        } else {
+            vo.setLatestPartners(Collections.emptyList());
+        }
+
+        return R.ok(vo);
+    }
+
+    @Override
+    public R<PartnerInfoIndexDataVo> partnerInfoIndexData(Long partnerId) {
+        PartnerInfoIndexDataVo vo = new PartnerInfoIndexDataVo();
+
+        // 1. 远程获取订单统计数据
+        PartnerOrderIndexDto orderData = remoteOrderInfoService.getPartnerOrderIndex(partnerId);
+        if (orderData != null) {
+            vo.setTodayOrders(orderData.getTodayOrders());
+            vo.setWeekRevenue(orderData.getWeekRevenue());
+            vo.setPendingShipment(orderData.getPendingShipment());
+
+            // 发货量走势
+            if (CollUtil.isNotEmpty(orderData.getShipmentTrend())) {
+                vo.setShipmentTrend(orderData.getShipmentTrend().stream().map(ds -> {
+                    PartnerInfoIndexDataVo.ShipmentTrend st = new PartnerInfoIndexDataVo.ShipmentTrend();
+                    st.setDate(ds.getDate());
+                    st.setCount(ds.getCount());
+                    return st;
+                }).collect(Collectors.toList()));
+            }
+
+            // 商品类型销售占比
+            if (CollUtil.isNotEmpty(orderData.getProductTypeSales())) {
+                vo.setProductTypeSales(orderData.getProductTypeSales().stream().map(ts -> {
+                    PartnerInfoIndexDataVo.ProductTypeSales pts = new PartnerInfoIndexDataVo.ProductTypeSales();
+                    pts.setName(ts.getName());
+                    pts.setValue(ts.getValue());
+                    return pts;
+                }).collect(Collectors.toList()));
+            }
+
+            // 最新发货动态
+            if (CollUtil.isNotEmpty(orderData.getLatestShipments())) {
+                vo.setLatestShipments(orderData.getLatestShipments().stream().map(so -> {
+                    PartnerInfoIndexDataVo.LatestShipment ls = new PartnerInfoIndexDataVo.LatestShipment();
+                    ls.setOrderNo(so.getOrderNo());
+                    ls.setProductName(so.getProductName());
+                    ls.setAmount(so.getAmount());
+                    ls.setCustomer(so.getCustomer());
+                    ls.setStatus(so.getStatus());
+                    ls.setDate(so.getDate());
+                    return ls;
+                }).collect(Collectors.toList()));
+            }
+        }
+
+        // 2. 在售商品数
+        vo.setOnSaleProducts(remoteProductService.getTotalProductCount());
+
+        return R.ok(vo);
+    }
 }

+ 61 - 36
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SupplierContractServiceImpl.java

@@ -75,46 +75,71 @@ public class SupplierContractServiceImpl  extends ServiceImpl<SupplierContractMa
      */
     @Override
     public TableDataInfo<SupplierContractVo> queryPageList(SupplierContractBo bo, PageQuery pageQuery) {
-        // 首先从SupplierInfo表进行分页查询
+        // 1. 先查询所有有合同的供应商ID(先过滤)
+        LambdaQueryWrapper<SupplierContract> contractWrapper = Wrappers.lambdaQuery();
+        contractWrapper.select(SupplierContract::getSupplierId)
+            .isNotNull(SupplierContract::getSupplierId)
+            .groupBy(SupplierContract::getSupplierId)
+            .having("COUNT(*) > 0");
+        List<SupplierContract> contractList = baseMapper.selectList(contractWrapper);
+            
+        // 提取有合同的供应商ID集合(防止contractList为null)
+        Set<Long> supplierIdsWithContracts = (contractList == null ? new ArrayList<SupplierContract>() : contractList).stream()
+            .map(SupplierContract::getSupplierId)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toSet());
+            
+        // 如果没有供应商有合同,直接返回空结果
+        if (supplierIdsWithContracts.isEmpty()) {
+            Page<SupplierContractVo> emptyResult = new Page<>();
+            emptyResult.setRecords(new ArrayList<>());
+            emptyResult.setTotal(0L);
+            emptyResult.setSize(pageQuery.getPageSize());
+            emptyResult.setCurrent(pageQuery.getPageNum());
+            return TableDataInfo.build(emptyResult);
+        }
+            
+        // 2. 根据有合同的供应商ID查询供应商信息(带分页)
         LambdaQueryWrapper<SupplierInfo> supplierInfoWrapper = Wrappers.lambdaQuery();
+        supplierInfoWrapper.in(SupplierInfo::getId, supplierIdsWithContracts);
+            
+        // 添加查询条件
         if (bo.getSupplierName() != null) {
             supplierInfoWrapper.eq(SupplierInfo::getEnterpriseName, bo.getSupplierName());
         }
-        if (bo.getSupplierId()!=null){
+        if (bo.getSupplierId() != null) {
             supplierInfoWrapper.eq(SupplierInfo::getId, bo.getSupplierId());
         }
-        if (bo.getSupplierNo()!=null){
+        if (bo.getSupplierNo() != null) {
             supplierInfoWrapper.eq(SupplierInfo::getSupplierNo, bo.getSupplierNo());
         }
-
-        // 添加其他SupplierInfo表的查询条件
+            
+        // 排序
         supplierInfoWrapper.orderByDesc(SupplierInfo::getSupplierNo);
-
-        // 执行分页查询供应商信息
+            
+        // 执行分页查询
         Page<SupplierInfo> supplierPage = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
         IPage<SupplierInfo> supplierInfoPage = supplierInfoService.page(supplierPage, supplierInfoWrapper);
         List<SupplierInfo> supplierInfoList = supplierInfoPage.getRecords();
-
-        // 获取所有供应商ID,用于后续查询合同统计信息
-        List<Long> supplierIds = supplierInfoList.stream()
+            
+        // 3. 查询这些供应商的合同统计信息(防止supplierInfoList为null)
+        List<Long> currentSupplierIds = (supplierInfoList == null ? new ArrayList<SupplierInfo>() : supplierInfoList).stream()
             .map(SupplierInfo::getId)
+            .filter(Objects::nonNull)
             .collect(Collectors.toList());
-
-
-
-        // 查询所有供应商的合同统计信息
+            
         Map<Long, ContractCountDTO> contractStatsMap = new HashMap<>();
-        if (!supplierIds.isEmpty()) {
-            // 查询所有相关合同
-            LambdaQueryWrapper<SupplierContract> contractWrapper = Wrappers.lambdaQuery();
-            contractWrapper.in(SupplierContract::getSupplierId, supplierIds);
-            List<SupplierContract> allContracts = baseMapper.selectList(contractWrapper);
-
-            // 获取当前时间(用于判断合同是否过期)
+        if (!currentSupplierIds.isEmpty()) {
+            // 查询当前页供应商的所有合同
+            LambdaQueryWrapper<SupplierContract> pageContractWrapper = Wrappers.lambdaQuery();
+            pageContractWrapper.in(SupplierContract::getSupplierId, currentSupplierIds);
+            List<SupplierContract> pageContracts = baseMapper.selectList(pageContractWrapper);
+                
+            // 获取当前时间(用于判断合同是否过期)
             Date now = new Date();
-
+                
             // 按供应商ID分组统计合同信息
-            contractStatsMap = allContracts.stream()
+            contractStatsMap = pageContracts.stream()
                 .collect(Collectors.groupingBy(
                     SupplierContract::getSupplierId,
                     Collectors.collectingAndThen(
@@ -122,43 +147,43 @@ public class SupplierContractServiceImpl  extends ServiceImpl<SupplierContractMa
                         list -> {
                             // 统计总数
                             long total = list.size();
-                            // 统计有效期内合同数(状态为已生效 且 到期时间晚于当前时间)
+                            // 统计有效期内合同数(状态为已生效 且 到期时间晚于当前时间)
                             long validCount = list.stream()
                                 .filter(contract ->
                                     2L != (contract.getContractStatus())
                                         && contract.getContractEndTime() != null && contract.getContractEndTime().after(now)
                                 ).count();
-                            // 统计失效合同数(总数 - 有效数)
+                            // 统计失效合同数(总数 - 有效数)
                             long invalidCount = total - validCount;
                             return new ContractCountDTO(total, validCount, invalidCount);
                         }
                     )
                 ));
         }
-
-        // 将供应商信息和合同统计信息组合成VO列表
-        final Map<Long, ContractCountDTO> finalContractStatsMap = contractStatsMap; // 创建final副本
-        List<SupplierContractVo> contractStats = supplierInfoList.stream()
+            
+        // 4. 将供应商信息和合同统计信息组合成VO列表(防止supplierInfoList为null)
+        final Map<Long, ContractCountDTO> finalContractStatsMap = contractStatsMap;
+        List<SupplierContractVo> contractStats = (supplierInfoList == null ? new ArrayList<SupplierInfo>() : supplierInfoList).stream()
             .map(supplierInfo -> {
                 SupplierContractVo vo = new SupplierContractVo();
                 vo.setSupplierId(supplierInfo.getId());
                 vo.setSupplierNo(supplierInfo.getSupplierNo());
                 vo.setSupplierName(supplierInfo.getEnterpriseName());
-
-                // 获取合同统计信息,如果没有则创建默认值为0的统计对象
-                ContractCountDTO defaultCountDTO = new ContractCountDTO(0, 0, 0);
+                    
+                // 获取合同统计信息
                 ContractCountDTO countDTO = finalContractStatsMap.getOrDefault(supplierInfo.getId(),
-                    defaultCountDTO);
-
+                    new ContractCountDTO(0, 0, 0));
+                    
                 // 设置合同数统计
                 vo.setContractNum(String.valueOf(countDTO.getTotal()));
                 vo.setValidContract(String.valueOf(countDTO.getValidCount()));
                 vo.setInvalidContract(String.valueOf(countDTO.getInvalidCount()));
-
+                    
                 return vo;
             })
             .collect(Collectors.toList());
-        // 构建分页结果
+            
+        // 5. 构建分页结果
         Page<SupplierContractVo> result = new Page<>();
         result.setRecords(contractStats);
         result.setTotal(supplierInfoPage.getTotal());

+ 9 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderMainController.java

@@ -22,6 +22,7 @@ import org.dromara.common.web.core.BaseController;
 import org.dromara.order.domain.bo.OrderMainBo;
 import org.dromara.order.domain.bo.OrderProductBo;
 import org.dromara.order.domain.dto.ChangeReturnedStatusRequestDto;
+import org.dromara.order.domain.vo.OrderIndexDataVo;
 import org.dromara.order.domain.vo.OrderMainVo;
 import org.dromara.order.domain.vo.OrderProductVo;
 import org.dromara.order.domain.vo.OrderStatusStats;
@@ -49,6 +50,14 @@ public class OrderMainController extends BaseController {
 
     private final IOrderMainService orderMainService;
 
+    /**
+     * 订单中心首页数据
+     */
+    @GetMapping("/orderIndexData")
+    public R<OrderIndexDataVo> orderIndexData() {
+        return orderMainService.orderIndexData();
+    }
+
     /**
      * 查询订单主信息列表
      */

+ 13 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/pc/PcOrderController.java

@@ -26,6 +26,7 @@ import org.dromara.order.domain.OrderCustomerFlowNodeLink;
 import org.dromara.order.domain.bo.*;
 import org.dromara.order.domain.dto.OrderPayDto;
 import org.dromara.order.domain.vo.OrderCountVo;
+import org.dromara.order.domain.vo.CustomerOrderTradeDataVo;
 import org.dromara.order.domain.vo.OrderMainVo;
 import org.dromara.order.domain.vo.OrderProductVo;
 import org.dromara.order.domain.vo.OrderStatusStats;
@@ -87,6 +88,18 @@ public class PcOrderController extends BaseController {
 
     private final IOrderCustomerFlowNodeLinkService orderCustomerFlowNodeLinkService;
 
+    /**
+     * 订单交易分析数据
+     */
+    @GetMapping("/customerOrderTradeData")
+    public R<CustomerOrderTradeDataVo> customerOrderTradeData() {
+        Long customerId = LoginHelper.getLoginUser().getCustomerId();
+        if (ObjectUtil.isEmpty(customerId)) {
+            return R.fail("未获取到当前客户信息");
+        }
+        return orderMainService.customerOrderTradeData(customerId);
+    }
+
     /**
      * 查询当前企业的订单列表
      * PC端用户只能查询自己企业的订单

+ 81 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/CustomerOrderTradeDataVo.java

@@ -0,0 +1,81 @@
+package org.dromara.order.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 客户订单交易分析数据视图对象
+ *
+ * @author LionLi
+ * @date 2026-06-01
+ */
+@Data
+public class CustomerOrderTradeDataVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /** 购买金额(元) */
+    private BigDecimal totalAmount;
+
+    /** 购买数量(件) */
+    private Long totalQuantity;
+
+    /** 订单量(单) */
+    private Long orderCount;
+
+    /** 客单价(元/单) */
+    private BigDecimal avgOrderAmount;
+
+    /** 采购金额月度趋势 */
+    private List<MonthTrend> amountTrend;
+
+    /** 采购品类占比 */
+    private List<CategoryProportion> categoryProportion;
+
+    /** 采购商品日变化 */
+    private List<DailyChange> dailyChange;
+
+    @Data
+    public static class MonthTrend implements Serializable {
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /** 月份, 格式: "yyyy/MM" */
+        private String month;
+
+        /** 采购金额 */
+        private BigDecimal amount;
+    }
+
+    @Data
+    public static class CategoryProportion implements Serializable {
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /** 品类名称 */
+        private String name;
+
+        /** 采购数量 */
+        private Long value;
+    }
+
+    @Data
+    public static class DailyChange implements Serializable {
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /** 日期序号, 如 "1", "2" */
+        private String day;
+
+        /** 购买金额 */
+        private BigDecimal amount;
+
+        /** 购买数量 */
+        private Long quantity;
+    }
+}

+ 137 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderIndexDataVo.java

@@ -0,0 +1,137 @@
+package org.dromara.order.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 订单中心首页数据视图对象
+ *
+ * @author LionLi
+ * @date 2026-06-01
+ */
+@Data
+public class OrderIndexDataVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 今日订单(笔)
+     */
+    private Long todayOrders;
+
+    /**
+     * 待发货订单(笔)
+     */
+    private Long pendingDeliveryOrders;
+
+    /**
+     * 本月成交额(元)
+     */
+    private BigDecimal monthlyRevenue;
+
+    /**
+     * 售后退款订单(笔)
+     */
+    private Long afterSaleOrders;
+
+    /**
+     * 近七日订单趋势
+     */
+    private List<DayTrend> weeklyTrend;
+
+    /**
+     * 平台订单占比
+     */
+    private List<PlatformProportion> platformProportion;
+
+    /**
+     * 最新订单动态
+     */
+    private List<LatestOrder> latestOrders;
+
+    /**
+     * 每日趋势
+     */
+    @Data
+    public static class DayTrend implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 日期,格式: "MM-dd"
+         */
+        private String date;
+
+        /**
+         * 订单数
+         */
+        private Long count;
+    }
+
+    /**
+     * 平台订单占比
+     */
+    @Data
+    public static class PlatformProportion implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 平台名称:供应商/伙伴商/自营客户
+         */
+        private String name;
+
+        /**
+         * 订单数
+         */
+        private Long value;
+    }
+
+    /**
+     * 最新订单
+     */
+    @Data
+    public static class LatestOrder implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 订单编号
+         */
+        private String orderNo;
+
+        /**
+         * 客户名称
+         */
+        private String customerName;
+
+        /**
+         * 订单来源
+         */
+        private String orderSource;
+
+        /**
+         * 订单金额(元)
+         */
+        private BigDecimal amount;
+
+        /**
+         * 订单状态
+         */
+        private String status;
+
+        /**
+         * 创建时间
+         */
+        private Date createTime;
+    }
+}

+ 265 - 17
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/dubbo/RemoteOrderInfoServiceImpl.java

@@ -1,22 +1,35 @@
 package org.dromara.order.dubbo;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.dromara.common.core.enums.OrderStatus;
+import org.dromara.customer.api.RemoteCustomerService;
 import org.dromara.order.domain.OrderMain;
+import org.dromara.order.domain.OrderProduct;
 import org.dromara.order.domain.OrderReturn;
 import org.dromara.order.service.IOrderMainService;
+import org.dromara.order.service.IOrderProductService;
 import org.dromara.order.service.IOrderReturnService;
 import org.dromara.product.api.RemoteOrderInfoService;
+import org.dromara.product.api.domain.dto.HotProductRankingDto;
+import org.dromara.product.api.domain.dto.LatestOrderDto;
+import org.dromara.product.api.domain.dto.OrderAmountTrendDto;
 import org.dromara.product.api.domain.dto.OrderStatusCountDto;
+import org.dromara.product.api.domain.dto.PartnerOrderIndexDto;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
-import java.util.List;
-import java.util.Objects;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @author
@@ -32,6 +45,11 @@ public class RemoteOrderInfoServiceImpl implements RemoteOrderInfoService {
 
     private final IOrderReturnService orderReturnService;
 
+    private final IOrderProductService orderProductService;
+
+    @DubboReference
+    private RemoteCustomerService remoteCustomerService;
+
     /**
      * 获取订单各个状态的数量
      */
@@ -41,50 +59,280 @@ public class RemoteOrderInfoServiceImpl implements RemoteOrderInfoService {
         // 订单数量
         orderStatusCount.setOrderCount(
             orderMainService.count(Wrappers.<OrderMain>lambdaQuery()
-                .eq(OrderMain::getDataSource, itemKey)
-        ));
+                .eq(StrUtil.isNotBlank(itemKey), OrderMain::getDataSource, itemKey)
+            ));
         // 已完成订单数量
         orderStatusCount.setCompletedCount(
             orderMainService.count(Wrappers.<OrderMain>lambdaQuery()
-                .eq(OrderMain::getDataSource, itemKey)
+                .eq(StrUtil.isNotBlank(itemKey), OrderMain::getDataSource, itemKey)
                 .eq(OrderMain::getOrderStatus, OrderStatus.COMPLETED)
-        ));
+            ));
         // 待付款订单数量
         orderStatusCount.setWaitPayCount(
             orderMainService.count(Wrappers.<OrderMain>lambdaQuery()
-                .eq(OrderMain::getDataSource, itemKey)
+                .eq(StrUtil.isNotBlank(itemKey), OrderMain::getDataSource, itemKey)
                 .eq(OrderMain::getOrderStatus, OrderStatus.PENDING_PAYMENT)
-        ));
+            ));
         // 待发货订单数量
         orderStatusCount.setWaitDeliverCount(
             orderMainService.count(Wrappers.<OrderMain>lambdaQuery()
-                .eq(OrderMain::getDataSource, itemKey)
+                .eq(StrUtil.isNotBlank(itemKey), OrderMain::getDataSource, itemKey)
                 .eq(OrderMain::getOrderStatus, OrderStatus.PENDING_SHIPMENT)
-        ));
+            ));
         // 售后订单数量
         orderStatusCount.setWaitDeliverCount(
             orderReturnService.count(Wrappers.<OrderReturn>lambdaQuery()
-                .eq(OrderReturn::getDataSource, itemKey)
-        ));
+                .eq(StrUtil.isNotBlank(itemKey), OrderReturn::getDataSource, itemKey)
+            ));
         // 订单总金额
         List<OrderMain> orderMains = orderMainService.list(Wrappers.<OrderMain>lambdaQuery()
-            .eq(OrderMain::getDataSource, itemKey)
+            .eq(StrUtil.isNotBlank(itemKey), OrderMain::getDataSource, itemKey)
             .select(OrderMain::getTotalAmount)
         );
-        if(ObjectUtil.isNotEmpty(orderMains)){
+        if (ObjectUtil.isNotEmpty(orderMains)) {
             orderStatusCount.setOrderAmount(orderMains.stream().map(OrderMain::getTotalAmount).filter(Objects::nonNull).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
         }
         // 售后订单金额 如果为null 则为0
         List<OrderReturn> orderReturns = orderReturnService.list(Wrappers.<OrderReturn>lambdaQuery()
-            .eq(OrderReturn::getDataSource, itemKey)
+            .eq(StrUtil.isNotBlank(itemKey), OrderReturn::getDataSource, itemKey)
             .select(OrderReturn::getAfterSaleAmount)
         );
-        if(ObjectUtil.isNotEmpty(orderReturns)){
+        if (ObjectUtil.isNotEmpty(orderReturns)) {
             orderStatusCount.setRefundAmount(
-            orderReturns.stream().map(OrderReturn::getAfterSaleAmount).filter(Objects::nonNull).reduce(BigDecimal::add).orElse(BigDecimal.ZERO)
+                orderReturns.stream().map(OrderReturn::getAfterSaleAmount).filter(Objects::nonNull).reduce(BigDecimal::add).orElse(BigDecimal.ZERO)
             );
         }
 
         return orderStatusCount;
     }
+
+    /**
+     * 获取最新订单列表
+     */
+    @Override
+    public List<LatestOrderDto> getLatestOrders(String itemKey, int limit) {
+        // 查询最新N条一级订单(currentLevel=1),按创建时间倒序
+        List<OrderMain> orderMains = orderMainService.list(Wrappers.<OrderMain>lambdaQuery()
+            .eq(StrUtil.isNotBlank(itemKey), OrderMain::getDataSource, itemKey)
+            .eq(OrderMain::getCurrentLevel, 1)
+            .orderByDesc(OrderMain::getCreateTime)
+            .last("LIMIT " + limit)
+        );
+
+        if (CollUtil.isEmpty(orderMains)) {
+            return Collections.emptyList();
+        }
+
+        // 收集所有订单ID
+        Set<Long> orderIds = orderMains.stream()
+            .map(OrderMain::getId)
+            .collect(Collectors.toSet());
+
+        // 查询订单商品
+        List<OrderProduct> orderProducts = orderProductService.list(Wrappers.<OrderProduct>lambdaQuery()
+            .in(OrderProduct::getOrderId, orderIds)
+        );
+
+        // 按订单ID分组(取每个订单的第一个商品名称)
+        Map<Long, String> orderProductMap = orderProducts.stream()
+            .collect(Collectors.groupingBy(
+                OrderProduct::getOrderId,
+                Collectors.collectingAndThen(
+                    Collectors.toList(),
+                    list -> list.isEmpty() ? "" : list.get(0).getProductName()
+                )
+            ));
+
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        // 收集所有客户ID,远程批量查询客户名称
+        Set<Long> customerIds = orderMains.stream()
+            .map(OrderMain::getCustomerId)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toSet());
+        Map<Long, String> customerNameMap = CollUtil.isEmpty(customerIds)
+            ? Collections.emptyMap()
+            : remoteCustomerService.selectCustomerNameByIds(customerIds);
+
+        return orderMains.stream().map(order -> {
+            LatestOrderDto dto = new LatestOrderDto();
+            dto.setOrderNo(order.getOrderNo());
+            dto.setCustomerName(customerNameMap.getOrDefault(order.getCustomerId(), ""));
+            dto.setProductName(orderProductMap.getOrDefault(order.getId(), ""));
+            dto.setAmount(order.getTotalAmount());
+            dto.setOrderStatus(order.getOrderStatus());
+            if (order.getOrderTime() != null) {
+                dto.setOrderTime(order.getOrderTime().toInstant()
+                    .atZone(java.time.ZoneId.systemDefault())
+                    .toLocalDateTime().format(formatter));
+            }
+            return dto;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 获取本月订单金额趋势
+     */
+    @Override
+    public List<OrderAmountTrendDto> getOrderAmountTrend(String itemKey) {
+        // 获取本月第一天
+        LocalDate firstDayOfMonth = LocalDate.now().withDayOfMonth(1);
+        LocalDate today = LocalDate.now();
+
+        List<OrderMain> orderMains = orderMainService.list(Wrappers.<OrderMain>lambdaQuery()
+            .eq(StrUtil.isNotBlank(itemKey), OrderMain::getDataSource, itemKey)
+            .ge(OrderMain::getCreateTime, java.sql.Date.valueOf(firstDayOfMonth))
+            .lt(OrderMain::getCreateTime, java.sql.Date.valueOf(today.plusDays(1)))
+            .select(OrderMain::getCreateTime, OrderMain::getTotalAmount)
+        );
+
+        // 按天分组汇总
+        Map<LocalDate, BigDecimal> dailyAmountMap = new LinkedHashMap<>();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d日");
+
+        // 初始化本月所有日期
+        LocalDate current = firstDayOfMonth;
+        while (!current.isAfter(today)) {
+            dailyAmountMap.put(current, BigDecimal.ZERO);
+            current = current.plusDays(1);
+        }
+
+        // 汇总每天金额
+        for (OrderMain order : orderMains) {
+            if (order.getCreateTime() != null && order.getTotalAmount() != null) {
+                LocalDate orderDate = order.getCreateTime().toInstant()
+                    .atZone(java.time.ZoneId.systemDefault())
+                    .toLocalDate();
+                dailyAmountMap.merge(orderDate, order.getTotalAmount(), BigDecimal::add);
+            }
+        }
+
+        return dailyAmountMap.entrySet().stream()
+            .map(entry -> new OrderAmountTrendDto(entry.getKey().format(formatter), entry.getValue()))
+            .collect(Collectors.toList());
+    }
+
+    /**
+     * 获取热销商品排行榜
+     */
+    @Override
+    public List<HotProductRankingDto> getHotProductRankings(String itemKey, int limit) {
+        // 查询所有订单商品,按商品名称分组汇总销量
+        List<OrderProduct> orderProducts = orderProductService.list(Wrappers.<OrderProduct>lambdaQuery()
+            .eq(StrUtil.isNotBlank(itemKey), OrderProduct::getDataSource, itemKey)
+            .select(OrderProduct::getProductName, OrderProduct::getOrderQuantity)
+        );
+
+        if (CollUtil.isEmpty(orderProducts)) {
+            return Collections.emptyList();
+        }
+
+        // 按商品名称分组汇总销量
+        Map<String, Long> productSalesMap = orderProducts.stream()
+            .filter(p -> p.getProductName() != null && p.getOrderQuantity() != null)
+            .collect(Collectors.groupingBy(
+                OrderProduct::getProductName,
+                Collectors.reducing(0L, OrderProduct::getOrderQuantity, Long::sum)
+            ));
+
+        // 按销量降序排列,取前N条
+        return productSalesMap.entrySet().stream()
+            .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
+            .limit(limit)
+            .map(entry -> new HotProductRankingDto(entry.getKey(), entry.getValue()))
+            .collect(Collectors.toList());
+    }
+
+    @Override
+    public PartnerOrderIndexDto getPartnerOrderIndex(Long partnerId) {
+        PartnerOrderIndexDto dto = new PartnerOrderIndexDto();
+        LocalDate today = LocalDate.now();
+        Date todayStart = java.sql.Date.valueOf(today);
+        Date todayEnd = java.sql.Date.valueOf(today.plusDays(1));
+        LocalDate weekStart = today.with(java.time.DayOfWeek.MONDAY);
+        Date weekStartDate = java.sql.Date.valueOf(weekStart);
+
+        dto.setTodayOrders(orderMainService.count(Wrappers.<OrderMain>lambdaQuery()
+            .eq(OrderMain::getAssigneeId, partnerId)
+            .ge(OrderMain::getCreateTime, todayStart)
+            .lt(OrderMain::getCreateTime, todayEnd)));
+
+        List<OrderMain> weekOrders = orderMainService.list(Wrappers.<OrderMain>lambdaQuery()
+            .eq(OrderMain::getAssigneeId, partnerId)
+            .ge(OrderMain::getCreateTime, weekStartDate)
+            .lt(OrderMain::getCreateTime, todayEnd)
+            .select(OrderMain::getTotalAmount));
+        dto.setWeekRevenue(weekOrders.stream()
+            .map(OrderMain::getTotalAmount).filter(Objects::nonNull)
+            .reduce(BigDecimal.ZERO, BigDecimal::add));
+
+        dto.setPendingShipment(orderMainService.count(Wrappers.<OrderMain>lambdaQuery()
+            .eq(OrderMain::getAssigneeId, partnerId)
+            .notIn(OrderMain::getOrderStatus, "3", "4")));
+
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM-dd");
+        List<PartnerOrderIndexDto.DayShipment> shipmentTrend = new ArrayList<>();
+        for (int i = 6; i >= 0; i--) {
+            LocalDate date = today.minusDays(i);
+            Long count = orderMainService.count(Wrappers.<OrderMain>lambdaQuery()
+                .eq(OrderMain::getAssigneeId, partnerId)
+                .in(OrderMain::getOrderStatus, "3", "4")
+                .ge(OrderMain::getCreateTime, java.sql.Date.valueOf(date))
+                .lt(OrderMain::getCreateTime, java.sql.Date.valueOf(date.plusDays(1))));
+            PartnerOrderIndexDto.DayShipment ds = new PartnerOrderIndexDto.DayShipment();
+            ds.setDate(date.format(dateFormatter));
+            ds.setCount(count);
+            shipmentTrend.add(ds);
+        }
+        dto.setShipmentTrend(shipmentTrend);
+
+        List<OrderMain> partnerOrders = orderMainService.list(Wrappers.<OrderMain>lambdaQuery()
+            .eq(OrderMain::getAssigneeId, partnerId).select(OrderMain::getId));
+        List<PartnerOrderIndexDto.TypeSales> typeSalesList = Collections.emptyList();
+        if (CollUtil.isNotEmpty(partnerOrders)) {
+            Set<Long> orderIds = partnerOrders.stream().map(OrderMain::getId).collect(Collectors.toSet());
+            List<OrderProduct> products = orderProductService.list(Wrappers.<OrderProduct>lambdaQuery()
+                .in(OrderProduct::getOrderId, orderIds).select(OrderProduct::getProductName));
+            Map<String, Long> nameCountMap = products.stream()
+                .filter(p -> p.getProductName() != null)
+                .collect(Collectors.groupingBy(OrderProduct::getProductName, Collectors.counting()));
+            typeSalesList = nameCountMap.entrySet().stream()
+                .sorted(Map.Entry.<String, Long>comparingByValue().reversed()).limit(5)
+                .map(entry -> { PartnerOrderIndexDto.TypeSales ts = new PartnerOrderIndexDto.TypeSales(); ts.setName(entry.getKey()); ts.setValue(entry.getValue()); return ts; })
+                .collect(Collectors.toList());
+        }
+        dto.setProductTypeSales(typeSalesList);
+
+        List<OrderMain> latestOrders = orderMainService.list(Wrappers.<OrderMain>lambdaQuery()
+            .eq(OrderMain::getAssigneeId, partnerId)
+            .orderByDesc(OrderMain::getCreateTime).last("LIMIT 10"));
+        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        List<PartnerOrderIndexDto.ShipmentOrder> shipments = new ArrayList<>();
+        if (CollUtil.isNotEmpty(latestOrders)) {
+            Set<Long> latestOrderIds = latestOrders.stream().map(OrderMain::getId).collect(Collectors.toSet());
+            List<OrderProduct> latestProducts = orderProductService.list(Wrappers.<OrderProduct>lambdaQuery()
+                .in(OrderProduct::getOrderId, latestOrderIds));
+            Map<Long, String> productNameMap = latestProducts.stream()
+                .collect(Collectors.groupingBy(OrderProduct::getOrderId,
+                    Collectors.collectingAndThen(Collectors.toList(), list -> list.isEmpty() ? "" : list.get(0).getProductName())));
+            Set<Long> customerIds = latestOrders.stream().map(OrderMain::getCustomerId).filter(Objects::nonNull).collect(Collectors.toSet());
+            Map<Long, String> customerNameMap = CollUtil.isEmpty(customerIds) ? Collections.emptyMap() : remoteCustomerService.selectCustomerNameByIds(customerIds);
+            for (OrderMain order : latestOrders) {
+                PartnerOrderIndexDto.ShipmentOrder so = new PartnerOrderIndexDto.ShipmentOrder();
+                so.setOrderNo(order.getOrderNo());
+                so.setProductName(productNameMap.getOrDefault(order.getId(), ""));
+                so.setAmount(order.getTotalAmount());
+                so.setCustomer(customerNameMap.getOrDefault(order.getCustomerId(), ""));
+                String status = order.getOrderStatus();
+                if ("3".equals(status)) so.setStatus("部分发货");
+                else if ("4".equals(status)) so.setStatus("已发货");
+                else so.setStatus(status);
+                if (order.getCreateTime() != null)
+                    so.setDate(order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().format(dtf));
+                shipments.add(so);
+            }
+        }
+        dto.setLatestShipments(shipments);
+        return dto;
+    }
 }

+ 5 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderMainService.java

@@ -1,6 +1,7 @@
 package org.dromara.order.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.common.core.domain.R;
 import org.dromara.common.core.exception.api.ZhongcheException;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -174,4 +175,8 @@ public interface IOrderMainService extends IService<OrderMain> {
 
     OrderTreeVo queryOrderWithChildren(Long orderId);
 
+    R<OrderIndexDataVo> orderIndexData();
+
+    R<CustomerOrderTradeDataVo> customerOrderTradeData(Long customerId);
+
 }

+ 238 - 1
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java

@@ -13,6 +13,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.common.core.context.PlatformContext;
+import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.*;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.api.ZhongcheException;
@@ -57,6 +58,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.math.BigDecimal;
 import java.sql.SQLIntegrityConstraintViolationException;
 import java.time.LocalDate;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Function;
@@ -144,6 +146,8 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
     private final IOrderAssignmentService orderAssignmentService;
 
+    private final OrderReturnMapper orderReturnMapper;
+
     /**
      * 查询订单主信息
      *
@@ -542,6 +546,8 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
             Long productQuantity = orderProductBos.stream().mapToLong(OrderProductBo::getOrderQuantity).sum();
 
+            Boolean needAffirmOrder = remoteCustomerService.isNeedAffirmOrder(bo.getCustomerId());
+
             // 应付总额 = 商品总价 + 运费
             BigDecimal payableAmount = totalAmount.add(bo.getShippingFee());
 
@@ -583,6 +589,16 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
                     bo.setOrderTime(orderTimeToUse);
                     bo.setOrderType("0");
                     bo.setAssigneeType(AssigneeTypeConstants.MKT.getCode());
+
+
+                    if ("0".equals(bo.getPayType())) {//信用支付
+                        String orderStatus = OrderStatus.PENDING_SHIPMENT.getCode();//待发货
+                        bo.setConfirmTime(new Date());
+                        if (needAffirmOrder) {
+                            orderStatus = OrderStatus.PENDING_CONFIRMATION.getCode();//待确认
+                        }
+                        bo.setOrderStatus(orderStatus);
+                    }
                     // --- 步骤 C: 转换对象 ---
                     orderMain = MapstructUtils.convert(bo, OrderMain.class);
 
@@ -719,6 +735,8 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
     public Long insertOrder(PcSubmitOrderBo bo, OrderMainBo mainBo) {
         CustomerInfoDTO customerInfoDTO = remoteCustomerService.selectCustomerInfoById(mainBo.getCustomerId());
 
+        Boolean affirmFlag = remoteCustomerService.isNeedAffirmOrder(mainBo.getCustomerId());
+
         RemoteCustomerContactVo remoteCustomerContactVo = remoteCustomerContactService.selectCustomerContactByCustomerIdAndUserId(mainBo.getCustomerId(), mainBo.getUserId());
         if (ObjectUtils.isNotEmpty(remoteCustomerContactVo)) {
             mainBo.setContactId(remoteCustomerContactVo.getId());
@@ -764,13 +782,17 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         if (orderId != null && orderId > 0) {
             // 3. 初始化审批流程
             Boolean initOrderFlow = orderCustomerFlowService.initOrderFlow(orderId, mainBo.getContactId());
+            String orderStatus = OrderStatus.PENDING_SHIPMENT.getCode();
+            if (affirmFlag) {
+                orderStatus = OrderStatus.PENDING_CONFIRMATION.getCode();
+            }
 
             // 4. 如果流程初始化成功,更新订单状态 (注意:这里再次触发了数据库更新)
             if (initOrderFlow) {
                 log.info("成功初始化审批流程,订单ID: {}", orderId);
                 this.update(Wrappers.lambdaUpdate(OrderMain.class)
                     .eq(OrderMain::getId, orderId)
-                    .set(OrderMain::getOrderStatus, OrderStatus.PENDING_SHIPMENT.getCode())// 待发货
+                    .set(OrderMain::getOrderStatus, orderStatus)// 根据当前客户设置的是否需要确认来设置订单状态
                     .set(OrderMain::getIsNeedCheck, SysPlatformYesNo.YES.getCode())
                 );
 
@@ -2051,4 +2073,219 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
         return null;
     }
+
+    @Override
+    public R<OrderIndexDataVo> orderIndexData() {
+        OrderIndexDataVo vo = new OrderIndexDataVo();
+        LocalDate today = LocalDate.now();
+        Date todayStart = Date.from(today.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
+        Date todayEnd = Date.from(today.plusDays(1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
+        Date monthStart = Date.from(today.withDayOfMonth(1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
+
+        // ========== 1. 统计卡片 ==========
+        // 今日订单数
+        Long todayOrders = baseMapper.selectCount(new LambdaQueryWrapper<OrderMain>()
+            .ge(OrderMain::getCreateTime, todayStart)
+            .lt(OrderMain::getCreateTime, todayEnd));
+        vo.setTodayOrders(todayOrders);
+
+        // 待发货订单数
+        Long pendingDelivery = baseMapper.selectCount(new LambdaQueryWrapper<OrderMain>()
+            .eq(OrderMain::getOrderStatus, OrderStatus.PENDING_SHIPMENT.getCode()));
+        vo.setPendingDeliveryOrders(pendingDelivery);
+
+        // 本月成交额
+        List<OrderMain> monthlyOrders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
+            .select(OrderMain::getTotalAmount)
+            .ge(OrderMain::getCreateTime, monthStart)
+            .lt(OrderMain::getCreateTime, todayEnd));
+        BigDecimal monthlyRevenue = monthlyOrders.stream()
+            .map(OrderMain::getTotalAmount)
+            .filter(Objects::nonNull)
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+        vo.setMonthlyRevenue(monthlyRevenue);
+
+        // 售后退款订单数
+        Long afterSaleOrders = orderReturnMapper.selectCount(new LambdaQueryWrapper<OrderReturn>()
+            .gt(OrderReturn::getReturnStatus, 0));
+        vo.setAfterSaleOrders(afterSaleOrders);
+
+        // ========== 2. 近七日订单趋势 ==========
+        List<OrderIndexDataVo.DayTrend> weeklyTrend = new ArrayList<>();
+        for (int i = 6; i >= 0; i--) {
+            LocalDate date = today.minusDays(i);
+            Date dayStart = Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
+            Date dayEnd = Date.from(date.plusDays(1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
+            Long count = baseMapper.selectCount(new LambdaQueryWrapper<OrderMain>()
+                .ge(OrderMain::getCreateTime, dayStart)
+                .lt(OrderMain::getCreateTime, dayEnd));
+
+            OrderIndexDataVo.DayTrend trend = new OrderIndexDataVo.DayTrend();
+            trend.setDate(date.format(DateTimeFormatter.ofPattern("MM-dd")));
+            trend.setCount(count);
+            weeklyTrend.add(trend);
+        }
+        vo.setWeeklyTrend(weeklyTrend);
+
+        // ========== 3. 平台订单占比(按 assigneeType: srm, bp, zy) ==========
+        List<OrderMain> platformOrders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
+            .select(OrderMain::getAssigneeType)
+            .isNotNull(OrderMain::getAssigneeType)
+            .ne(OrderMain::getAssigneeType, ""));
+        Map<String, Long> platformCountMap = platformOrders.stream()
+            .collect(Collectors.groupingBy(OrderMain::getAssigneeType, Collectors.counting()));
+
+        List<OrderIndexDataVo.PlatformProportion> proportions = new ArrayList<>();
+        proportions.add(buildProportion("供应商", platformCountMap.getOrDefault("srm", 0L)));
+        proportions.add(buildProportion("伙伴商", platformCountMap.getOrDefault("bp", 0L)));
+        proportions.add(buildProportion("自营客户", platformCountMap.getOrDefault("zy", 0L)));
+        vo.setPlatformProportion(proportions);
+
+        // ========== 4. 最新订单列表(前10条) ==========
+        List<OrderMain> latestOrders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
+            .orderByDesc(OrderMain::getCreateTime)
+            .last("LIMIT 10"));
+
+        Set<Long> customerIds = latestOrders.stream()
+            .map(OrderMain::getCustomerId)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toSet());
+        Map<Long, String> customerNameMap = customerIds.isEmpty()
+            ? Collections.emptyMap()
+            : remoteCustomerService.selectCustomerNameByIds(customerIds);
+
+        List<OrderIndexDataVo.LatestOrder> latestOrderList = latestOrders.stream().map(order -> {
+            OrderIndexDataVo.LatestOrder lo = new OrderIndexDataVo.LatestOrder();
+            lo.setOrderNo(order.getOrderNo());
+            lo.setCustomerName(customerNameMap.get(order.getCustomerId()));
+            lo.setOrderSource(order.getOrderSource());
+            lo.setAmount(order.getTotalAmount());
+            lo.setStatus(order.getOrderStatus());
+            if (order.getCreateTime() != null) {
+                lo.setCreateTime(order.getCreateTime());
+            }
+            return lo;
+        }).collect(Collectors.toList());
+        vo.setLatestOrders(latestOrderList);
+
+        return R.ok(vo);
+    }
+
+    private OrderIndexDataVo.PlatformProportion buildProportion(String name, Long value) {
+        OrderIndexDataVo.PlatformProportion proportion = new OrderIndexDataVo.PlatformProportion();
+        proportion.setName(name);
+        proportion.setValue(value);
+        return proportion;
+    }
+
+    @Override
+    public R<CustomerOrderTradeDataVo> customerOrderTradeData(Long customerId) {
+        CustomerOrderTradeDataVo vo = new CustomerOrderTradeDataVo();
+        LocalDate today = LocalDate.now();
+
+        // ========== 1. 统计卡片(全部历史数据) ==========
+        List<OrderMain> allOrders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
+            .eq(OrderMain::getCustomerId, customerId)
+            .select(OrderMain::getTotalAmount, OrderMain::getProductQuantity));
+
+        BigDecimal totalAmount = BigDecimal.ZERO;
+        long totalQuantity = 0;
+        long orderCount = allOrders.size();
+        for (OrderMain order : allOrders) {
+            if (order.getTotalAmount() != null) {
+                totalAmount = totalAmount.add(order.getTotalAmount());
+            }
+            if (order.getProductQuantity() != null) {
+                totalQuantity += order.getProductQuantity();
+            }
+        }
+        vo.setTotalAmount(totalAmount);
+        vo.setTotalQuantity(totalQuantity);
+        vo.setOrderCount(orderCount);
+        vo.setAvgOrderAmount(orderCount > 0
+            ? totalAmount.divide(BigDecimal.valueOf(orderCount), 2, java.math.RoundingMode.HALF_UP)
+            : BigDecimal.ZERO);
+
+        // ========== 2. 采购金额月度趋势(今年12个月) ==========
+        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy/MM");
+        List<CustomerOrderTradeDataVo.MonthTrend> amountTrend = new ArrayList<>();
+        for (int i = 0; i < 12; i++) {
+            LocalDate monthStart = LocalDate.of(today.getYear(), i + 1, 1);
+            LocalDate monthEnd = monthStart.plusMonths(1);
+
+            List<OrderMain> monthOrders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
+                .eq(OrderMain::getCustomerId, customerId)
+                .ge(OrderMain::getCreateTime, java.sql.Date.valueOf(monthStart))
+                .lt(OrderMain::getCreateTime, java.sql.Date.valueOf(monthEnd))
+                .select(OrderMain::getTotalAmount));
+
+            BigDecimal monthAmount = monthOrders.stream()
+                .map(OrderMain::getTotalAmount).filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            CustomerOrderTradeDataVo.MonthTrend mt = new CustomerOrderTradeDataVo.MonthTrend();
+            mt.setMonth(monthStart.format(monthFormatter));
+            mt.setAmount(monthAmount);
+            amountTrend.add(mt);
+        }
+        vo.setAmountTrend(amountTrend);
+
+        // ========== 3. 采购品类占比 ==========
+        List<OrderMain> customerOrders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
+            .eq(OrderMain::getCustomerId, customerId).eq(OrderMain::getCurrentLevel, "1")
+            .select(OrderMain::getId));
+        List<CustomerOrderTradeDataVo.CategoryProportion> categoryList = new ArrayList<>();
+        if (CollUtil.isNotEmpty(customerOrders)) {
+            Set<Long> orderIds = customerOrders.stream().map(OrderMain::getId).collect(Collectors.toSet());
+            List<OrderProduct> products = orderProductMapper.selectList(new LambdaQueryWrapper<OrderProduct>()
+                .in(OrderProduct::getOrderId, orderIds)
+                .select(OrderProduct::getCategoryName, OrderProduct::getOrderQuantity));
+
+            Map<String, Long> categoryMap = products.stream()
+                .filter(p -> p.getCategoryName() != null && p.getOrderQuantity() != null)
+                .collect(Collectors.groupingBy(OrderProduct::getCategoryName,
+                    Collectors.summingLong(OrderProduct::getOrderQuantity)));
+
+            categoryList = categoryMap.entrySet().stream()
+                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
+                .map(entry -> {
+                    CustomerOrderTradeDataVo.CategoryProportion cp = new CustomerOrderTradeDataVo.CategoryProportion();
+                    cp.setName(entry.getKey());
+                    cp.setValue(entry.getValue());
+                    return cp;
+                }).collect(Collectors.toList());
+        }
+        vo.setCategoryProportion(categoryList);
+
+        // ========== 4. 采购商品日变化(本月每天) ==========
+        LocalDate firstDayOfMonth = today.withDayOfMonth(1);
+        List<CustomerOrderTradeDataVo.DailyChange> dailyChange = new ArrayList<>();
+        for (int d = 1; d <= today.getDayOfMonth(); d++) {
+            LocalDate date = firstDayOfMonth.plusDays(d - 1);
+            Date dayStart = java.sql.Date.valueOf(date);
+            Date dayEnd = java.sql.Date.valueOf(date.plusDays(1));
+
+            List<OrderMain> dayOrders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
+                .eq(OrderMain::getCustomerId, customerId)
+                .ge(OrderMain::getCreateTime, dayStart)
+                .lt(OrderMain::getCreateTime, dayEnd)
+                .select(OrderMain::getTotalAmount, OrderMain::getProductQuantity));
+
+            BigDecimal dayAmount = dayOrders.stream()
+                .map(OrderMain::getTotalAmount).filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+            long dayQuantity = dayOrders.stream()
+                .map(OrderMain::getProductQuantity).filter(Objects::nonNull)
+                .mapToLong(Long::longValue).sum();
+
+            CustomerOrderTradeDataVo.DailyChange dc = new CustomerOrderTradeDataVo.DailyChange();
+            dc.setDay(String.valueOf(d));
+            dc.setAmount(dayAmount);
+            dc.setQuantity(dayQuantity);
+            dailyChange.add(dc);
+        }
+        vo.setDailyChange(dailyChange);
+
+        return R.ok(vo);
+    }
 }

+ 8 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductServiceImpl.java

@@ -701,4 +701,12 @@ public class RemoteProductServiceImpl implements RemoteProductService {
 
         return Objects.isNull(productBase) ? null : productBase.getId();
     }
+
+    /**
+     * 获取商品总数
+     */
+    @Override
+    public Long getTotalProductCount() {
+        return productBaseService.count();
+    }
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/pc/IndexSystemController.java

@@ -217,7 +217,7 @@ public class IndexSystemController {
     @GetMapping("/getHotSchemeList")
     public R<List<SysFloorAdvertManage>> getHotSchemeList() {
         List<SysFloorAdvertManage> list = sysFloorAdvertManageService.list(Wrappers.lambdaQuery(SysFloorAdvertManage.class)
-            .eq(SysFloorAdvertManage::getAdvertPosition, 3)
+            .eq(SysFloorAdvertManage::getAdvertPosition, 3).orderByAsc(SysFloorAdvertManage::getManageSerial)
         );
         return R.ok(list);
     }

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/ComStaff.java

@@ -100,6 +100,11 @@ public class ComStaff extends TenantEntity {
      */
     private String remark;
 
+    /**
+     * 平台使用范围(逗号分隔的平台编码,总控可访问所有平台)
+     */
+    private String platformRange;
+
     /*系统用户Id*/
     private Long userId;
 

+ 4 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java

@@ -118,6 +118,10 @@ public class SysUser extends TenantEntity {
     @TableField(value = "platform_code", fill = FieldFill.INSERT)
     private String platformCode;
 
+    /**
+     * 平台使用范围(逗号分隔的平台编码,总控可访问所有平台)
+     */
+    private String platformRange;
 
     public SysUser(Long userId) {
         this.userId = userId;

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/ComStaffBo.java

@@ -93,6 +93,11 @@ public class ComStaffBo extends BaseEntity {
      */
     private String remark;
 
+    /**
+     * 平台使用范围(逗号分隔的平台编码)
+     */
+    private String platformRange;
+
 
     /*系统用户Id*/
     private Long userId;

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java

@@ -128,6 +128,11 @@ public class SysUserBo extends BaseEntity {
 
     private String openId;
 
+    /**
+     * 平台使用范围(逗号分隔的平台编码)
+     */
+    private String platformRange;
+
     /**
      * 排除不查询的用户(工作流用)
      */

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ComStaffVo.java

@@ -132,5 +132,10 @@ public class ComStaffVo implements Serializable {
 
     private String roleName;
 
+    /**
+     * 平台使用范围(逗号分隔的平台编码)
+     */
+    private String platformRange;
+
 
 }

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java

@@ -147,6 +147,11 @@ public class SysUserVo implements Serializable {
     /*平台标识*/
     private String platformCode;
 
+    /**
+     * 平台使用范围(逗号分隔的平台编码)
+     */
+    private String platformRange;
+
     private String source;
 
     private String openId;

+ 70 - 5
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/ComStaffServiceImpl.java

@@ -8,6 +8,8 @@ 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.context.PlatformContext;
+import org.dromara.common.core.enums.SysPlatformCode;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.ObjectUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -228,6 +230,8 @@ public class ComStaffServiceImpl extends ServiceImpl<ComStaffMapper, ComStaff> i
             String defaultPassword = "123456";
             user.setPassword(BCrypt.hashpw(defaultPassword));
             user.setUserSonType("0");
+            // 同步平台使用范围
+            user.setPlatformRange(bo.getPlatformRange());
 //            user.setRoleIds(new Long[]{bo.getRoleId()});
             SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
             int insert = sysUserMapper.insert(sysUser);
@@ -277,10 +281,53 @@ public class ComStaffServiceImpl extends ServiceImpl<ComStaffMapper, ComStaff> i
      * @return 是否修改成功
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Boolean updateByBo(ComStaffBo bo) {
+        // 1. 查询人员信息,获取关联的userId
+        ComStaff oldStaff = baseMapper.selectById(bo.getStaffId());
+        if (oldStaff == null) {
+            throw new RuntimeException("人员不存在");
+        }
+
+        // 2. 更新人员信息
         ComStaff update = MapstructUtils.convert(bo, ComStaff.class);
         validEntityBeforeSave(update);
-        return baseMapper.updateById(update) > 0;
+        boolean flag = baseMapper.updateById(update) > 0;
+
+        // 3. 如果有关联的系统用户,同步更新用户信息
+        if (flag && oldStaff.getUserId() != null) {
+            SysUser updateUser = new SysUser();
+            updateUser.setUserId(oldStaff.getUserId());
+            
+            // 同步平台使用范围
+            if (StringUtils.isNotBlank(bo.getPlatformRange())) {
+                updateUser.setPlatformRange(bo.getPlatformRange());
+            }
+            
+            // 同步手机号
+            if (StringUtils.isNotBlank(bo.getPhone())) {
+                updateUser.setPhonenumber(bo.getPhone());
+            }
+            
+            // 同步昵称(使用人员姓名)
+            if (StringUtils.isNotBlank(bo.getStaffName())) {
+                updateUser.setNickName(bo.getStaffName());
+            }
+            
+            // 同步部门ID
+            if (bo.getDeptId() != null) {
+                updateUser.setDeptId(bo.getDeptId());
+            }
+            
+            // 同步状态
+            if (StringUtils.isNotBlank(bo.getStatus())) {
+                updateUser.setStatus(bo.getStatus());
+            }
+            
+            sysUserMapper.updateById(updateUser);
+        }
+
+        return flag;
     }
 
     /**
@@ -290,11 +337,29 @@ public class ComStaffServiceImpl extends ServiceImpl<ComStaffMapper, ComStaff> i
      * @return 结果
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int updateStatus(ComStaffBo bo) {
-        ComStaff staff = new ComStaff();
-        staff.setStaffId(bo.getStaffId());
-        staff.setStatus(bo.getStatus());
-        return baseMapper.updateById(staff);
+        // 1. 查询人员信息,获取关联的userId
+        ComStaff staff = baseMapper.selectById(bo.getStaffId());
+        if (staff == null) {
+            throw new RuntimeException("人员不存在");
+        }
+
+        // 2. 更新人员状态
+        ComStaff updateStaff = new ComStaff();
+        updateStaff.setStaffId(bo.getStaffId());
+        updateStaff.setStatus(bo.getStatus());
+        int result = baseMapper.updateById(updateStaff);
+
+        // 3. 如果有关联的系统用户,同步更新用户状态
+        if (staff.getUserId() != null) {
+            SysUser updateUser = new SysUser();
+            updateUser.setUserId(staff.getUserId());
+            updateUser.setStatus(bo.getStatus());
+            sysUserMapper.updateById(updateUser);
+        }
+
+        return result;
     }
 
     @Override

+ 22 - 16
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysAdContentServiceImpl.java

@@ -1,25 +1,26 @@
 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 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.springframework.stereotype.Service;
+import org.dromara.common.core.exception.ServiceException;
+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.system.domain.SysAdContent;
 import org.dromara.system.domain.bo.SysAdContentBo;
 import org.dromara.system.domain.vo.SysAdContentVo;
-import org.dromara.system.domain.SysAdContent;
 import org.dromara.system.mapper.SysAdContentMapper;
 import org.dromara.system.service.ISysAdContentService;
+import org.springframework.stereotype.Service;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Collection;
 
 /**
  * 广告内容(多类型统一存)Service业务层处理
@@ -30,7 +31,7 @@ import java.util.Collection;
 @Slf4j
 @RequiredArgsConstructor
 @Service
-public class SysAdContentServiceImpl  extends ServiceImpl<SysAdContentMapper, SysAdContent> implements ISysAdContentService {
+public class SysAdContentServiceImpl extends ServiceImpl<SysAdContentMapper, SysAdContent> implements ISysAdContentService {
 
     private final SysAdContentMapper baseMapper;
 
@@ -41,7 +42,7 @@ public class SysAdContentServiceImpl  extends ServiceImpl<SysAdContentMapper, Sy
      * @return 广告内容(多类型统一存)
      */
     @Override
-    public SysAdContentVo queryById(Long id){
+    public SysAdContentVo queryById(Long id) {
         return baseMapper.selectVoById(id);
     }
 
@@ -99,9 +100,14 @@ public class SysAdContentServiceImpl  extends ServiceImpl<SysAdContentMapper, Sy
     public Boolean insertByBo(SysAdContentBo bo) {
         SysAdContent add = MapstructUtils.convert(bo, SysAdContent.class);
         validEntityBeforeSave(add);
-        boolean flag = baseMapper.insert(add) > 0;
-        if (flag) {
-            bo.setId(add.getId());
+        boolean flag = false;
+        try {
+            flag = baseMapper.insert(add) > 0;
+            if (flag) {
+                bo.setId(add.getId());
+            }
+        } catch (Exception e) {
+            throw new ServiceException(String.format("已存在相同平台、租户、广告类型、标题的广告记录"));
         }
         return flag;
     }
@@ -122,7 +128,7 @@ public class SysAdContentServiceImpl  extends ServiceImpl<SysAdContentMapper, Sy
     /**
      * 保存前的数据校验
      */
-    private void validEntityBeforeSave(SysAdContent entity){
+    private void validEntityBeforeSave(SysAdContent entity) {
         //TODO 做一些数据校验,如唯一约束
     }
 
@@ -135,7 +141,7 @@ public class SysAdContentServiceImpl  extends ServiceImpl<SysAdContentMapper, Sy
      */
     @Override
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
-        if(isValid){
+        if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
         return baseMapper.deleteByIds(ids) > 0;

+ 1 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java

@@ -137,6 +137,7 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
         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());
+        lqw.eq(StringUtils.isNotBlank(bo.getIsCompanyFlag()), SysDept::getIsCompanyFlag, bo.getIsCompanyFlag());
         lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
             SysDept::getCreateTime, params.get("beginTime"), params.get("endTime"));
         if (ObjectUtil.isNotNull(bo.getCompanyId()) && !bo.getCompanyId().equals(0L)) {

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysFloorAdvertManageServiceImpl.java

@@ -74,7 +74,7 @@ public class SysFloorAdvertManageServiceImpl  extends ServiceImpl<SysFloorAdvert
     private LambdaQueryWrapper<SysFloorAdvertManage> buildQueryWrapper(SysFloorAdvertManageBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<SysFloorAdvertManage> lqw = Wrappers.lambdaQuery();
-        lqw.orderByAsc(SysFloorAdvertManage::getId);
+        lqw.orderByAsc(SysFloorAdvertManage::getManageSerial);
         lqw.eq(StringUtils.isNotBlank(bo.getManageNo()), SysFloorAdvertManage::getManageNo, bo.getManageNo());
         lqw.eq(StringUtils.isNotBlank(bo.getCoverImage()), SysFloorAdvertManage::getCoverImage, bo.getCoverImage());
         lqw.eq(StringUtils.isNotBlank(bo.getAdvertTitle()), SysFloorAdvertManage::getAdvertTitle, bo.getAdvertTitle());

+ 5 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@@ -105,7 +105,11 @@ public class SysUserServiceImpl implements ISysUserService {
                 List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
                 ids.add(user.getDeptId());
                 w.in(SysUser::getDeptId, ids);
-            }).orderByAsc(SysUser::getUserId);
+            })
+            // 总控平台不限制,其他平台根据 platformRange 过滤
+            .apply(!SysPlatformCode.MAIN.getCode().equals(PlatformContext.getPlatform()),
+                "FIND_IN_SET({0}, platform_range) > 0", PlatformContext.getPlatform())
+            .orderByAsc(SysUser::getUserId);
         if (StringUtils.isNotBlank(user.getExcludeUserIds())) {
             wrapper.notIn(SysUser::getUserId, StringUtils.splitList(user.getExcludeUserIds()));
         }