Răsfoiți Sursa

feat(order): 添加订单中心首页数据统计功能

- 在IOrderMainService接口中新增orderIndexData方法定义
- 在OrderMainController中添加/orderIndexData端点映射
- 在OrderMainServiceImpl中实现订单首页数据统计逻辑
- 新增OrderIndexDataVo数据传输对象用于封装首页统计数据
- 实现今日订单数、待发货订单数、月度成交额等统计卡片功能
- 添加近七日订单趋势图表数据查询
- 实现平台订单占比按供应商、伙伴商、自营客户分类统计
- 添加最新订单列表展示功能
- 集成远程客户服务获取客户名称信息
hurx 16 ore în urmă
părinte
comite
bb45ea428c

+ 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();
+    }
+
     /**
      * 查询订单主信息列表
      */

+ 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;
+    }
+}

+ 3 - 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,6 @@ public interface IOrderMainService extends IService<OrderMain> {
 
     OrderTreeVo queryOrderWithChildren(Long orderId);
 
+    R<OrderIndexDataVo> orderIndexData();
+
 }

+ 108 - 0
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;
@@ -56,6 +57,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;
@@ -140,6 +142,8 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
     private final IOrderAssignmentService orderAssignmentService;
 
+    private final OrderReturnMapper orderReturnMapper;
+
     /**
      * 查询订单主信息
      *
@@ -2029,4 +2033,108 @@ 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;
+    }
 }