feat(登录日志): 添加今日登录次数统计功能

新增今日登录次数统计接口,修复Dashboard显示问题
- 在ISysLoginLogService接口添加countToday方法
- 实现SysLoginLogService中的countToday逻辑
- 更新ISysLoginLogRepository接口
- 添加SysLogHandler中的getTodayLoginCount方法
- 在SystemRouter中配置新路由端点

fix(测试): 更新系统配置URL匹配规则
- 将uat-phase1.spec.ts中的sysconfig改为sys/config

docs: 添加E2E测试报告和Dashboard问题诊断文档
This commit is contained in:
张翔
2026-03-24 17:12:10 +08:00
parent 3d6a0bd7b8
commit 31d66103e4
14 changed files with 543 additions and 8 deletions
+300
View File
@@ -0,0 +1,300 @@
# Dashboard数据显示问题诊断报告
## 问题描述
用户反馈Dashboard页面显示异常:
- 登录次数一直显示为0
- 操作日志一直显示为0
## 问题根因分析
### 1. 登录次数显示为0
**前端代码分析**[Dashboard.vue](file:///Users/zhangxiang/Codes/Novalon/novalon-manage-system/novalon-manage-web/src/views/system/Dashboard.vue#L127)):
```javascript
const todayLoginRes: any = await request.get('/logs/login/today/count')
stats.todayLogin = todayLoginRes || 0
```
**后端路由配置**[SystemRouter.java](file:///Users/zhangxiang/Codes/Novalon/novalon-manage-system/novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/config/SystemRouter.java#L139)):
```java
@Bean
public RouterFunction<ServerResponse> logRoutes(SysLogHandler logHandler) {
return route()
.GET("/api/logs/login", logHandler::getAllLoginLogs)
.GET("/api/logs/login/page", logHandler::getLoginLogsByPage)
.GET("/api/logs/login/count", logHandler::getLoginLogCount)
// 注意:缺少 /api/logs/login/today/count 端点
.build();
}
```
**服务接口分析**[ISysLoginLogService.java](file:///Users/zhangxiang/Codes/Novalon/novalon-manage-system/novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/ISysLoginLogService.java)):
```java
public interface ISysLoginLogService {
Mono<SysLoginLog> findById(Long id);
Flux<SysLoginLog> findAll();
Flux<SysLoginLog> findByUsername(String username);
Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
Mono<SysLoginLog> save(SysLoginLog loginLog);
Mono<PageResponse<SysLoginLog>> findLoginLogsByPage(PageRequest pageRequest);
Mono<Long> count();
// 注意:缺少 countToday() 方法
}
```
**问题根因**
1. 前端请求 `/logs/login/today/count` 端点
2. 后端没有配置这个路由端点
3. `ISysLoginLogService` 接口缺少 `countToday()` 方法
4. 请求失败导致返回undefined,前端显示为0
### 2. 操作日志显示为0
**前端代码分析**[Dashboard.vue](file:///Users/zhangxiang/Codes/Novalon/novalon-manage-system/novalon-manage-web/src/views/system/Dashboard.vue#L131)):
```javascript
const operationLogRes: any = await request.get('/logs/operation/count')
stats.operationLog = operationLogRes || 0
```
**后端路由配置**[SystemRouter.java](file:///Users/zhangxiang/Codes/Novalon/novalon-manage-system/novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/config/SystemRouter.java#L152)):
```java
@Bean
public RouterFunction<ServerResponse> operationLogRoutes(OperationLogHandler operationLogHandler) {
return route()
.GET("/api/logs/operation", operationLogHandler::getAllOperationLogs)
.GET("/api/logs/operation/page", operationLogHandler::getOperationLogsByPage)
.GET("/api/logs/operation/count", operationLogHandler::getOperationLogCount)
// 端点存在
.build();
}
```
**可能原因**
1. 数据库中确实没有操作日志记录
2. 操作日志拦截器可能没有正确记录日志
3. 统计查询可能有问题
## 修复方案
### 方案1:添加今日登录统计功能(推荐)
#### 1.1 更新服务接口
**文件**`ISysLoginLogService.java`
```java
public interface ISysLoginLogService {
Mono<SysLoginLog> findById(Long id);
Flux<SysLoginLog> findAll();
Flux<SysLoginLog> findByUsername(String username);
Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
Mono<SysLoginLog> save(SysLoginLog loginLog);
Mono<PageResponse<SysLoginLog>> findLoginLogsByPage(PageRequest pageRequest);
Mono<Long> count();
Mono<Long> countToday(); // 新增方法
}
```
#### 1.2 实现今日登录统计
**文件**`SysLoginLogService.java`
```java
@Override
public Mono<Long> countToday() {
LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
LocalDateTime todayEnd = todayStart.plusDays(1);
return repository.findByLoginTimeBetween(todayStart, todayEnd)
.count();
}
```
#### 1.3 添加Repository方法
**文件**`ISysLoginLogRepository.java`
```java
Flux<SysLoginLog> findByLoginTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
```
#### 1.4 更新Handler
**文件**`SysLogHandler.java`
```java
@Operation(summary = "获取今日登录次数", description = "获取今日登录次数统计")
public Mono<ServerResponse> getTodayLoginCount(ServerRequest request) {
return loginLogService.countToday()
.flatMap(count -> ServerResponse.ok().bodyValue(count));
}
```
#### 1.5 更新路由配置
**文件**`SystemRouter.java`
```java
@Bean
public RouterFunction<ServerResponse> logRoutes(SysLogHandler logHandler) {
return route()
.GET("/api/logs/login", logHandler::getAllLoginLogs)
.GET("/api/logs/login/page", logHandler::getLoginLogsByPage)
.GET("/api/logs/login/count", logHandler::getLoginLogCount)
.GET("/api/logs/login/today/count", logHandler::getTodayLoginCount) // 新增路由
.build();
}
```
### 方案2:使用统一统计API(备选)
#### 2.1 更新前端Dashboard
**文件**`Dashboard.vue`
```javascript
const fetchStats = async () => {
loading.value = true
try {
// 使用统一的统计API
const statsRes: any = await request.get('/stats/overview')
stats.userCount = statsRes.userCount || 0
stats.roleCount = statsRes.roleCount || 0
stats.todayLogin = statsRes.todayOperationCount || 0 // 注意字段映射
stats.operationLog = statsRes.operationLogCount || 0
} catch (error) {
console.error('Failed to fetch stats:', error)
} finally {
loading.value = false
}
}
```
#### 2.2 更新StatsHandler
**文件**`StatsHandler.java`
```java
@Operation(summary = "获取系统概览", description = "获取系统统计概览信息")
public Mono<ServerResponse> getOverview(ServerRequest request) {
return Mono.zip(
userService.count(),
roleService.count(),
operationLogService.count(),
loginLogService.countToday(), // 添加今日登录统计
operationLogService.countToday()
).flatMap(tuple -> {
OverviewStats stats = new OverviewStats();
stats.setUserCount(tuple.getT1());
stats.setRoleCount(tuple.getT2());
stats.setOperationLogCount(tuple.getT3());
stats.setTodayLoginCount(tuple.getT4()); // 新增字段
stats.setTodayOperationCount(tuple.getT5());
return ServerResponse.ok().bodyValue(stats);
});
}
public static class OverviewStats {
private Long userCount;
private Long roleCount;
private Long operationLogCount;
private Long todayLoginCount; // 新增字段
private Long todayOperationCount;
// getters and setters...
}
```
### 方案3:检查操作日志记录
#### 3.1 检查操作日志拦截器
**文件**`OperationLogFilter.java`
确认拦截器是否正确配置和记录操作日志:
```java
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class OperationLogFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().value();
// 排除不需要记录的路径
if (shouldSkipLogging(path)) {
return chain.filter(exchange);
}
// 记录操作日志
return chain.filter(exchange).doFinally(signalType -> {
OperationLog log = new OperationLog();
log.setUsername(getUsername(exchange));
log.setOperation(path);
log.setMethod(request.getMethod().name());
log.setIp(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
log.setStatus(exchange.getResponse().getStatusCode().value());
operationLogService.save(log).subscribe();
});
}
}
```
#### 3.2 验证数据库
```sql
-- 检查操作日志表是否有数据
SELECT COUNT(*) FROM operation_log;
-- 检查今日操作日志
SELECT COUNT(*) FROM operation_log
WHERE created_at >= CURRENT_DATE;
-- 检查最近10条操作日志
SELECT * FROM operation_log
ORDER BY created_at DESC
LIMIT 10;
```
## 推荐实施步骤
1. **立即修复**:实施方案1,添加今日登录统计功能
2. **验证操作日志**:检查操作日志拦截器和数据库记录
3. **长期优化**:考虑实施方案2,使用统一统计API简化前端逻辑
## 测试验证
修复后需要验证:
1. Dashboard页面正确显示今日登录次数
2. Dashboard页面正确显示操作日志数量
3. 执行一些操作后,操作日志数量增加
4. 登录后,今日登录次数增加
## 相关文件清单
需要修改的文件:
- `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/ISysLoginLogService.java`
- `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysLoginLogService.java`
- `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/repository/ISysLoginLogRepository.java`
- `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/log/SysLogHandler.java`
- `novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/config/SystemRouter.java`
- `novalon-manage-web/src/views/system/Dashboard.vue`(可选,如果使用方案2
需要检查的文件:
- `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/interceptor/OperationLogFilter.java`
- 数据库表 `operation_log` 的数据记录情况