diff --git a/src/app/(admin)/admin/page.tsx b/src/app/(admin)/admin/page.tsx new file mode 100644 index 0000000..5817558 --- /dev/null +++ b/src/app/(admin)/admin/page.tsx @@ -0,0 +1,113 @@ +import { redirect } from "next/navigation"; + +import { prisma } from "@/lib/prisma"; +import { getCurrentUser } from "@/lib/session"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +async function getStats() { + const [userCount, clientCount] = await Promise.all([ + prisma.user.count(), + prisma.client.count(), + ]); + + const clients = await prisma.client.findMany({ + include: { + user: { + select: { + username: true, + email: true, + }, + }, + }, + orderBy: { + createdAt: "desc", + }, + take: 10, + }); + + return { + userCount, + clientCount, + recentClients: clients, + }; +} + +export default async function AdminPage() { + const user = await getCurrentUser(); + if (!user || user.role !== "ADMIN") { + redirect("/dashboard"); + } + + const stats = await getStats(); + + return ( +
+
+ + + 用户统计 + 系统中的总用户数 + + +

{stats.userCount}

+
+
+ + + + 应用统计 + 系统中的总应用数 + + +

{stats.clientCount}

+
+
+
+ + + + 最近创建的应用 + 显示最近创建的 10 个应用 + + + + + + 应用名称 + 创建者 + 创建时间 + Client ID + + + + {stats.recentClients.map((client) => ( + + {client.name} + {client.user.username} + + {new Date(client.createdAt).toLocaleString()} + + {client.clientId} + + ))} + +
+
+
+
+ ); +} diff --git a/src/app/(admin)/layout.tsx b/src/app/(admin)/layout.tsx new file mode 100644 index 0000000..58a73df --- /dev/null +++ b/src/app/(admin)/layout.tsx @@ -0,0 +1,26 @@ +import { redirect } from "next/navigation"; + +import { getCurrentUser } from "@/lib/session"; +import { DashboardHeader } from "@/components/layout/dashboard-header"; + +export default async function AdminLayout({ + children, +}: { + children: React.ReactNode; +}) { + const user = await getCurrentUser(); + if (!user) { + redirect("/sign-in"); + } + + if (user.role !== "ADMIN") { + redirect("/dashboard"); + } + + return ( +
+ + {children} +
+ ); +} diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx index eb31bdd..8947e23 100644 --- a/src/app/(auth)/layout.tsx +++ b/src/app/(auth)/layout.tsx @@ -10,7 +10,6 @@ export default async function AuthLayout({ const user = await getCurrentUser(); if (user) { - if (user.role === "ADMIN") redirect("/admin"); redirect("/dashboard"); } diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index a73f8d6..e3ce9a1 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -9,7 +9,9 @@ export default async function DashboardLayout({ children: React.ReactNode; }) { const user = await getCurrentUser(); - if (!user) redirect("/sign-in"); + if (!user) { + redirect("/sign-in"); + } return (
diff --git a/src/components/auth/user-authorize.tsx b/src/components/auth/user-authorize.tsx index 10125c6..7539573 100644 --- a/src/components/auth/user-authorize.tsx +++ b/src/components/auth/user-authorize.tsx @@ -1,7 +1,6 @@ "use client"; import { useCallback, useEffect, useState } from "react"; -import { useRouter } from "next/navigation"; import { signIn } from "@/actions/user-authorize"; import { useSession } from "next-auth/react"; @@ -17,7 +16,6 @@ export function UserAuthorize({ const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const { update } = useSession(); - const router = useRouter(); const signInCallback = useCallback(async () => { if (isLoading) { @@ -25,22 +23,18 @@ export function UserAuthorize({ } setIsLoading(true); try { - await signIn({ ...data, redirectTo: "/dashboard" }); + const result = await signIn({ ...data, redirectTo: "/dashboard" }); // 更新 session await update(); - router.push("/dashboard"); setIsLoading(false); } catch (error) { setError(error); setIsLoading(false); } - }, [data, isLoading, update, router]); + }, [data, isLoading, update]); useEffect(() => { - const timer = setTimeout(signInCallback, 5); - return () => { - clearTimeout(timer); - }; + signInCallback(); }, [signInCallback]); return ( @@ -48,7 +42,7 @@ export function UserAuthorize({ {error ? (

登录异常,授权失败!

) : ( -

账号信息验证中,准备跳转中,请稍等...

+

账号信息验证中,请稍等...

)} ); diff --git a/src/components/layout/dashboard-header.tsx b/src/components/layout/dashboard-header.tsx index 221ab41..4f30976 100644 --- a/src/components/layout/dashboard-header.tsx +++ b/src/components/layout/dashboard-header.tsx @@ -11,6 +11,7 @@ export function DashboardHeader() { if (pathname === "/dashboard") return "控制台"; if (pathname === "/dashboard/clients") return "应用管理"; if (pathname.includes("/dashboard/clients/")) return "应用编辑"; + if (pathname === "/admin") return "管理后台"; return ""; }; diff --git a/src/components/layout/nav-bar.tsx b/src/components/layout/nav-bar.tsx index 8e21dbb..a31e61a 100644 --- a/src/components/layout/nav-bar.tsx +++ b/src/components/layout/nav-bar.tsx @@ -89,6 +89,14 @@ export function NavBar() { 应用管理 + {user.role === "ADMIN" && ( + <> + + + 管理后台 + + + )}