diff --git a/app/canvas/[id]/page.tsx b/app/canvas/[id]/page.tsx index ca5411f19..a047d4efc 100644 --- a/app/canvas/[id]/page.tsx +++ b/app/canvas/[id]/page.tsx @@ -10,6 +10,7 @@ import { ChevronDown, ChevronLeft, ChevronRight, + Trash2, Save, Undo2, Redo2, @@ -941,6 +942,7 @@ export default function CanvasEditorPage({ params }: PageProps) { const clearCanvas = useCanvasStore((state) => state.clearCanvas); const getCanvasState = useCanvasStore((state) => state.getCanvasState); const addNode = useCanvasStore((state) => state.addNode); + const deleteNode = useCanvasStore((state) => state.deleteNode); const addEdge = useCanvasStore((state) => state.addEdge); const selectNodes = useCanvasStore((state) => state.selectNodes); const updateNode = useCanvasStore((state) => state.updateNode); @@ -1187,6 +1189,11 @@ export default function CanvasEditorPage({ params }: PageProps) { : 296 : 0; const selectedWorkflowPanelLeft = isVideoMode ? videoModuleSidebarWidth + 28 : 16; + const handleDeleteSelectedWorkflowNode = useCallback(() => { + if (!selectedVideoWorkflowNode) return; + deleteNode(selectedVideoWorkflowNode.id); + toast.success(`已删除模块:${selectedVideoWorkflowDefinition?.label || "当前模块"}`); + }, [deleteNode, selectedVideoWorkflowDefinition?.label, selectedVideoWorkflowNode]); const workflowGraph = useMemo( () => createWorkflowGraphContext(nodes, edges), [edges, nodes] @@ -7941,6 +7948,17 @@ export default function CanvasEditorPage({ params }: PageProps) { )} ) : null} + + diff --git a/components/canvas/nodes/TextNode.tsx b/components/canvas/nodes/TextNode.tsx index 73eeeb7c2..e98166d6e 100644 --- a/components/canvas/nodes/TextNode.tsx +++ b/components/canvas/nodes/TextNode.tsx @@ -1,6 +1,7 @@ "use client"; import React, { useState, useRef, useEffect } from "react"; +import { Trash2 } from "lucide-react"; import { useCanvasStore } from "@/store/canvas"; import type { CanvasNode, TextNodeData } from "@/types/canvas"; import { cn } from "@/lib/utils"; @@ -17,6 +18,7 @@ export function TextNode({ node, isSelected }: TextNodeProps) { const textareaRef = useRef(null); const updateNode = useCanvasStore((state) => state.updateNode); + const deleteNode = useCanvasStore((state) => state.deleteNode); // 进入编辑模式时聚焦 useEffect(() => { @@ -119,12 +121,33 @@ export function TextNode({ node, isSelected }: TextNodeProps) { )} - {/* 编辑提示 */} - {!isEditing && isSelected && ( -
- 双击编辑 -
- )} + {!isEditing && isSelected ? ( + <> + + +
+ 双击编辑 +
+ + ) : null} ); } diff --git a/components/canvas/nodes/WorkflowNode.tsx b/components/canvas/nodes/WorkflowNode.tsx index 8fa6dc0a6..f8ed0eda5 100644 --- a/components/canvas/nodes/WorkflowNode.tsx +++ b/components/canvas/nodes/WorkflowNode.tsx @@ -8,8 +8,10 @@ import { LayoutPanelTop, ScanSearch, Sparkles, + Trash2, } from "lucide-react"; import { Badge } from "@/components/ui/badge"; +import { useCanvasStore } from "@/store/canvas"; import { cn } from "@/lib/utils"; import { getVideoWorkflowNodeDefinition, @@ -78,6 +80,7 @@ const STATUS_LABELS = { } as const; export function WorkflowNode({ node, isSelected }: WorkflowNodeProps) { + const deleteNode = useCanvasStore((state) => state.deleteNode); const data = node.data as WorkflowNodeData; const definition = getVideoWorkflowNodeDefinition(data.templateType); const metadata = (data.metadata || {}) as Record; @@ -183,9 +186,27 @@ export function WorkflowNode({ node, isSelected }: WorkflowNodeProps) {

- - {STATUS_LABELS[data.status] || STATUS_LABELS.pending} - +
+ {isSelected ? ( + + ) : null} + + {STATUS_LABELS[data.status] || STATUS_LABELS.pending} + +