From c74a6f59490cfb9a0ee37f70427739b74e7fbd58 Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期三, 20 五月 2026 08:50:29 +0800
Subject: [PATCH] 代码生成

---
 server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java |  576 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 494 insertions(+), 82 deletions(-)

diff --git a/server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java
index 819b776..9514975 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/DataBoardServiceImpl.java
@@ -6,6 +6,8 @@
 import com.doumee.dao.business.*;
 import com.doumee.dao.business.model.*;
 import com.doumee.dao.dto.DataBoardQueryDTO;
+import com.doumee.dao.dto.FinanceQueryDTO;
+import com.doumee.dao.dto.TrendQueryDTO;
 import com.doumee.dao.vo.*;
 import com.doumee.service.business.DataBoardService;
 import lombok.extern.slf4j.Slf4j;
@@ -37,14 +39,17 @@
     private OtherOrdersMapper otherOrdersMapper;
     @Autowired
     private OrdersRefundMapper ordersRefundMapper;
+    @Autowired
+    private RevenueMapper revenueMapper;
 
     @Override
     public DataBoardVO overview(DataBoardQueryDTO query) {
+        query.resolveDateRange();
         DataBoardVO vo = new DataBoardVO();
-        // 浼氬憳鎬绘暟锛堜笉鍙楁椂闂�/闂ㄥ簵褰卞搷锛�
+        // 浼氬憳鎬绘暟锛堜笉鍙楁椂闂�/闂ㄥ簵褰卞搷锛寀serType=0 浼氬憳韬唤锛�
         vo.setMemberCount(memberMapper.selectCount(new QueryWrapper<Member>().lambda()
                 .eq(Member::getDeleted, Constants.ZERO)
-                .eq(Member::getStatus, Constants.ZERO)));
+                .eq(Member::getUserType, Constants.ZERO)));
         // 闂ㄥ簵鎬绘暟锛坅uditStatus=3 姝e紡鐗堟湰锛�
         vo.setShopCount(shopInfoMapper.selectCount(new QueryWrapper<ShopInfo>().lambda()
                 .eq(ShopInfo::getAuditStatus, Constants.THREE)
@@ -89,40 +94,63 @@
 
         // 琛屾潕绫诲瀷鍗犳瘮
         List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
-        List<LuggageTypeItem> luggageTypeList = new ArrayList<>();
-        if (!orderIds.isEmpty()) {
-            List<OrdersDetail> details = ordersDetailMapper.selectList(new QueryWrapper<OrdersDetail>().lambda()
-                    .in(OrdersDetail::getOrderId, orderIds)
-                    .eq(OrdersDetail::getDeleted, Constants.ZERO));
-            Map<String, List<OrdersDetail>> grouped = details.stream()
-                    .filter(d -> StringUtils.isNotBlank(d.getLuggageName()))
-                    .collect(Collectors.groupingBy(OrdersDetail::getLuggageName));
-            for (Map.Entry<String, List<OrdersDetail>> entry : grouped.entrySet()) {
-                LuggageTypeItem item = new LuggageTypeItem();
-                item.setLuggageName(entry.getKey());
-                item.setOrderCount((long) entry.getValue().stream().map(OrdersDetail::getOrderId).distinct().count());
-                item.setLuggageCount((long) entry.getValue().stream()
-                        .mapToInt(d -> d.getNum() != null ? d.getNum() : 0).sum());
-                luggageTypeList.add(item);
-            }
+        vo.setLuggageTypeList(buildLuggageTypeList(orderIds));
+
+        // 闂ㄥ簵鍏ラ┗鐜囷細auditStatus=3 鐨勯棬搴楁暟 / 鍏ㄩ儴闂ㄥ簵鏁�
+        long totalShopCount = shopInfoMapper.selectCount(new QueryWrapper<ShopInfo>().lambda()
+                .eq(ShopInfo::getVersionType, Constants.ZERO)
+                .eq(ShopInfo::getDeleted, Constants.ZERO));
+        if (totalShopCount > 0) {
+            vo.setShopSettlementRate(BigDecimal.valueOf(vo.getShopCount())
+                    .multiply(BigDecimal.valueOf(100))
+                    .divide(BigDecimal.valueOf(totalShopCount), 2, RoundingMode.HALF_UP));
+        } else {
+            vo.setShopSettlementRate(BigDecimal.ZERO);
         }
-        vo.setLuggageTypeList(luggageTypeList);
+
+        // 鍙告満閫氳繃鐜囷細auditStatus=3 鐨勫徃鏈烘暟 / 鍏ㄩ儴鍙告満鏁�
+        long totalDriverCount = driverInfoMapper.selectCount(new QueryWrapper<DriverInfo>().lambda()
+                .eq(DriverInfo::getVersionType, Constants.ZERO)
+                .eq(DriverInfo::getDeleted, Constants.ZERO));
+        if (totalDriverCount > 0) {
+            vo.setDriverPassRate(BigDecimal.valueOf(vo.getDriverCount())
+                    .multiply(BigDecimal.valueOf(100))
+                    .divide(BigDecimal.valueOf(totalDriverCount), 2, RoundingMode.HALF_UP));
+        } else {
+            vo.setDriverPassRate(BigDecimal.ZERO);
+        }
+
+        // 鍛ㄦ湡閫�娆惧崟鏁�
+        if (!orderIds.isEmpty()) {
+            QueryWrapper<OrdersRefund> refundQw = new QueryWrapper<>();
+            refundQw.lambda()
+                    .in(OrdersRefund::getOrderId, orderIds)
+                    .eq(OrdersRefund::getStatus, Constants.ONE)
+                    .eq(OrdersRefund::getDeleted, Constants.ZERO);
+            List<OrdersRefund> refundRecords = ordersRefundMapper.selectList(refundQw);
+            vo.setRefundOrderCount(refundRecords.stream()
+                    .map(OrdersRefund::getOrderId).distinct().count());
+        } else {
+            vo.setRefundOrderCount(0L);
+        }
+
         return vo;
     }
 
     @Override
-    public List<MemberTrendVO> memberTrend() {
-        Date startDate = get30DaysAgoStart();
+    public List<MemberTrendVO> memberTrend(TrendQueryDTO query) {
+        TrendDateRange range = parseTrendDateRange(query);
         List<Member> members = memberMapper.selectList(new QueryWrapper<Member>().lambda()
                 .eq(Member::getDeleted, Constants.ZERO)
-                .eq(Member::getStatus, Constants.ZERO)
-                .ge(Member::getCreateTime, startDate));
+                .eq(Member::getUserType, Constants.ZERO)
+                .ge(Member::getCreateTime, range.startDate)
+                .le(Member::getCreateTime, range.endDate));
 
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat sdf = new SimpleDateFormat(range.pattern);
         Map<String, Long> map = members.stream()
                 .collect(Collectors.groupingBy(m -> sdf.format(m.getCreateTime()), Collectors.counting()));
 
-        return buildDailyList(startDate, (date) -> {
+        return buildTrendList(range, (date) -> {
             MemberTrendVO vo = new MemberTrendVO();
             vo.setDate(date);
             vo.setCount(map.getOrDefault(date, 0L));
@@ -131,24 +159,17 @@
     }
 
     @Override
-    public List<OrderTrendVO> orderTrend() {
-        Date startDate = get30DaysAgoStart();
+    public List<OrderTrendVO> orderTrend(TrendQueryDTO query) {
+        TrendDateRange range = parseTrendDateRange(query);
         List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
-                .eq(Orders::getDeleted, Constants.ZERO)
-                .in(Orders::getStatus,
-                                Constants.OrderStatus.waitDeposit.getKey(),
-                                Constants.OrderStatus.deposited.getKey(),
-                                Constants.OrderStatus.accepted.getKey(),
-                                Constants.OrderStatus.delivering.getKey(),
-                                Constants.OrderStatus.arrived.getKey(),
-                                Constants.OrderStatus.overdue.getKey())
-                .ge(Orders::getCreateTime, startDate));
+                .ge(Orders::getCreateTime, range.startDate)
+                .le(Orders::getCreateTime, range.endDate));
 
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat sdf = new SimpleDateFormat(range.pattern);
         Map<String, List<Orders>> grouped = orders.stream()
                 .collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime())));
 
-        return buildDailyList(startDate, (date) -> {
+        return buildTrendList(range, (date) -> {
             List<Orders> dayOrders = grouped.getOrDefault(date, Collections.emptyList());
             OrderTrendVO vo = new OrderTrendVO();
             vo.setDate(date);
@@ -159,35 +180,45 @@
     }
 
     @Override
-    public List<RevenueTrendVO> revenueTrend() {
-        Date startDate = get30DaysAgoStart();
+    public List<RevenueTrendVO> revenueTrend(TrendQueryDTO query) {
+        TrendDateRange range = parseTrendDateRange(query);
+        SimpleDateFormat sdf = new SimpleDateFormat(range.pattern);
 
         List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
                 .eq(Orders::getDeleted, Constants.ZERO)
                 .in(Orders::getStatus,
-                                Constants.OrderStatus.waitDeposit.getKey(),
-                                Constants.OrderStatus.deposited.getKey(),
-                                Constants.OrderStatus.accepted.getKey(),
-                                Constants.OrderStatus.delivering.getKey(),
-                                Constants.OrderStatus.arrived.getKey(),
-                                Constants.OrderStatus.overdue.getKey())
-                .ge(Orders::getCreateTime, startDate));
+                        Constants.OrderStatus.waitDeposit.getKey(),
+                        Constants.OrderStatus.deposited.getKey(),
+                        Constants.OrderStatus.accepted.getKey(),
+                        Constants.OrderStatus.delivering.getKey(),
+                        Constants.OrderStatus.arrived.getKey(),
+                        Constants.OrderStatus.overdue.getKey(),
+                        Constants.OrderStatus.finished.getKey())
+                .ge(Orders::getCreateTime, range.startDate)
+                .le(Orders::getCreateTime, range.endDate));
 
-        List<OtherOrders> otherOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().lambda()
-                .eq(OtherOrders::getType, 2)
-                .eq(OtherOrders::getPayStatus, Constants.ONE)
-                .eq(OtherOrders::getDeleted, Constants.ZERO)
-                .ge(OtherOrders::getPayTime, startDate));
+        // 鏍规嵁绛涢�夊嚭鐨勮鍗曚富閿煡璇㈠凡鏀粯鐨勯�炬湡璐圭敤
+        List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
+        Map<Integer, Long> overduePaidMap = new HashMap<>();
+        if (!orderIds.isEmpty()) {
+            List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().lambda()
+                    .eq(OtherOrders::getType, 2)
+                    .eq(OtherOrders::getPayStatus, Constants.ONE)
+                    .eq(OtherOrders::getDeleted, Constants.ZERO)
+                    .in(OtherOrders::getOrderId, orderIds));
+            for (OtherOrders oo : overdueOrders) {
+                long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L;
+                overduePaidMap.merge(oo.getOrderId(), amt, Long::sum);
+            }
+        }
 
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         Map<String, Long> localOrderRevenue = new HashMap<>();
         Map<String, Long> remoteOrderRevenue = new HashMap<>();
         for (Orders o : orders) {
             String date = sdf.format(o.getCreateTime());
             long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
             long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
-            long overdue = (o.getOverdueStatus() != null && o.getOverdueStatus() == 2 && o.getOverdueAmount() != null)
-                    ? o.getOverdueAmount() : 0L;
+            long overdue = overduePaidMap.getOrDefault(o.getId(), 0L);
             long rev = pay - refund + overdue;
             if (Constants.equalsInteger(o.getType(), Constants.ZERO)) {
                 localOrderRevenue.merge(date, rev, Long::sum);
@@ -196,17 +227,10 @@
             }
         }
 
-        Map<String, Long> otherRevenueMap = new HashMap<>();
-        for (OtherOrders oo : otherOrders) {
-            String date = sdf.format(oo.getPayTime());
-            long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L;
-            otherRevenueMap.merge(date, amt, Long::sum);
-        }
-
-        return buildDailyList(startDate, (date) -> {
+        return buildTrendList(range, (date) -> {
             RevenueTrendVO vo = new RevenueTrendVO();
             vo.setDate(date);
-            long local = localOrderRevenue.getOrDefault(date, 0L) + otherRevenueMap.getOrDefault(date, 0L);
+            long local = localOrderRevenue.getOrDefault(date, 0L);
             long remote = remoteOrderRevenue.getOrDefault(date, 0L);
             vo.setLocalRevenue(BigDecimal.valueOf(local).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
             vo.setRemoteRevenue(BigDecimal.valueOf(remote).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
@@ -216,6 +240,7 @@
 
     @Override
     public ShopPerformanceVO shopPerformance(DataBoardQueryDTO query) {
+        query.resolveDateRange();
         ShopPerformanceVO vo = new ShopPerformanceVO();
 
         // 1. 鎬昏鍗曟暟 + 钀ユ敹锛坰tatus 1-6锛�
@@ -282,6 +307,295 @@
         return vo;
     }
 
+    @Override
+    public List<LuggageTypeItem> luggageTypeList(DataBoardQueryDTO query) {
+        query.resolveDateRange();
+        List<Orders> orders = ordersMapper.selectList(buildOrderQueryWrapper(query));
+        List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
+        return buildLuggageTypeList(orderIds);
+    }
+
+    @Override
+    public List<LuggageTypeItem> buildLuggageTypeList(List<Integer> orderIds) {
+        List<LuggageTypeItem> luggageTypeList = new ArrayList<>();
+        if (orderIds != null && !orderIds.isEmpty()) {
+            List<OrdersDetail> details = ordersDetailMapper.selectList(new QueryWrapper<OrdersDetail>().lambda()
+                    .in(OrdersDetail::getOrderId, orderIds)
+                    .eq(OrdersDetail::getDeleted, Constants.ZERO));
+            Map<String, List<OrdersDetail>> grouped = details.stream()
+                    .filter(d -> StringUtils.isNotBlank(d.getLuggageName()))
+                    .collect(Collectors.groupingBy(OrdersDetail::getLuggageName));
+            for (Map.Entry<String, List<OrdersDetail>> entry : grouped.entrySet()) {
+                LuggageTypeItem item = new LuggageTypeItem();
+                item.setLuggageName(entry.getKey());
+                item.setOrderCount((long) entry.getValue().stream().map(OrdersDetail::getOrderId).distinct().count());
+                item.setLuggageCount((long) entry.getValue().stream()
+                        .mapToInt(d -> d.getNum() != null ? d.getNum() : 0).sum());
+                luggageTypeList.add(item);
+            }
+        }
+        return luggageTypeList;
+    }
+
+    @Override
+    public List<FinanceOverviewVO> financeOverview(FinanceQueryDTO query) {
+        // 琛ラ綈鏃ユ湡锛歴tartDate 鍙栨湀鍒濓紝endDate 鍙栨湀鏈�
+        Calendar startCal = Calendar.getInstance();
+        startCal.setTime(query.getStartDate());
+        startCal.set(Calendar.DAY_OF_MONTH, 1);
+        startCal.set(Calendar.HOUR_OF_DAY, 0);
+        startCal.set(Calendar.MINUTE, 0);
+        startCal.set(Calendar.SECOND, 0);
+        startCal.set(Calendar.MILLISECOND, 0);
+        query.setStartDate(startCal.getTime());
+
+        Calendar endCal = Calendar.getInstance();
+        endCal.setTime(query.getEndDate());
+        endCal.set(Calendar.DAY_OF_MONTH, endCal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        endCal.set(Calendar.HOUR_OF_DAY, 23);
+        endCal.set(Calendar.MINUTE, 59);
+        endCal.set(Calendar.SECOND, 59);
+        endCal.set(Calendar.MILLISECOND, 999);
+        query.setEndDate(endCal.getTime());
+
+        List<Orders> orders = ordersMapper.selectList(buildFinanceOrderQueryWrapper(query));
+
+        // 鏍规嵁绛涢�夊嚭鐨勮鍗曚富閿煡璇㈠凡鏀粯鐨勯�炬湡璐圭敤
+        List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
+        Map<Integer, Long> overduePaidMap = new HashMap<>();
+        if (!orderIds.isEmpty()) {
+            List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().lambda()
+                    .eq(OtherOrders::getType, 2)
+                    .eq(OtherOrders::getPayStatus, Constants.ONE)
+                    .eq(OtherOrders::getDeleted, Constants.ZERO)
+                    .in(OtherOrders::getOrderId, orderIds));
+            for (OtherOrders oo : overdueOrders) {
+                long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L;
+                overduePaidMap.merge(oo.getOrderId(), amt, Long::sum);
+            }
+        }
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
+        Map<String, List<Orders>> grouped = orders.stream()
+                .collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime())));
+
+        // 鐢熸垚瀹屾暣骞存湀鍒楄〃
+        List<String> months = new ArrayList<>();
+        Calendar loop = Calendar.getInstance();
+        loop.setTime(query.getStartDate());
+        loop.set(Calendar.DAY_OF_MONTH, 1);
+        Calendar monthEnd = Calendar.getInstance();
+        monthEnd.setTime(query.getEndDate());
+        while (!loop.after(monthEnd)) {
+            months.add(sdf.format(loop.getTime()));
+            loop.add(Calendar.MONTH, 1);
+        }
+
+        BigDecimal hundred = BigDecimal.valueOf(100);
+        List<FinanceOverviewVO> result = new ArrayList<>();
+        for (String month : months) {
+            List<Orders> monthOrders = grouped.getOrDefault(month, Collections.emptyList());
+            long storageRev = 0L, deliveryRev = 0L, shopFee = 0L, driverFeeTotal = 0L, refundTotal = 0L, overdueTotal = 0L;
+            for (Orders o : monthOrders) {
+                long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+                long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+                long overdue = overduePaidMap.getOrDefault(o.getId(), 0L);
+                long actual = pay - refund + overdue;
+                long depFee = o.getDepositShopFee() != null ? o.getDepositShopFee() : 0L;
+                long takeFee = o.getTakeShopFee() != null ? o.getTakeShopFee() : 0L;
+                long dFee = Constants.equalsInteger(o.getType(),Constants.ONE)&&o.getDriverFee() != null ? o.getDriverFee() : 0L;
+                if (Constants.equalsInteger(o.getType(), Constants.ZERO)) {
+                    storageRev += actual;
+                    shopFee += depFee;
+                } else {
+                    deliveryRev += actual;
+                    shopFee += depFee + takeFee;
+                }
+                driverFeeTotal += dFee;
+                refundTotal += refund;
+                overdueTotal += overdue;
+            }
+            long totalRev = storageRev + deliveryRev;
+            long netRev = totalRev - shopFee - driverFeeTotal;
+
+            FinanceOverviewVO vo = new FinanceOverviewVO();
+            vo.setDate(month);
+            vo.setStorageRevenue(BigDecimal.valueOf(storageRev).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setDeliveryRevenue(BigDecimal.valueOf(deliveryRev).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setTotalRevenue(BigDecimal.valueOf(totalRev).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setShopFeeTotal(BigDecimal.valueOf(shopFee).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setDriverFeeTotal(BigDecimal.valueOf(driverFeeTotal).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setRefundAmount(BigDecimal.valueOf(refundTotal).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setOverdueAmount(BigDecimal.valueOf(overdueTotal).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setNetRevenue(BigDecimal.valueOf(netRev).divide(hundred, 2, RoundingMode.HALF_UP));
+            result.add(vo);
+        }
+        return result;
+    }
+
+    @Override
+    public List<ShopTopVO> shopTop(TrendQueryDTO query) {
+        TrendDateRange range = parseTrendDateRange(query);
+        List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
+                .eq(Orders::getDeleted, Constants.ZERO)
+                .eq(Orders::getStatus, Constants.OrderStatus.finished.getKey())
+                .ge(Orders::getCreateTime, range.startDate)
+                .le(Orders::getCreateTime, range.endDate));
+
+        // 鏍规嵁绛涢�夊嚭鐨勮鍗曚富閿煡璇㈠凡鏀粯鐨勯�炬湡璐圭敤
+        List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
+        Map<Integer, Long> overduePaidMap = new HashMap<>();
+        if (!orderIds.isEmpty()) {
+            List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().lambda()
+                    .eq(OtherOrders::getType, 2)
+                    .eq(OtherOrders::getPayStatus, Constants.ONE)
+                    .eq(OtherOrders::getDeleted, Constants.ZERO)
+                    .in(OtherOrders::getOrderId, orderIds));
+            for (OtherOrders oo : overdueOrders) {
+                long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L;
+                overduePaidMap.merge(oo.getOrderId(), amt, Long::sum);
+            }
+        }
+
+        // 鎸夐棬搴桰D褰掗泦: key = shopId
+        Map<Integer, long[]> map = new LinkedHashMap<>();
+        for (Orders o : orders) {
+            long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+            long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+            long overdue = overduePaidMap.getOrDefault(o.getId(), 0L);
+            boolean hasRefund = refund > 0;
+            long rev = pay - refund + overdue;
+
+            // 瀛樹欢闂ㄥ簵
+            if (o.getDepositShopId() != null) {
+                long depFee = o.getDepositShopFee() != null ? o.getDepositShopFee() : 0L;
+                long[] arr = map.computeIfAbsent(o.getDepositShopId(), k -> new long[4]); // [count, revenue, fee, refundCount]
+                arr[0]++;
+                arr[1] += rev;
+                arr[2] += depFee;
+                if (hasRefund) arr[3]++;
+            }
+            // 寮傚湴涓旀湁鍙栦欢闂ㄥ簵
+            if (Constants.equalsInteger(o.getType(), Constants.ONE) && o.getTakeShopId() != null) {
+                long takeFee = o.getTakeShopFee() != null ? o.getTakeShopFee() : 0L;
+                long[] arr = map.computeIfAbsent(o.getTakeShopId(), k -> new long[4]);
+                arr[0]++;
+                arr[1] += rev;
+                arr[2] += takeFee;
+                if (hasRefund) arr[3]++;
+            }
+        }
+
+        // 鎵归噺鏌ラ棬搴楀悕绉�
+        Set<Integer> shopIds = map.keySet();
+        Map<Integer, String> shopNameMap = new HashMap<>();
+        if (!shopIds.isEmpty()) {
+            List<ShopInfo> shops = shopInfoMapper.selectList(new QueryWrapper<ShopInfo>().lambda()
+                    .in(ShopInfo::getId, shopIds)
+                    .select(ShopInfo::getId, ShopInfo::getName));
+            for (ShopInfo s : shops) {
+                shopNameMap.put(s.getId(), s.getName());
+            }
+        }
+
+        BigDecimal hundred = BigDecimal.valueOf(100);
+        List<ShopTopVO> result = new ArrayList<>();
+        for (Map.Entry<Integer, long[]> entry : map.entrySet()) {
+            long[] arr = entry.getValue();
+            ShopTopVO vo = new ShopTopVO();
+            vo.setShopId(entry.getKey());
+            vo.setShopName(shopNameMap.getOrDefault(entry.getKey(), ""));
+            vo.setCompletedCount(arr[0]);
+            vo.setTotalRevenue(BigDecimal.valueOf(arr[1]).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setShopFeeTotal(BigDecimal.valueOf(arr[2]).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setRefundCount(arr[3]);
+            vo.setPenaltyAmount(BigDecimal.ZERO);
+            result.add(vo);
+        }
+        result.sort((a, b) -> Long.compare(b.getCompletedCount(), a.getCompletedCount()));
+        return result.size() > 10 ? result.subList(0, 10) : result;
+    }
+
+    @Override
+    public List<DriverTopVO> driverTop(TrendQueryDTO query) {
+        TrendDateRange range = parseTrendDateRange(query);
+        List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
+//                .eq(Orders::getDeleted, Constants.ZERO)
+                .in(Orders::getStatus,
+                        Constants.OrderStatus.waitDeposit.getKey(),
+                        Constants.OrderStatus.deposited.getKey(),
+                        Constants.OrderStatus.accepted.getKey(),
+                        Constants.OrderStatus.delivering.getKey(),
+                        Constants.OrderStatus.arrived.getKey(),
+                        Constants.OrderStatus.finished.getKey())
+                .eq(Orders::getType, Constants.ONE)
+                .ge(Orders::getCreateTime, range.startDate)
+                .le(Orders::getCreateTime, range.endDate));
+
+        System.out.println(
+                orders.stream().map(i->i.getDriverFee()).reduce(0L,Long::sum)
+        );
+
+        // 鏍规嵁绛涢�夊嚭鐨勮鍗曚富閿煡璇㈠凡鏀粯鐨勯�炬湡璐圭敤
+        List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
+        Map<Integer, Long> overduePaidMap = new HashMap<>();
+        if (!orderIds.isEmpty()) {
+            List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().lambda()
+                    .eq(OtherOrders::getType, 2)
+                    .eq(OtherOrders::getPayStatus, Constants.ONE)
+                    .eq(OtherOrders::getDeleted, Constants.ZERO)
+                    .in(OtherOrders::getOrderId, orderIds));
+            for (OtherOrders oo : overdueOrders) {
+                long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L;
+                overduePaidMap.merge(oo.getOrderId(), amt, Long::sum);
+            }
+        }
+
+        // 鎸夊徃鏈哄綊闆�: key = acceptDriver
+        Map<Integer, long[]> map = new LinkedHashMap<>();
+        for (Orders o : orders) {
+            if (o.getAcceptDriver() == null) continue;
+            long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+            long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+            long overdue = overduePaidMap.getOrDefault(o.getId(), 0L);
+            long dFee = o.getDriverFee() != null ? o.getDriverFee() : 0L;
+            long[] arr = map.computeIfAbsent(o.getAcceptDriver(), k -> new long[4]); // [count, revenue, fee, refundCount]
+            arr[0]++;
+            arr[1] += pay - refund + overdue;
+            arr[2] += dFee;
+            if (refund > 0) arr[3]++;
+        }
+
+        // 鎵归噺鏌ュ徃鏈哄鍚�
+        Set<Integer> driverIds = map.keySet();
+        Map<Integer, String> driverNameMap = new HashMap<>();
+        if (!driverIds.isEmpty()) {
+            List<DriverInfo> drivers = driverInfoMapper.selectList(new QueryWrapper<DriverInfo>().lambda()
+                    .in(DriverInfo::getId, driverIds)
+                    .select(DriverInfo::getMemberId, DriverInfo::getName));
+            for (DriverInfo d : drivers) {
+                driverNameMap.put(d.getMemberId(), d.getName());
+            }
+        }
+
+        BigDecimal hundred = BigDecimal.valueOf(100);
+        List<DriverTopVO> result = new ArrayList<>();
+        for (Map.Entry<Integer, long[]> entry : map.entrySet()) {
+            long[] arr = entry.getValue();
+            DriverTopVO vo = new DriverTopVO();
+            vo.setDriverId(entry.getKey());
+            vo.setDriverName(driverNameMap.getOrDefault(entry.getKey(), "鏈煡"));
+            vo.setCompletedCount(arr[0]);
+            vo.setTotalRevenue(BigDecimal.valueOf(arr[1]).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setDriverFeeTotal(BigDecimal.valueOf(arr[2]).divide(hundred, 2, RoundingMode.HALF_UP));
+            vo.setRefundCount(arr[3]);
+            vo.setPenaltyAmount(BigDecimal.ZERO);
+            result.add(vo);
+        }
+        result.sort((a, b) -> Long.compare(b.getCompletedCount(), a.getCompletedCount()));
+        return result.size() > 10 ? result.subList(0, 10) : result;
+    }
+
     // ========== 绉佹湁鏂规硶 ==========
 
     private QueryWrapper<Orders> buildOrderQueryWrapper(DataBoardQueryDTO query) {
@@ -294,7 +608,7 @@
                         Constants.OrderStatus.accepted.getKey(),
                         Constants.OrderStatus.delivering.getKey(),
                         Constants.OrderStatus.arrived.getKey(),
-                        Constants.OrderStatus.overdue.getKey());
+                        Constants.OrderStatus.finished.getKey());
         if (query.getStartDate() != null) {
             qw.lambda().ge(Orders::getCreateTime, query.getStartDate());
         }
@@ -308,30 +622,128 @@
         return qw;
     }
 
-    private Date get30DaysAgoStart() {
-        Calendar cal = Calendar.getInstance();
-        cal.set(Calendar.HOUR_OF_DAY, 0);
-        cal.set(Calendar.MINUTE, 0);
-        cal.set(Calendar.SECOND, 0);
-        cal.set(Calendar.MILLISECOND, 0);
-        cal.add(Calendar.DAY_OF_MONTH, -29);
-        return cal.getTime();
+    private QueryWrapper<Orders> buildFinanceOrderQueryWrapper(FinanceQueryDTO query) {
+        QueryWrapper<Orders> qw = new QueryWrapper<>();
+        qw.lambda()
+                .eq(Orders::getDeleted, Constants.ZERO)
+                .in(Orders::getStatus,
+                        Constants.OrderStatus.waitDeposit.getKey(),
+                        Constants.OrderStatus.deposited.getKey(),
+                        Constants.OrderStatus.accepted.getKey(),
+                        Constants.OrderStatus.delivering.getKey(),
+                        Constants.OrderStatus.arrived.getKey(),
+                        Constants.OrderStatus.finished.getKey());
+        if (query.getStartDate() != null) {
+            qw.lambda().ge(Orders::getCreateTime, query.getStartDate());
+        }
+        if (query.getEndDate() != null) {
+            qw.lambda().le(Orders::getCreateTime, Utils.Date.getEnd(query.getEndDate()));
+        }
+        return qw;
+    }
+
+    private TrendDateRange parseTrendDateRange(TrendQueryDTO query) {
+        Calendar now = Calendar.getInstance();
+        TrendDateRange range = new TrendDateRange();
+
+        if (StringUtils.isNotBlank(query.getMonth())) {
+            // 鎸夋湀鏌ヨ锛歽yyy-MM
+            SimpleDateFormat parseSdf = new SimpleDateFormat("yyyy-MM");
+            Date monthDate;
+            try {
+                monthDate = parseSdf.parse(query.getMonth());
+            } catch (Exception e) {
+                throw new IllegalArgumentException("month 鏍煎紡閿欒锛屽簲涓� yyyy-MM");
+            }
+            Calendar monthCal = Calendar.getInstance();
+            monthCal.setTime(monthDate);
+
+            // 褰撴湀1鏃ヨ捣濮�
+            monthCal.set(Calendar.DAY_OF_MONTH, 1);
+            monthCal.set(Calendar.HOUR_OF_DAY, 0);
+            monthCal.set(Calendar.MINUTE, 0);
+            monthCal.set(Calendar.SECOND, 0);
+            monthCal.set(Calendar.MILLISECOND, 0);
+            range.startDate = monthCal.getTime();
+
+            // 鏈堟湯
+            monthCal.set(Calendar.DAY_OF_MONTH, monthCal.getActualMaximum(Calendar.DAY_OF_MONTH));
+            monthCal.set(Calendar.HOUR_OF_DAY, 23);
+            monthCal.set(Calendar.MINUTE, 59);
+            monthCal.set(Calendar.SECOND, 59);
+            monthCal.set(Calendar.MILLISECOND, 999);
+            Date monthEnd = monthCal.getTime();
+
+            // 涓嶈兘瓒呰繃褰撳墠鏃堕棿
+            range.endDate = monthEnd.after(now.getTime()) ? now.getTime() : monthEnd;
+            range.byMonth = true;
+            range.pattern = "MM-dd";
+        } else if (StringUtils.isNotBlank(query.getYear())) {
+            // 鎸夊勾鏌ヨ锛歽yyy
+            int year = Integer.parseInt(query.getYear());
+            Calendar yearStart = Calendar.getInstance();
+            yearStart.set(Calendar.YEAR, year);
+            yearStart.set(Calendar.MONTH, Calendar.JANUARY);
+            yearStart.set(Calendar.DAY_OF_MONTH, 1);
+            yearStart.set(Calendar.HOUR_OF_DAY, 0);
+            yearStart.set(Calendar.MINUTE, 0);
+            yearStart.set(Calendar.SECOND, 0);
+            yearStart.set(Calendar.MILLISECOND, 0);
+            range.startDate = yearStart.getTime();
+
+            Calendar yearEnd = Calendar.getInstance();
+            yearEnd.set(Calendar.YEAR, year);
+            yearEnd.set(Calendar.MONTH, Calendar.DECEMBER);
+            yearEnd.set(Calendar.DAY_OF_MONTH, 31);
+            yearEnd.set(Calendar.HOUR_OF_DAY, 23);
+            yearEnd.set(Calendar.MINUTE, 59);
+            yearEnd.set(Calendar.SECOND, 59);
+            yearEnd.set(Calendar.MILLISECOND, 999);
+            Date end = yearEnd.getTime();
+            range.endDate = end.after(now.getTime()) ? now.getTime() : end;
+            range.byMonth = false;
+            range.pattern = "MM";
+        } else {
+            throw new IllegalArgumentException("璇蜂紶鍏� month 鎴� year 鍙傛暟");
+        }
+        return range;
+    }
+
+    private static class TrendDateRange {
+        Date startDate;
+        Date endDate;
+        boolean byMonth; // true=鎸夋湀鏌�(鎸夋棩杩斿洖)锛宖alse=鎸夊勾鏌�(鎸夋湀杩斿洖)
+        String pattern;  // SimpleDateFormat 鏍煎紡
     }
 
     @FunctionalInterface
-    private interface DailyVOBuilder<T> {
+    private interface TrendVOBuilder<T> {
         T build(String date);
     }
 
-    private <T> List<T> buildDailyList(Date startDate, DailyVOBuilder<T> builder) {
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+    private <T> List<T> buildTrendList(TrendDateRange range, TrendVOBuilder<T> builder) {
         List<T> result = new ArrayList<>();
-        Calendar loop = Calendar.getInstance();
-        loop.setTime(startDate);
-        Calendar end = Calendar.getInstance();
-        while (!loop.after(end)) {
-            result.add(builder.build(sdf.format(loop.getTime())));
-            loop.add(Calendar.DAY_OF_MONTH, 1);
+        SimpleDateFormat sdf = new SimpleDateFormat(range.pattern);
+
+        if (range.byMonth) {
+            // 鎸夋棩寰幆
+            Calendar loop = Calendar.getInstance();
+            loop.setTime(range.startDate);
+            Calendar end = Calendar.getInstance();
+            end.setTime(range.endDate);
+            while (!loop.after(end)) {
+                result.add(builder.build(sdf.format(loop.getTime())));
+                loop.add(Calendar.DAY_OF_MONTH, 1);
+            }
+        } else {
+            // 鎸夋湀寰幆 1~12锛屼笉鑳借秴杩� endDate 鎵�鍦ㄦ湀
+            Calendar endCal = Calendar.getInstance();
+            endCal.setTime(range.endDate);
+            int endMonth = endCal.get(Calendar.MONTH); // 0-based
+            for (int m = 0; m <= endMonth; m++) {
+                String label = String.format("%02d", m + 1);
+                result.add(builder.build(label));
+            }
         }
         return result;
     }

--
Gitblit v1.9.3