仪表盘功能完善

This commit is contained in:
2025-10-31 14:33:57 +08:00
parent 778f05daa5
commit bbe79ecffb
8 changed files with 416 additions and 20 deletions
@@ -14,6 +14,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 管理员控制器
@@ -143,4 +144,26 @@ public class AdminController {
DashboardStatsResponse.SystemStats systemStats = dashboardService.getSystemStats();
return Result.success("获取成功", systemStats);
}
/**
* 获取用户增长趋势数据
*/
@Operation(summary = "获取用户增长趋势数据", description = "获取指定天数的用户增长趋势数据")
@GetMapping("/dashboard/user-growth-trends")
public Result<List<DashboardStatsResponse.UserGrowthTrend>> getUserGrowthTrends(
@RequestParam(defaultValue = "7") int days) {
List<DashboardStatsResponse.UserGrowthTrend> trends = dashboardService.getUserGrowthTrends(days);
return Result.success("获取成功", trends);
}
/**
* 获取最近登录用户
*/
@Operation(summary = "获取最近登录用户", description = "获取最近登录的用户列表")
@GetMapping("/dashboard/recent-logins")
public Result<List<DashboardStatsResponse.RecentLogin>> getRecentLogins(
@RequestParam(defaultValue = "10") int limit) {
List<DashboardStatsResponse.RecentLogin> recentLogins = dashboardService.getRecentLogins(limit);
return Result.success("获取成功", recentLogins);
}
}
@@ -41,6 +41,12 @@ public class DashboardStatsResponse {
@Schema(description = "数据更新时间")
private LocalDateTime updateTime;
@Schema(description = "用户增长趋势数据")
private List<UserGrowthTrend> userGrowthTrends;
@Schema(description = "最近登录用户")
private List<RecentLogin> recentLogins;
/**
* 用户统计
*/
@@ -165,4 +171,51 @@ public class DashboardStatsResponse {
@Schema(description = "额外数据")
private Map<String, Object> extraData;
}
/**
* 用户增长趋势
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "用户增长趋势")
public static class UserGrowthTrend {
@Schema(description = "日期")
private String date;
@Schema(description = "新增用户数")
private Long newUsers;
@Schema(description = "累计用户数")
private Long totalUsers;
}
/**
* 最近登录用户
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "最近登录用户")
public static class RecentLogin {
@Schema(description = "用户ID")
private String userId;
@Schema(description = "用户名")
private String username;
@Schema(description = "昵称")
private String nickname;
@Schema(description = "头像")
private String avatar;
@Schema(description = "登录时间")
private LocalDateTime loginTime;
@Schema(description = "登录时间描述")
private String timeDescription;
}
}
@@ -1,6 +1,7 @@
package com.emotion.service;
import com.emotion.dto.response.DashboardStatsResponse;
import java.util.List;
/**
* 仪表盘服务接口
@@ -44,4 +45,20 @@ public interface DashboardService {
* @return 系统统计数据
*/
DashboardStatsResponse.SystemStats getSystemStats();
/**
* 获取用户增长趋势数据
*
* @param days 天数,默认7天
* @return 用户增长趋势数据
*/
List<DashboardStatsResponse.UserGrowthTrend> getUserGrowthTrends(int days);
/**
* 获取最近登录用户
*
* @param limit 限制数量,默认10个
* @return 最近登录用户列表
*/
List<DashboardStatsResponse.RecentLogin> getRecentLogins(int limit);
}
@@ -73,6 +73,8 @@ public class DashboardServiceImpl implements DashboardService {
.aiServiceStats(getAiServiceStats())
.systemStats(getSystemStats())
.recentActivities(getRecentActivities())
.userGrowthTrends(getUserGrowthTrends(7))
.recentLogins(getRecentLogins(10))
.updateTime(LocalDateTime.now())
.build();
} catch (Exception e) {
@@ -385,7 +387,110 @@ public class DashboardServiceImpl implements DashboardService {
.uptime("未知")
.build())
.recentActivities(new ArrayList<>())
.userGrowthTrends(new ArrayList<>())
.recentLogins(new ArrayList<>())
.updateTime(LocalDateTime.now())
.build();
}
@Override
public List<DashboardStatsResponse.UserGrowthTrend> getUserGrowthTrends(int days) {
List<DashboardStatsResponse.UserGrowthTrend> trends = new ArrayList<>();
try {
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusDays(days - 1);
// 获取指定日期范围内每天的用户注册数据
for (int i = 0; i < days; i++) {
LocalDate currentDate = startDate.plusDays(i);
LocalDateTime dayStart = currentDate.atStartOfDay();
LocalDateTime dayEnd = dayStart.plusDays(1);
// 统计当天新增用户数
Long newUsers = userService.count(new LambdaQueryWrapper<User>()
.eq(User::getIsDeleted, 0)
.ge(User::getCreateTime, dayStart)
.lt(User::getCreateTime, dayEnd));
// 统计截止到当天的总用户数
Long totalUsers = userService.count(new LambdaQueryWrapper<User>()
.eq(User::getIsDeleted, 0)
.lt(User::getCreateTime, dayEnd));
trends.add(DashboardStatsResponse.UserGrowthTrend.builder()
.date(currentDate.toString())
.newUsers(newUsers)
.totalUsers(totalUsers)
.build());
}
} catch (Exception e) {
log.error("获取用户增长趋势数据失败", e);
}
return trends;
}
@Override
public List<DashboardStatsResponse.RecentLogin> getRecentLogins(int limit) {
List<DashboardStatsResponse.RecentLogin> recentLogins = new ArrayList<>();
try {
// 获取最近活跃的用户(按最后活跃时间排序)
List<User> recentUsers = userService.list(new LambdaQueryWrapper<User>()
.eq(User::getIsDeleted, 0)
.isNotNull(User::getLastActiveTime)
.orderByDesc(User::getLastActiveTime)
.last("LIMIT " + limit));
for (User user : recentUsers) {
String timeDescription = formatTimeDescription(user.getLastActiveTime());
recentLogins.add(DashboardStatsResponse.RecentLogin.builder()
.userId(user.getId())
.username(user.getUsername())
.nickname(user.getNickname())
.avatar(user.getAvatar())
.loginTime(user.getLastActiveTime())
.timeDescription(timeDescription)
.build());
}
} catch (Exception e) {
log.error("获取最近登录用户失败", e);
}
return recentLogins;
}
/**
* 格式化时间描述
*/
private String formatTimeDescription(LocalDateTime dateTime) {
if (dateTime == null) {
return "未知";
}
LocalDateTime now = LocalDateTime.now();
long minutes = java.time.Duration.between(dateTime, now).toMinutes();
if (minutes < 1) {
return "刚刚";
} else if (minutes < 60) {
return minutes + "分钟前";
} else if (minutes < 1440) { // 24小时
long hours = minutes / 60;
return hours + "小时前";
} else {
long days = minutes / 1440;
if (days == 1) {
return "昨天";
} else if (days < 7) {
return days + "天前";
} else {
return dateTime.toLocalDate().toString();
}
}
}
}
@@ -85,6 +85,8 @@ public class DashboardServiceTest {
System.out.println("奖励数量: " + systemStats.getRewardCount());
System.out.println("系统运行时间: " + systemStats.getUptime());
System.out.println("最近活动数量: " + stats.getRecentActivities().size());
System.out.println("用户增长趋势数量: " + (stats.getUserGrowthTrends() != null ? stats.getUserGrowthTrends().size() : 0));
System.out.println("最近登录用户数量: " + (stats.getRecentLogins() != null ? stats.getRecentLogins().size() : 0));
}
@Test
@@ -137,4 +139,48 @@ public class DashboardServiceTest {
assertTrue(systemStats.getRewardCount() >= 0, "奖励数量应大于等于0");
assertNotNull(systemStats.getUptime(), "系统运行时间不应为空");
}
@Test
public void testGetUserGrowthTrends() {
// 测试获取用户增长趋势数据
var trends = dashboardService.getUserGrowthTrends(7);
assertNotNull(trends, "用户增长趋势数据不应为空");
assertTrue(trends.size() <= 7, "趋势数据数量应不超过7天");
for (var trend : trends) {
assertNotNull(trend.getDate(), "日期不应为空");
assertTrue(trend.getNewUsers() >= 0, "新增用户数应大于等于0");
assertTrue(trend.getTotalUsers() >= 0, "总用户数应大于等于0");
}
System.out.println("=== 用户增长趋势测试结果 ===");
for (var trend : trends) {
System.out.println(String.format("日期: %s, 新增: %d, 总计: %d",
trend.getDate(), trend.getNewUsers(), trend.getTotalUsers()));
}
}
@Test
public void testGetRecentLogins() {
// 测试获取最近登录用户
var recentLogins = dashboardService.getRecentLogins(10);
assertNotNull(recentLogins, "最近登录用户数据不应为空");
assertTrue(recentLogins.size() <= 10, "最近登录用户数量应不超过10个");
for (var login : recentLogins) {
assertNotNull(login.getUserId(), "用户ID不应为空");
assertNotNull(login.getUsername(), "用户名不应为空");
assertNotNull(login.getTimeDescription(), "时间描述不应为空");
}
System.out.println("=== 最近登录用户测试结果 ===");
for (var login : recentLogins) {
System.out.println(String.format("用户: %s (%s), 时间: %s",
login.getNickname() != null ? login.getNickname() : login.getUsername(),
login.getUsername(),
login.getTimeDescription()));
}
}
}