feat(assets&canvas): 实现素材回收站机制、自动定时清理策略与过期时间提示,增加画布创建与变更历史时间线

This commit is contained in:
Danborad committed 2026-09-01 14:51:07 +08:00
1 parent dca252434b
commit 867a18a948
17 files changed
+1411 -321

No files matched your search

+39 -28
View File
@@ -122,8 +122,11 @@ export function useCanvasRenderModel({
return [...frames, ...regular];
}, [dragPreview, nodes, renderBounds, renderHiddenNodeIds, selectedNodeIds]);
const imageAssets = useMemo(() => assets.filter((asset): asset is ImageAsset => asset.kind === "image"), [assets]);
const canvasImageNodes = useMemo(() => nodes.filter((node) => node.type === CanvasNodeType.Image && Boolean(node.metadata?.content) && !collapsedBatchChildIds.has(node.id) && !(node.parentId && nodeById.get(node.parentId)?.metadata?.frame?.collapsed)), [collapsedBatchChildIds, nodeById, nodes]);
const imageAssets = useMemo(() => assets.filter((asset): asset is ImageAsset => asset.kind === "image" && asset.status !== "archived"), [assets]);
const canvasImageNodes = useMemo(
() => nodes.filter((node) => node.type === CanvasNodeType.Image && Boolean(node.metadata?.content) && !collapsedBatchChildIds.has(node.id) && !(node.parentId && nodeById.get(node.parentId)?.metadata?.frame?.collapsed)),
[collapsedBatchChildIds, nodeById, nodes],
);
const semanticNodesRef = useRef(nodes);
const semanticNodes = useMemo(() => {
const previous = semanticNodesRef.current;
@@ -164,13 +167,17 @@ export function useCanvasRenderModel({
const bottom = Math.max(...selectedNodes.map((node) => node.position.y + node.height));
return { left, top, width: right - left, height: bottom - top, count: selectedNodes.length };
}, [nodes, renderHiddenNodeIds, selectedNodeIds]);
const selectedVideoNodes = useMemo(() => nodes
.filter((node) => selectedNodeIds.has(node.id) && node.type === CanvasNodeType.Video && Boolean(node.metadata?.content) && !renderHiddenNodeIds.has(node.id))
.sort((a, b) => {
const shotA = a.metadata?.shotIndex ?? Number.MAX_SAFE_INTEGER;
const shotB = b.metadata?.shotIndex ?? Number.MAX_SAFE_INTEGER;
return shotA - shotB || a.position.y - b.position.y || a.position.x - b.position.x;
}), [nodes, renderHiddenNodeIds, selectedNodeIds]);
const selectedVideoNodes = useMemo(
() =>
nodes
.filter((node) => selectedNodeIds.has(node.id) && node.type === CanvasNodeType.Video && Boolean(node.metadata?.content) && !renderHiddenNodeIds.has(node.id))
.sort((a, b) => {
const shotA = a.metadata?.shotIndex ?? Number.MAX_SAFE_INTEGER;
const shotB = b.metadata?.shotIndex ?? Number.MAX_SAFE_INTEGER;
return shotA - shotB || a.position.y - b.position.y || a.position.x - b.position.x;
}),
[nodes, renderHiddenNodeIds, selectedNodeIds],
);
const batchChildCountById = useMemo(() => {
const map = new Map<string, number>();
nodes.forEach((node) => {
@@ -216,25 +223,29 @@ export function useCanvasRenderModel({
});
return { nodeIds, connectionIds };
}, [activeNodeId, connections]);
const displayConnections = useMemo(() => connections.flatMap((connection) => {
if (collapsedBatchChildIds.has(connection.fromNodeId) || collapsedBatchChildIds.has(connection.toNodeId)) return [];
const fromNode = nodeById.get(connection.fromNodeId);
const toNode = nodeById.get(connection.toNodeId);
if (!fromNode || !toNode) return [];
const fromParent = fromNode.parentId ? nodeById.get(fromNode.parentId) : null;
const toParent = toNode.parentId ? nodeById.get(toNode.parentId) : null;
const displayFrom = fromParent && isFrameNode(fromParent) && fromParent.metadata?.frame?.collapsed ? fromParent : fromNode;
const displayTo = toParent && isFrameNode(toParent) && toParent.metadata?.frame?.collapsed ? toParent : toNode;
if (displayFrom.id === displayTo.id) return [];
const from = dragPreview?.nodeIds.has(displayFrom.id) ? { ...displayFrom, position: { x: displayFrom.position.x + dragPreview.x, y: displayFrom.position.y + dragPreview.y } } : displayFrom;
const to = dragPreview?.nodeIds.has(displayTo.id) ? { ...displayTo, position: { x: displayTo.position.x + dragPreview.x, y: displayTo.position.y + dragPreview.y } } : displayTo;
const connectionLeft = Math.min(from.position.x, to.position.x);
const connectionTop = Math.min(from.position.y, to.position.y);
const connectionRight = Math.max(from.position.x + from.width, to.position.x + to.width);
const connectionBottom = Math.max(from.position.y + from.height, to.position.y + to.height);
if (connectionRight <= renderBounds.left || connectionLeft >= renderBounds.right || connectionBottom <= renderBounds.top || connectionTop >= renderBounds.bottom) return [];
return [{ connection, from, to }];
}), [collapsedBatchChildIds, connections, dragPreview, nodeById, renderBounds]);
const displayConnections = useMemo(
() =>
connections.flatMap((connection) => {
if (collapsedBatchChildIds.has(connection.fromNodeId) || collapsedBatchChildIds.has(connection.toNodeId)) return [];
const fromNode = nodeById.get(connection.fromNodeId);
const toNode = nodeById.get(connection.toNodeId);
if (!fromNode || !toNode) return [];
const fromParent = fromNode.parentId ? nodeById.get(fromNode.parentId) : null;
const toParent = toNode.parentId ? nodeById.get(toNode.parentId) : null;
const displayFrom = fromParent && isFrameNode(fromParent) && fromParent.metadata?.frame?.collapsed ? fromParent : fromNode;
const displayTo = toParent && isFrameNode(toParent) && toParent.metadata?.frame?.collapsed ? toParent : toNode;
if (displayFrom.id === displayTo.id) return [];
const from = dragPreview?.nodeIds.has(displayFrom.id) ? { ...displayFrom, position: { x: displayFrom.position.x + dragPreview.x, y: displayFrom.position.y + dragPreview.y } } : displayFrom;
const to = dragPreview?.nodeIds.has(displayTo.id) ? { ...displayTo, position: { x: displayTo.position.x + dragPreview.x, y: displayTo.position.y + dragPreview.y } } : displayTo;
const connectionLeft = Math.min(from.position.x, to.position.x);
const connectionTop = Math.min(from.position.y, to.position.y);
const connectionRight = Math.max(from.position.x + from.width, to.position.x + to.width);
const connectionBottom = Math.max(from.position.y + from.height, to.position.y + to.height);
if (connectionRight <= renderBounds.left || connectionLeft >= renderBounds.right || connectionBottom <= renderBounds.top || connectionTop >= renderBounds.bottom) return [];
return [{ connection, from, to }];
}),
[collapsedBatchChildIds, connections, dragPreview, nodeById, renderBounds],
);
const configInputsById = useMemo(() => {
const map = new Map<string, NodeGenerationInput[]>();