调整 AdminShell 组件的子组件顺序,提升代码可读性。更新 admin-breadcrumb 组件,简化导航标签翻译逻辑,确保多语言支持的一致性。重构 admin-language-switcher 组件,优化语言切换的用户体验,增强界面交互性。更新多语言配置,新增登录界面的副标题,提升用户体验。
89 lines
2.0 KiB
TypeScript
89 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import { useRouter } from "next/navigation";
|
|
import { useEffect, useState, type ReactNode } from "react";
|
|
|
|
import { AdminAuthCheckingScreen } from "@/components/admin/admin-auth-checking";
|
|
import { verifyStoredAdminSession } from "@/lib/admin-session-verify";
|
|
import { useAdminSessionStore } from "@/stores/admin-session";
|
|
import { readToken } from "@/stores/admin-token";
|
|
|
|
type ShellAuthGateProps = {
|
|
children: ReactNode;
|
|
};
|
|
|
|
type GateStatus = "pending" | "authed" | "guest";
|
|
|
|
function hasAdminToken(bearerToken: string | null): boolean {
|
|
const token = bearerToken ?? readToken();
|
|
return token != null && token.trim() !== "";
|
|
}
|
|
|
|
/**
|
|
* Shell 路由守卫:无 Token 或 `/auth/me` 校验失败时跳转登录页。
|
|
*/
|
|
export function ShellAuthGate({ children }: ShellAuthGateProps) {
|
|
const router = useRouter();
|
|
const bearerToken = useAdminSessionStore((s) => s.bearerToken);
|
|
const [status, setStatus] = useState<GateStatus>("pending");
|
|
|
|
const setShellAuthPending = useAdminSessionStore((s) => s.setShellAuthPending);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
setShellAuthPending(true);
|
|
|
|
async function run() {
|
|
if (!hasAdminToken(bearerToken)) {
|
|
if (!cancelled) {
|
|
setStatus("guest");
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!cancelled) {
|
|
setStatus("pending");
|
|
}
|
|
|
|
const ok = await verifyStoredAdminSession();
|
|
if (cancelled) {
|
|
return;
|
|
}
|
|
|
|
if (ok) {
|
|
setStatus("authed");
|
|
return;
|
|
}
|
|
|
|
setStatus("guest");
|
|
}
|
|
|
|
void run().finally(() => {
|
|
if (!cancelled) {
|
|
setShellAuthPending(false);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
setShellAuthPending(false);
|
|
};
|
|
}, [bearerToken, setShellAuthPending]);
|
|
|
|
useEffect(() => {
|
|
if (status === "guest") {
|
|
router.replace("/admin/login");
|
|
}
|
|
}, [status, router]);
|
|
|
|
if (status === "pending") {
|
|
return <AdminAuthCheckingScreen variant="shell" />;
|
|
}
|
|
|
|
if (status === "guest") {
|
|
return null;
|
|
}
|
|
|
|
return children;
|
|
}
|