You've already forked FrameTour-BE
feat(clickhouse): 添加打印样片页面访问统计功能
- 实现按小时统计访问打印样片页面人数的功能 - 实现按日期统计访问打印样片页面人数的功能 - 在ClickHouse查询服务中添加相应的SQL查询方法 - 在MySQL查询服务中添加接口实现 - 更新统计图表合并逻辑,支持打印样片访问数据展示 - 修改mergeChartData方法以支持三组数据合并 - 在MyBatis映射文件中添加对应的SQL查询语句 - 完善相关接口定义和文档注释
This commit is contained in:
@@ -89,4 +89,16 @@ public interface StatsQueryService {
|
|||||||
* 返回格式: [{t: "MM-dd", count: "xxx"}, ...]
|
* 返回格式: [{t: "MM-dd", count: "xxx"}, ...]
|
||||||
*/
|
*/
|
||||||
List<HashMap<String, String>> scanCodeMemberChartByDate(CommonQueryReq query);
|
List<HashMap<String, String>> scanCodeMemberChartByDate(CommonQueryReq query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按小时统计访问打印样片页面人数
|
||||||
|
* 返回格式: [{t: "MM-dd HH", count: "xxx"}, ...]
|
||||||
|
*/
|
||||||
|
List<HashMap<String, String>> printerFromSampleChartByHour(CommonQueryReq query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按日期统计访问打印样片页面人数
|
||||||
|
* 返回格式: [{t: "MM-dd", count: "xxx"}, ...]
|
||||||
|
*/
|
||||||
|
List<HashMap<String, String>> printerFromSampleChartByDate(CommonQueryReq query);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -396,4 +396,62 @@ public class ClickHouseStatsQueryServiceImpl implements StatsQueryService {
|
|||||||
return map;
|
return map;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HashMap<String, String>> printerFromSampleChartByHour(CommonQueryReq query) {
|
||||||
|
StringBuilder sql = new StringBuilder();
|
||||||
|
sql.append("SELECT formatDateTime(toStartOfHour(s.create_time), '%m-%d %H') AS t, ");
|
||||||
|
sql.append(" uniqExact(s.member_id) AS count ");
|
||||||
|
sql.append("FROM t_stats_record r ");
|
||||||
|
sql.append("INNER JOIN t_stats s ON r.trace_id = s.trace_id ");
|
||||||
|
sql.append("WHERE r.action = 'LOAD' ");
|
||||||
|
sql.append("AND r.identifier = 'pages/printer/hello' ");
|
||||||
|
if (query.getScenicId() != null) {
|
||||||
|
sql.append("AND JSONExtractString(r.params, 'scenicId') = '").append(query.getScenicId()).append("' ");
|
||||||
|
}
|
||||||
|
if (query.getStartTime() != null) {
|
||||||
|
sql.append("AND r.create_time >= ").append(formatDateTime(query.getStartTime())).append(" ");
|
||||||
|
}
|
||||||
|
if (query.getEndTime() != null) {
|
||||||
|
sql.append("AND r.create_time <= ").append(formatDateTime(query.getEndTime())).append(" ");
|
||||||
|
}
|
||||||
|
sql.append("GROUP BY toStartOfHour(s.create_time) ");
|
||||||
|
sql.append("ORDER BY toStartOfHour(s.create_time)");
|
||||||
|
|
||||||
|
return getJdbcTemplate().query(sql.toString(), (rs, rowNum) -> {
|
||||||
|
HashMap<String, String> map = new HashMap<>();
|
||||||
|
map.put("t", rs.getString("t"));
|
||||||
|
map.put("count", rs.getString("count"));
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HashMap<String, String>> printerFromSampleChartByDate(CommonQueryReq query) {
|
||||||
|
StringBuilder sql = new StringBuilder();
|
||||||
|
sql.append("SELECT formatDateTime(toStartOfDay(s.create_time), '%m-%d') AS t, ");
|
||||||
|
sql.append(" uniqExact(s.member_id) AS count ");
|
||||||
|
sql.append("FROM t_stats_record r ");
|
||||||
|
sql.append("INNER JOIN t_stats s ON r.trace_id = s.trace_id ");
|
||||||
|
sql.append("WHERE r.action = 'LOAD' ");
|
||||||
|
sql.append("AND r.identifier = 'pages/printer/hello' ");
|
||||||
|
if (query.getScenicId() != null) {
|
||||||
|
sql.append("AND JSONExtractString(r.params, 'scenicId') = '").append(query.getScenicId()).append("' ");
|
||||||
|
}
|
||||||
|
if (query.getStartTime() != null) {
|
||||||
|
sql.append("AND r.create_time >= ").append(formatDateTime(query.getStartTime())).append(" ");
|
||||||
|
}
|
||||||
|
if (query.getEndTime() != null) {
|
||||||
|
sql.append("AND r.create_time <= ").append(formatDateTime(query.getEndTime())).append(" ");
|
||||||
|
}
|
||||||
|
sql.append("GROUP BY toStartOfDay(s.create_time) ");
|
||||||
|
sql.append("ORDER BY toStartOfDay(s.create_time)");
|
||||||
|
|
||||||
|
return getJdbcTemplate().query(sql.toString(), (rs, rowNum) -> {
|
||||||
|
HashMap<String, String> map = new HashMap<>();
|
||||||
|
map.put("t", rs.getString("t"));
|
||||||
|
map.put("count", rs.getString("count"));
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,4 +98,14 @@ public class MySqlStatsQueryServiceImpl implements StatsQueryService {
|
|||||||
public List<HashMap<String, String>> scanCodeMemberChartByDate(CommonQueryReq query) {
|
public List<HashMap<String, String>> scanCodeMemberChartByDate(CommonQueryReq query) {
|
||||||
return statisticsMapper.scanCodeMemberChartByDate(query);
|
return statisticsMapper.scanCodeMemberChartByDate(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HashMap<String, String>> printerFromSampleChartByHour(CommonQueryReq query) {
|
||||||
|
return statisticsMapper.printerFromSampleChartByHour(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HashMap<String, String>> printerFromSampleChartByDate(CommonQueryReq query) {
|
||||||
|
return statisticsMapper.printerFromSampleChartByDate(query);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,16 @@ public interface StatisticsMapper {
|
|||||||
*/
|
*/
|
||||||
List<HashMap<String, String>> scanCodeMemberChartByDate(CommonQueryReq query);
|
List<HashMap<String, String>> scanCodeMemberChartByDate(CommonQueryReq query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按小时统计访问打印样片页面人数
|
||||||
|
*/
|
||||||
|
List<HashMap<String, String>> printerFromSampleChartByHour(CommonQueryReq query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按日期统计访问打印样片页面人数
|
||||||
|
*/
|
||||||
|
List<HashMap<String, String>> printerFromSampleChartByDate(CommonQueryReq query);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按小时统计订单数据
|
* 按小时统计订单数据
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -83,8 +83,11 @@ public class StatisticsServiceImpl implements StatisticsService {
|
|||||||
// 2. 从 MySQL 获取订单数据
|
// 2. 从 MySQL 获取订单数据
|
||||||
List<HashMap<String, String>> orderData = statisticsMapper.orderChartByHourForMerge(query);
|
List<HashMap<String, String>> orderData = statisticsMapper.orderChartByHourForMerge(query);
|
||||||
|
|
||||||
// 3. 合并数据
|
// 3. 获取打印样片页面访问数据
|
||||||
return mergeChartData(statsData, orderData);
|
List<HashMap<String, String>> scanTvData = statsQueryService.printerFromSampleChartByHour(query);
|
||||||
|
|
||||||
|
// 4. 合并数据
|
||||||
|
return mergeChartData(statsData, orderData, scanTvData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,21 +100,26 @@ public class StatisticsServiceImpl implements StatisticsService {
|
|||||||
// 2. 从 MySQL 获取订单数据
|
// 2. 从 MySQL 获取订单数据
|
||||||
List<HashMap<String, String>> orderData = statisticsMapper.orderChartByDateForMerge(query);
|
List<HashMap<String, String>> orderData = statisticsMapper.orderChartByDateForMerge(query);
|
||||||
|
|
||||||
// 3. 合并数据
|
// 3. 获取打印样片页面访问数据
|
||||||
return mergeChartData(statsData, orderData);
|
List<HashMap<String, String>> scanTvData = statsQueryService.printerFromSampleChartByDate(query);
|
||||||
|
|
||||||
|
// 4. 合并数据
|
||||||
|
return mergeChartData(statsData, orderData, scanTvData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合并统计数据和订单数据
|
* 合并统计数据、订单数据和打印样片访问数据
|
||||||
* 统计数据包含: t, count
|
* 统计数据包含: t, count
|
||||||
* 订单数据包含: t, orderCount, orderAmount
|
* 订单数据包含: t, orderCount, orderAmount
|
||||||
* 合并结果: t, count, orderCount, orderAmount
|
* 打印样片数据包含: t, count
|
||||||
|
* 合并结果: t, count, orderCount, orderAmount, scanTvCount
|
||||||
*/
|
*/
|
||||||
private List<HashMap<String, String>> mergeChartData(
|
private List<HashMap<String, String>> mergeChartData(
|
||||||
List<HashMap<String, String>> statsData,
|
List<HashMap<String, String>> statsData,
|
||||||
List<HashMap<String, String>> orderData) {
|
List<HashMap<String, String>> orderData,
|
||||||
|
List<HashMap<String, String>> scanTvData) {
|
||||||
|
|
||||||
// 将订单数据转为 Map 以便快速查找(使用 Object 类型处理数值)
|
// 将订单数据转为 Map 以便快速查找
|
||||||
Map<String, HashMap<String, String>> orderMap = orderData.stream()
|
Map<String, HashMap<String, String>> orderMap = orderData.stream()
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
m -> String.valueOf(m.get("t")),
|
m -> String.valueOf(m.get("t")),
|
||||||
@@ -119,9 +127,19 @@ public class StatisticsServiceImpl implements StatisticsService {
|
|||||||
(existing, replacement) -> existing
|
(existing, replacement) -> existing
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// 将打印样片数据转为 Map 以便快速查找
|
||||||
|
Map<String, HashMap<String, String>> scanTvMap = scanTvData.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
m -> String.valueOf(m.get("t")),
|
||||||
|
m -> m,
|
||||||
|
(existing, replacement) -> existing
|
||||||
|
));
|
||||||
|
|
||||||
// 合并数据
|
// 合并数据
|
||||||
for (HashMap<String, String> stat : statsData) {
|
for (HashMap<String, String> stat : statsData) {
|
||||||
String timeKey = String.valueOf(stat.get("t"));
|
String timeKey = String.valueOf(stat.get("t"));
|
||||||
|
|
||||||
|
// 合并订单数据
|
||||||
HashMap<String, String> order = orderMap.get(timeKey);
|
HashMap<String, String> order = orderMap.get(timeKey);
|
||||||
if (order != null) {
|
if (order != null) {
|
||||||
stat.put("orderCount", String.valueOf(order.get("orderCount")));
|
stat.put("orderCount", String.valueOf(order.get("orderCount")));
|
||||||
@@ -130,6 +148,14 @@ public class StatisticsServiceImpl implements StatisticsService {
|
|||||||
stat.put("orderCount", "0");
|
stat.put("orderCount", "0");
|
||||||
stat.put("orderAmount", "0");
|
stat.put("orderAmount", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 合并打印样片访问数据
|
||||||
|
HashMap<String, String> scanTv = scanTvMap.get(timeKey);
|
||||||
|
if (scanTv != null) {
|
||||||
|
stat.put("scanTvCount", String.valueOf(scanTv.get("count")));
|
||||||
|
} else {
|
||||||
|
stat.put("scanTvCount", "0");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return statsData;
|
return statsData;
|
||||||
|
|||||||
@@ -456,6 +456,70 @@
|
|||||||
) scan_data ON scan_data.date_key = date_series.DATE_KEY
|
) scan_data ON scan_data.date_key = date_series.DATE_KEY
|
||||||
ORDER BY date_series.date_value
|
ORDER BY date_series.date_value
|
||||||
</select>
|
</select>
|
||||||
|
<select id="printerFromSampleChartByHour" resultType="java.util.HashMap">
|
||||||
|
WITH RECURSIVE hour_series AS (
|
||||||
|
SELECT
|
||||||
|
#{startTime} AS hour_time,
|
||||||
|
DATE_FORMAT(#{startTime}, '%m-%d %H') AS HOUR
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
DATE_ADD(hour_time, INTERVAL 1 HOUR) AS hour_time,
|
||||||
|
DATE_FORMAT(DATE_ADD(hour_time, INTERVAL 1 HOUR), '%m-%d %H') AS HOUR
|
||||||
|
FROM hour_series
|
||||||
|
WHERE DATE_ADD(hour_time, INTERVAL 1 HOUR) <= #{endTime}
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
hour_series.HOUR as t,
|
||||||
|
COALESCE(scan_data.member_count, 0) AS count
|
||||||
|
FROM hour_series
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
DATE_FORMAT(s.create_time, '%m-%d %H') AS hour_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.action = 'LOAD'
|
||||||
|
AND r.identifier = 'pages/printer/hello'
|
||||||
|
<if test="scenicId != null">
|
||||||
|
AND JSON_EXTRACT(r.params, '$.scenicId') = #{scenicId}
|
||||||
|
</if>
|
||||||
|
AND s.create_time BETWEEN #{startTime} AND #{endTime}
|
||||||
|
GROUP BY DATE_FORMAT(s.create_time, '%m-%d %H')
|
||||||
|
) scan_data ON scan_data.hour_key = hour_series.HOUR
|
||||||
|
ORDER BY hour_series.hour_time
|
||||||
|
</select>
|
||||||
|
<select id="printerFromSampleChartByDate" resultType="java.util.HashMap">
|
||||||
|
WITH RECURSIVE date_series AS (
|
||||||
|
SELECT
|
||||||
|
DATE(#{startTime}) AS date_value,
|
||||||
|
DATE_FORMAT(#{startTime}, '%m-%d') AS DATE_KEY
|
||||||
|
UNION ALL
|
||||||
|
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
|
||||||
|
WHERE DATE_ADD(date_value, INTERVAL 1 DAY) <= DATE(#{endTime})
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
date_series.DATE_KEY as t,
|
||||||
|
COALESCE(scan_data.member_count, 0) AS count
|
||||||
|
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.action = 'LOAD'
|
||||||
|
AND r.identifier = 'pages/printer/hello'
|
||||||
|
<if test="scenicId != null">
|
||||||
|
AND JSON_EXTRACT(r.params, '$.scenicId') = #{scenicId}
|
||||||
|
</if>
|
||||||
|
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
|
||||||
|
ORDER BY date_series.date_value
|
||||||
|
</select>
|
||||||
<select id="orderChartByHourForMerge" resultType="java.util.HashMap">
|
<select id="orderChartByHourForMerge" resultType="java.util.HashMap">
|
||||||
WITH RECURSIVE hour_series AS (
|
WITH RECURSIVE hour_series AS (
|
||||||
SELECT
|
SELECT
|
||||||
|
|||||||
Reference in New Issue
Block a user