import type { AdminOverviewResponse } from "@dada/shared-contracts"; import { useCallback, useEffect, useState, type ReactNode } from "react"; import "./admin-shell.css"; interface AdminSession { admin: { role: "super_admin"; status: "active"; user_id: string }; audience: "admin"; authenticated: true; expires_at: string; } interface AdminProtectedRouteProps { children: ReactNode; currentPath: string; title: string; } const adminNavigation = [ { href: "/admin", label: "总览", marker: "01" }, { href: "/admin/users", label: "用户与点数", marker: "02" }, { href: "/admin/invites", label: "邀请码", marker: "03" }, { href: "/admin/models", label: "模型", marker: "04" }, { href: "/admin/assets", label: "素材", marker: "05" }, { href: "/admin/preview", label: "内部预览", marker: "06" }, { href: "/admin/generations", label: "生成记录", marker: "07" }, { href: "/admin/services-storage", label: "服务与存储", marker: "08" }, { href: "/admin/audit", label: "审计", marker: "09" }, ] as const; function redirectToAdminLogin() { window.location.replace("/admin/login"); } export function AdminProtectedRoute({ children, currentPath, title }: AdminProtectedRouteProps) { const [session, setSession] = useState(); const [failed, setFailed] = useState(false); const [revision, setRevision] = useState(0); useEffect(() => { const controller = new AbortController(); setFailed(false); void fetch("/api/v1/admin-auth/session", { credentials: "same-origin", signal: controller.signal }) .then(async (response) => { if (response.status === 401) { redirectToAdminLogin(); return; } if (!response.ok) throw new Error("admin_session_unavailable"); const body = await response.json() as AdminSession; if (body.audience !== "admin" || body.admin.role !== "super_admin" || body.admin.status !== "active") { redirectToAdminLogin(); return; } setSession(body); }) .catch((error: unknown) => { if (!(error instanceof DOMException && error.name === "AbortError")) setFailed(true); }); return () => controller.abort(); }, [revision]); if (!session) { return (
{failed ? (
管理员会话暂时无法确认
) :

正在确认管理员会话

}
); } return (
跳到主要内容

{title}