31d66103e4
新增今日登录次数统计接口,修复Dashboard显示问题 - 在ISysLoginLogService接口添加countToday方法 - 实现SysLoginLogService中的countToday逻辑 - 更新ISysLoginLogRepository接口 - 添加SysLogHandler中的getTodayLoginCount方法 - 在SystemRouter中配置新路由端点 fix(测试): 更新系统配置URL匹配规则 - 将uat-phase1.spec.ts中的sysconfig改为sys/config docs: 添加E2E测试报告和Dashboard问题诊断文档
301 lines
9.6 KiB
Markdown
301 lines
9.6 KiB
Markdown
# 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` 的数据记录情况
|