fix(media,canvas): 对象存储参考素材优先 URL,并同步清理图片引用提示词 (#434)

* fix(media): 对象存储参考素材 - 协议支持 URL 时优先发送签名链接

开启对象存储后,支持 URL 的上游协议优先发送 OSS/COS/七牛/S3 签名链接;必须传字节的协议仍走 Base64 或 multipart。本地资源回退字节,签发失败直接报错,不自动重发生成。

* fix(canvas): 图片引用清理 - 取消引用时同步移除提示词引用
This commit is contained in:
Rou authored and GitHub committed 2026-09-07 22:28:19 +08:00
1 parent 469627c792
commit 21b83eca2e
9 files changed
+339 -41

No files matched your search

@@ -6,6 +6,7 @@ import { nanoid } from "nanoid";
import { NODE_DEFAULT_SIZE } from "@/constant/canvas";
import { FOLDER_COLLAPSED_HEIGHT, FOLDER_COLLAPSED_WIDTH, FRAME_HEADER_HEIGHT, getFrameChildIds, getFrameChildren, isFrameNode } from "@/lib/canvas/canvas-frame";
import { alignCanvasNodes, layoutCanvasAuto, layoutCanvasFlow, layoutCanvasNodes, nextCanvasVersionLabel, type CanvasAlignmentMode } from "@/lib/canvas/canvas-layout";
import { applyCanvasConnectionPromptSync } from "@/lib/canvas/canvas-resource-references";
import { createCanvasNode, isHiddenBatchChild, removeCanvasNodes } from "@/lib/canvas/canvas-project-domain";
import { isolateCopiedNodeMetadata, nextCopiedNodeTitle } from "@/lib/canvas/canvas-node-copy";
import { CanvasNodeType, type CanvasConnection, type CanvasFolderStyle, type CanvasFolderTheme, type CanvasNodeData, type CanvasNodeMetadata, type CanvasNodeTypeId, type ContextMenuState, type Position } from "@/types/canvas";
@@ -325,20 +326,28 @@ export function useCanvasNodeOperations({
const deleteNodes = useCallback((ids: Set<string>) => {
if (!ids.size) return;
const result = removeCanvasNodes(nodesRef.current, ids);
const removedNodes = nodesRef.current.filter((node) => result.removedIds.has(node.id));
const nextConnections = connectionsRef.current.filter((connection) => !result.removedIds.has(connection.fromNodeId) && !result.removedIds.has(connection.toNodeId));
commitNodes(result.nodes);
const previousNodes = nodesRef.current;
const previousConnections = connectionsRef.current;
const result = removeCanvasNodes(previousNodes, ids);
const removedNodes = previousNodes.filter((node) => result.removedIds.has(node.id));
const nextConnections = previousConnections.filter((connection) => !result.removedIds.has(connection.fromNodeId) && !result.removedIds.has(connection.toNodeId));
const nextNodes = applyCanvasConnectionPromptSync(previousNodes, previousConnections, result.nodes, nextConnections);
commitNodes(nextNodes);
commitConnections(nextConnections);
selectNodes(new Set());
onNodesDeleted(result.removedIds, result.nodes, removedNodes);
onNodesDeleted(result.removedIds, nextNodes, removedNodes);
}, [commitConnections, commitNodes, connectionsRef, nodesRef, onNodesDeleted, selectNodes]);
const deleteConnection = useCallback((connectionId: string) => {
commitConnections(connectionsRef.current.filter((connection) => connection.id !== connectionId));
const previousNodes = nodesRef.current;
const previousConnections = connectionsRef.current;
const nextConnections = previousConnections.filter((item) => item.id !== connectionId);
const nextNodes = applyCanvasConnectionPromptSync(previousNodes, previousConnections, previousNodes, nextConnections);
if (nextNodes !== previousNodes) commitNodes(nextNodes);
commitConnections(nextConnections);
setSelectedConnectionId((current) => current === connectionId ? null : current);
setContextMenu((current) => current?.type === "connection" && current.connectionId === connectionId ? null : current);
}, [commitConnections, connectionsRef, setContextMenu, setSelectedConnectionId]);
}, [commitConnections, commitNodes, connectionsRef, nodesRef, setContextMenu, setSelectedConnectionId]);
const duplicateNode = useCallback((nodeId: string, duplicateMode: "variant" | "copy" = "variant") => {
const source = nodesRef.current.find((node) => node.id === nodeId);