From 52867404f787cf0b1fc2fb0bbb3702df2805e2a1 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 2 Feb 2026 10:54:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=BB=E5=B8=83=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=B0=E5=AF=B9=E8=AF=9D=E6=A1=86=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E6=89=8B=E5=8A=A8=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在图片工具栏添加"添加到对话"按钮 - 移除选中图片时自动添加标签的逻辑 - 通过 canvas store 的 pendingChatAttachments 实现跨组件通信 - 用户点击按钮后才会将图片添加到对话框,避免标签越来越多 --- components/canvas/CanvasChatPanel.tsx | 25 ++++++++++++------------- components/canvas/nodes/ImageNode.tsx | 25 ++++++++++++++++++++++++- store/canvas/index.ts | 27 +++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 93aced713..d51ff2d8e 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -108,6 +108,8 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF const nodes = useCanvasStore((state) => state.nodes); const selectedNodeIds = useCanvasStore((state) => state.selectedNodeIds); const clearSelection = useCanvasStore((state) => state.clearSelection); + const pendingChatAttachments = useCanvasStore((state) => state.pendingChatAttachments); + const clearPendingChatAttachments = useCanvasStore((state) => state.clearPendingChatAttachments); // 获取纯 UUID(去掉 canvas- 前缀)用于 API 调用 const rawChatId = chatId.startsWith('canvas-') @@ -159,33 +161,30 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF } }, []); - // 当选中画布中的图片时,自动添加到附件并插入标签 + // 🆕 监听 pendingChatAttachments,当用户点击"添加到对话"按钮时添加标签 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', - }; - }); - + if (pendingChatAttachments.length > 0) { // 只添加还没在附件中的图片 setAttachments(prev => { const existingUrls = new Set(prev.map(a => a.url)); - const toAdd = newAttachments.filter(a => !existingUrls.has(a.url)); + const toAdd = pendingChatAttachments.filter(a => !existingUrls.has(a.url)); if (toAdd.length > 0) { // 插入图片标签到编辑器 toAdd.forEach((att, i) => { insertImageTagInEditor(att.url, att.name, prev.length + i); }); + // 聚焦到输入框 + setTimeout(() => { + (textareaRef.current as HTMLDivElement | null)?.focus(); + }, 0); return [...prev, ...toAdd]; } return prev; }); + // 清空待添加列表 + clearPendingChatAttachments(); } - }, [selectedImageNodes.length, selectedNodeIds, insertImageTagInEditor]); + }, [pendingChatAttachments, insertImageTagInEditor, clearPendingChatAttachments]); // 获取模型列表 const { data: modelsData } = useSWR<{ diff --git a/components/canvas/nodes/ImageNode.tsx b/components/canvas/nodes/ImageNode.tsx index 54666eede..6629d43c0 100644 --- a/components/canvas/nodes/ImageNode.tsx +++ b/components/canvas/nodes/ImageNode.tsx @@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect } from "react"; import { createPortal } from "react-dom"; -import { ImagePlus, Loader2, AlertCircle, MoreVertical, Scissors, Sparkles, Expand, Maximize2, Move3D, Layers, Download, Trash2, RefreshCw, Pencil } from "lucide-react"; +import { ImagePlus, Loader2, AlertCircle, MoreVertical, Scissors, Sparkles, Expand, Maximize2, Move3D, Layers, Download, Trash2, RefreshCw, Pencil, MessageSquarePlus } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -53,6 +53,7 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) { const updateNode = useCanvasStore((state) => state.updateNode); const deleteNode = useCanvasStore((state) => state.deleteNode); const addNode = useCanvasStore((state) => state.addNode); + const addPendingChatAttachment = useCanvasStore((state) => state.addPendingChatAttachment); // 获取工具栏位置 - 在渲染时直接计算 const getToolbarPosition = () => { @@ -572,6 +573,28 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) { }} onClick={(e) => e.stopPropagation()} > + {/* 🆕 添加到对话 */} + + + {/* 分隔线 */} +
+ {/* 放大/高清 */}