/* * This file is part of the kernelstudio package. * * (c) 2014-2026 zlin * * For the full copyright and license information, please view the LICENSE file * that was distributed with this source code. */ import { Edge, Graph, Node } from '@antv/x6'; import type { PlatformRelation } from './types'; import type { Platform, PlatformComponent } from '../types'; import type { GraphTaskElement } from '../graph'; /** * 解析节点端口连接关系(去重版) * @param graph X6 画布实例 * @returns 去重后的端口连接关系列表 */ export function resolveConnectionRelation(graph: Graph): PlatformRelation[] { const edges: Edge[] = graph.getEdges(); const items: PlatformRelation[] = []; const existsKeys: Set = new Set(); // 改用 Set 提升查询性能 const tempEdgeIds: Set = new Set(); // 存储临时边 ID // 过滤无效/临时边 const validEdges = edges.filter(edge => { // 过滤临时边(X6 拖拽连线时生成的未完成边) const isTempEdge = edge?.attr('line/stroke') === 'transparent' || edge.id.includes('temp'); if (isTempEdge) { tempEdgeIds.add(edge.id); return false; } // 过滤未正确关联节点的边 const sourceCell = edge.getSourceCell(); const targetCell = edge.getTargetCell(); if (!sourceCell || !targetCell || !(sourceCell instanceof Node) || !(targetCell instanceof Node)) { return false; } // 过滤端口 ID 为空的边 const sourcePortId = edge.getSourcePortId(); const targetPortId = edge.getTargetPortId(); if (!sourcePortId || !targetPortId) { return false; } return true; }); validEdges.forEach(edge => { try { const sourceCell = edge.getSourceCell() as Node; const targetCell = edge.getTargetCell() as Node; const sourcePortId = edge.getSourcePortId()!; const targetPortId = edge.getTargetPortId()!; // 1. 获取端口 DOM 元素和数据 const sourceView = graph.findViewByCell(sourceCell); const targetView = graph.findViewByCell(targetCell); if (!sourceView || !targetView) return; const sourcePortEl = sourceView.container.querySelector(`[data-port="${sourcePortId}"]`); const targetPortEl = targetView.container.querySelector(`[data-port="${targetPortId}"]`); if (!sourcePortEl || !targetPortEl) return; // 2. 解析端口数据 let sourcePortData: PlatformComponent | null = null; let targetPortData: PlatformComponent | null = null; try { const sourceDataAttr = sourcePortEl.getAttribute('data-item'); sourcePortData = sourceDataAttr ? JSON.parse(sourceDataAttr) : null; } catch (e) { console.warn(`解析源节点 ${sourceCell.id} 端口 ${sourcePortId} 数据失败`, e); return; // 数据解析失败直接跳过 } try { const targetDataAttr = targetPortEl.getAttribute('data-item'); targetPortData = targetDataAttr ? JSON.parse(targetDataAttr) : null; } catch (e) { console.warn(`解析目标节点 ${targetCell.id} 端口 ${targetPortId} 数据失败`, e); return; // 数据解析失败直接跳过 } // 过滤端口数据为空的情况 if (!sourcePortData || !targetPortData) return; // 解析节点平台数据 const sourceData = sourceCell.getData() as GraphTaskElement; const targetData = targetCell.getData() as GraphTaskElement; // 过滤平台数据不完整的节点 if (!sourceData.platformId || !targetData.platformId) return; const sourcePlatform: Platform = { id: sourceData.platformId as number, key: sourceData.key, name: sourceData.name, description: sourceData.description, scenarioId: sourceData.scenarioId as number, }; const targetPlatform: Platform = { id: targetData.platformId as number, key: targetData.key, name: targetData.name, description: targetData.description, scenarioId: targetData.scenarioId as number, }; // 生成唯一标识(支持单向/双向去重 const uniqueKey = `${sourceCell.id}@${sourcePortId}->${targetCell.id}@${targetPortId}`; if (!existsKeys.has(uniqueKey)) { existsKeys.add(uniqueKey); items.push({ sourceId: sourceCell.id, sourcePort: sourcePortId, sourcePlatform: sourcePlatform, sourceComponent: sourcePortData, targetId: targetCell.id, targetPort: targetPortId, targetPlatform: targetPlatform, targetComponent: targetPortData, edgeId: edge.id, }); } } catch (error) { console.error(`解析边 ${edge.id} 连接关系失败`, error); } }); return items; }