Files
auto-solution/modeler/src/views/decision/communication/relation.ts

135 lines
4.7 KiB
TypeScript
Raw Normal View History

2026-03-16 15:48:33 +08:00
/*
* This file is part of the kernelstudio package.
*
* (c) 2014-2026 zlin <admin@kernelstudio.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
2026-03-27 00:08:48 +08:00
import { Edge, Graph, Node } from '@antv/x6';
import type { PlatformRelation } from './types';
import type { Platform, PlatformComponent } from '../types';
2026-03-16 15:48:33 +08:00
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<string> = new Set(); // 改用 Set 提升查询性能
const tempEdgeIds: Set<string> = 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;
}