You've already forked FrameTour-BE
feat(database): 迁移统计数据查询到ClickHouse
- 添加ClickHouse数据源配置和相关依赖 - 实现ClickHouse统计查询服务和MySQL兜底方案 - 新增扫码统计、订单统计等数据查询接口 - 重构分销员数据统计逻辑,整合MySQL和ClickHouse数据源 - 更新应用配置文件以支持ClickHouse启用开关 - 修改分布式任务统计以支持跨库查询场景
This commit is contained in:
@@ -3,6 +3,7 @@ package com.ycwl.basic.service.mobile.impl;
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.ycwl.basic.clickhouse.service.StatsQueryService;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.ycwl.basic.enums.StatisticEnum;
|
||||
import com.ycwl.basic.mapper.StatisticsMapper;
|
||||
@@ -41,6 +42,9 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
||||
@Autowired
|
||||
private StatisticsMapper statisticsMapper;
|
||||
|
||||
@Autowired
|
||||
private StatsQueryService statsQueryService;
|
||||
|
||||
|
||||
/**
|
||||
* 支付订单金额、预览_支付转化率、扫码_付费用户转化率
|
||||
@@ -210,19 +214,19 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
||||
// Integer cameraShotOfMemberNum=statisticsMapper.countCameraShotOfMember(query);
|
||||
//扫码访问人数
|
||||
// 扫小程序码或景区码进入访问的用户数,包括授权用户(使用OpenID进行精准统计)和未授权用户(使用 UUID统计访问)。但当用户授权时,获取OpenID并与UUID关联,删除本地UUID,避免重复记录。
|
||||
Integer scanCodeVisitorOfMemberNum=statisticsMapper.countScanCodeOfMember(query);
|
||||
Integer scanCodeVisitorOfMemberNum=statsQueryService.countScanCodeOfMember(query);
|
||||
//上传头像(人脸)人数
|
||||
// 上传了人脸的用户数(包括本地临时ID和获取到OpenID的,同一设备微信获取到OpenID要覆盖掉之前生成的临时ID),上传多张人脸都只算一个人。
|
||||
Integer uploadFaceOfMemberNum=statisticsMapper.countUploadFaceOfMember(query);
|
||||
Integer uploadFaceOfMemberNum=statsQueryService.countUploadFaceOfMember(query);
|
||||
//推送订阅人数
|
||||
// 只要点了允许通知,哪怕只勾选1条订阅都算
|
||||
Integer pushOfMemberNum =statisticsMapper.countPushOfMember(query);
|
||||
Integer pushOfMemberNum =statsQueryService.countPushOfMember(query);
|
||||
//生成视频人数
|
||||
// 生成过Vlog视频的用户ID数,要注意屏蔽掉以前没有片段也能生成的情况
|
||||
Integer completeVideoOfMemberNum =statisticsMapper.countCompleteVideoOfMember(query);
|
||||
Integer completeVideoOfMemberNum =statsQueryService.countCompleteVideoOfMember(query);
|
||||
//预览视频人数
|
||||
// 购买前播放了5秒的视频条数。
|
||||
Integer previewVideoOfMemberNum =statisticsMapper.countPreviewVideoOfMember(query);
|
||||
Integer previewVideoOfMemberNum =statsQueryService.countPreviewVideoOfMember(query);
|
||||
if (previewVideoOfMemberNum==null){
|
||||
previewVideoOfMemberNum=0;
|
||||
}
|
||||
@@ -233,13 +237,13 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
||||
Integer payOfMemberNum =statisticsMapper.countPayOfMember(query);
|
||||
//总访问人数
|
||||
// 通过任何途径访问到小程序的总人数,包括授权用户和未授权用户。
|
||||
Integer totalVisitorOfMemberNum =statisticsMapper.countTotalVisitorOfMember(query);
|
||||
Integer totalVisitorOfMemberNum =statsQueryService.countTotalVisitorOfMember(query);
|
||||
// Integer totalVisitorOfMemberNum =scanCodeVisitorOfMemberNum;
|
||||
//生成视频条数
|
||||
// 仅指代生成的Vlog条数,不包含录像原片。
|
||||
Integer completeOfVideoNum =statisticsMapper.countCompleteOfVideo(query);
|
||||
Integer completeOfVideoNum =statsQueryService.countCompleteOfVideo(query);
|
||||
//预览视频条数
|
||||
Integer previewOfVideoNum =statisticsMapper.countPreviewOfVideo(query);
|
||||
Integer previewOfVideoNum =statsQueryService.countPreviewOfVideo(query);
|
||||
//支付订单数
|
||||
Integer payOfOrderNum =statisticsMapper.countPayOfOrder(query);
|
||||
//支付订单金额
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.ycwl.basic.service.pc.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.clickhouse.service.StatsQueryService;
|
||||
import com.ycwl.basic.mapper.BrokerRecordMapper;
|
||||
import com.ycwl.basic.model.pc.broker.entity.BrokerRecord;
|
||||
import com.ycwl.basic.model.pc.broker.req.BrokerRecordReqQuery;
|
||||
@@ -11,8 +13,9 @@ import com.ycwl.basic.service.pc.BrokerRecordService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
@@ -22,6 +25,8 @@ import java.util.List;
|
||||
public class BrokerRecordServiceImpl implements BrokerRecordService {
|
||||
@Autowired
|
||||
private BrokerRecordMapper brokerRecordMapper;
|
||||
@Autowired
|
||||
private StatsQueryService statsQueryService;
|
||||
|
||||
@Override
|
||||
public PageInfo<BrokerRecordRespVO> pageQuery(BrokerRecordReqQuery brokerRecordReqQuery) {
|
||||
@@ -58,7 +63,52 @@ public class BrokerRecordServiceImpl implements BrokerRecordService {
|
||||
|
||||
@Override
|
||||
public List<DailySummaryRespVO> getDailySummaryByBrokerId(Long brokerId, Date startTime, Date endTime) {
|
||||
return brokerRecordMapper.getDailySummaryByBrokerId(brokerId, startTime, endTime);
|
||||
// 从 MySQL 获取订单数据
|
||||
List<HashMap<String, Object>> orderStats = brokerRecordMapper.getDailyOrderStats(brokerId, startTime, endTime);
|
||||
|
||||
// 从 ClickHouse/MySQL 获取扫码数据
|
||||
List<HashMap<String, Object>> scanStats = statsQueryService.getDailyScanStats(brokerId, startTime, endTime);
|
||||
|
||||
// 将扫码数据转换为 Map 便于查找
|
||||
Map<String, Long> scanCountByDate = new HashMap<>();
|
||||
if (scanStats != null) {
|
||||
for (HashMap<String, Object> stat : scanStats) {
|
||||
Object dateObj = stat.get("date");
|
||||
String dateKey = dateObj != null ? DateUtil.formatDate((Date) dateObj) : null;
|
||||
Object scanCountObj = stat.get("scanCount");
|
||||
Long scanCount = scanCountObj != null ? ((Number) scanCountObj).longValue() : 0L;
|
||||
if (dateKey != null) {
|
||||
scanCountByDate.put(dateKey, scanCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合并数据
|
||||
List<DailySummaryRespVO> result = new ArrayList<>();
|
||||
for (HashMap<String, Object> orderStat : orderStats) {
|
||||
DailySummaryRespVO vo = new DailySummaryRespVO();
|
||||
|
||||
Object dateObj = orderStat.get("date");
|
||||
if (dateObj instanceof Date) {
|
||||
vo.setDate((Date) dateObj);
|
||||
}
|
||||
|
||||
String dateKey = dateObj != null ? DateUtil.formatDate((Date) dateObj) : null;
|
||||
vo.setScanCount(scanCountByDate.getOrDefault(dateKey, 0L));
|
||||
|
||||
Object orderCountObj = orderStat.get("orderCount");
|
||||
vo.setOrderCount(orderCountObj != null ? ((Number) orderCountObj).longValue() : 0L);
|
||||
|
||||
Object totalOrderPriceObj = orderStat.get("totalOrderPrice");
|
||||
vo.setTotalOrderPrice(totalOrderPriceObj != null ? new BigDecimal(totalOrderPriceObj.toString()) : BigDecimal.ZERO);
|
||||
|
||||
Object totalBrokerPriceObj = orderStat.get("totalBrokerPrice");
|
||||
vo.setTotalBrokerPrice(totalBrokerPriceObj != null ? new BigDecimal(totalBrokerPriceObj.toString()) : BigDecimal.ZERO);
|
||||
|
||||
result.add(vo);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.ycwl.basic.service.pc.impl;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.clickhouse.service.StatsQueryService;
|
||||
import com.ycwl.basic.mapper.BrokerMapper;
|
||||
import com.ycwl.basic.model.pc.broker.entity.BrokerEntity;
|
||||
import com.ycwl.basic.model.pc.broker.req.BrokerReqQuery;
|
||||
@@ -27,12 +28,14 @@ public class BrokerServiceImpl implements BrokerService {
|
||||
private BrokerMapper brokerMapper;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
@Autowired
|
||||
private StatsQueryService statsQueryService;
|
||||
|
||||
@Override
|
||||
public PageInfo<BrokerRespVO> pageQuery(BrokerReqQuery brokerReqQuery) {
|
||||
PageHelper.startPage(brokerReqQuery.getPageNum(),brokerReqQuery.getPageSize());
|
||||
List<BrokerRespVO> list = brokerMapper.list(brokerReqQuery);
|
||||
|
||||
|
||||
// 批量获取景区名称
|
||||
List<Long> scenicIds = list.stream()
|
||||
.map(BrokerRespVO::getScenicId)
|
||||
@@ -40,14 +43,17 @@ public class BrokerServiceImpl implements BrokerService {
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, String> scenicNames = scenicRepository.batchGetScenicNames(scenicIds);
|
||||
|
||||
// 设置景区名称
|
||||
|
||||
// 设置景区名称和扫码次数
|
||||
list.forEach(item -> {
|
||||
if (item.getScenicId() != null) {
|
||||
item.setScenicName(scenicNames.get(item.getScenicId()));
|
||||
}
|
||||
// 从 ClickHouse/MySQL 查询分销员扫码次数
|
||||
Integer scanCount = statsQueryService.countBrokerScanCount(item.getId());
|
||||
item.setBrokerScanCount(scanCount != null ? scanCount.longValue() : 0L);
|
||||
});
|
||||
|
||||
|
||||
PageInfo<BrokerRespVO> pageInfo = new PageInfo(list);
|
||||
return pageInfo;
|
||||
}
|
||||
@@ -55,7 +61,7 @@ public class BrokerServiceImpl implements BrokerService {
|
||||
@Override
|
||||
public List<BrokerRespVO> list(BrokerReqQuery brokerReqQuery) {
|
||||
List<BrokerRespVO> list = brokerMapper.list(brokerReqQuery);
|
||||
|
||||
|
||||
// 批量获取景区名称
|
||||
List<Long> scenicIds = list.stream()
|
||||
.map(BrokerRespVO::getScenicId)
|
||||
@@ -63,14 +69,17 @@ public class BrokerServiceImpl implements BrokerService {
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, String> scenicNames = scenicRepository.batchGetScenicNames(scenicIds);
|
||||
|
||||
// 设置景区名称
|
||||
|
||||
// 设置景区名称和扫码次数
|
||||
list.forEach(item -> {
|
||||
if (item.getScenicId() != null) {
|
||||
item.setScenicName(scenicNames.get(item.getScenicId()));
|
||||
}
|
||||
// 从 ClickHouse/MySQL 查询分销员扫码次数
|
||||
Integer scanCount = statsQueryService.countBrokerScanCount(item.getId());
|
||||
item.setBrokerScanCount(scanCount != null ? scanCount.longValue() : 0L);
|
||||
});
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user