From 2e26666c03b135abb84b6810ac67be4d8d660a60 Mon Sep 17 00:00:00 2001 From: ZLY Date: Thu, 30 Oct 2025 11:04:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(flowEditor):=20=E5=AE=9E=E7=8E=B0=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E8=BF=90=E8=A1=8C=E7=8A=B6=E6=80=81=E9=9A=94=E7=A6=BB?= =?UTF-8?q?=E4=B8=8E=E8=BF=90=E8=A1=8C=E6=97=A5=E5=BF=97=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 ideContainer 状态中增加 appRuntimeData 字段,用于按应用 ID 隔离存储运行状态 - 修改 FlowEditorMain 和 actionBar 组件,使用当前应用的独立运行状态控制界面交互 - 更新节点拖拽、连接、删除等操作的禁用逻辑,基于当前应用运行状态判断 - 在 logBar 中实现运行日志的分应用存储与展示功能 - 添加 addRuntimeLog 和 clearRuntimeLogs actions 用于管理各应用的运行日志- 优化 useFlowEditorState 和 useFlowCallbacks 钩子以支持新的状态结构 - 确保在应用启动时清空对应应用的历史运行日志 --- src/hooks/useFlowCallbacks.ts | 7 +- src/hooks/useFlowEditorState.ts | 13 ++-- src/pages/flowEditor/FlowEditorMain.tsx | 63 ++++++++++-------- src/pages/flowEditor/components/actionBar.tsx | 13 ++-- src/pages/ideContainer/logBar.tsx | 26 ++++++-- src/store/ideContainer.ts | 64 ++++++++++++++++++- 6 files changed, 142 insertions(+), 44 deletions(-) diff --git a/src/hooks/useFlowCallbacks.ts b/src/hooks/useFlowCallbacks.ts index f0bc3dd..3da3910 100644 --- a/src/hooks/useFlowCallbacks.ts +++ b/src/hooks/useFlowCallbacks.ts @@ -15,7 +15,7 @@ import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData'; import { useAlignmentGuidelines } from '@/hooks/useAlignmentGuidelines'; import LocalNode from '@/components/FlowEditor/node/localNode/LocalNode'; import LoopNode from '@/components/FlowEditor/node/loopNode/LoopNode'; -import { updateCanvasDataMap, resetNodeStatus, updateIsRunning, updateEventListOld } from '@/store/ideContainer'; +import { updateCanvasDataMap, resetNodeStatus, updateIsRunning, updateEventListOld, addRuntimeLog, clearRuntimeLogs } from '@/store/ideContainer'; import { validateAllNodes, showValidationErrors, @@ -1301,6 +1301,9 @@ export const useFlowCallbacks = ( animationProgress: 0 } }))); + + // 清空当前应用的运行日志 + dispatch(clearRuntimeLogs({ appId: currentAppData.id })); } }, [initialData?.appId]); @@ -1340,4 +1343,4 @@ export const useFlowCallbacks = ( handleRun }; }; -export default useFlowCallbacks; +export default useFlowCallbacks; \ No newline at end of file diff --git a/src/hooks/useFlowEditorState.ts b/src/hooks/useFlowEditorState.ts index bc28dc5..fe5df89 100644 --- a/src/hooks/useFlowEditorState.ts +++ b/src/hooks/useFlowEditorState.ts @@ -9,9 +9,14 @@ import { Dispatch } from 'redux'; export const useFlowEditorState = (initialData?: any) => { const [nodes, setNodes] = useState([]); const [edges, setEdges] = useState([]); - const { canvasDataMap, nodeStatusMap, isRunning } = useSelector((state: any) => state.ideContainer); + const { canvasDataMap, nodeStatusMap, isRunning, appRuntimeData, currentAppData } = useSelector((state: any) => state.ideContainer); const dispatch = useDispatch(); + // 获取当前应用的运行状态 + const currentAppIsRunning = currentAppData?.id && appRuntimeData[currentAppData.id] + ? appRuntimeData[currentAppData.id].isRunning + : false; + // 添加编辑弹窗相关状态 const [editingNode, setEditingNode] = useState(null); const [isEditModalOpen, setIsEditModalOpen] = useState(false); @@ -33,11 +38,11 @@ export const useFlowEditorState = (initialData?: any) => { data: { ...node.data, status: nodeStatusMap[node.id] || 'waiting', - isStatusVisible: isRunning // 只有在运行时才显示状态指示器 + isStatusVisible: currentAppIsRunning // 只有在运行时才显示状态指示器 } })) ); - }, [nodeStatusMap, isRunning]); + }, [nodeStatusMap, currentAppIsRunning]); const updateCanvasDataMapDebounced = useRef( debounce((dispatch: Dispatch, canvasDataMap: any, id: string, nodes: Node[], edges: Edge[]) => { @@ -65,7 +70,7 @@ export const useFlowEditorState = (initialData?: any) => { setEdgeForNodeAdd, positionForNodeAdd, setPositionForNodeAdd, - isRunning, + isRunning: currentAppIsRunning, // 使用当前应用的运行状态 historyInitialized, setHistoryInitialized, historyTimeoutRef, diff --git a/src/pages/flowEditor/FlowEditorMain.tsx b/src/pages/flowEditor/FlowEditorMain.tsx index 2573032..e1d3eb4 100644 --- a/src/pages/flowEditor/FlowEditorMain.tsx +++ b/src/pages/flowEditor/FlowEditorMain.tsx @@ -24,6 +24,7 @@ import ActionBar from './components/actionBar'; import { useAlignmentGuidelines } from '@/hooks/useAlignmentGuidelines'; import { useHistory } from './components/historyContext'; import { NodeTypes } from '@xyflow/react'; +import { useSelector } from 'react-redux'; const edgeTypes = { custom: CustomEdge @@ -137,6 +138,12 @@ const FlowEditorMain: React.FC = (props) => { const { getGuidelines, clearGuidelines, AlignmentGuides } = useAlignmentGuidelines(); const { undo, redo, canUndo, canRedo } = useHistory(); const reactFlowId = useMemo(() => new Date().getTime().toString(), []); + + // 从Redux store中获取当前应用的运行状态 + const { appRuntimeData, currentAppData } = useSelector((state: any) => state.ideContainer); + const currentAppIsRunning = currentAppData?.id && appRuntimeData[currentAppData.id] + ? appRuntimeData[currentAppData.id].isRunning + : false; // 监听键盘事件实现快捷键 useEffect(() => { @@ -178,17 +185,17 @@ const FlowEditorMain: React.FC = (props) => { onContextMenu={(e) => e.preventDefault()}> ({ ...node, draggable: !isRunning }))} // 运行时禁用节点拖拽 + nodes={nodes.map(node => ({ ...node, draggable: !currentAppIsRunning }))} // 运行时禁用节点拖拽 edges={edges} nodeTypes={nodeTypes} edgeTypes={edgeTypes} snapToGrid={true} snapGrid={[2, 2]} - nodesConnectable={!isRunning} // 运行时禁用节点连接 - nodesDraggable={!isRunning} // 运行时禁用节点拖拽 - elementsSelectable={!isRunning} // 运行时禁用元素选择 - connectOnClick={!isRunning} // 运行时禁用点击连接 - disableKeyboardA11y={isRunning} // 运行时禁用键盘交互 + nodesConnectable={!currentAppIsRunning} // 运行时禁用节点连接 + nodesDraggable={!currentAppIsRunning} // 运行时禁用节点拖拽 + elementsSelectable={!currentAppIsRunning} // 运行时禁用元素选择 + connectOnClick={!currentAppIsRunning} // 运行时禁用点击连接 + disableKeyboardA11y={currentAppIsRunning} // 运行时禁用键盘交互 onBeforeDelete={async ({ nodes }) => { // 检查是否有开始或结束节点 const hasStartOrEndNode = nodes.some(node => node.type === 'start' || node.type === 'end'); @@ -203,7 +210,7 @@ const FlowEditorMain: React.FC = (props) => { ); // 允许删除操作继续进行 - return !isRunning; // 运行时禁止删除节点 + return !currentAppIsRunning; // 运行时禁止删除节点 }} onNodesDelete={(deleted) => { // 检查是否有循环节点 @@ -262,21 +269,21 @@ const FlowEditorMain: React.FC = (props) => { setIsEditModalOpen(false); }} - onNodesChange={!isRunning ? onNodesChange : undefined} // 运行时禁用节点变更 - onEdgesChange={!isRunning ? onEdgesChange : undefined} // 运行时禁用边变更 - onConnect={!isRunning ? onConnect : undefined} // 运行时禁用连接 - onReconnect={!isRunning ? onReconnect : undefined} // 运行时禁用重新连接 - onDragOver={!isRunning ? onDragOver : undefined} // 运行时禁用拖拽 - onDrop={!isRunning ? onDrop : undefined} // 运行时禁用放置 - onNodeDrag={!isRunning ? onNodeDrag : undefined} // 运行时禁用节点拖拽 + onNodesChange={!currentAppIsRunning ? onNodesChange : undefined} // 运行时禁用节点变更 + onEdgesChange={!currentAppIsRunning ? onEdgesChange : undefined} // 运行时禁用边变更 + onConnect={!currentAppIsRunning ? onConnect : undefined} // 运行时禁用连接 + onReconnect={!currentAppIsRunning ? onReconnect : undefined} // 运行时禁用重新连接 + onDragOver={!currentAppIsRunning ? onDragOver : undefined} // 运行时禁用拖拽 + onDrop={!currentAppIsRunning ? onDrop : undefined} // 运行时禁用放置 + onNodeDrag={!currentAppIsRunning ? onNodeDrag : undefined} // 运行时禁用节点拖拽 connectionLineType={ConnectionLineType.SmoothStep} connectionLineComponent={CustomConnectionLine} - onNodeDragStop={!isRunning ? onNodeDragStop : undefined} // 运行时禁用节点拖拽停止 - onNodeContextMenu={!isRunning ? onNodeContextMenu : undefined} // 运行时禁用节点上下文菜单 - onNodeDoubleClick={!isRunning ? onNodeDoubleClick : undefined} // 运行时禁用节点双击 - onEdgeContextMenu={!isRunning ? onEdgeContextMenu : undefined} // 运行时禁用边上下文菜单 - onPaneClick={!isRunning ? onPaneClick : undefined} // 运行时禁用面板点击 - onPaneContextMenu={!isRunning ? onPaneContextMenu : undefined} // 运行时禁用面板上下文菜单 + onNodeDragStop={!currentAppIsRunning ? onNodeDragStop : undefined} // 运行时禁用节点拖拽停止 + onNodeContextMenu={!currentAppIsRunning ? onNodeContextMenu : undefined} // 运行时禁用节点上下文菜单 + onNodeDoubleClick={!currentAppIsRunning ? onNodeDoubleClick : undefined} // 运行时禁用节点双击 + onEdgeContextMenu={!currentAppIsRunning ? onEdgeContextMenu : undefined} // 运行时禁用边上下文菜单 + onPaneClick={!currentAppIsRunning ? onPaneClick : undefined} // 运行时禁用面板点击 + onPaneContextMenu={!currentAppIsRunning ? onPaneContextMenu : undefined} // 运行时禁用面板上下文菜单 onEdgeMouseEnter={(_event, edge) => { setEdges((eds) => eds.map(e => { if (e.id === edge.id) { @@ -294,8 +301,8 @@ const FlowEditorMain: React.FC = (props) => { })); }} fitView - selectionOnDrag={!isRunning} // 运行时禁用拖拽选择 - selectionMode={!isRunning ? SelectionMode.Partial : undefined} // 运行时禁用选择模式 + selectionOnDrag={!currentAppIsRunning} // 运行时禁用拖拽选择 + selectionMode={!currentAppIsRunning ? SelectionMode.Partial : undefined} // 运行时禁用选择模式 > @@ -307,14 +314,14 @@ const FlowEditorMain: React.FC = (props) => { canUndo={canUndo} canRedo={canRedo} onRun={handleRun} - isRunning={isRunning} + isRunning={currentAppIsRunning} > {/*节点右键上下文*/} - {!isRunning && menu && menu.type === 'node' && ( + {!currentAppIsRunning && menu && menu.type === 'node' && (
= (props) => { )} {/*边右键上下文*/} - {!isRunning && menu && menu.type === 'edge' && ( + {!currentAppIsRunning && menu && menu.type === 'edge' && (
= (props) => { )} {/*画布右键上下文*/} - {!isRunning && menu && menu.type === 'pane' && ( + {!currentAppIsRunning && menu && menu.type === 'pane' && (
= (props) => { {/*统一的添加节点菜单*/} - {!isRunning && (edgeForNodeAdd || positionForNodeAdd) && ( + {!currentAppIsRunning && (edgeForNodeAdd || positionForNodeAdd) && (
= ({ onRun, isRunning = false }) => { - const { logBarStatus } = useSelector((state) => state.ideContainer); + const { logBarStatus, appRuntimeData, currentAppData } = useSelector((state: any) => state.ideContainer); const dispatch = useDispatch(); + + // 获取当前应用的运行状态 + const currentAppIsRunning = currentAppData?.id && appRuntimeData[currentAppData.id] + ? appRuntimeData[currentAppData.id].isRunning + : false; const changeLogBarStatus = () => { dispatch(updateLogBarStatus(!logBarStatus)); }; const handleRun = () => { - onRun?.(!isRunning); + onRun?.(!currentAppIsRunning); }; return ( @@ -50,9 +55,9 @@ const ActionBar: React.FC = ({ icon={} onClick={() => handleRun()} style={{ padding: '0 8px', backgroundColor: '#fff' }} - status={isRunning ? 'danger' : undefined} + status={currentAppIsRunning ? 'danger' : undefined} > - {isRunning ? '停止' : '运行'} + {currentAppIsRunning ? '停止' : '运行'}