新增数据统计页面

This commit was merged in pull request #47.
This commit is contained in:
2026-07-10 13:56:16 +08:00
parent 8ee326b43a
commit 593f6f13e7
11 changed files with 637 additions and 7 deletions
+6 -1
View File
@@ -67,7 +67,12 @@
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
<!-- Fix commons-compress version for POI compatibility -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</dependency>
<!-- Gym Modules -->
@@ -59,6 +59,12 @@ public class DataStatistics {
public static final String WEEK = "WEEK";
/** 月统计 */
public static final String MONTH = "MONTH";
/** 近30天 */
public static final String LAST_30_DAYS = "LAST_30_DAYS";
/** 近90天 */
public static final String LAST_90_DAYS = "LAST_90_DAYS";
/** 今年 */
public static final String YEAR = "YEAR";
private PeriodType() {}
}
@@ -458,13 +458,16 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
String periodType = query.getPeriodType();
if (DataStatistics.PeriodType.WEEK.equals(periodType)) {
// 周统计:本周一
return today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).atStartOfDay();
} else if (DataStatistics.PeriodType.MONTH.equals(periodType)) {
// 月统计:本月第一天
return today.withDayOfMonth(1).atStartOfDay();
} else if (DataStatistics.PeriodType.LAST_30_DAYS.equals(periodType)) {
return today.minusDays(29).atStartOfDay();
} else if (DataStatistics.PeriodType.LAST_90_DAYS.equals(periodType)) {
return today.minusDays(89).atStartOfDay();
} else if (DataStatistics.PeriodType.YEAR.equals(periodType)) {
return today.withDayOfYear(1).atStartOfDay();
} else {
// 日统计:当天零点
return today.atStartOfDay();
}
}
@@ -478,13 +481,14 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
String periodType = query.getPeriodType();
if (DataStatistics.PeriodType.WEEK.equals(periodType)) {
// 周统计:本周日 23:59:59
return today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).atTime(23, 59, 59);
} else if (DataStatistics.PeriodType.MONTH.equals(periodType)) {
// 月统计:本月最后一天 23:59:59
return today.with(TemporalAdjusters.lastDayOfMonth()).atTime(23, 59, 59);
} else if (DataStatistics.PeriodType.LAST_30_DAYS.equals(periodType)
|| DataStatistics.PeriodType.LAST_90_DAYS.equals(periodType)
|| DataStatistics.PeriodType.YEAR.equals(periodType)) {
return LocalDateTime.now();
} else {
// 日统计:当前时间
return LocalDateTime.now();
}
}
@@ -503,6 +507,15 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
} else if (DataStatistics.PeriodType.MONTH.equals(periodType)) {
startTime = date.withDayOfMonth(1).atStartOfDay();
endTime = date.with(TemporalAdjusters.lastDayOfMonth()).atTime(23, 59, 59);
} else if (DataStatistics.PeriodType.LAST_30_DAYS.equals(periodType)) {
startTime = date.minusDays(29).atStartOfDay();
endTime = date.atTime(23, 59, 59);
} else if (DataStatistics.PeriodType.LAST_90_DAYS.equals(periodType)) {
startTime = date.minusDays(89).atStartOfDay();
endTime = date.atTime(23, 59, 59);
} else if (DataStatistics.PeriodType.YEAR.equals(periodType)) {
startTime = date.withDayOfYear(1).atStartOfDay();
endTime = date.atTime(23, 59, 59);
} else {
startTime = date.atStartOfDay();
endTime = date.plusDays(1).atStartOfDay();
@@ -0,0 +1,19 @@
-- ============================================
-- V31: 新增数据统计菜单
-- 描述: 为数据统计看板功能创建菜单项
-- ============================================
-- 数据统计一级菜单(目录)
INSERT INTO sys_menu (id, menu_name, parent_id, order_num, menu_type, perms, component, status, created_at, updated_at) VALUES
(504, '数据统计', 0, 7, 'M', NULL, NULL, 1, NOW(), NOW());
-- 数据统计子菜单(页面)
INSERT INTO sys_menu (id, menu_name, parent_id, order_num, menu_type, perms, component, status, created_at, updated_at) VALUES
(505, '数据统计看板', 504, 1, 'C', 'business:statistics:view', 'statistics/dashboard/index', 1, NOW(), NOW());
-- 数据统计按钮权限
INSERT INTO sys_menu (id, menu_name, parent_id, order_num, menu_type, perms, component, status, created_at, updated_at) VALUES
(5051, '数据统计导出', 505, 1, 'F', 'business:statistics:export', NULL, 1, NOW(), NOW());
-- 重置菜单序列
SELECT setval('sys_menu_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_menu));
@@ -0,0 +1,66 @@
-- ============================================================
-- V32: 新增测试数据(用于数据统计看板展示)
-- 描述: 基于当天日期,创建跨多个时间区间的会员、签到、预约数据
-- 覆盖时间区间: 今日、本周、本月、近30天、近90天、今年
-- ============================================================
-- ============================================================
-- 1. 新增会员(100人,ID 2001-2100
-- 按时间分布:今日10人 / 本周20人 / 本月30人 / 近30天60人 / 近90天85人 / 今年100人
-- 创建日期从 180 天前均匀分布到今天
-- ============================================================
INSERT INTO member_user (id, member_no, nickname, phone, gender, subscribed, is_deleted, created_at, updated_at)
SELECT
2000 + g,
'M' || TO_CHAR(CURRENT_DATE - (g % 180), 'YYYYMMDD') || LPAD(g::text, 3, '0'),
'测试会员' || g,
'138' || LPAD(g::text, 8, '0'),
(g % 3)::int,
false,
false,
(CURRENT_DATE - (g % 180) + TIME '10:00:00')::timestamp,
(CURRENT_DATE - (g % 180) + TIME '10:00:00')::timestamp
FROM generate_series(1, 100) AS g
ON CONFLICT (id) DO NOTHING;
-- ============================================================
-- 2. 签到记录(80条,使用已有会员 ID 1001-1010
-- 按时间分布:最近90天,每天约1条
-- 签到类型:QR_CODE/MANUAL/FACE 均匀分布
-- 签到状态:SUCCESS(90%) / FAILED(10%)
-- ============================================================
INSERT INTO sign_in_record (member_id, sign_in_time, sign_in_type, sign_in_status, source, is_delete, created_at, updated_at)
SELECT
1001 + (g % 10),
(CURRENT_DATE - (g % 90) + TIME '08:00:00' + (INTERVAL '1 hour' * (g % 12)))::timestamp,
CASE (g % 3) WHEN 0 THEN 'QR_CODE' WHEN 1 THEN 'MANUAL' ELSE 'FACE' END,
CASE WHEN (g % 10) = 0 THEN 'FAILED' ELSE 'SUCCESS' END,
CASE (g % 2) WHEN 0 THEN 'MINI_PROGRAM' ELSE 'PC_BACKEND' END,
false,
(CURRENT_DATE - (g % 90) + TIME '08:00:00')::timestamp,
(CURRENT_DATE - (g % 90) + TIME '08:00:00')::timestamp
FROM generate_series(1, 80) AS g;
-- ============================================================
-- 3. 团课预约(40条,使用已有会员 ID 1001-1010
-- 按时间分布:最近90天
-- 状态分布:出勤(2) 60% / 取消(1) 20% / 缺席(3) 20%
-- ============================================================
INSERT INTO group_course_booking (id, course_id, member_id, member_card_id, booking_time, status, created_at, updated_at)
SELECT
5100 + g,
CASE (g % 3) WHEN 0 THEN 3001 WHEN 1 THEN 3002 ELSE 3003 END,
1001 + (g % 10),
(SELECT id FROM member_card_record ORDER BY id LIMIT 1),
(CURRENT_DATE - (g % 90) + TIME '10:00:00')::timestamp,
CASE WHEN (g % 5) = 0 THEN '1' WHEN (g % 5) = 1 THEN '3' ELSE '2' END,
(CURRENT_DATE - (g % 90) + TIME '10:00:00')::timestamp,
(CURRENT_DATE - (g % 90) + TIME '10:00:00')::timestamp
FROM generate_series(1, 40) AS g;
-- ============================================================
-- 4. 重置序列(防止后续自动插入 ID 冲突)
-- ============================================================
SELECT setval('member_user_id_seq', (SELECT COALESCE(MAX(id), 1) FROM member_user));
SELECT setval('group_course_booking_id_seq', (SELECT COALESCE(MAX(id), 1) FROM group_course_booking));
SELECT setval('sign_in_record_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sign_in_record));
+6
View File
@@ -106,6 +106,12 @@
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<!-- Fix commons-compress version for POI compatibility -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</dependency>
</dependencies>
<build>
+5
View File
@@ -213,6 +213,11 @@
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.21</version>
</dependency>
</dependencies>
</dependencyManagement>