judge4c/src/app/(protected)/dashboard/(userdashboard)/_actions/student-dashboard.ts

175 lines
5.6 KiB
TypeScript
Raw Normal View History

2025-06-21 09:44:14 +00:00
"use server";
import prisma from "@/lib/prisma";
import { auth } from "@/lib/auth";
export async function getStudentDashboardData() {
try {
console.log("=== 开始获取学生仪表板数据 ===");
const session = await auth();
console.log("Session 获取成功:", !!session);
console.log("Session user:", session?.user);
if (!session?.user?.id) {
console.log("用户未登录或session无效");
throw new Error("未登录");
}
const userId = session.user.id;
console.log("当前用户ID:", userId);
// 检查用户是否存在
const currentUser = await prisma.user.findUnique({
where: { id: userId },
select: { id: true, name: true, email: true, role: true }
});
console.log("当前用户信息:", currentUser);
if (!currentUser) {
throw new Error("用户不存在");
}
// 获取所有已发布的题目(包含英文标题)
const allProblems = await prisma.problem.findMany({
where: { isPublished: true },
select: {
id: true,
displayId: true,
difficulty: true,
localizations: {
where: {
type: "TITLE",
},
}
}
});
console.log("已发布题目数量:", allProblems.length);
console.log("题目列表:", allProblems.map(p => ({
id: p.id,
displayId: p.displayId,
title: p.localizations[0]?.content || "无标题",
difficulty: p.difficulty
})));
// 获取当前学生的所有提交记录(包含题目英文标题)
const userSubmissions = await prisma.submission.findMany({
where: { userId: userId },
include: {
problem: {
select: {
id: true,
displayId: true,
difficulty: true,
localizations: {
where: {
type: "TITLE",
locale: "en" // 或者根据需求使用其他语言
},
select: {
content: true
}
}
}
}
}
});
console.log("当前用户提交记录数量:", userSubmissions.length);
console.log("提交记录详情:", userSubmissions.map(s => ({
problemId: s.problemId,
problemDisplayId: s.problem.displayId,
title: s.problem.localizations[0]?.content || "无标题",
difficulty: s.problem.difficulty,
status: s.status
})));
// 计算题目完成情况
const completedProblems = new Set<string | number>();
const attemptedProblems = new Set<string | number>();
const wrongSubmissions = new Map<string | number, number>(); // problemId -> count
userSubmissions.forEach((submission) => {
attemptedProblems.add(submission.problemId);
if (submission.status === "AC") {
completedProblems.add(submission.problemId);
} else {
// 统计错误提交次数
const currentCount = wrongSubmissions.get(submission.problemId) || 0;
wrongSubmissions.set(submission.problemId, currentCount + 1);
}
});
console.log("尝试过的题目数:", attemptedProblems.size);
console.log("完成的题目数:", completedProblems.size);
console.log("错误提交统计:", Object.fromEntries(wrongSubmissions));
// 题目完成比例数据
const completionData = {
total: allProblems.length,
completed: completedProblems.size,
percentage: allProblems.length > 0 ? Math.round((completedProblems.size / allProblems.length) * 100) : 0,
};
// 错题比例数据 - 基于已完成的题目计算
const wrongProblems = new Set<string | number>();
// 统计在已完成的题目中,哪些题目曾经有过错误提交
userSubmissions.forEach((submission) => {
if (submission.status !== "AC" && completedProblems.has(submission.problemId)) {
wrongProblems.add(submission.problemId);
}
});
const errorData = {
total: completedProblems.size, // 已完成的题目总数
wrong: wrongProblems.size, // 在已完成的题目中有过错误的题目数
percentage: completedProblems.size > 0 ? Math.round((wrongProblems.size / completedProblems.size) * 100) : 0,
};
// 易错题列表(按错误次数排序)
const difficultProblems = Array.from(wrongSubmissions.entries())
.map(([problemId, errorCount]) => {
const problem = allProblems.find((p) => p.id === problemId);
// 从 problem.localizations 中获取标题
const title = problem?.localizations?.find((loc) => loc.type === "TITLE")?.content || "未知题目";
return {
id: problem?.displayId || problemId,
title: title, // 使用从 localizations 获取的标题
difficulty: problem?.difficulty || "未知",
errorCount: errorCount as number,
};
})
.sort((a, b) => b.errorCount - a.errorCount)
.slice(0, 10); // 只显示前10个
const result = {
completionData,
errorData,
difficultProblems,
pieChartData: [
{ name: "已完成", value: completionData.completed },
{ name: "未完成", value: completionData.total - completionData.completed },
],
errorPieChartData: [
{ name: "正确", value: errorData.total - errorData.wrong },
{ name: "错误", value: errorData.wrong },
],
};
console.log("=== 返回的数据 ===");
console.log("完成情况:", completionData);
console.log("错误情况:", errorData);
console.log("易错题数量:", difficultProblems.length);
console.log("=== 数据获取完成 ===");
return result;
} catch (error) {
console.error("获取学生仪表板数据失败:", error);
throw new Error(`获取数据失败: ${error instanceof Error ? error.message : '未知错误'}`);
}
}