"use client"; import { AlertTriangle, ChevronDown, ExternalLink, LogOut, RefreshCw, UserRound, } from "lucide-react"; import { useRouter } from "next/navigation"; import type { User } from "next-auth"; import { signOut } from "next-auth/react"; import { useMemo, useState } from "react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { guestRegex } from "@/lib/constants"; import { cn } from "@/lib/utils"; type PascalEditorFrameProps = { fallbackSrc: string; isReady: boolean; selfHostedSrc: string; siteLogo?: null | string; siteLogoDark?: null | string; siteName?: null | string; src: string; sourceLabel: string; user?: null | User; }; export function PascalEditorFrame({ fallbackSrc, isReady, selfHostedSrc, siteLogo, siteLogoDark, siteName, src, sourceLabel, user, }: PascalEditorFrameProps) { const router = useRouter(); const [frameKey, setFrameKey] = useState(0); const [loaded, setLoaded] = useState(false); const resolvedSrc = useMemo(() => src || fallbackSrc, [fallbackSrc, src]); const resolvedSiteName = useMemo( () => String(siteName || "AI Chatbot").trim() || "AI Chatbot", [siteName] ); const displayLogo = useMemo(() => { const darkLogo = String(siteLogoDark || "").trim(); const lightLogo = String(siteLogo || "").trim(); return darkLogo || lightLogo; }, [siteLogo, siteLogoDark]); const userEmail = String(user?.email || "").trim(); const userLabel = String(user?.name || userEmail || "已登录用户").trim(); const isGuest = guestRegex.test(userEmail); const handleAuthAction = async () => { if (isGuest) { router.push("/login?callbackUrl=%2Fpascal-editor"); return; } try { await fetch("/api/auth/logout", { method: "POST" }); await signOut({ callbackUrl: "/login", redirect: false }); window.location.replace("/login"); } catch (error) { console.error("退出登录失败:", error); window.location.replace("/login"); } }; const header = (
{displayLogo ? ( {resolvedSiteName} ) : ( {Array.from(resolvedSiteName)[0] || "A"} )} {resolvedSiteName} 建筑编辑
{user ? (
{isGuest ? "访客用户" : userLabel}
{userEmail ? (
{userEmail}
) : null}
{ event.preventDefault(); void handleAuthAction(); }} > {isGuest ? "登录正式账号" : "退出登录"}
) : null}
); if (!isReady) { return (
{header}

Pascal Editor 尚未配置

当前页面已经切换为自托管模式。请启动本机 Pascal standalone 服务,或把构建产物放到 public/vendor/pascal-editor/index.html ,或设置 NEXT_PUBLIC_PASCAL_EDITOR_URL 指向自托管 Pascal 服务地址。

NEXT_PUBLIC_PASCAL_EDITOR_URL={selfHostedSrc}

默认本机服务:{selfHostedSrc};同源静态 bundle:{fallbackSrc}

); } return (
{header}
{!loaded && (
正在加载 {sourceLabel}
)}