Pārlūkot izejas kodu

fix: 日统计汇总卡片改为调用后端聚合接口获取真实汇总值

- 后端新增 POST /daily-stat/aggregate 接口,按筛选条件聚合所有匹配行
- admin-h5 日统计页汇总数据改为调用聚合接口,不再累加分页列表
- 聚合接口无筛选条件时返回全量数据,避免分页导致的汇总值不完整

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 1 nedēļu atpakaļ
vecāks
revīzija
032ee0d5e3

+ 9 - 0
admin-h5/src/api/stat.js

@@ -52,3 +52,12 @@ export const getDailyStatList = (params) => {
 export const getMonthlyStatList = (params) => {
   return post('/month-stat/list', params)
 }
+
+/**
+ * 获取日统计汇总
+ * @param {Object} params - 查询参数(stationId, startDate, endDate)
+ * @returns {Promise} 汇总数据
+ */
+export const getDailyStatAggregate = (params) => {
+  return post('/daily-stat/aggregate', params)
+}

+ 41 - 9
admin-h5/src/pages/statistics/index.vue

@@ -189,9 +189,9 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted } from 'vue'
+import { ref, onMounted } from 'vue'
 import { onReachBottom } from '@dcloudio/uni-app'
-import { getDailyStatList, getMonthlyStatList } from '../../api/stat.js'
+import { getDailyStatList, getMonthlyStatList, getDailyStatAggregate } from '../../api/stat.js'
 import { getStationList } from '../../api/station.js'
 import { formatTime, showToast, formatAmount } from '../../utils/index.js'
 import { loadDicts } from '../../utils/dict.js'
@@ -212,14 +212,45 @@ const selectedStationName = ref('')
 const showDetail = ref(false)
 const detailItem = ref(null)
 
-const summary = computed(() => {
-  const totalIncome = list.value.reduce((sum, item) => sum + (item.totalIncome || 0), 0)
-  const totalConsumption = list.value.reduce((sum, item) => sum + (item.consumption || 0), 0)
-  const totalOrders = list.value.reduce((sum, item) => sum + (item.ordersCount || 0), 0)
-  const totalRegistrations = list.value.reduce((sum, item) => sum + (item.registrations || 0), 0)
-  const totalActiveUsers = list.value.reduce((sum, item) => sum + (item.activeUserCount || 0), 0)
-  return { totalIncome, totalConsumption, totalOrders, totalRegistrations, totalActiveUsers }
+const summary = ref({
+  totalIncome: 0,
+  totalConsumption: 0,
+  totalOrders: 0,
+  totalRegistrations: 0,
+  totalActiveUsers: 0
 })
+const summaryLoading = ref(false)
+
+const loadSummary = async () => {
+  if (activeTab.value !== 0) {
+    // 月统计暂不走聚合接口
+    summary.value = { totalIncome: 0, totalConsumption: 0, totalOrders: 0, totalRegistrations: 0, totalActiveUsers: 0 }
+    return
+  }
+  summaryLoading.value = true
+  try {
+    const params = {}
+    if (selectedStationId.value) params.stationId = selectedStationId.value
+    if (filterKey.value) {
+      params.startDate = filterKey.value
+      params.endDate = filterKey.value
+    }
+    const res = await getDailyStatAggregate(params)
+    if (res && res.code === 200 && res.data) {
+      summary.value = {
+        totalIncome: res.data.totalIncome || 0,
+        totalConsumption: res.data.totalConsumption || 0,
+        totalOrders: res.data.ordersCount || 0,
+        totalRegistrations: res.data.registrations || 0,
+        totalActiveUsers: res.data.activeUserCount || 0
+      }
+    }
+  } catch (e) {
+    console.error('加载汇总数据失败:', e)
+  } finally {
+    summaryLoading.value = false
+  }
+}
 
 const loadStations = async () => {
   try {
@@ -295,6 +326,7 @@ const loadData = async (isLoadMore = false) => {
       } else {
         list.value = records
         page.value = 2
+        loadSummary()
       }
     }
   } catch (error) {

+ 6 - 0
car-wash-admin/src/main/java/com/kym/admin/controller/DailyStatController.java

@@ -49,4 +49,10 @@ public class DailyStatController {
         dailyStatService.syncDailyStatBatch(startDate, endDate);
         return R.success();
     }
+
+    @SaCheckPermission("dailyStat.list")
+    @PostMapping("/aggregate")
+    public R<?> aggregate(@RequestBody DailyStatQueryParam params) {
+        return R.success(dailyStatService.aggregateDailyStat(params));
+    }
 }

+ 40 - 0
car-wash-entity/src/main/java/com/kym/entity/vo/DailyStatSummaryVo.java

@@ -0,0 +1,40 @@
+package com.kym.entity.vo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 日统计汇总 VO
+ *
+ * @author skyline
+ * @since 2026-07-05
+ */
+@Data
+@Accessors(chain = true)
+public class DailyStatSummaryVo {
+
+    /**
+     * 总收入(分)
+     */
+    private Integer totalIncome;
+
+    /**
+     * 消费金额(分)
+     */
+    private Integer totalConsumption;
+
+    /**
+     * 订单数
+     */
+    private Integer ordersCount;
+
+    /**
+     * 注册用户数
+     */
+    private Integer registrations;
+
+    /**
+     * 活跃用户数
+     */
+    private Integer activeUserCount;
+}

+ 3 - 0
car-wash-service/src/main/java/com/kym/service/DailyStatService.java

@@ -3,6 +3,7 @@ package com.kym.service;
 import com.kym.entity.DailyStat;
 import com.kym.entity.common.PageBean;
 import com.kym.entity.queryParams.DailyStatQueryParam;
+import com.kym.entity.vo.DailyStatSummaryVo;
 import com.kym.entity.vo.DailyStatVo;
 import com.kym.service.mybatisplus.MyBaseService;
 
@@ -19,4 +20,6 @@ public interface DailyStatService extends MyBaseService<DailyStat> {
     void syncDailyStat(String statDate);
 
     void syncDailyStatBatch(String startDate, String endDate);
+
+    DailyStatSummaryVo aggregateDailyStat(DailyStatQueryParam params);
 }

+ 35 - 0
car-wash-service/src/main/java/com/kym/service/impl/DailyStatServiceImpl.java

@@ -7,6 +7,7 @@ import com.kym.entity.DailyStat;
 import com.kym.entity.StatSyncLog;
 import com.kym.entity.common.PageBean;
 import com.kym.entity.queryParams.DailyStatQueryParam;
+import com.kym.entity.vo.DailyStatSummaryVo;
 import com.kym.entity.vo.DailyStatVo;
 import com.kym.mapper.DailyStatMapper;
 import com.kym.service.*;
@@ -187,4 +188,38 @@ public class DailyStatServiceImpl extends MyBaseServiceImpl<DailyStatMapper, Dai
         }
         log.info("批量同步日统计完成: {} ~ {}", startDate, endDate);
     }
+
+    @Override
+    public DailyStatSummaryVo aggregateDailyStat(DailyStatQueryParam params) {
+        var query = lambdaQuery()
+                .eq(CommUtil.isNotEmptyAndNull(params.getStationId()),
+                        DailyStat::getStationId, params.getStationId())
+                .ge(params.getStartDate() != null,
+                        DailyStat::getStatDate, params.getStartDate() != null ? params.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE) : null)
+                .le(params.getEndDate() != null,
+                        DailyStat::getStatDate, params.getEndDate() != null ? params.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE) : null);
+        var list = query.list();
+
+        if (list.isEmpty()) {
+            return new DailyStatSummaryVo()
+                    .setTotalIncome(0)
+                    .setTotalConsumption(0)
+                    .setOrdersCount(0)
+                    .setRegistrations(0)
+                    .setActiveUserCount(0);
+        }
+
+        var totalIncome = list.stream().filter(s -> s.getTotalIncome() != null).mapToInt(DailyStat::getTotalIncome).sum();
+        var totalConsumption = list.stream().filter(s -> s.getConsumption() != null).mapToInt(DailyStat::getConsumption).sum();
+        var ordersCount = list.stream().filter(s -> s.getOrdersCount() != null).mapToInt(DailyStat::getOrdersCount).sum();
+        var registrations = list.stream().filter(s -> s.getRegistrations() != null).mapToInt(DailyStat::getRegistrations).sum();
+        var activeUserCount = list.stream().filter(s -> s.getActiveUserCount() != null).mapToInt(DailyStat::getActiveUserCount).sum();
+
+        return new DailyStatSummaryVo()
+                .setTotalIncome(totalIncome)
+                .setTotalConsumption(totalConsumption)
+                .setOrdersCount(ordersCount)
+                .setRegistrations(registrations)
+                .setActiveUserCount(activeUserCount);
+    }
 }