Merge branch 'feature-transform-node-data'
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import { HttpRequestClient } from '@/utils/request';
|
||||
import type { Scenario, ScenarioDetailsResponse, ScenarioPageableResponse, ScenarioRequest } from './types';
|
||||
import type { Scenario, ScenarioDetailsResponse, ScenarioPageableResponse, ScenarioRequest, CommunicationRelationsResponse } from './types';
|
||||
import type { PlatformWithComponentsResponse } from '../types';
|
||||
import type { BasicResponse } from '@/types';
|
||||
import type { BehaviorTree } from '../designer/tree';
|
||||
@@ -33,6 +33,15 @@ export const findPlatformWithComponents = (id: number): Promise<PlatformWithComp
|
||||
return req.get<PlatformWithComponentsResponse>(`/system/firerule/platforms/${id}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取场景的所有通信关系
|
||||
* @param id 场景ID
|
||||
* @returns 通信关系列表
|
||||
*/
|
||||
export const findRelations = (id: number): Promise<CommunicationRelationsResponse> => {
|
||||
return req.get<CommunicationRelationsResponse>(`/system/scene/getAllRelation/${id}`);
|
||||
};
|
||||
|
||||
export const saveScenario = (scenario: Scenario): Promise<BasicResponse> => {
|
||||
return req.postJson<BasicResponse>(`/system/scene/saveSceneConfig`,scenario);
|
||||
};
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
<div class="ks-model-builder-content" style="width: calc(100% - 250px);">
|
||||
<div class="ks-model-builder-actions">
|
||||
<a-space>
|
||||
<a-button v-if="graph && currentScenario" class="ks-model-builder-save" style="width: auto;" size="small" @click="handleGenerateRandom">
|
||||
<ThunderboltOutlined />
|
||||
<span>随机生成</span>
|
||||
</a-button>
|
||||
<a-button v-if="graph && currentScenario && currentScenario.id > 0" class="ks-model-builder-save" style="width: auto;" size="small" @click="handleLoadFromBackend">
|
||||
<DatabaseOutlined />
|
||||
<span>从后端加载</span>
|
||||
</a-button>
|
||||
<a-button v-if="graph && currentScenario" class="ks-model-builder-save" size="small" @click="handleSave">
|
||||
<CheckOutlined />
|
||||
<span>保存</span>
|
||||
@@ -50,22 +58,24 @@ import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { getTeleport } from '@antv/x6-vue-shape';
|
||||
import { Graph, Node, type NodeProperties } from '@antv/x6';
|
||||
import { CheckCircleOutlined, CheckOutlined, RollbackOutlined, SaveOutlined } from '@ant-design/icons-vue';
|
||||
import { CheckCircleOutlined, CheckOutlined, DatabaseOutlined, RollbackOutlined, SaveOutlined, ThunderboltOutlined } from '@ant-design/icons-vue';
|
||||
import { Wrapper } from '@/components/wrapper';
|
||||
import { safePreventDefault, safeStopPropagation } from '@/utils/event';
|
||||
import Header from '../header.vue';
|
||||
|
||||
import type { Scenario } from './types';
|
||||
import type { PlatformWithComponents } from '../types';
|
||||
import { createLineOptions, type GraphContainer, type GraphTaskElement, resolveGraph, useGraphCanvas } from '../graph';
|
||||
import { createLineOptions, type GraphContainer, type GraphEdgeElement, type GraphTaskElement, resolveGraph, useGraphCanvas } from '../graph';
|
||||
|
||||
import { registerScenarioElement } from './register';
|
||||
import { createGraphScenarioElement, createGraphTaskElementFromScenario } from './utils';
|
||||
|
||||
import PlatformCard from './platform-card.vue';
|
||||
import NodesCard from './nodes-card.vue';
|
||||
import { findOneScenarioById, saveScenario, getAllBehaviorTreesBySceneId } from './api';
|
||||
import { findOneScenarioById, saveScenario, findRelations } from './api';
|
||||
import { resolveConnectionRelation } from './relation';
|
||||
import { generateRandomCommunicationData } from './random-data-generator';
|
||||
import { convertRecordsToGraphContainer, type CommunicationRecord } from './data-converter';
|
||||
|
||||
const TeleportContainer = defineComponent(getTeleport());
|
||||
|
||||
@@ -81,6 +91,8 @@ export default defineComponent({
|
||||
CheckCircleOutlined,
|
||||
CheckOutlined,
|
||||
RollbackOutlined,
|
||||
ThunderboltOutlined,
|
||||
DatabaseOutlined,
|
||||
TeleportContainer,
|
||||
},
|
||||
setup() {
|
||||
@@ -218,36 +230,67 @@ export default defineComponent({
|
||||
} catch (e: any) {
|
||||
console.error('parse error,cause:', e);
|
||||
}
|
||||
if (!nodeGraph) {
|
||||
nodeGraph = {
|
||||
nodes: [],
|
||||
edges: [],
|
||||
};
|
||||
}
|
||||
|
||||
// 设置当前场景
|
||||
currentScenario.value = {
|
||||
...scenario,
|
||||
graph: nodeGraph,
|
||||
graph: nodeGraph || { nodes: [], edges: [] },
|
||||
relations: []
|
||||
};
|
||||
console.log('选中场景:', currentScenario.value);
|
||||
|
||||
currentScenarioEditing.value = true;
|
||||
|
||||
// 将场景ID存储到graph对象中,供子组件访问
|
||||
if (graph.value) {
|
||||
(graph.value as any).currentScenario = currentScenario.value;
|
||||
|
||||
// 加载该场景下的行为树列表
|
||||
// 如果场景有ID且没有已保存的图数据,尝试从后端加载通信关系
|
||||
if (scenario.id > 0 && !nodeGraph) {
|
||||
try {
|
||||
const response = await getAllBehaviorTreesBySceneId(scenario.id);
|
||||
if (response.code === 200 && response.data) {
|
||||
(graph.value as any).behaviorTrees = response.data;
|
||||
console.log(`加载场景${scenario.id}的行为树列表:`, response.data.length, '个');
|
||||
message.loading({ content: '正在加载通信关系...', key: 'loading-relations' });
|
||||
const response = await findRelations(scenario.id);
|
||||
|
||||
console.log('API完整响应:', response);
|
||||
|
||||
// 解析API响应(支持多种格式)
|
||||
let relations: any[] = [];
|
||||
if (Array.isArray(response.data)) {
|
||||
relations = response.data;
|
||||
} else if (response.data && Array.isArray((response.data as any).data)) {
|
||||
relations = (response.data as any).data;
|
||||
} else if (response.data && Array.isArray((response.data as any).rows)) {
|
||||
relations = (response.data as any).rows;
|
||||
} else if (response.data && Array.isArray((response.data as any).list)) {
|
||||
relations = (response.data as any).list;
|
||||
}
|
||||
|
||||
console.log('解析后的通信关系数量:', relations.length);
|
||||
|
||||
if (relations.length > 0) {
|
||||
// 字段名标准化(驼峰转下划线)
|
||||
const normalizedRelations = relations.map((item: any) => ({
|
||||
id: item.id,
|
||||
command_platform: item.commandPlatform || item.command_platform,
|
||||
subordinate_platform: item.subordinatePlatform || item.subordinate_platform,
|
||||
command_comm: item.commandComm || item.command_comm,
|
||||
subordinate_comm: item.subordinateComm || item.subordinate_comm,
|
||||
scenary_id: item.scenaryId || item.scenary_id,
|
||||
}));
|
||||
|
||||
console.log('标准化后的第一条记录:', normalizedRelations[0]);
|
||||
|
||||
// 转换为图数据
|
||||
const convertedGraph = convertRecordsToGraphContainer(normalizedRelations);
|
||||
console.log('转换后的图数据:', convertedGraph);
|
||||
|
||||
// 更新当前场景的图数据
|
||||
currentScenario.value.graph = convertedGraph;
|
||||
currentScenario.value.communicationGraph = JSON.stringify(convertedGraph);
|
||||
|
||||
message.success({ content: `成功加载 ${normalizedRelations.length} 条通信关系`, key: 'loading-relations' });
|
||||
} else {
|
||||
(graph.value as any).behaviorTrees = [];
|
||||
console.warn('获取行为树列表失败:', response.msg);
|
||||
message.warning({ content: '该场景暂无通信关系数据', key: 'loading-relations' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取行为树列表失败:', error);
|
||||
(graph.value as any).behaviorTrees = [];
|
||||
console.error('从后端加载通信关系失败:', error);
|
||||
message.error({ content: '加载通信关系失败,请手动点击"从后端加载"', key: 'loading-relations' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,6 +325,7 @@ export default defineComponent({
|
||||
}, 100); // 延迟一会儿,免得连线错位
|
||||
}
|
||||
}
|
||||
|
||||
}, 100);
|
||||
});
|
||||
};
|
||||
@@ -442,6 +486,193 @@ export default defineComponent({
|
||||
});
|
||||
};
|
||||
|
||||
// 随机生成节点流图
|
||||
const handleGenerateRandom = () => {
|
||||
if (!graph.value) {
|
||||
message.error('画布未初始化');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 生成随机数据
|
||||
const { records, graph: randomGraph } = generateRandomCommunicationData(30);
|
||||
|
||||
console.log('生成的随机数据:', records);
|
||||
console.log('转换后的图数据:', randomGraph);
|
||||
|
||||
// 清空现有内容
|
||||
graph.value.clearCells();
|
||||
|
||||
// 设置当前场景
|
||||
if (!currentScenario.value) {
|
||||
currentScenario.value = {
|
||||
id: 0,
|
||||
name: `随机场景_${Date.now()}`,
|
||||
description: '自动生成的测试场景',
|
||||
communicationGraph: null,
|
||||
relations: [],
|
||||
graph: randomGraph,
|
||||
};
|
||||
} else {
|
||||
currentScenario.value.graph = randomGraph;
|
||||
currentScenario.value.communicationGraph = JSON.stringify(randomGraph);
|
||||
}
|
||||
|
||||
// 渲染节点
|
||||
setTimeout(() => {
|
||||
if (randomGraph.nodes) {
|
||||
randomGraph.nodes.forEach(ele => {
|
||||
const node = createGraphScenarioElement(ele as GraphTaskElement);
|
||||
graph.value?.addNode(node as Node);
|
||||
});
|
||||
}
|
||||
|
||||
// 延迟添加边,确保节点已渲染
|
||||
setTimeout(() => {
|
||||
if (randomGraph.edges) {
|
||||
randomGraph.edges.forEach(edgeData => {
|
||||
graph.value?.addEdge({
|
||||
...edgeData,
|
||||
...createLineOptions(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 自动适应视图
|
||||
fitToScreen();
|
||||
|
||||
message.success(`已生成 ${randomGraph.nodes.length} 个节点和 ${randomGraph.edges.length} 条连接线`);
|
||||
}, 100);
|
||||
}, 50);
|
||||
|
||||
} catch (error) {
|
||||
console.error('随机生成时出错:', error);
|
||||
message.error('生成失败,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
// 从后端加载平台数据并转换为通信关系图(当前使用模拟数据)
|
||||
const handleLoadFromBackend = async () => {
|
||||
if (!graph.value || !currentScenario.value) {
|
||||
message.error('请先选择场景');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
message.loading({ content: '正在加载通信关系数据...', key: 'loading' });
|
||||
|
||||
// 调用真实API获取通信关系
|
||||
console.log(`正在从后端加载场景 ${currentScenario.value.id} 的通信关系...`);
|
||||
const response = await findRelations(currentScenario.value.id);
|
||||
|
||||
console.log('API完整响应:', response);
|
||||
console.log('response.data类型:', typeof response.data, Array.isArray(response.data) ? 'Array' : 'Object');
|
||||
|
||||
// API返回的是 CommunicationRelationRecord[],与 CommunicationRecord 结构兼容
|
||||
// 处理可能的多种返回格式
|
||||
let relations: any[] = [];
|
||||
if (Array.isArray(response.data)) {
|
||||
relations = response.data;
|
||||
} else if (response.data && Array.isArray((response.data as any).data)) {
|
||||
relations = (response.data as any).data;
|
||||
} else if (response.data && Array.isArray((response.data as any).rows)) {
|
||||
relations = (response.data as any).rows;
|
||||
} else if (response.data && Array.isArray((response.data as any).list)) {
|
||||
relations = (response.data as any).list;
|
||||
}
|
||||
|
||||
console.log('解析后的通信关系数量:', relations.length);
|
||||
if (relations.length > 0) {
|
||||
console.log('第一条记录:', JSON.stringify(relations[0], null, 2));
|
||||
}
|
||||
|
||||
// 后端返回的是驼峰命名,需要转换为下划线命名以匹配前端类型
|
||||
const normalizedRelations = relations.map((item: any) => ({
|
||||
id: item.id,
|
||||
command_platform: item.commandPlatform || item.command_platform,
|
||||
subordinate_platform: item.subordinatePlatform || item.subordinate_platform,
|
||||
command_comm: item.commandComm || item.command_comm,
|
||||
subordinate_comm: item.subordinateComm || item.subordinate_comm,
|
||||
scenary_id: item.scenaryId || item.scenary_id,
|
||||
}));
|
||||
|
||||
console.log('标准化后的第一条记录:', normalizedRelations[0]);
|
||||
|
||||
if (normalizedRelations.length === 0) {
|
||||
console.warn('API未返回任何通信关系数据,使用模拟数据作为fallback');
|
||||
// Fallback到模拟数据(保留以便测试)
|
||||
relations.push(
|
||||
{ id: 6, command_platform: 'chief', subordinate_platform: 'task1_commander', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 7, command_platform: 'chief', subordinate_platform: 'task2_commander', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 8, command_platform: 'chief', subordinate_platform: 'task3_commander', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 9, command_platform: 'task1_commander', subordinate_platform: 'platform1', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 10, command_platform: 'task1_commander', subordinate_platform: 'platform3', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 11, command_platform: 'task1_commander', subordinate_platform: 'platform4', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 12, command_platform: 'task1_commander', subordinate_platform: 'platform5', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 13, command_platform: 'task1_commander', subordinate_platform: 'platform6', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 14, command_platform: 'task2_commander', subordinate_platform: 'platform3', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 15, command_platform: 'task2_commander', subordinate_platform: 'platform5', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 16, command_platform: 'task2_commander', subordinate_platform: 'platform4', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 17, command_platform: 'task3_commander', subordinate_platform: 'platform6', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 18, command_platform: 'task3_commander', subordinate_platform: 'platform6', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 19, command_platform: 'task3_commander', subordinate_platform: 'platform7', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
{ id: 20, command_platform: 'task3_commander', subordinate_platform: 'platform8', command_comm: 'radio', subordinate_comm: 'radio', scenary_id: currentScenario.value.id },
|
||||
);
|
||||
}
|
||||
|
||||
console.log('最终使用的通信记录:', normalizedRelations);
|
||||
|
||||
// 使用数据进行转换
|
||||
const convertedGraph = convertRecordsToGraphContainer(normalizedRelations);
|
||||
|
||||
console.log('转换后的图数据:', convertedGraph);
|
||||
|
||||
// 清空现有内容
|
||||
graph.value.clearCells();
|
||||
|
||||
// 更新当前场景
|
||||
currentScenario.value.graph = convertedGraph;
|
||||
currentScenario.value.communicationGraph = JSON.stringify(convertedGraph);
|
||||
|
||||
// 渲染节点
|
||||
setTimeout(() => {
|
||||
if (convertedGraph.nodes) {
|
||||
convertedGraph.nodes.forEach(ele => {
|
||||
const node = createGraphScenarioElement(ele as GraphTaskElement);
|
||||
graph.value?.addNode(node as Node);
|
||||
});
|
||||
}
|
||||
|
||||
// 延迟添加边,确保节点已渲染
|
||||
setTimeout(() => {
|
||||
if (convertedGraph.edges) {
|
||||
convertedGraph.edges.forEach(edgeData => {
|
||||
graph.value?.addEdge({
|
||||
...edgeData,
|
||||
...createLineOptions(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 自动适应视图
|
||||
fitToScreen();
|
||||
|
||||
message.success({
|
||||
content: `已从后端加载 ${convertedGraph.nodes.length} 个平台和 ${convertedGraph.edges.length} 条连接关系`,
|
||||
key: 'loading'
|
||||
});
|
||||
}, 100);
|
||||
}, 50);
|
||||
|
||||
} catch (error) {
|
||||
console.error('从后端加载时出错:', error);
|
||||
message.error({
|
||||
content: error instanceof Error ? error.message : '加载失败,请重试',
|
||||
key: 'loading'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
init();
|
||||
@@ -471,6 +702,8 @@ export default defineComponent({
|
||||
handleDrop,
|
||||
isDraggingOver,
|
||||
handleSave,
|
||||
handleGenerateRandom,
|
||||
handleLoadFromBackend,
|
||||
handleUpdateElement,
|
||||
handleSelect,
|
||||
};
|
||||
|
||||
1049
modeler/src/views/decision/communication/data-converter.ts
Normal file
1049
modeler/src/views/decision/communication/data-converter.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { GraphContainer } from '../graph';
|
||||
import { convertRecordsToGraphContainer, type CommunicationRecord } from './data-converter';
|
||||
|
||||
/**
|
||||
* 生成随机的通信关系数据用于测试
|
||||
* @param nodeCount 节点数量(默认5-8个)
|
||||
* @param edgeDensity 边的密度(0.3-0.7之间,表示连接概率)
|
||||
* @returns 随机生成的通信关系记录和对应的GraphContainer
|
||||
*/
|
||||
export const generateRandomCommunicationData = (
|
||||
nodeCount: number = Math.floor(Math.random() * 4) + 5, // 5-8个节点
|
||||
edgeDensity: number = 0.5
|
||||
): { records: CommunicationRecord[]; graph: GraphContainer } => {
|
||||
// 生成随机平台名称
|
||||
const platformTypes = ['指挥中心', '雷达站', '导弹阵地', '预警机', '战斗机', '驱逐舰', '潜艇', '电子战飞机'];
|
||||
const platforms: string[] = [];
|
||||
|
||||
for (let i = 0; i < nodeCount; i++) {
|
||||
const baseName = platformTypes[i % platformTypes.length];
|
||||
const suffix = Math.floor(i / platformTypes.length) > 0 ? `-${Math.floor(i / platformTypes.length) + 1}` : '';
|
||||
platforms.push(`${baseName}${suffix}`);
|
||||
}
|
||||
|
||||
// 生成随机通信关系 - 改进版:更符合实际指挥层级
|
||||
const records: CommunicationRecord[] = [];
|
||||
let recordId = 1;
|
||||
|
||||
// 确定根节点(指挥中心)
|
||||
const rootPlatformName = platforms.find(p => p.includes('指挥')) || platforms[0] || '默认平台';
|
||||
const rootIndex = platforms.indexOf(rootPlatformName);
|
||||
|
||||
if (rootIndex === -1) {
|
||||
console.warn('未找到根节点,使用第一个平台');
|
||||
return { records: [], graph: { nodes: [], edges: [] } };
|
||||
}
|
||||
|
||||
// 第一层:指挥中心直接管理的单位(通常是主要作战单元)
|
||||
// 选择2-4个作为一级下属
|
||||
const firstLevelCount = Math.min(Math.max(2, Math.floor(platforms.length / 2)), 4);
|
||||
const firstLevelIndices: number[] = [];
|
||||
|
||||
for (let i = 0; i < platforms.length && firstLevelIndices.length < firstLevelCount; i++) {
|
||||
if (i !== rootIndex) {
|
||||
firstLevelIndices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 建立第一层连接:指挥中心 -> 一级下属
|
||||
firstLevelIndices.forEach(idx => {
|
||||
const subordinatePlatform = platforms[idx];
|
||||
if (subordinatePlatform) {
|
||||
records.push({
|
||||
id: recordId++,
|
||||
command_platform: rootPlatformName,
|
||||
subordinate_platform: subordinatePlatform,
|
||||
command_comm: '加密指挥链路',
|
||||
subordinate_comm: '接收端',
|
||||
scenary_id: 1,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 第二层:一级下属可以有二级下属
|
||||
const remainingIndices = platforms.map((_, i) => i).filter(i =>
|
||||
i !== rootIndex && !firstLevelIndices.includes(i)
|
||||
);
|
||||
|
||||
remainingIndices.forEach(idx => {
|
||||
// 随机选择一个一级下属作为父节点
|
||||
const parentIdx = firstLevelIndices[Math.floor(Math.random() * firstLevelIndices.length)];
|
||||
|
||||
if (parentIdx !== undefined) {
|
||||
const parentPlatform = platforms[parentIdx];
|
||||
const childPlatform = platforms[idx];
|
||||
|
||||
if (parentPlatform && childPlatform) {
|
||||
records.push({
|
||||
id: recordId++,
|
||||
command_platform: parentPlatform,
|
||||
subordinate_platform: childPlatform,
|
||||
command_comm: Math.random() > 0.5 ? '战术数据链' : '无线通信',
|
||||
subordinate_comm: '双向通信',
|
||||
scenary_id: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 第三层:添加少量横向协同连接(不超过总边数的20%)
|
||||
const maxCrossLinks = Math.floor(records.length * 0.2);
|
||||
let crossLinkCount = 0;
|
||||
|
||||
if (platforms.length > 4 && crossLinkCount < maxCrossLinks) {
|
||||
// 在同级之间添加协同连接
|
||||
for (let i = 0; i < firstLevelIndices.length - 1 && crossLinkCount < maxCrossLinks; i++) {
|
||||
if (Math.random() < 0.4) { // 40%概率
|
||||
const j = i + 1 + Math.floor(Math.random() * 2);
|
||||
if (j < firstLevelIndices.length) {
|
||||
const idxI = firstLevelIndices[i];
|
||||
const idxJ = firstLevelIndices[j];
|
||||
|
||||
if (idxI !== undefined && idxJ !== undefined) {
|
||||
const platformI = platforms[idxI];
|
||||
const platformJ = platforms[idxJ];
|
||||
|
||||
if (platformI && platformJ) {
|
||||
const exists = records.some(r =>
|
||||
r.command_platform === platformI &&
|
||||
r.subordinate_platform === platformJ
|
||||
);
|
||||
|
||||
if (!exists) {
|
||||
records.push({
|
||||
id: recordId++,
|
||||
command_platform: platformI,
|
||||
subordinate_platform: platformJ,
|
||||
command_comm: '协同通信',
|
||||
subordinate_comm: '双向通信',
|
||||
scenary_id: 1,
|
||||
});
|
||||
crossLinkCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 转换为GraphContainer
|
||||
const graph = convertRecordsToGraphContainer(records);
|
||||
|
||||
return { records, graph };
|
||||
};
|
||||
@@ -48,3 +48,22 @@ export interface ScenarioDetailsResponse extends ApiDataResponse<Scenario> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 通信关系记录(对应数据库表结构)
|
||||
*/
|
||||
export interface CommunicationRelationRecord {
|
||||
id: number;
|
||||
command_platform: string; // 指挥平台名称
|
||||
subordinate_platform: string; // 下属平台名称
|
||||
command_comm?: string; // 指挥端通信方式
|
||||
subordinate_comm?: string; // 下属端通信方式
|
||||
scenary_id?: number; // 场景ID
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景所有通信关系的响应
|
||||
*/
|
||||
export interface CommunicationRelationsResponse extends ApiDataResponse<CommunicationRelationRecord[]> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user