import { lazy, Suspense, useEffect, useRef, useState } from "react"; import { App } from "antd"; import { AppModal } from "@/components/ui/product/app-modal"; import { Check, Maximize2, X } from "lucide-react"; import type { CanvasDrawingEditorHandle } from "@/components/canvas/canvas-drawing-editor-types"; import { drawingEngineForNode, drawingEngineLabel, isDrawingEngineAvailable } from "@/lib/canvas/canvas-drawing-engine"; import { loadCanvasDrawing, saveCanvasDrawing, type CanvasDrawingSnapshot } from "@/lib/canvas/canvas-drawing-storage"; import { useActiveTheme } from "@/stores/canvas/use-canvas-theme-store"; import { useUserStore } from "@/stores/use-user-store"; import type { CanvasNodeData } from "@/types/canvas"; const CanvasDrawingTldrawEditor = lazy(() => import("@/components/canvas/canvas-drawing-tldraw-editor").then((module) => ({ default: module.CanvasDrawingTldrawEditor }))); const CanvasDrawingExcalidrawEditor = lazy(() => import("@/components/canvas/canvas-drawing-excalidraw-editor").then((module) => ({ default: module.CanvasDrawingExcalidrawEditor }))); type CanvasDrawingEditorModalProps = { open: boolean; projectId: string; node: CanvasNodeData | null; onClose: () => void; onSaved: (nodeId: string, summary: Pick) => void; }; export function CanvasDrawingEditorModal({ open, projectId, node, onClose, onSaved }: CanvasDrawingEditorModalProps) { const { message } = App.useApp(); const colorScheme = useActiveTheme(); const tldrawLicenseKey = useUserStore((state) => state.drawingEngine.tldrawLicenseKey); const engine = drawingEngineForNode(node); const currentRef = useRef(null); const editorRef = useRef(null); const [snapshot, setSnapshot] = useState(null); const [loaded, setLoaded] = useState(false); const [ready, setReady] = useState(false); const [saving, setSaving] = useState(false); const [loadError, setLoadError] = useState(""); useEffect(() => { if (!open || !node?.metadata?.drawingId) return; let cancelled = false; setLoaded(false); setReady(false); setLoadError(""); setSnapshot(null); currentRef.current = null; void loadCanvasDrawing(projectId, node.metadata.drawingId).then((saved) => { if (cancelled) return; if (saved && saved.engine !== engine) throw new Error(`绘图节点标记为 ${drawingEngineLabel(engine)},但文档属于 ${drawingEngineLabel(saved.engine)}`); currentRef.current = saved; setSnapshot(saved?.snapshot || null); setLoaded(true); }).catch((error) => { if (cancelled) return; const detail = error instanceof Error ? error.message : "本地绘图文档无法读取"; setLoadError(detail); message.error(`绘图加载失败:${detail}`); }); return () => { cancelled = true; }; }, [engine, message, node?.metadata?.drawingId, open, projectId]); const handleSave = async () => { if (!node?.metadata?.drawingId || !ready || !editorRef.current) return false; setSaving(true); try { const draft = await editorRef.current.createSave(); const saved = await saveCanvasDrawing(projectId, node.metadata.drawingId, engine, draft.snapshot, currentRef.current, draft.preview, draft.render); currentRef.current = saved; onSaved(node.id, saved); return true; } catch (error) { message.error(error instanceof Error ? `绘图保存失败:${error.message}` : "绘图保存失败"); return false; } finally { setSaving(false); } }; const handleClose = async () => { if (!loadError && ready && !(await handleSave())) return; onClose(); }; const unavailable = !isDrawingEngineAvailable(engine, tldrawLicenseKey); return ( void handleClose()} footer={null} closable={false} destroyOnHidden width="100vw" centered className="canvas-drawing-editor-modal">
{node?.title || "绘图"}{drawingEngineLabel(engine)} · {ready ? "已加载" : "正在加载"}
{unavailable ? : loadError ? : loaded ? ( }> {engine === "excalidraw" ? setReady(true)} /> : setReady(true)} />} ) : }
); } function EditorState({ title, detail }: { title: string; detail?: string }) { return
{title}
{detail ?
{detail}
: null}
; }