diff --git a/modeler/src/views/decision/communication/communication.vue b/modeler/src/views/decision/communication/communication.vue index 585e6b9..b1efcfb 100644 --- a/modeler/src/views/decision/communication/communication.vue +++ b/modeler/src/views/decision/communication/communication.vue @@ -72,7 +72,7 @@ import { createGraphScenarioElement, createGraphTaskElementFromScenario } from ' import PlatformCard from './platform-card.vue'; import NodesCard from './nodes-card.vue'; -import { findOneScenarioById, saveScenario, findRelations, getAllBehaviorTreesBySceneId } from './api'; +import { findOneScenarioById, saveScenario, findRelations, getAllBehaviorTreesBySceneId, findPlatformWithComponents } from './api'; import { resolveConnectionRelation } from './relation'; import { generateRandomCommunicationData } from './random-data-generator'; import { convertRecordsToGraphContainer, type CommunicationRecord } from './data-converter'; @@ -278,8 +278,45 @@ export default defineComponent({ console.log('标准化后的第一条记录:', normalizedRelations[0]); - // 转换为图数据 - const convertedGraph = convertRecordsToGraphContainer(normalizedRelations); + // 获取平台列表(包含完整的组件信息) + message.loading({ content: '正在获取平台信息...', key: 'loading-platforms' }); + const platformResponse = await findPlatformWithComponents(currentScenario.value.id); + + if (!platformResponse.data || platformResponse.data.length === 0) { + console.warn('未能获取平台列表,将使用简化的组件信息'); + message.destroy('loading-platforms'); + + // 即使没有平台数据也继续转换(传入场景ID) + const convertedGraph = convertRecordsToGraphContainer( + normalizedRelations, + undefined, + undefined, + currentScenario.value.id + ); + console.log('转换后的图数据:', convertedGraph); + + currentScenario.value.graph = convertedGraph; + currentScenario.value.communicationGraph = JSON.stringify(convertedGraph); + + message.success({ content: `成功加载 ${normalizedRelations.length} 条通信关系(无详细组件信息)`, key: 'loading-relations' }); + return; + } + + console.log(`获取到 ${platformResponse.data.length} 个平台的完整数据`); + platformResponse.data.forEach(platform => { + console.log(` 平台 "${platform.name}" (ID=${platform.id}) 有 ${platform.components?.length || 0} 个组件:`, + platform.components?.map(c => c.name)); + }); + + // 转换为图数据(传入完整的平台数据数组和场景ID) + const convertedGraph = convertRecordsToGraphContainer( + normalizedRelations, + undefined, + platformResponse.data, + currentScenario.value.id + ); + + // 验证转换后的节点数据结构 console.log('转换后的图数据:', convertedGraph); // 更新当前场景的图数据 @@ -469,10 +506,12 @@ export default defineComponent({ const handleSave = () => { const graphData: GraphContainer = resolveGraph(graph.value as Graph); + console.log(graph.value); + + const relations = resolveConnectionRelation(graph.value as Graph); console.error('relations',relations) - console.info('handleSave', graphData); if (!currentScenario.value) { message.error('当前决策树不存在'); diff --git a/modeler/src/views/decision/communication/data-converter.ts b/modeler/src/views/decision/communication/data-converter.ts index 01b0880..39f7aed 100644 --- a/modeler/src/views/decision/communication/data-converter.ts +++ b/modeler/src/views/decision/communication/data-converter.ts @@ -9,6 +9,8 @@ import type { GraphTaskElement, GraphContainer, GraphEdgeElement } from '../graph'; import { generateKey } from '@/utils/strings'; +import { createLineOptions } from '../graph/line'; +import type { PlatformWithComponents } from '../types/platform'; // ==================== 类型定义 ==================== @@ -121,11 +123,15 @@ const createVerticalMapper = (params: LayoutParams): CoordinateMapper => ({ * 从数据库记录转换为 GraphContainer 格式 * @param records 数据库通信关系记录数组 * @param config 布局配置(可选),默认为水平布局 + * @param platformsData 完整的平台数据数组(包含components),如果提供则优先使用 + * @param scenarioId 场景ID,用于设置节点的scenarioId字段 * @returns GraphContainer 格式的节点和边数据 */ export const convertRecordsToGraphContainer = ( records: CommunicationRecord[], - config?: Partial + config?: Partial, + platformsData?: PlatformWithComponents[], + scenarioId?: number ): GraphContainer => { if (!records || records.length === 0) { return { nodes: [], edges: [] }; @@ -140,6 +146,19 @@ export const convertRecordsToGraphContainer = ( startPosition: typeof config?.startPosition === 'number' ? config.startPosition : 80, }; + // 构建平台名称到完整数据的映射 + const platformDataMap = new Map(); + if (platformsData && platformsData.length > 0) { + platformsData.forEach(platform => { + if (platform.name) { + platformDataMap.set(platform.name, platform); + } + }); + console.log(`[convertRecordsToGraphContainer] 提供了 ${platformDataMap.size} 个平台的完整数据`); + } else { + console.warn('[convertRecordsToGraphContainer] 未提供平台完整数据,将使用简化的组件信息'); + } + // 收集所有唯一的平台名称(过滤无效值) const platformSet = new Set(); records.forEach(record => { @@ -221,8 +240,8 @@ export const convertRecordsToGraphContainer = ( mapper ); - // 创建节点对象 - const nodeMap = createNodeObjects(levelsMap, nodePositions); + // 创建节点对象(传入完整的平台数据映射和场景ID) + const nodeMap = createNodeObjects(levelsMap, nodePositions, platformDataMap, scenarioId); console.log(` 分量 ${componentIndex + 1} 创建了 ${nodeMap.size} 个节点:`, Array.from(nodeMap.keys())); @@ -230,7 +249,7 @@ export const convertRecordsToGraphContainer = ( if (!nodeMap.has(rootPlatformName)) { console.warn(` 根节点 "${rootPlatformName}" 未在 levelsMap 中找到,手动创建`); } - createRootNode(nodeMap, rootPlatformName, parentToChildren, layoutParams, mapper); + createRootNode(nodeMap, rootPlatformName, parentToChildren, layoutParams, mapper, platformDataMap, scenarioId); console.log(` 最终节点数: ${nodeMap.size}`); @@ -238,7 +257,7 @@ export const convertRecordsToGraphContainer = ( const componentEdges = filterEdgesForComponent(records, component); const edges = createEdges(componentEdges, nodeMap); - // 添加到总结果 + // 将GraphTaskElement直接添加到总结果(GraphContainer需要的是GraphTaskElement[]) allNodes.push(...Array.from(nodeMap.values())); allEdges.push(...edges); @@ -679,43 +698,58 @@ const restoreIsoscelesTriangles = ( const createNodeObjects = ( levelsMap: Map, - nodePositions: Map + nodePositions: Map, + platformDataMap: Map, + scenarioId?: number ): Map => { const nodeMap = new Map(); levelsMap.forEach((platformsInLevel, level) => { platformsInLevel.forEach(platform => { const pos = nodePositions.get(platform)!; - const componentId = 1; + + // 从映射表中获取平台完整数据 + const platformData = platformDataMap.get(platform); + const platformId = platformData?.id || 0; + + // 优先使用platformData自带的scenarioId,其次使用传入的参数 + const nodeScenarioId = platformData?.scenarioId ?? scenarioId ?? 0; + + // 使用真实的组件数据(保持完整结构),如果没有则创建默认组件 + const components = platformData?.components && platformData.components.length > 0 + ? platformData.components // 直接使用完整组件数组,不做字段筛选 + : [ + { + id: 1, + name: `${platform}_comm`, + type: 'communication', + description: `通信组件` + } + ]; + + console.log(`[createNodeObjects] 平台 "${platform}" 有 ${components.length} 个组件:`, components.map(c => c.name)); const node: GraphTaskElement = { id: 0, key: generateKey(), type: 'scenario', name: platform, - platformId: 0, - scenarioId: 0, - components: [ - { - id: componentId, - name: `${platform}_comm`, - type: 'communication', - description: `通信组件` - } - ], + platformId: platformId, + scenarioId: nodeScenarioId, // 修复:优先使用platformData.scenarioId + components: components, template: 0, templateType: null, category: null, multiable: false, group: null, - description: platform, + description: platformData?.description || platform, order: 0, position: { x: Math.round(pos.x), y: Math.round(pos.y), }, width: 250, - height: 145, + height: 120, inputs: null, outputs: null, parameters: [], @@ -736,7 +770,9 @@ const createRootNode = ( rootPlatformName: string, parentToChildren: Map, params: LayoutParams, - mapper: CoordinateMapper + mapper: CoordinateMapper, + platformDataMap: Map, + scenarioId?: number ): void => { if (nodeMap.size === 0 || !rootPlatformName) return; @@ -766,31 +802,45 @@ const createRootNode = ( centerSecondaryCoord = (minCoord + maxCoord) / 2; } + // 从映射表中获取平台完整数据 + const platformData = platformDataMap.get(rootPlatformName); + const platformId = platformData?.id || 0; + + // 优先使用platformData自带的scenarioId,其次使用传入的参数 + const rootNodeScenarioId = platformData?.scenarioId ?? scenarioId ?? 0; + + // 使用真实的组件数据(保持完整结构),如果没有则创建默认组件 + const components = platformData?.components && platformData.components.length > 0 + ? platformData.components // 直接使用完整组件数组,不做字段筛选 + : [ + { + id: 1, + name: `${rootPlatformName}_comm`, + type: 'communication', + description: `通信组件` + } + ]; + + console.log(`[createRootNode] 根节点 "${rootPlatformName}" 有 ${components.length} 个组件:`, components.map(c => c.name)); + const rootNode: GraphTaskElement = { id: 0, key: generateKey(), type: 'scenario', name: rootPlatformName, - platformId: 0, - scenarioId: 0, - components: [ - { - id: 1, - name: `${rootPlatformName}_comm`, - type: 'communication', - description: `通信组件` - } - ], + platformId: platformId, + scenarioId: rootNodeScenarioId, // 修复:优先使用platformData.scenarioId + components: components, template: 0, templateType: null, category: null, multiable: false, group: null, - description: rootPlatformName, + description: platformData?.description || rootPlatformName, order: 0, position: mapper.setCoords(params.ROOT_POSITION, Math.round(centerSecondaryCoord)), width: 250, - height: 145, + height: 120, inputs: null, outputs: null, parameters: [], @@ -813,19 +863,48 @@ const createEdges = ( const targetNode = nodeMap.get(record.subordinate_platform); if (sourceNode && targetNode && sourceNode.key && targetNode.key) { - const sourceCompId = sourceNode.components?.[0]?.id || 1; - const targetCompId = targetNode.components?.[0]?.id || 1; + // 根据通信组件名称查找对应的组件 + const sourceComp = sourceNode.components?.find( + comp => comp.name === record.command_comm + ); + const targetComp = targetNode.components?.find( + comp => comp.name === record.subordinate_comm + ); + + if (!sourceComp || !targetComp) { + console.warn(`无法找到匹配的组件 - 记录 ${index + 1}:`, { + record, + sourceComps: sourceNode.components?.map(c => c.name), + targetComps: targetNode.components?.map(c => c.name), + }); + return; + } + + // 根据node.vue的命名规则生成端口ID + // 格式:out-{comp.id} 或 in-{comp.id} + const sourcePortId = `out-${sourceComp.id}`; + const targetPortId = `in-${targetComp.id}`; edges.push({ id: index + 1, key: generateKey(), - source: sourceNode.key, - target: targetNode.key, - sourcePort: `out-${sourceCompId}`, - targetPort: `in-${targetCompId}`, - attrs: {}, - router: { name: 'normal' }, - connector: { name: 'smooth' }, + source: { + cell: sourceNode.key, + port: sourcePortId, + }, + target: { + cell: targetNode.key, + port: targetPortId, + }, + ...createLineOptions(), // 应用标准边样式配置 + }); + } else { + console.warn(`无法创建边 ${index + 1}:`, { + record, + sourceNodeExists: !!sourceNode, + targetNodeExists: !!targetNode, + sourceKey: sourceNode?.key, + targetKey: targetNode?.key, }); } }); @@ -835,30 +914,6 @@ const createEdges = ( // ==================== 新增功能:平台数据转通信关系 ==================== -/** - * 平台组件接口(来自后端API) - */ -export interface PlatformComponent { - id: number; - name: string | null; - type: string | null; - description: string | null; - platformId: number; - [key: string]: unknown; -} - -/** - * 带组件的平台接口(来自后端API) - */ -export interface PlatformWithComponents { - id: number; - name: string | null; - description: string | null; - scenarioId: number; - components: PlatformComponent[]; - [key: string]: unknown; -} - /** * 智能推断通信关系的策略类型 */