"use client"; import Link from "next/link"; import { useEffect, useState } from "react"; import { Menu } from "lucide-react"; import { usePathname, useRouter } from "next/navigation"; import { HeaderActions } from "@/components/header-actions"; import { Button } from "@/components/ui/button"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Sheet, SheetClose, SheetContent, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"; import webConfig from "@/constants/common-env"; import { fetchThirdPartyApps, type ThirdPartyAppsSettings } from "@/lib/api"; import { getValidatedAuthSession } from "@/lib/auth-session"; import { cn } from "@/lib/utils"; import { clearStoredAuthSession, type StoredAuthSession } from "@/store/auth"; const adminNavItems = [ { href: "/image", label: "生图" }, { href: "/accounts", label: "号池管理" }, { href: "/image-manager", label: "图片管理" }, { href: "/logs", label: "日志管理" }, { href: "/debug", label: "调试" }, { href: "/settings", label: "设置" }, ]; const userNavItems = [{ href: "/image", label: "画图" }]; function buildThirdPartyHref(appUrl: string, baseUrl: string, apiKey: string) { const url = appUrl.trim(); try { const target = new URL(url); target.searchParams.set("apiKey", apiKey); target.searchParams.set("baseUrl", baseUrl); return target.toString(); } catch { return `${url}${url.includes("?") ? "&" : "?"}apiKey=${encodeURIComponent(apiKey)}&baseUrl=${encodeURIComponent(baseUrl)}`; } } export function TopNav() { const pathname = usePathname(); const router = useRouter(); const [session, setSession] = useState(undefined); const [thirdPartyApps, setThirdPartyApps] = useState(null); const [isCanvasDialogOpen, setIsCanvasDialogOpen] = useState(false); useEffect(() => { let active = true; const load = async () => { if (pathname === "/login") { if (!active) { return; } setSession(null); return; } const storedSession = await getValidatedAuthSession(); if (!active) { return; } setSession(storedSession); }; void load(); return () => { active = false; }; }, [pathname]); useEffect(() => { if (!session) { setThirdPartyApps(null); return; } let active = true; const load = async () => { try { const data = await fetchThirdPartyApps(); if (active) { setThirdPartyApps(data.third_party_apps); } } catch { if (active) { setThirdPartyApps(null); } } }; const reload = () => void load(); void load(); window.addEventListener("third-party-apps-updated", reload); return () => { active = false; window.removeEventListener("third-party-apps-updated", reload); }; }, [session]); const handleLogout = async () => { await clearStoredAuthSession(); router.replace("/login"); }; if (pathname === "/login" || session === undefined || !session) { return null; } const navItems = session.role === "admin" ? adminNavItems : userNavItems; const roleLabel = session.role === "admin" ? "管理员" : "普通用户"; const displayName = session.name.trim() || roleLabel; const baseUrl = webConfig.apiUrl.replace(/\/$/, "") || window.location.origin; const canvas = thirdPartyApps?.infinite_canvas; const canvasHref = canvas?.enabled && canvas.url.trim() ? buildThirdPartyHref(canvas.url, baseUrl, session.key) : ""; const canvasDisplayHref = canvasHref ? decodeURIComponent(canvasHref) : ""; const handleCanvasOpen = () => { if (!canvasHref) { return; } setIsCanvasDialogOpen(true); }; const confirmCanvasOpen = () => { if (canvasHref) { window.open(canvasHref, "_blank", "noopener,noreferrer"); } setIsCanvasDialogOpen(false); }; return ( <>
打开导航 chatgpt2api {roleLabel} · {displayName} chatgpt2api
{roleLabel} · {displayName}
跳转到三方应用 该入口仅供个人测试使用,建议自行本机部署后再长期使用。跳转地址会默认带上本项目地址和当前密钥,用于自动填充连接信息;如果不放心,可以取消后手动前往应用并自行输入。
完整跳转地址
{canvasDisplayHref}
); }