"use client"; import { useParams } from "next/navigation"; import { useCallback, useEffect, useRef, useState, type MouseEvent as ReactMouseEvent, } from "react"; import MindmapCanvas from "@/components/MindmapCanvas"; import ChatPanel from "@/components/ChatPanel"; import { getMindmap } from "@/lib/api"; import type { Mindmap } from "@/types/mindmap"; type TriggerRequest = { id: number; content: string; }; const MIN_CHAT_PANEL_WIDTH = 320; const DEFAULT_CHAT_PANEL_WIDTH = 420; const MAX_CHAT_PANEL_WIDTH_RATIO = 0.55; export default function MindmapDetailPage() { const params = useParams<{ id: string }>(); const uniqueId = params?.id ?? ""; const containerRef = useRef(null); const [mindmap, setMindmap] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [showChat, setShowChat] = useState(false); const [isResizingChatPanel, setIsResizingChatPanel] = useState(false); const [chatPanelWidth, setChatPanelWidth] = useState(DEFAULT_CHAT_PANEL_WIDTH); const [triggerRequest, setTriggerRequest] = useState(); const clampChatPanelWidth = useCallback((nextWidth: number) => { const containerWidth = containerRef.current?.clientWidth ?? (typeof window === "undefined" ? DEFAULT_CHAT_PANEL_WIDTH : window.innerWidth); const maxWidth = Math.max( MIN_CHAT_PANEL_WIDTH, Math.floor(containerWidth * MAX_CHAT_PANEL_WIDTH_RATIO), ); return Math.min(Math.max(nextWidth, MIN_CHAT_PANEL_WIDTH), maxWidth); }, []); useEffect(() => { async function loadPageData() { if (!uniqueId) { setLoading(false); setError("缺少脑图 ID"); return; } try { setLoading(true); setError(""); const mindmapData = await getMindmap(uniqueId); setMindmap(mindmapData); } catch (pageError) { const message = pageError instanceof Error ? pageError.message : "加载脑图失败"; setError(message); } finally { setLoading(false); } } void loadPageData(); }, [uniqueId]); const handleNodeChat = useCallback( (nodeLabel: string) => { setShowChat(true); setChatPanelWidth((currentWidth) => clampChatPanelWidth(currentWidth)); setTriggerRequest({ id: Date.now() + Math.floor(Math.random() * 1000), content: `帮我解释一下 ${nodeLabel}`, }); }, [clampChatPanelWidth], ); const handleCloseChat = useCallback(() => { setIsResizingChatPanel(false); setShowChat(false); setTriggerRequest(undefined); }, []); const handleResizeStart = useCallback( (event: ReactMouseEvent) => { event.preventDefault(); setChatPanelWidth((currentWidth) => clampChatPanelWidth(currentWidth)); setIsResizingChatPanel(true); }, [clampChatPanelWidth], ); useEffect(() => { if (!showChat) { setIsResizingChatPanel(false); return; } const handleWindowResize = () => { setChatPanelWidth((currentWidth) => clampChatPanelWidth(currentWidth)); }; handleWindowResize(); window.addEventListener("resize", handleWindowResize); return () => window.removeEventListener("resize", handleWindowResize); }, [clampChatPanelWidth, showChat]); useEffect(() => { if (!showChat || !isResizingChatPanel) { return; } const handleMouseMove = (event: MouseEvent) => { if (!containerRef.current) { return; } const bounds = containerRef.current.getBoundingClientRect(); const nextWidth = bounds.right - event.clientX; setChatPanelWidth(clampChatPanelWidth(nextWidth)); }; const stopResizing = () => { setIsResizingChatPanel(false); }; const { style } = document.body; const previousCursor = style.cursor; const previousUserSelect = style.userSelect; style.cursor = "col-resize"; style.userSelect = "none"; window.addEventListener("mousemove", handleMouseMove); window.addEventListener("mouseup", stopResizing); window.addEventListener("blur", stopResizing); return () => { style.cursor = previousCursor; style.userSelect = previousUserSelect; window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mouseup", stopResizing); window.removeEventListener("blur", stopResizing); }; }, [clampChatPanelWidth, isResizingChatPanel, showChat]); if (loading) { return (
正在加载思维导图...
); } if (error || !mindmap) { return (

{error || "未找到对应脑图"}

); } return (
{showChat && ( <>
)}
); }