feat(canvas): 批量创作表 - 支持全局提示词、参考图编排与连线同步

This commit is contained in:
ddCat committed 2026-09-18 13:03:35 +08:00
1 parent a8770c89b0
commit c994566ffe
13 files changed
+714 -116

No files matched your search

+41 -1
View File
@@ -68,6 +68,7 @@ import { CanvasZoomControls } from "@/components/canvas/canvas-zoom-controls";
import { CanvasShareModal } from "@/components/canvas/canvas-share-modal";
import { CanvasScriptEditor, CanvasScriptNodeContent } from "@/components/canvas/canvas-script-node";
import { CanvasBatchTableNodeContent } from "@/components/canvas/canvas-batch-table-node";
import { promoteLegacyBatchTableSize } from "@/lib/canvas/canvas-batch-table";
import { STORYBOARD_HEADER_HEIGHT, STORYBOARD_ROW_HEIGHT, storyboardMinNodeHeight, storyboardTableHeight } from "@/lib/canvas/canvas-storyboard-layout";
import { CanvasDirectorNodePanel } from "@/components/canvas/director/canvas-director-node-panel";
import { CanvasVersionCompareModal } from "@/components/canvas/canvas-version-compare-modal";
@@ -742,6 +743,7 @@ function InfiniteCanvasPage() {
pasteAssistantImage,
pasteSystemClipboard,
replaceNodeMedia,
createFileNode,
startUploadStatus,
uploadModalOpen,
uploadTimelineMedia,
@@ -1886,7 +1888,7 @@ function InfiniteCanvasPage() {
handleGenerateNode,
});
const { addReferenceColumn: addBatchReferenceColumn, addRow: addBatchRow, fillRowsFromConnections, generateRows: generateBatchRows, patchTable: patchBatchTable, removeRow: removeBatchRow, updateRow: updateBatchRow } = useCanvasBatchTable({
const { addReferenceColumn: addBatchReferenceColumn, addRow: addBatchRow, fillRowsFromConnections, generateRows: generateBatchRows, moveReferenceCell: moveBatchReferenceCell, patchTable: patchBatchTable, removeReferenceColumn: removeBatchReferenceColumn, removeRow: removeBatchRow, reorderReferenceColumns: reorderBatchReferenceColumns, syncRowsFromConnections, updateRow: updateBatchRow } = useCanvasBatchTable({
nodesRef,
connectionsRef,
setNodes,
@@ -1895,6 +1897,22 @@ function InfiniteCanvasPage() {
enqueueGenerationBatch,
});
useEffect(() => {
if (!projectLoaded) return;
setNodes((current) => {
let changed = false;
const next = current.map((node) => {
const promoted = promoteLegacyBatchTableSize(node);
if (promoted !== node) changed = true;
return promoted;
});
return changed ? next : current;
});
nodesRef.current.filter((node) => node.type === CanvasNodeType.BatchTable).forEach((node) => {
syncRowsFromConnections(node.id, true);
});
}, [connections, projectLoaded, setNodes, syncRowsFromConnections]);
const { addScriptRow, createAndGenerateScriptVideos, createScriptActionBoards, createScriptImageNodes, createScriptVideoNodes, generateScriptImages, generateScriptRows, generateScriptVideos, removeScriptRow, replaceScriptRows, updateScriptRow } =
useCanvasStoryboard({
projectId,
@@ -2105,6 +2123,26 @@ function InfiniteCanvasPage() {
onGenerate={(rowIds) => void generateBatchRows(contentNode.id, rowIds)}
onRetryItem={(batchId, itemId) => retryFailedBatchItems(contentNode.id, batchId, itemId)}
onAddReferenceColumn={() => addBatchReferenceColumn(contentNode.id)}
onRemoveReferenceColumn={() => removeBatchReferenceColumn(contentNode.id)}
onFocusOutput={(nodeId) => focusCanvasImageNode(nodeId)}
onReorderReferenceColumns={(fromColumnId, toColumnId) => reorderBatchReferenceColumns(contentNode.id, fromColumnId, toColumnId)}
onMoveReferenceCell={(sourceRowId, sourceColumnIndex, targetRowId, targetColumnIndex) => moveBatchReferenceCell(contentNode.id, sourceRowId, sourceColumnIndex, targetRowId, targetColumnIndex)}
onUploadReference={(rowId, columnIndex, file) => {
const row = contentNode.metadata?.batchTable?.rows.find((item) => item.id === rowId);
const existingId = row?.inputNodeIds[columnIndex];
if (existingId) {
void replaceNodeMedia(existingId, file);
return;
}
void createFileNode(file, { x: contentNode.position.x - 180, y: contentNode.position.y + columnIndex * 90 }).then((insertedId) => {
if (!insertedId) return;
const currentRow = nodesRef.current.find((item) => item.id === contentNode.id)?.metadata?.batchTable?.rows.find((item) => item.id === rowId);
const ids = [...(currentRow?.inputNodeIds || [])];
while (ids.length <= columnIndex) ids.push("");
ids[columnIndex] = insertedId;
updateBatchRow(contentNode.id, rowId, { inputNodeIds: ids });
});
}}
onConnectStart={(event, handleId) => handleConnectStart(event, contentNode.id, "target", handleId)}
onConnectDrop={(event, handleId) => handleConnectDrop(event, contentNode.id, handleId)}
/>
@@ -2189,6 +2227,7 @@ function InfiniteCanvasPage() {
createScriptVideoNodes,
currentProject?.directorScenes,
fillRowsFromConnections,
focusCanvasImageNode,
generateBatchRows,
generateScriptImages,
generateScriptRows,
@@ -2203,6 +2242,7 @@ function InfiniteCanvasPage() {
openDirectorWorkbench,
openStoryInput,
patchBatchTable,
removeBatchReferenceColumn,
removeBatchRow,
removeScriptRow,
retryFailedBatchItems,