2025-06-17 09:05:15 +00:00
|
|
|
|
import {
|
|
|
|
|
SidebarInset,
|
|
|
|
|
SidebarProvider,
|
|
|
|
|
SidebarTrigger,
|
2025-06-20 12:18:13 +00:00
|
|
|
|
} from "@/components/ui/sidebar";
|
2025-06-21 09:44:14 +00:00
|
|
|
|
import prisma from "@/lib/prisma";
|
2025-06-21 15:19:49 +00:00
|
|
|
|
import { auth } from "@/lib/auth";
|
2025-06-21 09:44:14 +00:00
|
|
|
|
import { redirect } from "next/navigation";
|
2025-06-21 15:19:49 +00:00
|
|
|
|
import { Separator } from "@/components/ui/separator";
|
|
|
|
|
import { AppSidebar } from "@/components/sidebar/app-sidebar";
|
|
|
|
|
import { AdminSidebar } from "@/components/sidebar/admin-sidebar";
|
|
|
|
|
import { DynamicBreadcrumb } from "@/components/dynamic-breadcrumb";
|
|
|
|
|
import { TeacherSidebar } from "@/components/sidebar/teacher-sidebar";
|
2025-06-17 09:05:15 +00:00
|
|
|
|
|
2025-06-20 12:18:13 +00:00
|
|
|
|
interface LayoutProps {
|
|
|
|
|
children: React.ReactNode;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-21 09:44:14 +00:00
|
|
|
|
interface WrongProblem {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
status: string;
|
|
|
|
|
url?: string;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-20 12:18:13 +00:00
|
|
|
|
export default async function Layout({ children }: LayoutProps) {
|
|
|
|
|
const session = await auth();
|
|
|
|
|
const user = session?.user;
|
|
|
|
|
if (!user) {
|
2025-06-21 09:44:14 +00:00
|
|
|
|
redirect("/sign-in");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取用户的完整信息(包括角色)
|
|
|
|
|
const fullUser = await prisma.user.findUnique({
|
|
|
|
|
where: { id: user.id },
|
2025-06-21 15:19:49 +00:00
|
|
|
|
select: { id: true, name: true, email: true, image: true, role: true },
|
2025-06-21 09:44:14 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!fullUser) {
|
|
|
|
|
redirect("/sign-in");
|
2025-06-20 12:18:13 +00:00
|
|
|
|
}
|
2025-06-21 09:44:14 +00:00
|
|
|
|
|
|
|
|
|
// 根据用户角色决定显示哪个侧边栏
|
|
|
|
|
const renderSidebar = () => {
|
|
|
|
|
switch (fullUser.role) {
|
|
|
|
|
case "ADMIN":
|
|
|
|
|
return <AdminSidebar user={user} />;
|
|
|
|
|
case "TEACHER":
|
|
|
|
|
return <TeacherSidebar user={user} />;
|
|
|
|
|
case "GUEST":
|
|
|
|
|
default:
|
|
|
|
|
// 学生(GUEST)需要查询错题数据
|
|
|
|
|
return <AppSidebar user={user} wrongProblems={[]} />;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 只有学生才需要查询错题数据
|
|
|
|
|
let wrongProblemsData: WrongProblem[] = [];
|
|
|
|
|
if (fullUser.role === "GUEST") {
|
|
|
|
|
// 查询未完成(未AC)题目的最新一次提交
|
|
|
|
|
const wrongProblems = await prisma.problem.findMany({
|
|
|
|
|
where: {
|
|
|
|
|
submissions: {
|
|
|
|
|
some: { userId: user.id },
|
|
|
|
|
},
|
|
|
|
|
NOT: {
|
|
|
|
|
submissions: {
|
|
|
|
|
some: { userId: user.id, status: "AC" },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
displayId: true,
|
|
|
|
|
localizations: {
|
|
|
|
|
where: { locale: "zh", type: "TITLE" },
|
|
|
|
|
select: { content: true },
|
|
|
|
|
},
|
|
|
|
|
submissions: {
|
|
|
|
|
where: { userId: user.id },
|
|
|
|
|
orderBy: { createdAt: "desc" },
|
|
|
|
|
take: 1,
|
|
|
|
|
select: {
|
|
|
|
|
status: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 组装传递给 AppSidebar 的数据格式
|
|
|
|
|
wrongProblemsData = wrongProblems.map((p) => ({
|
|
|
|
|
id: p.id,
|
|
|
|
|
name: p.localizations[0]?.content || `题目${p.displayId}`,
|
|
|
|
|
status: p.submissions[0]?.status || "-",
|
|
|
|
|
url: `/problems/${p.id}`,
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-17 09:05:15 +00:00
|
|
|
|
return (
|
|
|
|
|
<SidebarProvider>
|
2025-06-21 09:44:14 +00:00
|
|
|
|
{fullUser.role === "GUEST" ? (
|
|
|
|
|
<AppSidebar user={user} wrongProblems={wrongProblemsData} />
|
|
|
|
|
) : (
|
|
|
|
|
renderSidebar()
|
|
|
|
|
)}
|
2025-06-17 09:05:15 +00:00
|
|
|
|
<SidebarInset>
|
|
|
|
|
<header className="flex h-16 shrink-0 items-center gap-2">
|
|
|
|
|
<div className="flex items-center gap-2 px-4">
|
|
|
|
|
<SidebarTrigger className="-ml-1" />
|
|
|
|
|
<Separator orientation="vertical" className="mr-2 h-4" />
|
2025-06-21 09:44:14 +00:00
|
|
|
|
<DynamicBreadcrumb />
|
2025-06-17 09:05:15 +00:00
|
|
|
|
</div>
|
|
|
|
|
</header>
|
2025-06-20 12:18:13 +00:00
|
|
|
|
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">{children}</div>
|
2025-06-17 09:05:15 +00:00
|
|
|
|
</SidebarInset>
|
|
|
|
|
</SidebarProvider>
|
2025-06-20 12:18:13 +00:00
|
|
|
|
);
|
2025-06-17 09:05:15 +00:00
|
|
|
|
}
|