diff --git a/src/api/interface/index.ts b/src/api/interface/index.ts index e3455d1..5c5ba29 100644 --- a/src/api/interface/index.ts +++ b/src/api/interface/index.ts @@ -205,7 +205,7 @@ export interface DeleteEventParams { export interface DeleteEventForAppParams { appId: string, - eventIds: string[] + topics: string[] } // runtime diff --git a/src/hooks/useFlowCallbacks.ts b/src/hooks/useFlowCallbacks.ts index 90b0121..b856faf 100644 --- a/src/hooks/useFlowCallbacks.ts +++ b/src/hooks/useFlowCallbacks.ts @@ -36,13 +36,14 @@ import { } from '@/utils/flowCommon'; import { projectFlowHandle } from '@/pages/flowEditor/utils/projectFlowHandle'; import { appFLowHandle } from '@/pages/flowEditor/utils/appFlowhandle'; +import { handelEventNodeList, updateEvent, upDatePublish } from '@/pages/flowEditor/utils/common'; import { Dispatch } from 'redux'; import { runMainFlow, stopApp } from '@/api/apps'; import store from '@/store'; import { updateAppEvent, updateAppEventChannel, updateAppFlowData } from '@/api/appEvent'; import { sleep } from '@/utils/common'; -import { queryEventItemBySceneIdOld } from '@/api/event'; +import { queryEventItemBySceneIdOld, deleteEventSub, deleteEventPub } from '@/api/event'; export const useFlowCallbacks = ( nodes: Node[], @@ -810,7 +811,11 @@ export const useFlowCallbacks = ( target: loopStartNode.id, sourceHandle: edgeForNodeAdd.sourceHandle, targetHandle: 'start', // 循环开始节点的输入句柄 - type: 'custom' + type: 'custom', + lineType: 'api', + data: { + lineType: 'api' + } }, { id: `e${loopEndNode.id}-${edgeForNodeAdd.target}`, @@ -818,7 +823,11 @@ export const useFlowCallbacks = ( target: edgeForNodeAdd.target, sourceHandle: 'break', // 循环结束节点的输出句柄 targetHandle: edgeForNodeAdd.targetHandle, - type: 'custom' + type: 'custom', + lineType: 'api', + data: { + lineType: 'api' + } } ]; @@ -977,7 +986,11 @@ export const useFlowCallbacks = ( target: newNode.id, sourceHandle: edgeForNodeAdd.sourceHandle, targetHandle: newNodeTargetHandle, - type: 'custom' + type: 'custom', + lineType: 'api', + data: { + lineType: 'api' + } }, { id: `e${newNode.id}-${edgeForNodeAdd.target}`, @@ -985,7 +998,11 @@ export const useFlowCallbacks = ( target: edgeForNodeAdd.target, sourceHandle: newNodeSourceHandle, targetHandle: edgeForNodeAdd.targetHandle, - type: 'custom' + type: 'custom', + lineType: 'api', + data: { + lineType: 'api' + } } ]; @@ -1111,168 +1128,7 @@ export const useFlowCallbacks = ( }, [edgeForNodeAdd, positionForNodeAdd, addNodeOnEdge, addNodeOnPane]); // endregion - // 保存所有节点和边数据到服务器,更新事件相关数据 - const updateEvent = (revertedData, appid) => { - // 初始化参数对象 - const params: any = { - eventListenes: [], - eventSends: [] - }; - - // 遍历所有节点,查找事件相关节点 - Object.entries(revertedData).forEach(([nodeId, nodeConfig]: [string, any]) => { - // 检查节点是否有component属性和type定义 - if (nodeConfig.component?.type) { - const nodeType = nodeConfig.component.type; - const customDef = nodeConfig.component.customDef; - - // 解析customDef,可能是字符串也可能是对象 - let eventConfig; - if (typeof customDef === 'string') { - try { - eventConfig = JSON.parse(customDef); - } catch (e) { - console.error('Failed to parse customDef:', e); - return; - } - } - else { - eventConfig = customDef; - } - // 根据节点类型处理事件节点 - if (nodeType === 'EVENTLISTENE') { - // 事件接收节点 - params.eventListenes.push({ - nodeName: nodeConfig.nodeName || '', - eventId: eventConfig?.eventId || null, - topic: eventConfig?.topic || '', - eventName: eventConfig?.name || '', - dataOuts: nodeConfig.dataOuts || [], - nodeId: nodeConfig.nodeId - }); - } - else if (nodeType === 'EVENTSEND') { - // 事件发送节点 - params.eventSends.push({ - nodeName: nodeConfig.nodeName || '', - eventId: eventConfig?.eventId || null, - topic: eventConfig?.topic || '', - eventName: eventConfig?.name || '', - dataIns: nodeConfig.dataIns || [], - nodeId: nodeConfig.nodeId - }); - } - } - }); - // 调用更新事件的API - if (params.eventListenes.length > 0 || params.eventSends.length > 0) { - return params; - } - else return null; - }; - const upDatePublish = async (revertedData) => { - const { currentAppData } = store.getState().ideContainer; - const params = { - appId: currentAppData.id, - publishAppId: [] - }; - revertedData.forEach(item => { - if (item?.component && item.component.type === 'SUB' && !item.component.customDef) params.publishAppId.push(item.component.compId); // 复合组件的这个compId实际上就是flowHousVO里面的id - }); - if (params.publishAppId.length > 0) { - const res: any = await refPublish(params); - if (res.code === 200) return res.data; - else return {}; - } - 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 { @@ -1295,7 +1151,7 @@ export const useFlowCallbacks = ( const newRevertedData = reverseConvertFlowData(nodes, edges, upDatePublishCB); const { flowData, currentAppData, info } = store.getState().ideContainer; const { deleteEventSendNodeList, deleteEventlisteneList } = handelEventNodeList(newRevertedData); - // console.log(deleteEventSendNodeList, deleteEventlisteneList); + console.log('事件处理数据', deleteEventSendNodeList, deleteEventlisteneList); // return; let params = {}; // 更新复合组件/子流程 @@ -1344,6 +1200,18 @@ export const useFlowCallbacks = ( Message.error(res.message); } } + + // 事件节点变动数据有长度就通知后端,主流程和子流程(复合节点)通用 + if (deleteEventSendNodeList.length > 0 || deleteEventlisteneList.length > 0) { + deleteEventSendNodeList.length > 0 && deleteEventPub({ + appId: currentAppData.id, + topics: deleteEventSendNodeList + }); + deleteEventlisteneList.length > 0 && deleteEventSub({ + appId: currentAppData.id, + topics: deleteEventlisteneList + }); + } } catch (error) { console.error('Error saving flow data:', error); Message.error('保存失败'); @@ -1391,7 +1259,7 @@ export const useFlowCallbacks = ( eventId: Array.from(new Set(item.eventId)) })); try { - updateAppFlowData(appFlowParams); + updateAppFlowData(appEventParams); if (appEventParams.length > 0) { for (const item of appEventParams) { await sleep(500); diff --git a/src/pages/flowEditor/utils/common.ts b/src/pages/flowEditor/utils/common.ts new file mode 100644 index 0000000..e01145a --- /dev/null +++ b/src/pages/flowEditor/utils/common.ts @@ -0,0 +1,255 @@ +import store from '@/store'; +import { refPublish } from '@/api/appRes'; + +export 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); + + // 分类事件节点 [{nodeId:topic}] + const eventSendNodes = []; + const eventListenerNodes = []; + + // 从nodeEntries中提取事件节点 + nodeEntries.forEach(([nodeId, nodeConfig]) => { + if (nodeConfig.component?.type === 'EVENTSEND') { + try { + const customDef = JSON.parse(nodeConfig.component.customDef); + eventSendNodes.push({ nodeId, topic: customDef.topic }); + } catch (e) { + eventSendNodes.push({ nodeId, topic: nodeConfig.component.customDef.topic }); + } + } + else if (nodeConfig.component?.type === 'EVENTLISTENE') { + try { + const customDef = JSON.parse(nodeConfig.component.customDef); + eventListenerNodes.push({ nodeId, topic: customDef.topic }); + } catch (e) { + eventListenerNodes.push({ nodeId, topic: nodeConfig.component.customDef.topic }); + } + } + }); + + // 处理EVENTSEND节点 + // 1. 原始数据中有但新数据中没有的节点,直接加入删除列表(节点被删除) + currentEventSendNodeList.forEach((eventNode) => { + const nodeId = Object.keys(eventNode)[0]; + const nodeInCanvas = eventSendNodes.find(node => node.nodeId === nodeId); + + if (!nodeInCanvas) { + // 画布数据中没有该节点,说明节点被删除了,直接加入删除列表 + deleteEventSendNodeList.push(eventNode[nodeId]); + } + }); + + // 2. 遍历新数据中的每个事件节点 + eventSendNodes.forEach((newNode) => { + const newNodeId = newNode.nodeId; + // nodeId格式为"节点类型-时间戳" + const newNodeParts = newNodeId.split('-'); + const newNodeTimestamp = parseInt(newNodeParts[newNodeParts.length - 1]) || 0; + + // 在原始数据中查找相同类型的节点 + const sameTypeNodes = currentEventSendNodeList.filter(node => { + const nodeIdKey = Object.keys(node)[0]; + const nodeIdParts = nodeIdKey.split('-'); + // 比较节点类型部分(除了时间戳) + return nodeIdParts.slice(0, -1).join('-') === newNodeParts.slice(0, -1).join('-'); + }); + + if (sameTypeNodes.length > 0) { + // 获取这些同类型节点中的最大时间戳 + const maxTimestamp = Math.max(...sameTypeNodes.map(node => { + const nodeIdKey = Object.keys(node)[0]; + return parseInt(nodeIdKey.split('-')[nodeIdKey.split('-').length - 1]) || 0; + })); + + // 查找新节点在原始数据中的对应项 + const correspondingNode = currentEventSendNodeList.find(node => { + const nodeIdKey = Object.keys(node)[0]; + return nodeIdKey === newNodeId; + }); + + // 如果找到了对应的节点 + if (correspondingNode) { + const correspondingNodeId = Object.keys(correspondingNode)[0]; + const correspondingTopic = correspondingNode[correspondingNodeId]; + + // 比较topic是否一致 + if (newNode.topic !== correspondingTopic) { + // topic不一致,将原始数据的topic加入删除列表 + deleteEventSendNodeList.push(correspondingTopic); + } + } + // 如果新节点的时间戳小于最大时间戳,则说明它是一个旧版本,应该被删除 + else if (newNodeTimestamp < maxTimestamp) { + // 查找该节点在currentEventSendNodeList中的完整对象 + const nodeToDelete = currentEventSendNodeList.find(node => { + const nodeIdKey = Object.keys(node)[0]; + return nodeIdKey === newNodeId; + }); + + if (nodeToDelete) { + const nodeIdKey = Object.keys(nodeToDelete)[0]; + deleteEventSendNodeList.push(nodeToDelete[nodeIdKey]); + } + } + } + // 如果sameTypeNodes为空,说明这是一个全新的节点类型,不需要处理 + }); + + // 处理EVENTLISTENE节点 + // 1. 原始数据中有但新数据中没有的节点,直接加入删除列表(节点被删除) + currentEventlisteneList.forEach((eventNode) => { + const nodeId = Object.keys(eventNode)[0]; + const nodeInCanvas = eventListenerNodes.find(node => node.nodeId === nodeId); + + if (!nodeInCanvas) { + // 画布数据中没有该节点,说明节点被删除了,直接加入删除列表 + deleteEventlisteneList.push(eventNode[nodeId]); + } + }); + + // 2. 遍历新数据中的每个事件节点 + eventListenerNodes.forEach((newNode) => { + const newNodeId = newNode.nodeId; + // nodeId格式为"节点类型-时间戳" + const newNodeParts = newNodeId.split('-'); + const newNodeTimestamp = parseInt(newNodeParts[newNodeParts.length - 1]) || 0; + + // 在原始数据中查找相同类型的节点 + const sameTypeNodes = currentEventlisteneList.filter(node => { + const nodeIdKey = Object.keys(node)[0]; + const nodeIdParts = nodeIdKey.split('-'); + // 比较节点类型部分(除了时间戳) + return nodeIdParts.slice(0, -1).join('-') === newNodeParts.slice(0, -1).join('-'); + }); + + if (sameTypeNodes.length > 0) { + // 获取这些同类型节点中的最大时间戳 + const maxTimestamp = Math.max(...sameTypeNodes.map(node => { + const nodeIdKey = Object.keys(node)[0]; + return parseInt(nodeIdKey.split('-')[nodeIdKey.split('-').length - 1]) || 0; + })); + + // 查找新节点在原始数据中的对应项 + const correspondingNode = currentEventlisteneList.find(node => { + const nodeIdKey = Object.keys(node)[0]; + return nodeIdKey === newNodeId; + }); + + // 如果找到了对应的节点 + if (correspondingNode) { + const correspondingNodeId = Object.keys(correspondingNode)[0]; + const correspondingTopic = correspondingNode[correspondingNodeId]; + + // 比较topic是否一致 + if (newNode.topic !== correspondingTopic) { + // topic不一致,将原始数据的topic加入删除列表 + deleteEventlisteneList.push(correspondingTopic); + } + } + // 如果新节点的时间戳小于最大时间戳,则说明它是一个旧版本,应该被删除 + else if (newNodeTimestamp < maxTimestamp) { + // 查找该节点在currentEventlisteneList中的完整对象 + const nodeToDelete = currentEventlisteneList.find(node => { + const nodeIdKey = Object.keys(node)[0]; + return nodeIdKey === newNodeId; + }); + + if (nodeToDelete) { + const nodeIdKey = Object.keys(nodeToDelete)[0]; + deleteEventlisteneList.push(nodeToDelete[nodeIdKey]); + } + } + } + // 如果sameTypeNodes为空,说明这是一个全新的节点类型,不需要处理 + }); + + return { + deleteEventSendNodeList, + deleteEventlisteneList + }; +}; + +export const updateEvent = (revertedData, appid) => { + // 初始化参数对象 + const params: any = { + eventListenes: [], + eventSends: [] + }; + + // 遍历所有节点,查找事件相关节点 + Object.entries(revertedData).forEach(([nodeId, nodeConfig]: [string, any]) => { + // 检查节点是否有component属性和type定义 + if (nodeConfig.component?.type) { + const nodeType = nodeConfig.component.type; + const customDef = nodeConfig.component.customDef; + + // 解析customDef,可能是字符串也可能是对象 + let eventConfig; + if (typeof customDef === 'string') { + try { + eventConfig = JSON.parse(customDef); + } catch (e) { + console.error('Failed to parse customDef:', e); + return; + } + } + else { + eventConfig = customDef; + } + + // 根据节点类型处理事件节点 + if (nodeType === 'EVENTLISTENE') { + // 事件接收节点 + params.eventListenes.push({ + nodeName: nodeConfig.nodeName || '', + eventId: eventConfig?.eventId || null, + topic: eventConfig?.topic || '', + eventName: eventConfig?.name || '', + dataOuts: nodeConfig.dataOuts || [], + nodeId: nodeConfig.nodeId + }); + } + else if (nodeType === 'EVENTSEND') { + // 事件发送节点 + params.eventSends.push({ + nodeName: nodeConfig.nodeName || '', + eventId: eventConfig?.eventId || null, + topic: eventConfig?.topic || '', + eventName: eventConfig?.name || '', + dataIns: nodeConfig.dataIns || [], + nodeId: nodeConfig.nodeId + }); + } + } + }); + // 调用更新事件的API + if (params.eventListenes.length > 0 || params.eventSends.length > 0) { + return params; + } + else return null; +}; +export const upDatePublish = async (revertedData) => { + const { currentAppData } = store.getState().ideContainer; + const params = { + appId: currentAppData.id, + publishAppId: [] + }; + revertedData.forEach(item => { + if (item?.component && item.component.type === 'SUB' && !item.component.customDef) params.publishAppId.push(item.component.compId); // 复合组件的这个compId实际上就是flowHousVO里面的id + }); + if (params.publishAppId.length > 0) { + const res: any = await refPublish(params); + if (res.code === 200) return res.data; + else return {}; + } + else return {}; +}; \ No newline at end of file diff --git a/src/store/ideContainer.ts b/src/store/ideContainer.ts index 2981138..5c9e9e4 100644 --- a/src/store/ideContainer.ts +++ b/src/store/ideContainer.ts @@ -21,8 +21,8 @@ interface IDEContainerState { isRunning: boolean; logs: any[]; runId: string; - eventSendNodeList: string[], - eventlisteneList: string[] + eventSendNodeList: any[], // [{nodeID:topic}] + eventlisteneList: any[] // [{nodeID:topic}] }>; } diff --git a/src/utils/convertFlowData.ts b/src/utils/convertFlowData.ts index ad70d94..cdbc223 100644 --- a/src/utils/convertFlowData.ts +++ b/src/utils/convertFlowData.ts @@ -75,12 +75,28 @@ export const convertFlowData = (flowData: any, useDefault = true) => { const nodeConfig: any = entry[1]; // 更新应用中的事件节点列表 - if (nodeId.includes('EVENTLISTENE')) eventlisteneList.push(nodeId); - else if (nodeId.includes('EVENTSEND')) eventSendNodeList.push(nodeId); + if (nodeId.includes('EVENTLISTENE')) { + try { + const customDef = JSON.parse(nodeConfig.component.customDef); + // 使用展开运算符创建新数组,避免修改冻结对象 + eventlisteneList.splice(eventlisteneList.length, 0, { [nodeId]: customDef.topic }); + } catch (error) { + console.log(error); + } + } + else if (nodeId.includes('EVENTSEND')) { + try { + const customDef = JSON.parse(nodeConfig.component.customDef); + // 使用展开运算符创建新数组,避免修改冻结对象 + eventSendNodeList.splice(eventSendNodeList.length, 0, { [nodeId]: customDef.topic }); + } catch (error) { + console.log(error); + } + } if (eventlisteneList.length > 0 || eventSendNodeList.length > 0) store.dispatch(updateEventNodeList({ - eventSendNodeList, - eventlisteneList + eventSendNodeList: [...eventSendNodeList], + eventlisteneList: [...eventlisteneList] })); // 确定节点类型