diff --git a/web/src/components/canvas/canvas-script-node.tsx b/web/src/components/canvas/canvas-script-node.tsx index d496885f7..a7bec814e 100644 --- a/web/src/components/canvas/canvas-script-node.tsx +++ b/web/src/components/canvas/canvas-script-node.tsx @@ -1,7 +1,8 @@ -import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type PointerEvent as ReactPointerEvent, type ReactNode } from "react"; -import { Button, Checkbox, Input, InputNumber, Modal, Popover, Segmented, Select, Table, Tooltip } from "antd"; +import { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type PointerEvent as ReactPointerEvent, type ReactNode } from "react"; +import { Button, Checkbox, Dropdown, Input, InputNumber, Modal, Segmented, Select, Table, Tooltip } from "antd"; +import type { MenuProps } from "antd"; import type { ColumnsType } from "antd/es/table"; -import { ChevronDown, ChevronUp, Clapperboard, Copy, Expand, Film, Grid3X3, Image as ImageIcon, ListTree, Merge, Minus, Plus, RefreshCw, Send, Square, Trash2, Video, X } from "lucide-react"; +import { ChevronDown, ChevronUp, Clapperboard, Copy, Expand, Film, Grid3X3, Image as ImageIcon, ListTree, Merge, Minus, MoreHorizontal, Plus, RefreshCw, Send, Square, Trash2, Video, X } from "lucide-react"; import { CanvasResourceMentionTextarea } from "@/components/canvas/canvas-resource-mention-textarea"; import { ModelPicker } from "@/components/model-picker"; @@ -68,8 +69,8 @@ export function CanvasScriptNodeContent({ node, batch, pipeline, scale, mentionR onOpen: () => void; onCreateImageNodes: () => void; onCreateVideoNodes: () => void; - onGenerateImages: () => void; - onGenerateVideos: () => void; + onGenerateImages: (rowIds: string[]) => void; + onGenerateVideos: (rowIds: string[]) => void; onVideoInputModeChange: (mode: StoryboardVideoInputMode) => void; onMergeVideos: () => void; onCreateActionBoards: () => void; @@ -113,6 +114,34 @@ export function CanvasScriptNodeContent({ node, batch, pipeline, scale, mentionR const taskFeedback = node.metadata?.status === "loading" ? `${node.metadata.taskStage || "正在创建任务"}${typeof node.metadata.taskProgress === "number" ? ` · ${node.metadata.taskProgress}%` : ""}` : node.metadata?.status === "error" ? generationErrorMessage(node.metadata.errorDetails) : ""; + const [batchDetailsOpen, setBatchDetailsOpen] = useState(false); + const pipelineDisabled = !rows.length || node.metadata?.status === "loading" || hasActiveBatchItems; + const missingImages = Math.max(0, pipeline.images.total - pipeline.images.created); + const missingVideos = Math.max(0, pipeline.videos.total - pipeline.videos.created); + const canMerge = pipeline.successfulVideoNodeIds.length >= 2 && pipeline.final.success === 0; + const allRowIds = pipeline.rows.map((item) => item.row.id); + const moreMenuItems: MenuProps["items"] = [ + { key: "generate-images", icon: , label: "生成未完成分镜图", disabled: pipelineDisabled || pipeline.images.incomplete === 0, onClick: () => onGenerateImages(allRowIds) }, + { key: "generate-videos", icon: