From 4c52702b416392474327d52cbdd38475d3c3bf19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=AC=91=E7=9A=84=E6=AF=9B=E6=AF=9B=E8=99=AB?= <315515767@qq.com> Date: Fri, 7 Aug 2026 18:46:23 +0800 Subject: [PATCH] =?UTF-8?q?refactor(canvas):=20=E5=88=86=E9=95=9C=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E8=8A=82=E7=82=B9=20-=20=E6=8C=89=E6=96=B9=E6=A1=88?= =?UTF-8?q?=20A=20=E4=BF=A1=E6=81=AF=E5=88=86=E5=B1=82=E9=87=8D=E6=9E=84?= =?UTF-8?q?=EF=BC=88=E5=A4=B4=E9=83=A8=E7=98=A6=E8=BA=AB=20+=204=20?= =?UTF-8?q?=E6=AD=A5=E8=BF=B7=E4=BD=A0=E6=B5=81=E7=A8=8B=E6=9D=A1=EF=BC=89?= =?UTF-8?q?=20(#171)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(canvas): 分镜脚本节点 - 新增表格/卡片视图切换与镜头卡片流 * fix(canvas): 分镜卡片 - 缩略图尺寸改用标准间距类 * fix(canvas): 分镜脚本节点 - 头部视图切换 Segmented 补齐事件隔离 * refactor(canvas): 分镜脚本节点 - 按方案 A 信息分层重构,头部瘦身为全屏编辑+更多菜单并启用 4 步迷你流程条 * fix(canvas): 分镜脚本节点 - 迷你流程条改为步骤水平分布,连接线拉伸填充整行宽度 * fix(canvas): 分镜脚本节点 - 迷你流程条改为水平居中分布,连接线限宽不拉伸 --------- Co-authored-by: zhaoyue --- .../components/canvas/canvas-script-node.tsx | 194 ++++++++---------- web/src/pages/canvas/project.tsx | 5 +- 2 files changed, 85 insertions(+), 114 deletions(-) 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: