From f8c6604a8a2db6edef94aefcee63aa2b8b578f09 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Mon, 12 Jan 2026 18:30:27 +0800 Subject: [PATCH] =?UTF-8?q?refactor(statistics):=20=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9F=A5=E8=AF=A2=E6=9C=8D=E5=8A=A1=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=89=AB=E7=A0=81=E7=BB=9F=E8=AE=A1=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 BrokerBiz 和 OrderBiz 中的数据查询从 StatisticsMapper 切换到 StatsQueryService - 更新 StatisticsServiceImpl 使用 StatsQueryService 进行数据查询 - 添加订单数据合并功能到扫码统计图表中 - 重构扫码统计查询逻辑以支持统计数据和订单数据的合并显示 - 新增按小时和按日期统计订单数据的查询方法 - 优化 SQL 查询以分离统计数据和订单数据的查询逻辑 --- .../java/com/ycwl/basic/biz/BrokerBiz.java | 5 +- .../java/com/ycwl/basic/biz/OrderBiz.java | 5 +- .../clickhouse/service/StatsQueryService.java | 6 +- .../ycwl/basic/mapper/StatisticsMapper.java | 16 ++++ .../pc/impl/StatisticsServiceImpl.java | 87 ++++++++++++++--- .../resources/mapper/StatisticsMapper.xml | 96 +++++++++++++------ 6 files changed, 165 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/ycwl/basic/biz/BrokerBiz.java b/src/main/java/com/ycwl/basic/biz/BrokerBiz.java index 06f0e074..9721e239 100644 --- a/src/main/java/com/ycwl/basic/biz/BrokerBiz.java +++ b/src/main/java/com/ycwl/basic/biz/BrokerBiz.java @@ -1,6 +1,7 @@ package com.ycwl.basic.biz; import cn.hutool.core.date.DateUtil; +import com.ycwl.basic.clickhouse.service.StatsQueryService; import com.ycwl.basic.mapper.BrokerMapper; import com.ycwl.basic.mapper.BrokerRecordMapper; import com.ycwl.basic.mapper.StatisticsMapper; @@ -34,7 +35,7 @@ public class BrokerBiz { @Autowired private ScenicRepository scenicRepository; @Autowired - private StatisticsMapper statisticsMapper; + private StatsQueryService statsQueryService; public void processOrder(Long orderId) { log.info("开始处理订单分佣,订单ID:{}", orderId); @@ -52,7 +53,7 @@ public class BrokerBiz { if (scenicConfig.getInteger("sample_store_day") != null) { expireDay = scenicConfig.getInteger("sample_store_day"); } - List brokerIdList = statisticsMapper.getBrokerIdListForUser(order.getMemberId(), DateUtil.offsetDay(DateUtil.beginOfDay(order.getCreateAt()), -expireDay), order.getCreateAt()); + List brokerIdList = statsQueryService.getBrokerIdListForUser(order.getMemberId(), DateUtil.offsetDay(DateUtil.beginOfDay(order.getCreateAt()), -expireDay), order.getCreateAt()); if (brokerIdList == null || brokerIdList.isEmpty()) { log.info("用户与推客无关,订单ID:{}", orderId); return; diff --git a/src/main/java/com/ycwl/basic/biz/OrderBiz.java b/src/main/java/com/ycwl/basic/biz/OrderBiz.java index a3fc6ed7..e4f604cd 100644 --- a/src/main/java/com/ycwl/basic/biz/OrderBiz.java +++ b/src/main/java/com/ycwl/basic/biz/OrderBiz.java @@ -1,5 +1,6 @@ package com.ycwl.basic.biz; +import com.ycwl.basic.clickhouse.service.StatsQueryService; import com.ycwl.basic.enums.StatisticEnum; import com.ycwl.basic.integration.common.manager.ScenicConfigManager; import com.ycwl.basic.mapper.OrderMapper; @@ -66,6 +67,8 @@ public class OrderBiz { private PrinterService printerService; @Autowired private IPriceCalculationService iPriceCalculationService; + @Autowired + private StatsQueryService statsQueryService; public PriceObj queryPrice(Long scenicId, Long memberId, int goodsType, Long goodsId) { PriceObj priceObj = new PriceObj(); @@ -254,7 +257,7 @@ public class OrderBiz { orderRepository.clearOrderCache(orderId); // 更新完了,清理下 StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq(); statisticsRecordAddReq.setMemberId(order.getMemberId()); - Long enterType = statisticsMapper.getUserRecentEnterType(order.getMemberId(), order.getCreateAt()); + Long enterType = statsQueryService.getUserRecentEnterType(order.getMemberId(), order.getCreateAt()); if(!Long.valueOf(1014).equals(enterType)){// statisticsRecordAddReq.setType(StatisticEnum.ON_SITE_PAYMENT.code); }else { diff --git a/src/main/java/com/ycwl/basic/clickhouse/service/StatsQueryService.java b/src/main/java/com/ycwl/basic/clickhouse/service/StatsQueryService.java index bd99add1..8478a473 100644 --- a/src/main/java/com/ycwl/basic/clickhouse/service/StatsQueryService.java +++ b/src/main/java/com/ycwl/basic/clickhouse/service/StatsQueryService.java @@ -79,12 +79,14 @@ public interface StatsQueryService { List> getDailyScanStats(Long brokerId, Date startTime, Date endTime); /** - * 按小时统计扫码人数 + * 按小时统计扫码人数(仅返回统计数据,不含订单) + * 返回格式: [{t: "MM-dd HH", count: "xxx"}, ...] */ List> scanCodeMemberChartByHour(CommonQueryReq query); /** - * 按日期统计扫码人数 + * 按日期统计扫码人数(仅返回统计数据,不含订单) + * 返回格式: [{t: "MM-dd", count: "xxx"}, ...] */ List> scanCodeMemberChartByDate(CommonQueryReq query); } diff --git a/src/main/java/com/ycwl/basic/mapper/StatisticsMapper.java b/src/main/java/com/ycwl/basic/mapper/StatisticsMapper.java index 9ecd5183..8f5e0067 100644 --- a/src/main/java/com/ycwl/basic/mapper/StatisticsMapper.java +++ b/src/main/java/com/ycwl/basic/mapper/StatisticsMapper.java @@ -105,10 +105,26 @@ public interface StatisticsMapper { List> orderChartByHour(CommonQueryReq query); + /** + * 按小时统计扫码人数(仅统计数据,不含订单) + */ List> scanCodeMemberChartByHour(CommonQueryReq query); + /** + * 按日期统计扫码人数(仅统计数据,不含订单) + */ List> scanCodeMemberChartByDate(CommonQueryReq query); + /** + * 按小时统计订单数据 + */ + List> orderChartByHourForMerge(CommonQueryReq query); + + /** + * 按日期统计订单数据 + */ + List> orderChartByDateForMerge(CommonQueryReq query); + /** * 统计分销员扫码次数 */ diff --git a/src/main/java/com/ycwl/basic/service/pc/impl/StatisticsServiceImpl.java b/src/main/java/com/ycwl/basic/service/pc/impl/StatisticsServiceImpl.java index d058c321..8d64bc2f 100644 --- a/src/main/java/com/ycwl/basic/service/pc/impl/StatisticsServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/pc/impl/StatisticsServiceImpl.java @@ -1,5 +1,6 @@ package com.ycwl.basic.service.pc.impl; +import com.ycwl.basic.clickhouse.service.StatsQueryService; import com.ycwl.basic.mapper.StatisticsMapper; import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq; import com.ycwl.basic.model.pc.statistics.resp.OrderStatisticsResp; @@ -13,6 +14,8 @@ import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * @Author:longbinbin @@ -21,17 +24,11 @@ import java.util.List; @Service public class StatisticsServiceImpl implements StatisticsService { + @Autowired + private StatsQueryService statsQueryService; @Autowired private StatisticsMapper statisticsMapper; - List> getScanCodeMemberChartByHour(CommonQueryReq query) { - return statisticsMapper.scanCodeMemberChartByHour(query); - } - - List> getScanCodeMemberChartByDate(CommonQueryReq query) { - return statisticsMapper.scanCodeMemberChartByDate(query); - } - @Override public List> getScanCodeMemberChartAuto(CommonQueryReq query) { // 检查时间范围 @@ -40,34 +37,34 @@ public class StatisticsServiceImpl implements StatisticsService { // 如果开始和结束时间均为空,则默认为当天0点到23时59分59秒 // 如果只有一个为空,则往前或往后推24小时 LocalDateTime now = LocalDateTime.now(); - + if (query.getStartTime() == null && query.getEndTime() == null) { // 都为空,设置为当天0点到23:59:59 LocalDateTime startOfDay = now.withHour(0).withMinute(0).withSecond(0).withNano(0); LocalDateTime endOfDay = now.withHour(23).withMinute(59).withSecond(59).withNano(0); - + query.setStartTime(Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant())); query.setEndTime(Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant())); } else if (query.getStartTime() == null) { // 开始时间为空,结束时间不为空,往前推24小时 LocalDateTime endDateTime = query.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); LocalDateTime startDateTime = endDateTime.minusHours(24); - + query.setStartTime(Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant())); } else { // 结束时间为空,开始时间不为空,往后推24小时 LocalDateTime startDateTime = query.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); LocalDateTime endDateTime = startDateTime.plusHours(24); - + query.setEndTime(Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant())); } } - + // 计算时间差(天数) LocalDateTime startDateTime = query.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); LocalDateTime endDateTime = query.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); long daysBetween = ChronoUnit.DAYS.between(startDateTime, endDateTime); - + // 超过7天使用日期级别,否则使用小时级别 if (daysBetween > 7) { return getScanCodeMemberChartByDate(query); @@ -76,6 +73,68 @@ public class StatisticsServiceImpl implements StatisticsService { } } + /** + * 按小时统计扫码人数(合并统计数据和订单数据) + */ + private List> getScanCodeMemberChartByHour(CommonQueryReq query) { + // 1. 从 StatsQueryService 获取统计数据(根据配置走 ClickHouse 或 MySQL) + List> statsData = statsQueryService.scanCodeMemberChartByHour(query); + + // 2. 从 MySQL 获取订单数据 + List> orderData = statisticsMapper.orderChartByHourForMerge(query); + + // 3. 合并数据 + return mergeChartData(statsData, orderData); + } + + /** + * 按日期统计扫码人数(合并统计数据和订单数据) + */ + private List> getScanCodeMemberChartByDate(CommonQueryReq query) { + // 1. 从 StatsQueryService 获取统计数据(根据配置走 ClickHouse 或 MySQL) + List> statsData = statsQueryService.scanCodeMemberChartByDate(query); + + // 2. 从 MySQL 获取订单数据 + List> orderData = statisticsMapper.orderChartByDateForMerge(query); + + // 3. 合并数据 + return mergeChartData(statsData, orderData); + } + + /** + * 合并统计数据和订单数据 + * 统计数据包含: t, count + * 订单数据包含: t, orderCount, orderAmount + * 合并结果: t, count, orderCount, orderAmount + */ + private List> mergeChartData( + List> statsData, + List> orderData) { + + // 将订单数据转为 Map 以便快速查找 + Map> orderMap = orderData.stream() + .collect(Collectors.toMap( + m -> m.get("t"), + m -> m, + (existing, replacement) -> existing + )); + + // 合并数据 + for (HashMap stat : statsData) { + String timeKey = stat.get("t"); + HashMap order = orderMap.get(timeKey); + if (order != null) { + stat.put("orderCount", order.get("orderCount")); + stat.put("orderAmount", order.get("orderAmount")); + } else { + stat.put("orderCount", "0"); + stat.put("orderAmount", "0"); + } + } + + return statsData; + } + @Override public OrderStatisticsResp getOrderStatistics(CommonQueryReq query) { // 时间参数兜底与规范化 diff --git a/src/main/resources/mapper/StatisticsMapper.xml b/src/main/resources/mapper/StatisticsMapper.xml index 2fe256bb..3eda8aef 100644 --- a/src/main/resources/mapper/StatisticsMapper.xml +++ b/src/main/resources/mapper/StatisticsMapper.xml @@ -386,11 +386,11 @@ + + - WITH RECURSIVE date_series AS ( - SELECT + SELECT DATE(#{startTime}) AS date_value, DATE_FORMAT(#{startTime}, '%m-%d') AS DATE_KEY UNION ALL - SELECT + SELECT DATE_ADD(date_value, INTERVAL 1 DAY) AS date_value, DATE_FORMAT(DATE_ADD(date_value, INTERVAL 1 DAY), '%m-%d') AS DATE_KEY FROM date_series @@ -449,30 +502,11 @@ ) SELECT date_series.DATE_KEY as t, - COALESCE(scan_data.member_count, 0) AS count, COALESCE(order_data.order_count, 0) AS orderCount, COALESCE(order_data.order_amount, 0) AS orderAmount FROM date_series LEFT JOIN ( - SELECT - DATE_FORMAT(s.create_time, '%m-%d') AS date_key, - COUNT(DISTINCT s.member_id) AS member_count - FROM `t_stats_record` r - LEFT JOIN `t_stats` s ON r.trace_id = s.trace_id - WHERE r.trace_id IN ( - SELECT trace_id FROM `t_stats_record` - WHERE action = 'ENTER_SCENIC' - - AND `identifier` = #{scenicId} - - ) - AND r.action = 'LAUNCH' - AND JSON_EXTRACT(`params`, '$.scene') IN (1047, 1048, 1049) - AND s.create_time BETWEEN #{startTime} AND #{endTime} - GROUP BY DATE_FORMAT(s.create_time, '%m-%d') - ) scan_data ON scan_data.date_key = date_series.DATE_KEY - LEFT JOIN ( - SELECT + SELECT DATE_FORMAT(create_at, '%m-%d') AS date_key, COUNT(id) AS order_count, SUM(pay_price) AS order_amount