From 778f05daa54692861a6bf78db48e6a45570ece01 Mon Sep 17 00:00:00 2001 From: huazhongmin Date: Fri, 31 Oct 2025 14:23:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=AA=E8=A1=A8=E6=9D=BF=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/DashboardServiceImpl.java | 179 +++++++++++++----- .../emotion/service/DashboardServiceTest.java | 140 ++++++++++++++ 2 files changed, 276 insertions(+), 43 deletions(-) create mode 100644 backend-single/src/test/java/com/emotion/service/DashboardServiceTest.java diff --git a/backend-single/src/main/java/com/emotion/service/impl/DashboardServiceImpl.java b/backend-single/src/main/java/com/emotion/service/impl/DashboardServiceImpl.java index 52e79ce..ee3f6ff 100644 --- a/backend-single/src/main/java/com/emotion/service/impl/DashboardServiceImpl.java +++ b/backend-single/src/main/java/com/emotion/service/impl/DashboardServiceImpl.java @@ -1,6 +1,8 @@ package com.emotion.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.emotion.dto.response.DashboardStatsResponse; +import com.emotion.entity.*; import com.emotion.service.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -84,14 +86,25 @@ public class DashboardServiceImpl implements DashboardService { public DashboardStatsResponse.UserStats getUserStats() { try { // 获取用户统计数据 - Long totalUsers = userService.count(); - Long guestUsers = guestUserService.count(); + Long totalUsers = userService.count(new LambdaQueryWrapper() + .eq(User::getIsDeleted, 0)); - // 获取今日新增用户(这里简化处理,实际可能需要根据创建时间查询) - Long todayNewUsers = 0L; // 可以通过查询今日创建的用户数量来获取 + Long guestUsers = guestUserService.count(new LambdaQueryWrapper() + .eq(GuestUser::getIsDeleted, 0)); - // 活跃用户数(这里简化处理,可以根据最近登录时间或活动时间来计算) - Long activeUsers = totalUsers; // 简化处理 + // 获取今日新增用户 + LocalDateTime todayStart = LocalDate.now().atStartOfDay(); + LocalDateTime todayEnd = todayStart.plusDays(1); + Long todayNewUsers = userService.count(new LambdaQueryWrapper() + .eq(User::getIsDeleted, 0) + .ge(User::getCreateTime, todayStart) + .lt(User::getCreateTime, todayEnd)); + + // 活跃用户数(最近7天有活动的用户) + LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7); + Long activeUsers = userService.count(new LambdaQueryWrapper() + .eq(User::getIsDeleted, 0) + .ge(User::getLastActiveTime, sevenDaysAgo)); return DashboardStatsResponse.UserStats.builder() .totalUsers(totalUsers) @@ -113,11 +126,20 @@ public class DashboardServiceImpl implements DashboardService { @Override public DashboardStatsResponse.ContentStats getContentStats() { try { - Long totalConversations = conversationService.count(); - Long totalMessages = messageService.count(); - Long diaryPosts = diaryPostService.count(); - Long communityPosts = communityPostService.count(); - Long emotionRecords = emotionRecordService.count(); + Long totalConversations = conversationService.count(new LambdaQueryWrapper() + .eq(Conversation::getIsDeleted, 0)); + + Long totalMessages = messageService.count(new LambdaQueryWrapper() + .eq(Message::getIsDeleted, 0)); + + Long diaryPosts = diaryPostService.count(new LambdaQueryWrapper() + .eq(DiaryPost::getIsDeleted, 0)); + + Long communityPosts = communityPostService.count(new LambdaQueryWrapper() + .eq(CommunityPost::getIsDeleted, 0)); + + Long emotionRecords = emotionRecordService.count(new LambdaQueryWrapper() + .eq(EmotionRecord::getIsDeleted, 0)); return DashboardStatsResponse.ContentStats.builder() .totalConversations(totalConversations) @@ -141,18 +163,40 @@ public class DashboardServiceImpl implements DashboardService { @Override public DashboardStatsResponse.AiServiceStats getAiServiceStats() { try { - Long totalApiCalls = cozeApiCallService.count(); - Long aiConfigCount = aiConfigService.count(); + Long totalApiCalls = cozeApiCallService.count(new LambdaQueryWrapper() + .eq(CozeApiCall::getIsDeleted, 0)); - // 获取今日API调用次数(简化处理) - Long todayApiCalls = 0L; // 可以通过查询今日的API调用记录来获取 + Long aiConfigCount = aiConfigService.count(new LambdaQueryWrapper() + .eq(AiConfig::getIsDeleted, 0)); - // 获取成功和失败的调用次数(简化处理) - Long successfulCalls = totalApiCalls; // 可以通过状态字段查询 - Long failedCalls = 0L; + // 获取今日API调用次数 + LocalDateTime todayStart = LocalDate.now().atStartOfDay(); + LocalDateTime todayEnd = todayStart.plusDays(1); + Long todayApiCalls = cozeApiCallService.count(new LambdaQueryWrapper() + .eq(CozeApiCall::getIsDeleted, 0) + .ge(CozeApiCall::getCreateTime, todayStart) + .lt(CozeApiCall::getCreateTime, todayEnd)); - // 平均响应时间(简化处理) - Double avgResponseTime = 500.0; // 可以通过计算duration_ms字段的平均值来获取 + // 获取成功和失败的调用次数 + Long successfulCalls = cozeApiCallService.count(new LambdaQueryWrapper() + .eq(CozeApiCall::getIsDeleted, 0) + .eq(CozeApiCall::getStatus, "success")); + + Long failedCalls = cozeApiCallService.count(new LambdaQueryWrapper() + .eq(CozeApiCall::getIsDeleted, 0) + .eq(CozeApiCall::getStatus, "failed")); + + // 计算平均响应时间(从duration_ms字段) + List apiCalls = cozeApiCallService.list(new LambdaQueryWrapper() + .eq(CozeApiCall::getIsDeleted, 0) + .isNotNull(CozeApiCall::getDurationMs) + .last("LIMIT 1000")); // 取最近1000条记录计算平均值 + + Double avgResponseTime = apiCalls.stream() + .filter(call -> call.getDurationMs() != null) + .mapToInt(CozeApiCall::getDurationMs) + .average() + .orElse(0.0); return DashboardStatsResponse.AiServiceStats.builder() .totalApiCalls(totalApiCalls) @@ -178,9 +222,15 @@ public class DashboardServiceImpl implements DashboardService { @Override public DashboardStatsResponse.SystemStats getSystemStats() { try { - Long adminCount = adminService.count(); - Long achievementCount = achievementService.count(); - Long rewardCount = rewardService.count(); + Long adminCount = adminService.count(new LambdaQueryWrapper() + .eq(Admin::getIsDeleted, 0) + .eq(Admin::getStatus, 1)); // 只统计正常状态的管理员 + + Long achievementCount = achievementService.count(new LambdaQueryWrapper() + .eq(Achievement::getIsDeleted, 0)); + + Long rewardCount = rewardService.count(new LambdaQueryWrapper() + .eq(Reward::getIsDeleted, 0)); // 获取系统运行时间 long uptimeMs = ManagementFactory.getRuntimeMXBean().getUptime(); @@ -210,27 +260,70 @@ public class DashboardServiceImpl implements DashboardService { List activities = new ArrayList<>(); try { - // 这里可以添加获取最近活动的逻辑 - // 例如:最近的用户注册、消息发送、帖子创建等 + // 获取最近注册的用户 + List recentUsers = userService.list(new LambdaQueryWrapper() + .eq(User::getIsDeleted, 0) + .orderByDesc(User::getCreateTime) + .last("LIMIT 3")); - // 示例活动 - activities.add(DashboardStatsResponse.RecentActivity.builder() - .type("user_register") - .description("新用户注册") - .userId("system") - .username("系统") - .activityTime(LocalDateTime.now().minusMinutes(30)) - .extraData(new HashMap<>()) - .build()); - - activities.add(DashboardStatsResponse.RecentActivity.builder() - .type("ai_chat") - .description("AI聊天对话") - .userId("system") - .username("系统") - .activityTime(LocalDateTime.now().minusMinutes(15)) - .extraData(new HashMap<>()) - .build()); + for (User user : recentUsers) { + activities.add(DashboardStatsResponse.RecentActivity.builder() + .type("user_register") + .description("新用户注册: " + (user.getNickname() != null ? user.getNickname() : user.getUsername())) + .userId(user.getId()) + .username(user.getNickname() != null ? user.getNickname() : user.getUsername()) + .activityTime(user.getCreateTime()) + .extraData(new HashMap<>()) + .build()); + } + + // 获取最近的对话 + List recentConversations = conversationService.list(new LambdaQueryWrapper() + .eq(Conversation::getIsDeleted, 0) + .orderByDesc(Conversation::getCreateTime) + .last("LIMIT 3")); + + for (Conversation conversation : recentConversations) { + Map extraData = new HashMap<>(); + extraData.put("conversationId", conversation.getId()); + extraData.put("title", conversation.getTitle()); + + activities.add(DashboardStatsResponse.RecentActivity.builder() + .type("ai_chat") + .description("新的AI对话: " + (conversation.getTitle() != null ? conversation.getTitle() : "未命名对话")) + .userId(conversation.getUserId()) + .username("用户") + .activityTime(conversation.getCreateTime()) + .extraData(extraData) + .build()); + } + + // 获取最近的日记帖子 + List recentDiaryPosts = diaryPostService.list(new LambdaQueryWrapper() + .eq(DiaryPost::getIsDeleted, 0) + .orderByDesc(DiaryPost::getCreateTime) + .last("LIMIT 2")); + + for (DiaryPost post : recentDiaryPosts) { + Map extraData = new HashMap<>(); + extraData.put("postId", post.getId()); + extraData.put("title", post.getTitle()); + + activities.add(DashboardStatsResponse.RecentActivity.builder() + .type("diary_post") + .description("新的日记: " + (post.getTitle() != null ? post.getTitle() : "无标题")) + .userId(post.getUserId()) + .username("用户") + .activityTime(post.getCreateTime()) + .extraData(extraData) + .build()); + } + + // 按时间排序,取最新的10条 + activities.sort((a, b) -> b.getActivityTime().compareTo(a.getActivityTime())); + if (activities.size() > 10) { + activities = activities.subList(0, 10); + } } catch (Exception e) { log.error("获取最近活动失败", e); diff --git a/backend-single/src/test/java/com/emotion/service/DashboardServiceTest.java b/backend-single/src/test/java/com/emotion/service/DashboardServiceTest.java new file mode 100644 index 0000000..09053d4 --- /dev/null +++ b/backend-single/src/test/java/com/emotion/service/DashboardServiceTest.java @@ -0,0 +1,140 @@ +package com.emotion.service; + +import com.emotion.dto.response.DashboardStatsResponse; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 仪表盘服务测试类 + * + * @author system + * @date 2025-10-31 + */ +@SpringBootTest +@ActiveProfiles("local") +public class DashboardServiceTest { + + @Autowired + private DashboardService dashboardService; + + @Test + public void testGetDashboardStats() { + // 测试获取仪表盘统计数据 + DashboardStatsResponse stats = dashboardService.getDashboardStats(); + + assertNotNull(stats, "仪表盘统计数据不应为空"); + assertNotNull(stats.getUserStats(), "用户统计数据不应为空"); + assertNotNull(stats.getContentStats(), "内容统计数据不应为空"); + assertNotNull(stats.getAiServiceStats(), "AI服务统计数据不应为空"); + assertNotNull(stats.getSystemStats(), "系统统计数据不应为空"); + assertNotNull(stats.getUpdateTime(), "更新时间不应为空"); + + // 验证用户统计数据 + DashboardStatsResponse.UserStats userStats = stats.getUserStats(); + assertTrue(userStats.getTotalUsers() >= 0, "总用户数应大于等于0"); + assertTrue(userStats.getTodayNewUsers() >= 0, "今日新增用户数应大于等于0"); + assertTrue(userStats.getActiveUsers() >= 0, "活跃用户数应大于等于0"); + assertTrue(userStats.getGuestUsers() >= 0, "访客用户数应大于等于0"); + + // 验证内容统计数据 + DashboardStatsResponse.ContentStats contentStats = stats.getContentStats(); + assertTrue(contentStats.getTotalConversations() >= 0, "总对话数应大于等于0"); + assertTrue(contentStats.getTotalMessages() >= 0, "总消息数应大于等于0"); + assertTrue(contentStats.getDiaryPosts() >= 0, "日记帖子数应大于等于0"); + assertTrue(contentStats.getCommunityPosts() >= 0, "社区帖子数应大于等于0"); + assertTrue(contentStats.getEmotionRecords() >= 0, "情绪记录数应大于等于0"); + + // 验证AI服务统计数据 + DashboardStatsResponse.AiServiceStats aiStats = stats.getAiServiceStats(); + assertTrue(aiStats.getTotalApiCalls() >= 0, "总API调用次数应大于等于0"); + assertTrue(aiStats.getTodayApiCalls() >= 0, "今日API调用次数应大于等于0"); + assertTrue(aiStats.getSuccessfulCalls() >= 0, "成功调用次数应大于等于0"); + assertTrue(aiStats.getFailedCalls() >= 0, "失败调用次数应大于等于0"); + assertTrue(aiStats.getAvgResponseTime() >= 0, "平均响应时间应大于等于0"); + assertTrue(aiStats.getAiConfigCount() >= 0, "AI配置数量应大于等于0"); + + // 验证系统统计数据 + DashboardStatsResponse.SystemStats systemStats = stats.getSystemStats(); + assertTrue(systemStats.getAdminCount() >= 0, "管理员数量应大于等于0"); + assertTrue(systemStats.getAchievementCount() >= 0, "成就数量应大于等于0"); + assertTrue(systemStats.getRewardCount() >= 0, "奖励数量应大于等于0"); + assertNotNull(systemStats.getUptime(), "系统运行时间不应为空"); + + System.out.println("=== 仪表盘统计数据测试结果 ==="); + System.out.println("总用户数: " + userStats.getTotalUsers()); + System.out.println("今日新增用户: " + userStats.getTodayNewUsers()); + System.out.println("活跃用户数: " + userStats.getActiveUsers()); + System.out.println("访客用户数: " + userStats.getGuestUsers()); + System.out.println("总对话数: " + contentStats.getTotalConversations()); + System.out.println("总消息数: " + contentStats.getTotalMessages()); + System.out.println("日记帖子数: " + contentStats.getDiaryPosts()); + System.out.println("社区帖子数: " + contentStats.getCommunityPosts()); + System.out.println("情绪记录数: " + contentStats.getEmotionRecords()); + System.out.println("总API调用次数: " + aiStats.getTotalApiCalls()); + System.out.println("今日API调用次数: " + aiStats.getTodayApiCalls()); + System.out.println("成功调用次数: " + aiStats.getSuccessfulCalls()); + System.out.println("失败调用次数: " + aiStats.getFailedCalls()); + System.out.println("平均响应时间: " + aiStats.getAvgResponseTime() + "ms"); + System.out.println("AI配置数量: " + aiStats.getAiConfigCount()); + System.out.println("管理员数量: " + systemStats.getAdminCount()); + System.out.println("成就数量: " + systemStats.getAchievementCount()); + System.out.println("奖励数量: " + systemStats.getRewardCount()); + System.out.println("系统运行时间: " + systemStats.getUptime()); + System.out.println("最近活动数量: " + stats.getRecentActivities().size()); + } + + @Test + public void testGetUserStats() { + // 测试获取用户统计数据 + DashboardStatsResponse.UserStats userStats = dashboardService.getUserStats(); + + assertNotNull(userStats, "用户统计数据不应为空"); + assertTrue(userStats.getTotalUsers() >= 0, "总用户数应大于等于0"); + assertTrue(userStats.getTodayNewUsers() >= 0, "今日新增用户数应大于等于0"); + assertTrue(userStats.getActiveUsers() >= 0, "活跃用户数应大于等于0"); + assertTrue(userStats.getGuestUsers() >= 0, "访客用户数应大于等于0"); + } + + @Test + public void testGetContentStats() { + // 测试获取内容统计数据 + DashboardStatsResponse.ContentStats contentStats = dashboardService.getContentStats(); + + assertNotNull(contentStats, "内容统计数据不应为空"); + assertTrue(contentStats.getTotalConversations() >= 0, "总对话数应大于等于0"); + assertTrue(contentStats.getTotalMessages() >= 0, "总消息数应大于等于0"); + assertTrue(contentStats.getDiaryPosts() >= 0, "日记帖子数应大于等于0"); + assertTrue(contentStats.getCommunityPosts() >= 0, "社区帖子数应大于等于0"); + assertTrue(contentStats.getEmotionRecords() >= 0, "情绪记录数应大于等于0"); + } + + @Test + public void testGetAiServiceStats() { + // 测试获取AI服务统计数据 + DashboardStatsResponse.AiServiceStats aiStats = dashboardService.getAiServiceStats(); + + assertNotNull(aiStats, "AI服务统计数据不应为空"); + assertTrue(aiStats.getTotalApiCalls() >= 0, "总API调用次数应大于等于0"); + assertTrue(aiStats.getTodayApiCalls() >= 0, "今日API调用次数应大于等于0"); + assertTrue(aiStats.getSuccessfulCalls() >= 0, "成功调用次数应大于等于0"); + assertTrue(aiStats.getFailedCalls() >= 0, "失败调用次数应大于等于0"); + assertTrue(aiStats.getAvgResponseTime() >= 0, "平均响应时间应大于等于0"); + assertTrue(aiStats.getAiConfigCount() >= 0, "AI配置数量应大于等于0"); + } + + @Test + public void testGetSystemStats() { + // 测试获取系统统计数据 + DashboardStatsResponse.SystemStats systemStats = dashboardService.getSystemStats(); + + assertNotNull(systemStats, "系统统计数据不应为空"); + assertTrue(systemStats.getAdminCount() >= 0, "管理员数量应大于等于0"); + assertTrue(systemStats.getAchievementCount() >= 0, "成就数量应大于等于0"); + assertTrue(systemStats.getRewardCount() >= 0, "奖励数量应大于等于0"); + assertNotNull(systemStats.getUptime(), "系统运行时间不应为空"); + } +} \ No newline at end of file