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" && (
+ <>
+
+
+ 管理后台
+
+ >
+ )}