From 61b766d9393600c53cf25c7e2afa422356a39fd1 Mon Sep 17 00:00:00 2001 From: luorijun Date: Tue, 31 Mar 2026 11:59:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=9D=83=E9=99=90=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/auth.ts | 5 ++-- src/app/(root)/appbar.tsx | 55 ++++++++++++--------------------------- src/app/(root)/layout.tsx | 22 +++++++++++++--- src/app/(root)/scopes.tsx | 14 ++++++++++ src/app/login/page.tsx | 6 +---- src/models/user.ts | 6 ++--- src/proxy.ts | 1 + 7 files changed, 56 insertions(+), 53 deletions(-) create mode 100644 src/app/(root)/scopes.tsx diff --git a/src/actions/auth.ts b/src/actions/auth.ts index 62eefa4..0dabb64 100644 --- a/src/actions/auth.ts +++ b/src/actions/auth.ts @@ -1,7 +1,7 @@ "use server" import { cookies } from "next/headers" import type { ApiResponse } from "@/lib/api" -import type { User } from "@/models/user" +import type { Admin } from "@/models/admin" import { callByDevice, callByUser } from "./base" export type TokenResp = { @@ -79,7 +79,7 @@ export async function logout() { } export async function getProfile() { - return await callByUser("/api/auth/introspect") + return await callByUser("/api/auth/introspect") } export async function refreshAuth() { @@ -128,5 +128,6 @@ export async function refreshAuth() { return { access_token: nextAccessToken, refresh_token: nextRefreshToken, + scopes: data.scope?.split(" ") || [], } } diff --git a/src/app/(root)/appbar.tsx b/src/app/(root)/appbar.tsx index bcff5b2..0afcb10 100644 --- a/src/app/(root)/appbar.tsx +++ b/src/app/(root)/appbar.tsx @@ -14,13 +14,12 @@ import Image from "next/image" import Link from "next/link" import { usePathname, useRouter } from "next/navigation" import { useEffect, useRef, useState } from "react" -import { getProfile, logout } from "@/actions/auth" +import { logout } from "@/actions/auth" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" -import type { User } from "@/models/user" +import type { Admin } from "@/models/admin" -export default function Appbar() { - const [currentUser, setCurrentUser] = useState() +export default function Appbar(props: { admin: Admin }) { const router = useRouter() const [showDropdown, setShowDropdown] = useState(false) const [showNotifications, setShowNotifications] = useState(false) @@ -122,28 +121,6 @@ export default function Appbar() { } } - useEffect(() => { - async function fetchUserProfile() { - try { - const resp = await getProfile() - console.log(resp, "resp") - - if (resp.success) { - setCurrentUser(resp.data) - } else { - console.error("获取用户信息失败:", resp.message) - if (resp.status === 401) { - router.replace("/login") - } - } - } catch (error) { - console.error("获取用户信息时出错:", error) - } - } - - fetchUserProfile() - }, [router]) - return (
{/* 面包屑导航 */} @@ -259,10 +236,10 @@ export default function Appbar() { aria-label="用户菜单" >
- {currentUser ? ( - currentUser.avatar ? ( + {props.admin ? ( + props.admin.avatar ? ( 用户头像 - {currentUser.name.charAt(0).toUpperCase()} + {props.admin.name?.charAt(0).toUpperCase()} ) ) : ( @@ -290,12 +267,14 @@ export default function Appbar() { )}
- {currentUser && ( + {props.admin && (

- {currentUser.name} + {props.admin.name} +

+

+ {props.admin.username}

-

{currentUser.username}

)}
@@ -305,13 +284,13 @@ export default function Appbar() { {/* 用户下拉内容 */} {showDropdown && (
- {currentUser && ( + {props.admin && (

- {currentUser.name} + {props.admin.name}

-

{currentUser.name}

+

{props.admin.name}

)} diff --git a/src/app/(root)/layout.tsx b/src/app/(root)/layout.tsx index 238115d..3ed97f7 100644 --- a/src/app/(root)/layout.tsx +++ b/src/app/(root)/layout.tsx @@ -1,24 +1,38 @@ -import type { ReactNode } from "react" +import { type ReactNode, Suspense } from "react" +import { getProfile } from "@/actions/auth" import Appbar from "@/app/(root)/appbar" import Navigation from "@/app/(root)/navigation" +import SetScopes from "./scopes" export type RootLayoutProps = { children: ReactNode } -export default function RootLayout({ children }: RootLayoutProps) { +export default async function RootLayout({ children }: RootLayoutProps) { + return ( + + {children} + + ) +} + +async function Layout(props: { children: ReactNode }) { + const profile = await getProfile() + if (!profile.success) throw new Error("页面渲染失败:无法获取账号信息") return (
+ + {/* 侧边栏 */} {/* 主内容区 */}
{/* 顶部导航栏 */} - + {/* 内容区域 */} -
{children}
+
{props.children}
) diff --git a/src/app/(root)/scopes.tsx b/src/app/(root)/scopes.tsx new file mode 100644 index 0000000..921ec1d --- /dev/null +++ b/src/app/(root)/scopes.tsx @@ -0,0 +1,14 @@ +"use client" +import { useSetAtom } from "jotai" +import { scopesAtom } from "@/lib/stores/scopes" +import type { Admin } from "@/models/admin" + +export default function SetScopes(props: { + admin: Admin & { scopes: string[] } +}) { + const setScopes = useSetAtom(scopesAtom) + + console.log("用户权限", props.admin.scopes) + setScopes(props.admin.scopes) + return null +} diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index f9229e0..0eca39c 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,6 +1,5 @@ "use client" import { zodResolver } from "@hookform/resolvers/zod" -import { useSetAtom } from "jotai" import { useRouter } from "next/navigation" import { Controller, useForm } from "react-hook-form" import { toast } from "sonner" @@ -17,7 +16,6 @@ import { FieldLegend, } from "@/components/ui/field" import { Input } from "@/components/ui/input" -import { scopesAtom } from "@/lib/stores/scopes" const schema = z.object({ username: z.string().min(4).max(50), @@ -38,7 +36,6 @@ export default function LoginPage() { }) const router = useRouter() - const setScopes = useSetAtom(scopesAtom) const onSubmit = async (data: Schema) => { try { const resp = await login(data) @@ -47,9 +44,8 @@ export default function LoginPage() { } // 登录成功后跳转到首页 - console.log("用户权限列表", resp.data) - setScopes(resp.data) router.push("/") + router.refresh() } catch (e) { toast.error("登录失败", { description: e instanceof Error ? e.message : "未知错误", diff --git a/src/models/user.ts b/src/models/user.ts index 05b2b06..1e0ddae 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -1,3 +1,5 @@ +import type { Admin } from "./admin" + export type User = { id: number admin_id?: number @@ -21,7 +23,3 @@ export type User = { created_at: Date updated_at: Date } - -export type Admin = { - name: string -} diff --git a/src/proxy.ts b/src/proxy.ts index 9f5e62b..db17533 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -1,3 +1,4 @@ +import { useSetAtom } from "jotai" import { type NextRequest, NextResponse, type ProxyConfig } from "next/server" import { refreshAuth } from "@/actions/auth"