feat: 画布图片添加到对话框改为手动触发
- 在图片工具栏添加"添加到对话"按钮 - 移除选中图片时自动添加标签的逻辑 - 通过 canvas store 的 pendingChatAttachments 实现跨组件通信 - 用户点击按钮后才会将图片添加到对话框,避免标签越来越多
This commit is contained in:
parent
ba99ad212e
commit
52867404f7
@ -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<{
|
||||
|
||||
@ -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()}
|
||||
>
|
||||
{/* 🆕 添加到对话 */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-blue-50 text-blue-600 hover:text-blue-700"
|
||||
onClick={() => {
|
||||
addPendingChatAttachment({
|
||||
url: data.src!,
|
||||
name: data.prompt || '画布图片',
|
||||
contentType: 'image/jpeg',
|
||||
});
|
||||
toast.success('已添加到对话框');
|
||||
}}
|
||||
title="添加到对话框"
|
||||
>
|
||||
<MessageSquarePlus className="h-4 w-4" />
|
||||
<span>对话</span>
|
||||
</Button>
|
||||
|
||||
{/* 分隔线 */}
|
||||
<div className="h-5 w-px bg-gray-200 mx-1" />
|
||||
|
||||
{/* 放大/高清 */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
|
||||
@ -22,6 +22,13 @@ const defaultViewport: Viewport = {
|
||||
zoom: 1,
|
||||
};
|
||||
|
||||
// 待添加到对话框的图片附件
|
||||
interface PendingChatAttachment {
|
||||
url: string;
|
||||
name: string;
|
||||
contentType: string;
|
||||
}
|
||||
|
||||
// Store 状态接口
|
||||
interface CanvasStore {
|
||||
// 项目信息
|
||||
@ -43,6 +50,9 @@ interface CanvasStore {
|
||||
isPanelOpen: boolean;
|
||||
isGenerating: boolean;
|
||||
|
||||
// 🆕 待添加到对话框的图片(用于从画布添加图片到对话)
|
||||
pendingChatAttachments: PendingChatAttachment[];
|
||||
|
||||
// 项目操作
|
||||
setProject: (id: string | null, title?: string) => void;
|
||||
setProjectTitle: (title: string) => void;
|
||||
@ -96,6 +106,10 @@ interface CanvasStore {
|
||||
getNode: (id: string) => CanvasNode | undefined;
|
||||
getSelectedNodes: () => CanvasNode[];
|
||||
getNodesByType: (type: NodeType) => CanvasNode[];
|
||||
|
||||
// 🆕 对话框附件操作
|
||||
addPendingChatAttachment: (attachment: PendingChatAttachment) => void;
|
||||
clearPendingChatAttachments: () => void;
|
||||
}
|
||||
|
||||
export const useCanvasStore = create<CanvasStore>()(
|
||||
@ -114,6 +128,7 @@ export const useCanvasStore = create<CanvasStore>()(
|
||||
historyIndex: -1,
|
||||
isPanelOpen: true,
|
||||
isGenerating: false,
|
||||
pendingChatAttachments: [], // 🆕 待添加到对话框的图片
|
||||
|
||||
// 项目操作
|
||||
setProject: (id, title) => set((state) => {
|
||||
@ -369,6 +384,18 @@ export const useCanvasStore = create<CanvasStore>()(
|
||||
},
|
||||
|
||||
getNodesByType: (type) => get().nodes.filter(n => n.type === type),
|
||||
|
||||
// 🆕 对话框附件操作
|
||||
addPendingChatAttachment: (attachment) => set((state) => {
|
||||
// 避免重复添加
|
||||
if (!state.pendingChatAttachments.some(a => a.url === attachment.url)) {
|
||||
state.pendingChatAttachments.push(attachment);
|
||||
}
|
||||
}),
|
||||
|
||||
clearPendingChatAttachments: () => set((state) => {
|
||||
state.pendingChatAttachments = [];
|
||||
}),
|
||||
})),
|
||||
{
|
||||
name: 'canvas-storage',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user