From 8f90aaba0873279641b6e35968c2f03f40e2a0f0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 1 Feb 2026 15:13:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=BB=E5=B8=83=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E5=8A=9F=E8=83=BD=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 加载历史对话消息(从 API 获取) 2. 选中画布图片时自动添加到对话附件 3. 修复类型错误 Co-authored-by: Cursor --- components/canvas/CanvasChatPanel.tsx | 61 +++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index f9bb24f..5add067 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -104,6 +104,46 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF // Canvas store const addNode = useCanvasStore((state) => state.addNode); const nodes = useCanvasStore((state) => state.nodes); + const selectedNodeIds = useCanvasStore((state) => state.selectedNodeIds); + + // 获取纯 UUID(去掉 canvas- 前缀)用于 API 调用 + const rawChatId = chatId.startsWith('canvas-') + ? chatId.replace('canvas-', '') + : chatId; + + // 从 API 加载历史消息 + const { data: historyData, isLoading: isLoadingHistory } = useSWR<{ + messages: ChatMessage[]; + }>(rawChatId ? `/api/messages?chatId=${rawChatId}` : null, fetcher); + + // 获取选中的图片节点 + const selectedImageNodes = nodes.filter( + n => selectedNodeIds.includes(n.id) && n.type === 'image' && (n.data as any)?.src + ); + + // 当选中画布中的图片时,自动添加到附件 + useEffect(() => { + if (selectedImageNodes.length > 0) { + const newAttachments: Attachment[] = selectedImageNodes.map(node => { + const data = node.data as any; + return { + url: data.src, + name: data.prompt || '画布图片', + contentType: 'image/jpeg', + }; + }); + + // 只添加还没在附件中的图片 + setAttachments(prev => { + const existingUrls = new Set(prev.map(a => a.url)); + const toAdd = newAttachments.filter(a => !existingUrls.has(a.url)); + if (toAdd.length > 0) { + return [...prev, ...toAdd]; + } + return prev; + }); + } + }, [selectedImageNodes.length, selectedNodeIds]); // 获取模型列表 const { data: modelsData } = useSWR<{ @@ -145,6 +185,11 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF imageParamsRef.current = imageParams; }, [imageParams]); + // 合并 initialMessages 和历史消息 + const mergedInitialMessages = historyData?.messages?.length + ? historyData.messages + : initialMessages; + const { messages, setMessages, @@ -153,7 +198,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF stop, } = useChat({ id: chatId, - messages: initialMessages, + messages: mergedInitialMessages, experimental_throttle: 100, generateId: generateUUID, transport: new DefaultChatTransport({ @@ -217,6 +262,16 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF toast.error(error.message || "生成失败"); }, }); + + // 当历史消息加载完成后,更新消息列表 + const hasLoadedHistory = useRef(false); + useEffect(() => { + if (historyData?.messages?.length && !hasLoadedHistory.current) { + hasLoadedHistory.current = true; + setMessages(historyData.messages); + console.log('[CanvasChat] 已加载历史消息:', historyData.messages.length); + } + }, [historyData, setMessages]); // 监听消息变化,提取图片并添加到画布 const processedMessageIds = useRef>(new Set()); @@ -574,9 +629,9 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF )} > {/* 附件预览 */} - {message.attachments && message.attachments.length > 0 && ( + {(message as any).attachments && (message as any).attachments.length > 0 && (
- {message.attachments.map((att: any, i: number) => ( + {(message as any).attachments.map((att: any, i: number) => (