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

198 lines
5.9 KiB
TypeScript

"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 : "未知错误"}`
);
}
}