diff --git a/src/api/event.ts b/src/api/event.ts index a84104e..c6bd89d 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -38,9 +38,10 @@ export function queryEventItem(name: string) { export function queryEventItemBySceneIdOld(sceneId: string) { return axios.get(`${urlPrefix}/event/${sceneId}/get`); } + // 事件管理-使用场景ID查询事件新 -export function queryEventItemBySceneId(sceneId: string) { - return axios.get(`${urlPrefix}/event/${sceneId}/getTopic`); +export function queryEventItemBySceneId(data: { sceneId: string, nodeId?: string, appId?: string }) { + return axios.post(`${urlPrefix}/event/getTopic`, data); } // 事件管理-获取工程下可用的topic diff --git a/src/components/FlowEditor/nodeEditors/LocalNodeEditor.tsx b/src/components/FlowEditor/nodeEditors/LocalNodeEditor.tsx index 347ae2b..2e55682 100644 --- a/src/components/FlowEditor/nodeEditors/LocalNodeEditor.tsx +++ b/src/components/FlowEditor/nodeEditors/LocalNodeEditor.tsx @@ -41,9 +41,9 @@ const LocalNodeEditor: React.FC = ({ case 'CYCLE': // 周期 return ; case 'EVENTLISTENE': // 事件接收 - return ; + return ; case 'EVENTSEND': // 事件发送 - return ; + return ; case 'JSON2STR': // JSON转字符串 return ; case 'STR2JSON': // 字符串转JSON diff --git a/src/components/FlowEditor/nodeEditors/components/EventListenEditor.tsx b/src/components/FlowEditor/nodeEditors/components/EventListenEditor.tsx index 01a9a20..2c8ce11 100644 --- a/src/components/FlowEditor/nodeEditors/components/EventListenEditor.tsx +++ b/src/components/FlowEditor/nodeEditors/components/EventListenEditor.tsx @@ -7,12 +7,17 @@ import { useDispatch, useSelector } from 'react-redux'; import { queryEventItemBySceneId } from '@/api/event'; import ParamsTable from '@/components/FlowEditor/nodeEditors/components/ParamsTable'; -const EventListenEditor: React.FC = ({ nodeData, updateNodeData }) => { +const EventListenEditor: React.FC = ({ node, nodeData, updateNodeData }) => { const [eventList, setEventList] = useState(); const { currentAppData } = useSelector(state => state.ideContainer); const getEventList = async () => { - const res = await queryEventItemBySceneId(currentAppData.sceneId); + const params = { + nodeId: node.id, + appId: currentAppData.id, + sceneId: currentAppData.sceneId + }; + const res = await queryEventItemBySceneId(params); setEventList(res.data); }; diff --git a/src/components/FlowEditor/nodeEditors/components/EventSelect.tsx b/src/components/FlowEditor/nodeEditors/components/EventSelect.tsx index 749721f..8db875b 100644 --- a/src/components/FlowEditor/nodeEditors/components/EventSelect.tsx +++ b/src/components/FlowEditor/nodeEditors/components/EventSelect.tsx @@ -27,25 +27,29 @@ const EventSelect: React.FC = ({ nodeData, eventList, type, on const [form] = Form.useForm(); const [showModal, setShowModal] = useState(false); const [currentEvent, setCurrentEvent] = useState(null); - const { currentAppData } = useSelector(state => state.ideContainer); + const { currentAppData, eventListOld } = useSelector(state => state.ideContainer); useEffect(() => { if (nodeData && eventList && eventList.length > 0) { setOptions(eventList.filter(item => !item.topic.includes('**empty**'))); try { + // 数据是JSON字符串,标识是接口回来的 const customDef = JSON.parse(nodeData.component?.customDef); // 先判断topic是不是**empty**,是就不设置currentevent - if (customDef.topic && customDef.topic.includes('**empty**')) { - setCurrentEvent(null); - } + if (customDef.topic && customDef.topic.includes('**empty**')) setCurrentEvent(null); else { - setCurrentEvent(eventList.find(item => customDef.topic === item.topic)); + if (!customDef.eventId) { + setCurrentEvent(eventList.find(item => customDef.topic === item.topic)); + } + else { + const currentItem = eventListOld.find(item => customDef.eventId === item.eventId); + setCurrentEvent(currentItem.topic); + } } } catch (e) { + // 数据是普通对象标识是当前操作数据 // 先判断topic是不是**empty**,是就不设置currentevent - if (nodeData.component?.customDef?.topic && nodeData.component?.customDef?.topic.includes('**empty**')) { - setCurrentEvent(null); - } + if (nodeData.component?.customDef?.topic && nodeData.component?.customDef?.topic.includes('**empty**')) setCurrentEvent(null); else { setCurrentEvent(eventList.find(item => nodeData.component?.customDef.topic === item.topic)); } @@ -80,10 +84,11 @@ const EventSelect: React.FC = ({ nodeData, eventList, type, on }; const handelSelect = (e) => { + console.log('e:', e); const data = { type: typeMap[type], customDef: { - eventId: null, + eventId: e.eventId, name: e.name, topic: e.topic } @@ -123,8 +128,8 @@ const EventSelect: React.FC = ({ nodeData, eventList, type, on )} dropdownMenuStyle={{ maxHeight: 300 }} > - {options.map((option) => ( - ))} diff --git a/src/components/FlowEditor/nodeEditors/components/EventSendEditor.tsx b/src/components/FlowEditor/nodeEditors/components/EventSendEditor.tsx index 55c06a2..e595ff6 100644 --- a/src/components/FlowEditor/nodeEditors/components/EventSendEditor.tsx +++ b/src/components/FlowEditor/nodeEditors/components/EventSendEditor.tsx @@ -12,7 +12,7 @@ const EventSendEditor: React.FC = ({ nodeData, updateNodeData } const { currentAppData } = useSelector(state => state.ideContainer); const getEventList = async () => { - const res = await queryEventItemBySceneId(currentAppData.sceneId); + const res = await queryEventItemBySceneId({sceneId:currentAppData.sceneId}); setEventList(res.data); }; diff --git a/src/components/FlowEditor/nodeEditors/components/ParamsTable.tsx b/src/components/FlowEditor/nodeEditors/components/ParamsTable.tsx index 8e6c57b..2fd852e 100644 --- a/src/components/FlowEditor/nodeEditors/components/ParamsTable.tsx +++ b/src/components/FlowEditor/nodeEditors/components/ParamsTable.tsx @@ -34,17 +34,17 @@ const ParamsTable: React.FC = ({ }, [initialData]); const dataTypeOptions = [ - { label: '字符串', value: 'string' }, - { label: '数字', value: 'number' }, - { label: '布尔值', value: 'boolean' }, - { label: '数组', value: 'array' }, - { label: '对象', value: 'object' } + { label: '字符串', value: 'STRING' }, + { label: '数字', value: 'INTEGER' }, + { label: '布尔值', value: 'BOOLEAN' }, + { label: '数组', value: 'ARRAY' }, + { label: '对象', value: 'OBJECT' } ]; const arrayTypeOptions = [ - { label: '字符串数组', value: 'string' }, - { label: '数字数组', value: 'number' }, - { label: '布尔数组', value: 'boolean' } + { label: '字符串数组', value: 'STRING' }, + { label: '数字数组', value: 'INTEGER' }, + { label: '布尔数组', value: 'BOOLEAN' } ]; const columns = [ diff --git a/src/components/FlowEditor/nodeEditors/validators/nodeValidators.ts b/src/components/FlowEditor/nodeEditors/validators/nodeValidators.ts index 03fb8b8..82a62f7 100644 --- a/src/components/FlowEditor/nodeEditors/validators/nodeValidators.ts +++ b/src/components/FlowEditor/nodeEditors/validators/nodeValidators.ts @@ -313,6 +313,15 @@ const validateCycleNode = (nodeData: any): string[] => { const validateBasicParams = (nodeData: any): string[] => { const errors: string[] = []; + // 检查BASIC节点是否有关联的组件实例 + if (nodeData.type === 'BASIC') { + // 检查节点是否具有component属性和customDef属性 + console.log('nodeData:', nodeData); + if (!nodeData.component || !nodeData.component.compIdentifier) { + errors.push('基础节点缺少组件实例配置'); + } + } + // 检查输入参数的完整性 if (nodeData.parameters?.dataIns) { nodeData.parameters.dataIns.forEach((param: any, index: number) => { diff --git a/src/hooks/useFlowCallbacks.ts b/src/hooks/useFlowCallbacks.ts index e08d838..90b0121 100644 --- a/src/hooks/useFlowCallbacks.ts +++ b/src/hooks/useFlowCallbacks.ts @@ -15,7 +15,15 @@ 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, + updateRuntimeId +} from '@/store/ideContainer'; import { validateAllNodes, showValidationErrors, @@ -122,7 +130,6 @@ export const useFlowCallbacks = ( if (!sourceNode || !targetNode) { return; } - // 获取源节点和目标节点的参数信息 const sourceParams: any = sourceNode.data?.parameters || {}; const targetParams: any = targetNode.data?.parameters || {}; @@ -148,19 +155,43 @@ export const useFlowCallbacks = ( // 创建带有事件信息的连接 const edgeParams = { ...params, type: 'custom' }; + // 添加lineType字段,用于区分API连接和数据连接 + edgeParams.data = { + ...edgeParams.data, + lineType: sourceHandleType // 'api' 或 'data' + }; + + // 对于数据类型的边,需要额外验证dataIns和dataOuts中的数据类型是否一致 + if (sourceHandleType === 'data') { + // 查找源节点的dataOuts中对应的数据 + const sourceDataOut = (sourceParams.dataOuts || []).find((dataOut: any) => + dataOut.name === params.sourceHandle || dataOut.id === params.sourceHandle); + + // 查找目标节点的dataIns中对应的数据 + const targetDataIn = (targetParams.dataIns || []).find((dataIn: any) => + dataIn.name === params.targetHandle || dataIn.id === params.targetHandle); + + // 验证数据类型是否一致 + if (sourceDataOut && targetDataIn && sourceDataOut.dataType !== targetDataIn.dataType) { + console.warn('数据类型不匹配,源节点数据类型:', sourceDataOut.dataType, '目标节点数据类型:', targetDataIn.dataType); + Message.warning(`数据类型不匹配,源节点数据类型: ${sourceDataOut.dataType},目标节点数据类型: ${targetDataIn.dataType}`); + return edgesSnapshot; // 不创建连接 + } + } + // 检查源节点和目标节点是否都有事件信息 - const sourceApi = (sourceParams.apiOuts || []).find((api: any) => - api.name === params.sourceHandle || api.id === params.sourceHandle); - const targetApi = (targetParams.apiIns || []).find((api: any) => - api.name === params.targetHandle || api.id === params.targetHandle); + const sourceApi = (sourceParams.apiOuts || []).find((api: any) => (api?.eventId || api.name || api.id) === params.sourceHandle); + const targetApi = (targetParams.apiIns || []).find((api: any) => (api?.eventId || api.name || api.id) === params.targetHandle); // 如果源节点有事件topic信息 if (sourceApi && sourceApi.topic) { // 如果目标节点的topic是**empty**或没有topic,则使用源节点的事件信息 if (!targetApi || !targetApi.topic || targetApi.topic.includes('**empty**')) { edgeParams.data = { + ...edgeParams.data, + lineType: 'api', displayData: { - name: sourceApi.name, + name: sourceApi.eventName, eventId: sourceApi.eventId, topic: sourceApi.topic } @@ -171,8 +202,10 @@ export const useFlowCallbacks = ( !sourceApi.topic.includes('**empty**') && !targetApi.topic.includes('**empty**')) { edgeParams.data = { + ...edgeParams.data, + lineType: 'api', displayData: { - name: sourceApi.name, + name: sourceApi.eventName, eventId: sourceApi.eventId, topic: sourceApi.topic } @@ -182,8 +215,10 @@ export const useFlowCallbacks = ( // 如果源节点没有事件信息,但目标节点有 else if (targetApi && targetApi.topic && !targetApi.topic.includes('**empty**')) { edgeParams.data = { + ...edgeParams.data, + lineType: 'api', displayData: { - name: targetApi.name, + name: targetApi.eventName, eventId: targetApi.eventId, topic: targetApi.topic } @@ -559,6 +594,12 @@ export const useFlowCallbacks = ( // region 节点/边操作 // 删除节点函数 const deleteNode = useCallback((node: Node) => { + // 在应用编排模式下(useDefault为false)不允许删除节点 + if (!useDefault) { + console.warn('在应用编排模式下不允许删除节点'); + return; + } + // 开始和结束节点不允许删除 if (node.type === 'start' || node.type === 'end') { console.warn('开始和结束节点不允许删除'); @@ -646,9 +687,21 @@ export const useFlowCallbacks = ( }); document.dispatchEvent(event); }, 0); - }, [nodes, edges]); + }, [nodes, edges, useDefault]); // 删除边函数 const deleteEdge = useCallback((edge: Edge) => { + // 获取当前应用的运行状态 + const { appRuntimeData, currentAppData } = store.getState().ideContainer; + const currentAppIsRunning = currentAppData?.id && appRuntimeData[currentAppData.id] + ? appRuntimeData[currentAppData.id].isRunning + : false; + + // 在运行时禁止删除边 + if (currentAppIsRunning) { + console.warn('在运行时不允许删除边'); + return; + } + setEdges((eds: Edge[]) => eds.filter((e) => e.id !== edge.id)); // 删除边后记录历史 @@ -1024,7 +1077,6 @@ export const useFlowCallbacks = ( const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key)); // 目前默认添加的都是系统组件/本地组件 if (!nodeMap.includes(nodeType)) { - // console.log('getRegisterNodes():', getRegisterNodes(nodeType)); registerNodeType(nodeType, getNodeComponent(nodeType), nodeDefinition.nodeName); } @@ -1135,6 +1187,92 @@ export const useFlowCallbacks = ( } else return {}; }; + const handelEventNodeList = (newRevertedData) => { + const { appRuntimeData, currentAppData } = store.getState().ideContainer; + const current = appRuntimeData[currentAppData.id]; + const deleteEventSendNodeList = []; + const deleteEventlisteneList = []; + // 处理流程接口后的数据 + const currentEventSendNodeList = current.eventSendNodeList; + const currentEventlisteneList = current.eventlisteneList; + // 画布数据 + const nodeEntries: [string, any][] = Object.entries(newRevertedData); + + // 分类事件节点 + const eventSendNodes = []; + const eventListenerNodes = []; + + // 从nodeEntries中提取事件节点 + nodeEntries.forEach(([nodeId, nodeConfig]) => { + if (nodeConfig.component?.type === 'EVENTSEND') { + eventSendNodes.push({ nodeId, ...nodeConfig }); + } + else if (nodeConfig.component?.type === 'EVENTLISTENE') { + eventListenerNodes.push({ nodeId, ...nodeConfig }); + } + }); + + // 处理EVENTSEND节点 + // 如果currentEventSendNodeList中有而nodeEntries中没有,则加入删除列表 + currentEventSendNodeList.forEach((eventNode) => { + const nodeId = eventNode; + const nodeInCanvas = eventSendNodes.find(node => node.nodeId === nodeId); + + if (!nodeInCanvas) { + // 画布数据中没有该节点,加入删除列表 + deleteEventSendNodeList.push(eventNode); + } + else { + // 节点存在于画布中,比较时间戳 + // nodeId格式为"节点类型-时间戳" + const canvasNode = nodeInCanvas.nodeId.split('-'); + const canvasTimestamp = canvasNode[canvasNode.length - 1]; + + const interfaceNode = nodeId.split('-'); + const interfaceTimestamp = interfaceNode[interfaceNode.length - 1]; + + // 如果画布数据的时间戳是最新的,那就是新增的事件节点,不需要添加到deleteList中 + // 反之需要进一步判断 + if (canvasTimestamp < interfaceTimestamp) { + // 画布节点时间戳较旧,需要进一步判断 + // 这里留空,等待后续实现 + } + } + }); + + // 处理EVENTLISTENE节点 + // 如果currentEventlisteneList中有而nodeEntries中没有,则加入删除列表 + currentEventlisteneList.forEach((eventNode) => { + const nodeId = eventNode; + const nodeInCanvas = eventListenerNodes.find(node => node.nodeId === nodeId); + + if (!nodeInCanvas) { + // 画布数据中没有该节点,加入删除列表 + deleteEventlisteneList.push(eventNode); + } + else { + // 节点存在于画布中,比较时间戳 + // nodeId格式为"节点类型-时间戳" + const canvasNode = nodeInCanvas.nodeId.split('-'); + const canvasTimestamp = canvasNode[canvasNode.length - 1]; + + const interfaceNode = nodeId.split('-'); + const interfaceTimestamp = interfaceNode[interfaceNode.length - 1]; + + // 如果画布数据的时间戳是最新的,那就是新增的事件节点,不需要添加到deleteList中 + // 反之需要进一步判断 + if (canvasTimestamp < interfaceTimestamp) { + // 画布节点时间戳较旧,需要进一步判断 + // 这里留空,等待后续实现 + } + } + }); + + return { + deleteEventSendNodeList, + deleteEventlisteneList + }; + }; const saveFlowDataToServer = useCallback(async () => { if (useDefault) { try { @@ -1156,6 +1294,9 @@ export const useFlowCallbacks = ( const upDatePublishCB = await upDatePublish(revertedData.nodeConfigs); const newRevertedData = reverseConvertFlowData(nodes, edges, upDatePublishCB); const { flowData, currentAppData, info } = store.getState().ideContainer; + const { deleteEventSendNodeList, deleteEventlisteneList } = handelEventNodeList(newRevertedData); + // console.log(deleteEventSendNodeList, deleteEventlisteneList); + // return; let params = {}; // 更新复合组件/子流程 if (currentAppData.key.includes('sub')) { @@ -1192,6 +1333,12 @@ export const useFlowCallbacks = ( // 更新事件枚举表 const res1: any = await queryEventItemBySceneIdOld(info.id); if (res1.code === 200) dispatch(updateEventListOld(res1.data)); + + // 更新缓存数据 + dispatch(updateCanvasDataMap({ + ...canvasDataMap, + [currentAppData.id]: { nodes, edges } + })); } else { Message.error(res.message); @@ -1243,48 +1390,63 @@ export const useFlowCallbacks = ( ...item, eventId: Array.from(new Set(item.eventId)) })); - - updateAppFlowData(appFlowParams); - if (appEventParams.length > 0) { - for (const item of appEventParams) { - await sleep(500); - updateAppEventChannel(item); + try { + updateAppFlowData(appFlowParams); + if (appEventParams.length > 0) { + for (const item of appEventParams) { + await sleep(500); + await updateAppEventChannel(item); + } } + + Message.success('保存成功'); + } catch (error) { + console.error('保存失败:', error); + Message.error('保存失败: ' + (error.message)); } } }, [nodes, edges, initialData?.appId]); // 运行处理函数 const handleRun = useCallback(async (running: boolean) => { - const { currentAppData, socketId } = store.getState().ideContainer; + const { currentAppData, socketId, appRuntimeData } = store.getState().ideContainer; if (running) { // 启动运行 const params = { appId: currentAppData.id, socketId }; - runMainFlow(params); - - // 设置运行状态为true - dispatch(updateIsRunning(true)); - - // 重置节点状态 - dispatch(resetNodeStatus()); - - // 开始运行时动画 - setEdges((eds) => eds.map(edge => ({ - ...edge, - data: { - ...edge.data, - isRunning: true, - animationProgress: 0 - } - }))); + const res: any = await runMainFlow(params); + if (res.code === 200) { + // 设置运行状态为true + dispatch(updateIsRunning(true)); + + // 重置节点状态 + dispatch(resetNodeStatus()); + + // 更新运行ID + dispatch(updateRuntimeId(res.data)); + + // 开始运行时动画 + setEdges((eds) => eds.map(edge => ({ + ...edge, + data: { + ...edge.data, + isRunning: true, + animationProgress: 0 + } + }))); + } + else { + Message.error(res.message); + } } else { // 设置运行状态为false dispatch(updateIsRunning(false)); - stopApp(currentAppData.id); + await stopApp(appRuntimeData[currentAppData.id].runId); + // 更新运行ID + dispatch(updateRuntimeId('')); // 停止运行 setEdges((eds) => eds.map(edge => ({ @@ -1295,6 +1457,9 @@ export const useFlowCallbacks = ( animationProgress: 0 } }))); + + // 清空当前应用的运行日志 + dispatch(clearRuntimeLogs({ appId: currentAppData.id })); } }, [initialData?.appId]); @@ -1334,4 +1499,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..fb35c24 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 @@ -138,6 +139,15 @@ const FlowEditorMain: React.FC = (props) => { 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; + + // 在应用编排模式下(useDefault为false)禁用删除功能 + const isDeleteDisabled = currentAppIsRunning; + // 监听键盘事件实现快捷键 useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { @@ -178,18 +188,24 @@ 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} // 运行时禁用键盘交互 - onBeforeDelete={async ({ nodes }) => { + nodesConnectable={!currentAppIsRunning} // 运行时禁用节点连接 + nodesDraggable={!currentAppIsRunning} // 运行时禁用节点拖拽 + elementsSelectable={!currentAppIsRunning} // 运行时禁用元素选择 + connectOnClick={!currentAppIsRunning} // 运行时禁用点击连接 + disableKeyboardA11y={currentAppIsRunning} // 运行时禁用键盘交互 + onBeforeDelete={async ({ nodes, edges }) => { + // 在应用编排模式下(useDefault为false)只允许删除边,不允许删除节点 + if (!useDefault && nodes.length > 0) { + console.warn('在应用编排模式下不允许删除节点'); + return false; // 阻止删除节点操作 + } + // 检查是否有开始或结束节点 const hasStartOrEndNode = nodes.some(node => node.type === 'start' || node.type === 'end'); if (hasStartOrEndNode) { @@ -203,9 +219,20 @@ const FlowEditorMain: React.FC = (props) => { ); // 允许删除操作继续进行 - return !isRunning; // 运行时禁止删除节点 + return !currentAppIsRunning; // 在运行时禁止删除任何元素 }} onNodesDelete={(deleted) => { + // 在应用编排模式下(useDefault为false)不允许删除节点 + if (!useDefault) { + console.warn('在应用编排模式下不允许删除节点'); + return; + } + + // 如果在运行时,禁止删除 + if (currentAppIsRunning) { + return; + } + // 检查是否有循环节点 const loopNodes = deleted.filter(node => node.data?.type === 'LOOP_START' || node.data?.type === 'LOOP_END' @@ -262,21 +289,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 && useDefault) ? onNodeContextMenu : undefined} // 运行时或应用编排模式下禁用节点上下文菜单 + onNodeDoubleClick={!currentAppIsRunning ? onNodeDoubleClick : undefined} // 运行时禁用节点双击 + onEdgeContextMenu={(!currentAppIsRunning && useDefault) ? onEdgeContextMenu : undefined} // 运行时或应用编排模式下禁用边上下文菜单 + onPaneClick={!currentAppIsRunning ? onPaneClick : undefined} // 运行时禁用面板点击 + onPaneContextMenu={(!currentAppIsRunning && useDefault) ? onPaneContextMenu : undefined} // 运行时或应用编排模式下禁用面板上下文菜单 onEdgeMouseEnter={(_event, edge) => { setEdges((eds) => eds.map(e => { if (e.id === edge.id) { @@ -294,8 +321,8 @@ const FlowEditorMain: React.FC = (props) => { })); }} fitView - selectionOnDrag={!isRunning} // 运行时禁用拖拽选择 - selectionMode={!isRunning ? SelectionMode.Partial : undefined} // 运行时禁用选择模式 + selectionOnDrag={!currentAppIsRunning} // 运行时禁用拖拽选择 + selectionMode={!currentAppIsRunning ? SelectionMode.Partial : undefined} // 运行时禁用选择模式 > @@ -307,14 +334,14 @@ const FlowEditorMain: React.FC = (props) => { canUndo={canUndo} canRedo={canRedo} onRun={handleRun} - isRunning={isRunning} + isRunning={currentAppIsRunning} > - {/*节点右键上下文*/} - {!isRunning && menu && menu.type === 'node' && ( + {/*节点右键上下文 - 仅在默认模式且非运行时显示*/} + {!currentAppIsRunning && useDefault && menu && menu.type === 'node' && (
= (props) => {
)} - {/*边右键上下文*/} - {!isRunning && menu && menu.type === 'edge' && ( + {/*边右键上下文 - 在非运行时显示,应用编排模式下也允许*/} + {!currentAppIsRunning && menu && menu.type === 'edge' && (
= (props) => {
)} - {/*画布右键上下文*/} - {!isRunning && menu && menu.type === 'pane' && ( + {/*画布右键上下文 - 仅在默认模式且非运行时显示*/} + {!currentAppIsRunning && useDefault && menu && menu.type === 'pane' && (
= (props) => { - {/*统一的添加节点菜单*/} - {!isRunning && (edgeForNodeAdd || positionForNodeAdd) && ( + {/*统一的添加节点菜单 - 仅在默认模式且非运行时显示*/} + {!currentAppIsRunning && useDefault && (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 ? '停止' : '运行'}
)} - {hovered && Object.keys(displayData).length === 0 && Object.keys(displayData).length === 0 && ( + {hovered && Object.keys(displayData).length === 0 && lineType !== 'data' && ( handleEdgeAddNode(e)} /> diff --git a/src/pages/flowEditor/components/nodeContentApp.tsx b/src/pages/flowEditor/components/nodeContentApp.tsx index 635b82c..d43d04b 100644 --- a/src/pages/flowEditor/components/nodeContentApp.tsx +++ b/src/pages/flowEditor/components/nodeContentApp.tsx @@ -286,7 +286,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { color: group ? group.color : '#000' }} > - {isValidData(input) ? (input.name || input.id || `输入${index + 1}`) : ''} + {isValidData(input) ? `${input.name || input.id} ${input?.dataType}` : ''}
); })} @@ -307,7 +307,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { color: group ? group.color : '#000' }} > - {isValidData(output) ? (output.name || output.id || `输出${index + 1}`) : ''} + {isValidData(output) ? `${output.dataType} ${output.name || output.id}` : ''} ); })} diff --git a/src/pages/flowEditor/components/nodeContentCode.tsx b/src/pages/flowEditor/components/nodeContentCode.tsx index b509400..2de608f 100644 --- a/src/pages/flowEditor/components/nodeContentCode.tsx +++ b/src/pages/flowEditor/components/nodeContentCode.tsx @@ -155,7 +155,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataIns.map((input, index) => (
- {input.id || `输入${index + 1}`} + {input.id || `输入${index + 1}`} {input.dataType}
))}
@@ -165,7 +165,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataOuts.map((output, index) => (
- {`${output.id} ${output.dataType}` || `输出${index + 1}`} + {output.dataType} {`${output.id}` || `输出${index + 1}`}
))}
diff --git a/src/pages/flowEditor/components/nodeContentImage.tsx b/src/pages/flowEditor/components/nodeContentImage.tsx index d600ff8..93f3c03 100644 --- a/src/pages/flowEditor/components/nodeContentImage.tsx +++ b/src/pages/flowEditor/components/nodeContentImage.tsx @@ -161,7 +161,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataOuts.map((output, index) => (
- {output.id || `输出${index + 1}`} + {output.dataType} {output.id || `输出${index + 1}`}
))}
diff --git a/src/pages/flowEditor/components/nodeContentLoop.tsx b/src/pages/flowEditor/components/nodeContentLoop.tsx index 8bf4ded..5f33725 100644 --- a/src/pages/flowEditor/components/nodeContentLoop.tsx +++ b/src/pages/flowEditor/components/nodeContentLoop.tsx @@ -150,7 +150,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataIns.map((input, index) => (
- {input.id || `输入${index + 1}`} + {input.id || `输入${index + 1}`} {input.dataType}
))}
@@ -160,7 +160,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataOuts.map((output, index) => (
- {output.id || `输出${index + 1}`} + {output.dataType} {output.id || `输出${index + 1}`}
))}
diff --git a/src/pages/flowEditor/components/nodeContentOther.tsx b/src/pages/flowEditor/components/nodeContentOther.tsx index 456c1ff..fd66f09 100644 --- a/src/pages/flowEditor/components/nodeContentOther.tsx +++ b/src/pages/flowEditor/components/nodeContentOther.tsx @@ -193,10 +193,18 @@ const formatFooter = (data: any, eventListOld = []) => { return cronstrue.toString(intervalSeconds, { locale: 'zh_CN' }); case 'EVENTSEND': case 'EVENTLISTENE': - const { eventId, topic, name } = isJSON(data.customDef) ? JSON.parse(data.customDef) : data.customDef; - if (topic.includes('**empty**')) return ''; - const currentEvent = eventListOld.length > 0 ? eventListOld.find(item => item.eventId === eventId) : { name: '无' }; - return `事件: ${name || currentEvent.name}`; + const parsedData = isJSON(data.customDef) ? JSON.parse(data.customDef) : null; + // 数据是JSON字符串,标识是接口回来的,数据是普通对象标识是当前操作 + if (parsedData) { + const { eventId, topic, name } = parsedData; + if (topic.includes('**empty**')) return ''; + const currentEvent = eventListOld.length > 0 ? eventListOld.find(item => item.eventId === eventId) : { name: '无' }; + return `事件: ${currentEvent.name}`; + } + else { + const { name } = data.customDef; + return `事件: ${name}`; + } case 'BASIC': return data.compIdentifier ? `当前实例:${data.compIdentifier}` : ''; default: @@ -215,7 +223,6 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { const dataOuts = data.parameters?.dataOuts || []; const showFooter = formatFooter(data.component) || false; const footerData = (showFooter && data.component) || {}; - // console.log(apiIns, apiOuts, dataIns, dataOuts); // 判断节点类型 const isStartNode = data.type === 'start'; @@ -241,7 +248,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{apiOuts.map((output, index) => (
- {output.desc} + {output.dataType} {output.desc}
))}
@@ -264,7 +271,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataIns.map((input, index) => (
- {input.id || `输入${index + 1}`} + {input.id || `输入${index + 1}`} {input.dataType}
))}
@@ -274,7 +281,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataOuts.map((output, index) => (
- {output.id || `输出${index + 1}`} + {output.dataType} {output.id || `输出${index + 1}`}
))}
diff --git a/src/pages/flowEditor/components/nodeContentREST.tsx b/src/pages/flowEditor/components/nodeContentREST.tsx index 22797ec..5fceddb 100644 --- a/src/pages/flowEditor/components/nodeContentREST.tsx +++ b/src/pages/flowEditor/components/nodeContentREST.tsx @@ -152,7 +152,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataIns.map((input, index) => (
- {input.id || `输入${index + 1}`} + {input.id || `输入${index + 1}`} {input.dataType}
))}
@@ -162,7 +162,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataOuts.map((output, index) => (
- {`${output.id} ${output.dataType}` || `输出${index + 1}`} + {output.dataType} {`${output.id}` || `输出${index + 1}`}
))}
diff --git a/src/pages/flowEditor/components/nodeContentSwitch.tsx b/src/pages/flowEditor/components/nodeContentSwitch.tsx index 4120a2c..590b6aa 100644 --- a/src/pages/flowEditor/components/nodeContentSwitch.tsx +++ b/src/pages/flowEditor/components/nodeContentSwitch.tsx @@ -148,7 +148,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataIns.map((input, index) => (
- {input.id || `输入${index + 1}`} + {input.id || `输入${index + 1}`} {input.dataType}
))}
@@ -158,7 +158,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataOuts.map((output, index) => (
- {output.id || `输出${index + 1}`} + {output.dataType} {output.id || `输出${index + 1}`}
))}
diff --git a/src/pages/ideContainer/index.tsx b/src/pages/ideContainer/index.tsx index ef0fff0..ac37cb9 100644 --- a/src/pages/ideContainer/index.tsx +++ b/src/pages/ideContainer/index.tsx @@ -219,7 +219,7 @@ function IDEContainer() { }; const getEvent = async () => { - const res: any = await queryEventItemBySceneId(urlParams.id); + const res: any = await queryEventItemBySceneId({ sceneId: urlParams.id }); const res1: any = await queryEventItemBySceneIdOld(urlParams.id); if (res.code === 200) dispatch(updateEventList(res.data)); if (res1.code === 200) dispatch(updateEventListOld(res1.data)); diff --git a/src/pages/ideContainer/logBar.tsx b/src/pages/ideContainer/logBar.tsx index e345749..e233d01 100644 --- a/src/pages/ideContainer/logBar.tsx +++ b/src/pages/ideContainer/logBar.tsx @@ -44,11 +44,12 @@ const LogBar: React.FC = () => { const [tabs] = useState(data); const [activeTab, setActiveTab] = useState('1'); const resizeBoxRef = useRef(null); // 引用 ResizeBox 容器 - const { logBarStatus } = useSelector((state) => state.ideContainer); + const { logBarStatus, appRuntimeData } = useSelector((state: any) => state.ideContainer); const dispatch = useDispatch(); const [validationLogs, setValidationLogs] = useState([]); const [runtimeLogs, setRuntimeLogs] = useState([]); // 添加运行时日志状态 const [logContainerHeight, setLogContainerHeight] = useState('250px'); // 添加日志容器高度状态 + const { currentAppData } = useSelector((state: any) => state.ideContainer); // 处理 Tab 点击事件 const handleTabClick = (key: string) => { @@ -120,6 +121,18 @@ const LogBar: React.FC = () => { // 自动切换到运行日志tab并展开logBar setActiveTab('1'); dispatch(updateLogBarStatus(true)); + + // 同时将日志添加到当前应用的运行日志中 + const appId = currentAppData?.id; + if (appId) { + dispatch({ + type: 'ideContainer/addRuntimeLog', + payload: { + log: newLog, + appId: appId + } + }); + } } }; @@ -130,7 +143,7 @@ const LogBar: React.FC = () => { return () => { document.removeEventListener('logMessage', handleLogMessage as EventListener); }; - }, [dispatch]); + }, [dispatch, currentAppData?.id]); // 渲染校验日志内容 const renderValidationLogs = () => { @@ -156,12 +169,17 @@ const LogBar: React.FC = () => { // 渲染运行时日志内容 const renderRuntimeLogs = () => { + // 获取当前应用的运行日志 + const currentAppLogs = currentAppData?.id && appRuntimeData[currentAppData.id] + ? appRuntimeData[currentAppData.id].logs || [] + : []; + return (
- {runtimeLogs.length === 0 ? ( + {currentAppLogs.length === 0 ? (

暂无运行时日志

) : ( - runtimeLogs.map(log => ( + currentAppLogs.map((log: LogMessage) => (
{new Date(log.timestamp).toLocaleString()} diff --git a/src/pages/orchestration/application/index.tsx b/src/pages/orchestration/application/index.tsx index c9c1f2e..6420a95 100644 --- a/src/pages/orchestration/application/index.tsx +++ b/src/pages/orchestration/application/index.tsx @@ -16,7 +16,7 @@ const ApplicationContainer = () => { }; const getEventList = async () => { - const res: any = await queryEventItemBySceneId(info.id); + const res: any = await queryEventItemBySceneId({ sceneId: info.id }); if (res.code === 200) { dispatch(updateEventTopicList(res.data diff --git a/src/pages/orchestration/event/index.tsx b/src/pages/orchestration/event/index.tsx index dd0d51a..304ff69 100644 --- a/src/pages/orchestration/event/index.tsx +++ b/src/pages/orchestration/event/index.tsx @@ -235,7 +235,7 @@ const EventContainer = () => { ]; const fetchEventData = async () => { - const res: any = await queryEventItemBySceneId(info.id); + const res: any = await queryEventItemBySceneId({sceneId:info.id}); if (res && res.code === 200) setEventData(res.data.filter(item => !item.topic.includes('**empty**'))); }; diff --git a/src/store/ideContainer.ts b/src/store/ideContainer.ts index bfd9c99..2981138 100644 --- a/src/store/ideContainer.ts +++ b/src/store/ideContainer.ts @@ -15,6 +15,15 @@ interface IDEContainerState { socketId: string; nodeStatusMap: Record; // 节点状态映射 isRunning: boolean; // 是否正在运行 + // 应用运行状态和日志数据,按应用ID隔离存储 + appRuntimeData: Record; + isRunning: boolean; + logs: any[]; + runId: string; + eventSendNodeList: string[], + eventlisteneList: string[] + }>; } // 初始状态 @@ -31,7 +40,8 @@ const initialState: IDEContainerState = { logBarStatus: false, socketId: '', // 工程的socketId nodeStatusMap: {}, // 初始化节点状态映射 - isRunning: false // 默认未运行 + isRunning: false, // 默认未运行 + appRuntimeData: {} // 按应用ID隔离的应用运行状态和日志数据 }; // 创建切片 @@ -78,18 +88,109 @@ const ideContainerSlice = createSlice({ // 如果是运行时更新,不记录到历史记录中 if (actionType !== 'RUNTIME_UPDATE') { state.nodeStatusMap[nodeId] = status; - } else { + } + else { // 对于运行时更新,我们仍然更新状态但标记为运行时状态 state.nodeStatusMap[nodeId] = status; } + + // 同时更新当前应用的节点状态 + const appId = state.currentAppData?.id; + if (appId) { + if (!state.appRuntimeData[appId]) { + state.appRuntimeData[appId] = { + nodeStatusMap: {}, + isRunning: false, + logs: [], + runId: '', + eventSendNodeList: [], + eventlisteneList: [] + }; + } + state.appRuntimeData[appId].nodeStatusMap[nodeId] = status; + } }, // 重置节点状态 resetNodeStatus: (state) => { state.nodeStatusMap = {}; + + // 同时重置当前应用的节点状态 + const appId = state.currentAppData?.id; + if (appId && state.appRuntimeData[appId]) { + state.appRuntimeData[appId].nodeStatusMap = {}; + } }, // 更新运行状态 updateIsRunning: (state, { payload }) => { state.isRunning = payload; + + // 同时更新当前应用的运行状态 + const appId = state.currentAppData?.id; + if (appId) { + if (!state.appRuntimeData[appId]) { + state.appRuntimeData[appId] = { + nodeStatusMap: {}, + isRunning: false, + logs: [], + runId: '', + eventSendNodeList: [], + eventlisteneList: [] + }; + } + state.appRuntimeData[appId].isRunning = payload; + } + }, + // 添加运行id + updateRuntimeId: (state, { payload }) => { + const appId = state.currentAppData?.id; + if (!state.appRuntimeData[appId]) { + state.appRuntimeData[appId] = { + nodeStatusMap: {}, + isRunning: false, + logs: [], + runId: '', + eventSendNodeList: [], + eventlisteneList: [] + }; + } + state.appRuntimeData[appId].runId = payload; + }, + // 更新事件节点列表 + updateEventNodeList: (state, { payload }) => { + const appId = state.currentAppData?.id; + if (!state.appRuntimeData[appId]) { + state.appRuntimeData[appId] = { + nodeStatusMap: {}, + isRunning: false, + logs: [], + runId: '', + eventSendNodeList: [], + eventlisteneList: [] + }; + } + state.appRuntimeData[appId] = { ...state.appRuntimeData[appId], ...payload }; + }, + // 添加运行日志 + addRuntimeLog: (state, { payload }) => { + const { log, appId } = payload; + if (!state.appRuntimeData[appId]) { + state.appRuntimeData[appId] = { + nodeStatusMap: {}, + isRunning: false, + logs: [], + runId: '', + eventSendNodeList: [], + eventlisteneList: [] + }; + } + state.appRuntimeData[appId].logs.push(log); + }, + // 清空指定应用的运行日志 + clearRuntimeLogs: (state, { payload }) => { + const { appId } = payload; + if (state.appRuntimeData[appId]) { + state.appRuntimeData[appId].logs = []; + } } } }); @@ -109,7 +210,11 @@ export const { updateSocketId, updateNodeStatus, resetNodeStatus, - updateIsRunning + updateIsRunning, + updateRuntimeId, + updateEventNodeList, + addRuntimeLog, + clearRuntimeLogs } = ideContainerSlice.actions; // 默认导出 reducer diff --git a/src/utils/convertAppFlowData.ts b/src/utils/convertAppFlowData.ts index 7fc6e0d..486727e 100644 --- a/src/utils/convertAppFlowData.ts +++ b/src/utils/convertAppFlowData.ts @@ -33,21 +33,23 @@ export const convertAppFlowData = (appFlowData: any[]) => { parameters: { // eventListenes 作为 apiIns(输入) apiIns: app.eventListenes ? app.eventListenes.map((event: any) => ({ - name: event.eventName, + name: event.nodeName, desc: event.description || '', dataType: '', defaultValue: '', topic: event.topic, - eventId: event.eventId + eventId: event.eventId, + eventName: event.eventName })) : [], // eventSends 作为 apiOuts(输出) apiOuts: app.eventSends ? app.eventSends.map((event: any) => ({ - name: event.eventName, + name: event.nodeName, desc: event.description || '', dataType: '', defaultValue: '', topic: event.topic, - eventId: event.eventId + eventId: event.eventId, + eventName: event.eventName })) : [], // 提取 dataIns 和 dataOuts 属性 dataIns: [], @@ -118,6 +120,7 @@ export const convertAppFlowData = (appFlowData: any[]) => { targetHandle: targetEvent.eventId, type: 'custom', data: { + lineType: 'api', // 应用间连接始终是API类型 displayData: { name: sourceEvent.eventName, eventId: sourceEvent.eventId, diff --git a/src/utils/convertFlowData.ts b/src/utils/convertFlowData.ts index c49dff8..25deb98 100644 --- a/src/utils/convertFlowData.ts +++ b/src/utils/convertFlowData.ts @@ -7,6 +7,8 @@ import BasicNode from '@/components/FlowEditor/node/basicNode/BasicNode'; import ImageNode from '@/components/FlowEditor/node/imageNode/ImageNode'; import CodeNode from '@/components/FlowEditor/node/codeNode/CodeNode'; import RestNode from '@/components/FlowEditor/node/restNode/RestNode'; +import { updateEventNodeList } from '@/store/ideContainer'; + /** * 将提供的数据结构转换为适用于 flow editor 的 nodes 和 edges @@ -17,6 +19,8 @@ import RestNode from '@/components/FlowEditor/node/restNode/RestNode'; export const convertFlowData = (flowData: any, useDefault = true) => { const nodes: any[] = []; const edges: any[] = []; + const eventSendNodeList = []; + const eventlisteneList = []; const currentProjectCompData = getCurrentProjectStoreData(); if (!flowData || Object.keys(flowData).length === 0) { @@ -70,6 +74,15 @@ export const convertFlowData = (flowData: any, useDefault = true) => { const nodeId: string = entry[0]; const nodeConfig: any = entry[1]; + // 更新应用中的事件节点列表 + if (nodeId.includes('EVENTLISTENE')) eventlisteneList.push(nodeId); + else if (nodeId.includes('EVENTSEND')) eventSendNodeList.push(nodeId); + + if (eventlisteneList.length > 0 || eventSendNodeList.length > 0) store.dispatch(updateEventNodeList({ + eventSendNodeList, + eventlisteneList + })); + // 确定节点类型 let nodeType = 'BASIC'; if (nodeId === 'start') { @@ -492,7 +505,6 @@ export const reverseConvertFlowData = (nodes: any[], edges: any[], complexKV: an position: node.position || { x: 0, y: 0 } }; - console.log('node:', node); // 处理 component 信息 if (node.type === 'SUB' && !node.customDef) { nodeConfig.component = { diff --git a/src/utils/flowCommon.ts b/src/utils/flowCommon.ts index 9cf3f37..5f1c4a0 100644 --- a/src/utils/flowCommon.ts +++ b/src/utils/flowCommon.ts @@ -12,8 +12,8 @@ const getHandleType = (handleId: string, nodeParams: any) => { const apiOuts = nodeParams.apiOuts || []; const apiIns = nodeParams.apiIns || []; - if (apiOuts.some((api: any) => (api.name || api.id) === handleId) || - apiIns.some((api: any) => (api.name || api.id) === handleId) || (handleId.includes('loop'))) { + if (apiOuts.some((api: any) => (api?.eventId || api.name || api.id) === handleId) || + apiIns.some((api: any) => (api?.eventId || api.name || api.id) === handleId) || (handleId.includes('loop'))) { return 'api'; }