mirror of
https://github.com/massbug/judge4c.git
synced 2025-07-03 15:20:50 +00:00
feat(auth): add protected layout with role-based access control
This commit is contained in:
parent
0695dd2f61
commit
19fac9b3d6
@ -1,5 +1,4 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { ProblemEditLayout } from "@/features/admin/ui/layouts/problem-edit-layout";
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
@ -13,7 +12,7 @@ const Layout = async ({ children, params }: LayoutProps) => {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
return <ProblemEditLayout>{children}</ProblemEditLayout>;
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
BarChart3,
|
||||
Target,
|
||||
Activity,
|
||||
GraduationCapIcon,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
@ -197,21 +198,26 @@ export default async function DashboardPage() {
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
label: "管理员管理",
|
||||
href: "/dashboard/management",
|
||||
icon: Target,
|
||||
},
|
||||
{
|
||||
label: "用户管理",
|
||||
href: "/dashboard/usermanagement/guest",
|
||||
icon: Users,
|
||||
},
|
||||
{
|
||||
label: "教师管理",
|
||||
href: "/dashboard/usermanagement/teacher",
|
||||
icon: GraduationCapIcon,
|
||||
},
|
||||
{
|
||||
label: "题目管理",
|
||||
href: "/dashboard/usermanagement/problem",
|
||||
icon: BookOpen,
|
||||
},
|
||||
{
|
||||
label: "管理员设置",
|
||||
href: "/dashboard/management",
|
||||
icon: Target,
|
||||
},
|
||||
],
|
||||
};
|
||||
case "TEACHER":
|
||||
@ -240,7 +246,7 @@ export default async function DashboardPage() {
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
label: "学生管理",
|
||||
label: "用户管理",
|
||||
href: "/dashboard/usermanagement/guest",
|
||||
icon: Users,
|
||||
},
|
||||
@ -250,7 +256,7 @@ export default async function DashboardPage() {
|
||||
icon: BookOpen,
|
||||
},
|
||||
{
|
||||
label: "统计分析",
|
||||
label: "完成情况",
|
||||
href: "/dashboard/teacher/dashboard",
|
||||
icon: BarChart3,
|
||||
},
|
||||
@ -281,12 +287,12 @@ export default async function DashboardPage() {
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{ label: "开始做题", href: "/problemset", icon: BookOpen },
|
||||
{
|
||||
label: "我的进度",
|
||||
href: "/dashboard/student/dashboard",
|
||||
icon: TrendingUp,
|
||||
},
|
||||
{ label: "开始做题", href: "/problemset", icon: BookOpen },
|
||||
{ label: "个人设置", href: "/dashboard/management", icon: Target },
|
||||
],
|
||||
};
|
||||
@ -361,7 +367,7 @@ export default async function DashboardPage() {
|
||||
<CardDescription>常用功能快速访问</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
{config.actions.map((action, index) => (
|
||||
<Link key={index} href={action.href}>
|
||||
<Button variant="outline" className="w-full justify-start">
|
||||
|
15
src/app/(protected)/layout.tsx
Normal file
15
src/app/(protected)/layout.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { ProtectedLayout } from "@/features/dashboard/layouts/protected-layout";
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const Layout = ({ children }: LayoutProps) => {
|
||||
return (
|
||||
<ProtectedLayout roles={["ADMIN", "TEACHER", "GUEST"]}>
|
||||
{children}
|
||||
</ProtectedLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
@ -33,8 +33,8 @@ const adminData = {
|
||||
},
|
||||
],
|
||||
navSecondary: [
|
||||
{ title: "帮助", url: "/", icon: LifeBuoy },
|
||||
{ title: "反馈", url: siteConfig.url.repo.github, icon: Send },
|
||||
{ title: "帮助", url: `${siteConfig.url.repo.github}/issues`, icon: LifeBuoy },
|
||||
{ title: "反馈", url: `${siteConfig.url.repo.github}/pulls`, icon: Send },
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -16,24 +16,28 @@ import { NavMain } from "@/components/nav-main";
|
||||
import { NavUser } from "@/components/nav-user";
|
||||
import { NavProjects } from "@/components/nav-projects";
|
||||
import { NavSecondary } from "@/components/nav-secondary";
|
||||
import { Command, LifeBuoy, Send, SquareTerminal } from "lucide-react";
|
||||
import { Command, LifeBuoy, Send, Shield } from "lucide-react";
|
||||
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "页面",
|
||||
url: "#",
|
||||
icon: SquareTerminal,
|
||||
title: "管理面板",
|
||||
url: "/dashboard",
|
||||
icon: Shield,
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
title: "主页",
|
||||
title: "我的进度",
|
||||
url: "/dashboard/student/dashboard",
|
||||
},
|
||||
{
|
||||
title: "题目集",
|
||||
title: "开始做题",
|
||||
url: "/problemset",
|
||||
},
|
||||
{
|
||||
title: "个人设置",
|
||||
url: "/dashboard/management",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -71,12 +75,12 @@ const data = {
|
||||
navSecondary: [
|
||||
{
|
||||
title: "帮助",
|
||||
url: "/",
|
||||
url: `${siteConfig.url.repo.github}/issues`,
|
||||
icon: LifeBuoy,
|
||||
},
|
||||
{
|
||||
title: "反馈",
|
||||
url: siteConfig.url.repo.github,
|
||||
url: `${siteConfig.url.repo.github}/pulls`,
|
||||
icon: Send,
|
||||
},
|
||||
],
|
||||
|
@ -1,12 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Command,
|
||||
LifeBuoy,
|
||||
PieChart,
|
||||
Send,
|
||||
SquareTerminal,
|
||||
} from "lucide-react";
|
||||
import { Command, LifeBuoy, Send, Shield } from "lucide-react";
|
||||
import * as React from "react";
|
||||
import {
|
||||
Sidebar,
|
||||
@ -26,9 +20,9 @@ import { NavSecondary } from "@/components/nav-secondary";
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "教师管理",
|
||||
url: "#",
|
||||
icon: SquareTerminal,
|
||||
title: "管理面板",
|
||||
url: "/dashboard",
|
||||
icon: Shield,
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
@ -36,47 +30,25 @@ const data = {
|
||||
url: "/dashboard/usermanagement/guest",
|
||||
},
|
||||
{
|
||||
title: "题库管理",
|
||||
title: "题目管理",
|
||||
url: "/dashboard/usermanagement/problem",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "统计分析",
|
||||
url: "#",
|
||||
icon: PieChart,
|
||||
items: [
|
||||
{
|
||||
title: "完成情况",
|
||||
url: "/dashboard/teacher/dashboard",
|
||||
},
|
||||
// {
|
||||
// title: "错题统计",
|
||||
// url: "/dashboard/teacher/dashboard",
|
||||
// },
|
||||
],
|
||||
},
|
||||
// {
|
||||
// title: "设置",
|
||||
// url: "#",
|
||||
// icon: Settings2,
|
||||
// items: [
|
||||
// {
|
||||
// title: "语言",
|
||||
// url: "#",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
navSecondary: [
|
||||
{
|
||||
title: "帮助",
|
||||
url: "/",
|
||||
url: `${siteConfig.url.repo.github}/issues`,
|
||||
icon: LifeBuoy,
|
||||
},
|
||||
{
|
||||
title: "反馈",
|
||||
url: siteConfig.url.repo.github,
|
||||
url: `${siteConfig.url.repo.github}/pulls`,
|
||||
icon: Send,
|
||||
},
|
||||
],
|
||||
|
@ -25,7 +25,7 @@ export const ProtectedLayout = async ({
|
||||
});
|
||||
|
||||
if (!user || !roles.includes(user.role)) {
|
||||
redirect("unauthorized");
|
||||
redirect("/unauthorized");
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
@ -251,7 +251,7 @@ export function UserTable(props: UserTableProps) {
|
||||
if (isProblem) {
|
||||
// 如果是problem类型,跳转到编辑路由,使用displayId
|
||||
const problem = item as Problem;
|
||||
router.push(`/admin/problems/${problem.displayId}/edit`);
|
||||
router.push(`/dashboard/admin/problems/${problem.id}/edit`);
|
||||
} else {
|
||||
// 如果是用户类型,打开编辑弹窗
|
||||
setEditingUser(item);
|
||||
|
Loading…
Reference in New Issue
Block a user