feat: 更新地面站和卫星状态管理为使用 Set
Some checks failed
/ build-and-deploy-to-vercel (push) Successful in 3m13s
/ lint-build-and-check (push) Successful in 4m38s
/ playwright (push) Failing after 12m17s
/ surge (push) Successful in 2m47s

This commit is contained in:
严浩
2025-04-02 19:09:00 +08:00
parent 02ce0fa9a0
commit 7261a45cab
12 changed files with 180 additions and 68 deletions

View File

@ -1,15 +1,27 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import { eciToEcf, gstime, propagate, type SatRec, twoline2satrec } from 'satellite.js'; import {
eciToEcf,
gstime,
propagate,
type SatRec,
twoline2satrec,
} from 'satellite.js';
import type { GroundStationOptions, SatelliteOptions } from './h-cesium-viewer-class.types'; // 2小时 import type {
GroundStationOptions,
SatelliteOptions,
} from './h-cesium-viewer-class.types';
import { VIEWER_OPTIONS_FN } from './helper/_VIEWER_OPTIONS'; import { VIEWER_OPTIONS_FN } from './helper/_VIEWER_OPTIONS';
import { configureCesium } from './helper/configureCesium'; import { configureCesium } from './helper/configureCesium';
import { configureTimeLine } from './helper/configureTimeLine'; import { configureTimeLine } from './helper/configureTimeLine';
const = 2 * 60 * 60; const = 2 * 60 * 60; // 2小时
export { type GroundStationOptions, type SatelliteOptions } from './h-cesium-viewer-class.types'; export {
type GroundStationOptions,
type SatelliteOptions,
} from './h-cesium-viewer-class.types';
Cesium.Ion.defaultAccessToken = import.meta.env.VITE_CESIUM_ION_TOKEN; // 用了离线地图的情况是不需要的。 Cesium.Ion.defaultAccessToken = import.meta.env.VITE_CESIUM_ION_TOKEN; // 用了离线地图的情况是不需要的。
@ -67,12 +79,19 @@ export class HCesiumViewerCls {
} }
// 解构赋值获取站点信息 // 解构赋值获取站点信息
const { height = 0, id, latitude, longitude, name, pixelSize = 10 } = options; const {
height = 0,
id,
latitude,
longitude,
name,
pixelSize = 10,
} = options;
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height); const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
const groundStationEntity = new Cesium.Entity({ const groundStationEntity = new Cesium.Entity({
// 使用传入的 id 作为实体的唯一标识符 // 使用传入的 id 作为实体的唯一标识符
id: id, id,
label: { label: {
font: '14pt sans-serif', font: '14pt sans-serif',
outlineWidth: 2, outlineWidth: 2,
@ -81,14 +100,14 @@ export class HCesiumViewerCls {
text: name, text: name,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
}, },
name: name, name,
point: { point: {
color: Cesium.Color.fromRandom(), // 随机颜色 color: Cesium.Color.fromRandom(), // 随机颜色
outlineColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.WHITE,
outlineWidth: 2, outlineWidth: 2,
pixelSize, pixelSize,
}, },
position: position, position,
}); });
const addedEntity = this.viewer.entities.add(groundStationEntity); const addedEntity = this.viewer.entities.add(groundStationEntity);
@ -161,9 +180,11 @@ export class HCesiumViewerCls {
} = options; } = options;
// --- 从 tle 字符串解析 name, tle1, tle2 --- // --- 从 tle 字符串解析 name, tle1, tle2 ---
const tleLines = tle.trim().split('\n'); const tleLines = tle.trim().split('\n') as [string, string, string];
if (tleLines.length < 3) { if (tleLines.length < 3) {
console.error(`无效的 TLE 格式 (ID: ${id}): TLE 字符串 "${tle}" 至少需要三行`); console.error(
`无效的 TLE 格式 (ID: ${id}): TLE 字符串 "${tle}" 至少需要三行`,
);
return null; return null;
} }
const name = tleLines[0].trim(); const name = tleLines[0].trim();
@ -185,8 +206,8 @@ export class HCesiumViewerCls {
// 创建卫星实体 // 创建卫星实体
const satelliteEntity = this.viewer.entities.add({ const satelliteEntity = this.viewer.entities.add({
id: id, id,
name: name, name,
label: { label: {
text: name, text: name,
font: '14pt sans-serif', font: '14pt sans-serif',
@ -223,7 +244,11 @@ export class HCesiumViewerCls {
const orbitPositions: Cesium.Cartesian3[] = []; // 用于存储完整轨道点 const orbitPositions: Cesium.Cartesian3[] = []; // 用于存储完整轨道点
for (let i = 0; i <= orbitDurationSeconds; i += timeStepSeconds) { for (let i = 0; i <= orbitDurationSeconds; i += timeStepSeconds) {
const time = Cesium.JulianDate.addSeconds(startTime, i, new Cesium.JulianDate()); const time = Cesium.JulianDate.addSeconds(
startTime,
i,
new Cesium.JulianDate(),
);
const jsDate = Cesium.JulianDate.toDate(time); const jsDate = Cesium.JulianDate.toDate(time);
try { try {
@ -238,7 +263,11 @@ export class HCesiumViewerCls {
const positionEcf = eciToEcf(positionAndVelocity.position, gmst); const positionEcf = eciToEcf(positionAndVelocity.position, gmst);
// 转换为 Cesium 坐标(单位:米) // 转换为 Cesium 坐标(单位:米)
const cesiumPosition = new Cesium.Cartesian3(positionEcf.x * 1000, positionEcf.y * 1000, positionEcf.z * 1000); const cesiumPosition = new Cesium.Cartesian3(
positionEcf.x * 1000,
positionEcf.y * 1000,
positionEcf.z * 1000,
);
// 添加位置样本 // 添加位置样本
positionProperty.addSample(time, cesiumPosition); positionProperty.addSample(time, cesiumPosition);
@ -254,7 +283,9 @@ export class HCesiumViewerCls {
// 设置卫星的位置和方向 // 设置卫星的位置和方向
satelliteEntity.position = positionProperty; satelliteEntity.position = positionProperty;
satelliteEntity.orientation = new Cesium.VelocityOrientationProperty(positionProperty); satelliteEntity.orientation = new Cesium.VelocityOrientationProperty(
positionProperty,
);
// --- 添加卫星地面覆盖范围 --- // --- 添加卫星地面覆盖范围 ---
// 使用 CallbackProperty 动态计算星下点位置 // 使用 CallbackProperty 动态计算星下点位置
@ -266,7 +297,8 @@ export class HCesiumViewerCls {
return; // 如果位置无效,则不返回任何内容 return; // 如果位置无效,则不返回任何内容
} }
// 转换为地理坐标(包含高度) // 转换为地理坐标(包含高度)
const satelliteCartographic = Cesium.Cartographic.fromCartesian(satelliteCartesian); const satelliteCartographic =
Cesium.Cartographic.fromCartesian(satelliteCartesian);
if (!satelliteCartographic) { if (!satelliteCartographic) {
return; // 如果转换失败,则不返回任何内容 return; // 如果转换失败,则不返回任何内容
} }
@ -277,7 +309,11 @@ export class HCesiumViewerCls {
0, 0,
); );
// 转换回笛卡尔坐标 // 转换回笛卡尔坐标
return Cesium.Cartographic.toCartesian(subsatelliteCartographic, Cesium.Ellipsoid.WGS84, result); return Cesium.Cartographic.toCartesian(
subsatelliteCartographic,
Cesium.Ellipsoid.WGS84,
result,
);
}, },
false, false,
Cesium.ReferenceFrame.FIXED, Cesium.ReferenceFrame.FIXED,
@ -289,7 +325,8 @@ export class HCesiumViewerCls {
if (!satelliteCartesian) { if (!satelliteCartesian) {
return 100_000; // 默认半径 100km return 100_000; // 默认半径 100km
} }
const satelliteCartographic = Cesium.Cartographic.fromCartesian(satelliteCartesian); const satelliteCartographic =
Cesium.Cartographic.fromCartesian(satelliteCartesian);
if (!satelliteCartographic) { if (!satelliteCartographic) {
return 100_000; return 100_000;
} }
@ -336,7 +373,11 @@ export class HCesiumViewerCls {
} }
// 存储实体引用 // 存储实体引用
this.currentSatelliteEntities.set(id, { entity: satelliteEntity, orbitEntity, coverageEntity }); this.currentSatelliteEntities.set(id, {
entity: satelliteEntity,
orbitEntity,
coverageEntity,
});
return satelliteEntity; return satelliteEntity;
} }
@ -361,7 +402,9 @@ export class HCesiumViewerCls {
if (satelliteData.entity) { if (satelliteData.entity) {
removedMain = this.viewer.entities.remove(satelliteData.entity); removedMain = this.viewer.entities.remove(satelliteData.entity);
if (!removedMain) { if (!removedMain) {
console.warn(`尝试从 Cesium 移除卫星主体 ID 为 "${entityId}" 的实体失败。`); console.warn(
`尝试从 Cesium 移除卫星主体 ID 为 "${entityId}" 的实体失败。`,
);
} }
} }
@ -369,15 +412,21 @@ export class HCesiumViewerCls {
if (satelliteData.orbitEntity) { if (satelliteData.orbitEntity) {
removedOrbit = this.viewer.entities.remove(satelliteData.orbitEntity); removedOrbit = this.viewer.entities.remove(satelliteData.orbitEntity);
if (!removedOrbit) { if (!removedOrbit) {
console.warn(`尝试从 Cesium 移除卫星轨道 ID 为 "${satelliteData.orbitEntity.id}" 的实体失败。`); console.warn(
`尝试从 Cesium 移除卫星轨道 ID 为 "${satelliteData.orbitEntity.id}" 的实体失败。`,
);
} }
} }
// 移除覆盖范围 // 移除覆盖范围
if (satelliteData.coverageEntity) { if (satelliteData.coverageEntity) {
removedCoverage = this.viewer.entities.remove(satelliteData.coverageEntity); removedCoverage = this.viewer.entities.remove(
satelliteData.coverageEntity,
);
if (!removedCoverage) { if (!removedCoverage) {
console.warn(`尝试从 Cesium 移除卫星覆盖范围 ID 为 "${satelliteData.coverageEntity.id}" 的实体失败。`); console.warn(
`尝试从 Cesium 移除卫星覆盖范围 ID 为 "${satelliteData.coverageEntity.id}" 的实体失败。`,
);
} }
} }

View File

@ -1,19 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import 'cesium/Build/Cesium/Widgets/widgets.css';
import type { GroundStationState, SatelliteState } from './types'; import type { GroundStationState, SatelliteState } from './types';
import { useHCesiumViewerCls } from './useHCesiumViewerCls'; import { useHCesiumViewerCls } from './useHCesiumViewerCls';
import { useHCesiumViewerClsGroundStation } from './useHCesiumViewerClsGroundStation'; import { useHCesiumViewerClsGroundStation } from './useHCesiumViewerClsGroundStation';
import { useHCesiumViewerClsSatellite } from './useHCesiumViewerClsSatellite'; import { useHCesiumViewerClsSatellite } from './useHCesiumViewerClsSatellite';
import 'cesium/Build/Cesium/Widgets/widgets.css';
const props = defineProps<{ const props = defineProps<{
groundStationState?: GroundStationState; groundStationState?: GroundStationState;
satelliteState?: SatelliteState; satelliteState?: SatelliteState;
}>(); }>();
// 1. 管理 Cesium Viewer 实例生命周期 // 1. 管理 Cesium Viewer 实例生命周期
const { hCesiumViewerInst } = useHCesiumViewerCls('cesiumContainer'); const { hCesiumViewerInst } = useHCesiumViewerCls('cesium-container');
// 2. 同步地面站实体 // 2. 同步地面站实体
// 将实例的 getter 和 props 的 getter 传递给组合函数 // 将实例的 getter 和 props 的 getter 传递给组合函数
@ -32,14 +32,14 @@ useHCesiumViewerClsSatellite(
</script> </script>
<template> <template>
<div id="cesiumContainer" class="h-full w-full relative inset-0 isolate"> <div id="cesium-container" class="relative inset-0 isolate h-full w-full">
<slot /> <slot></slot>
</div> </div>
</template> </template>
<style scoped> <style scoped>
#cesiumContainer { #cesium-container {
min-height: 300px; min-height: 100px;
background-color: #000; background-color: #000;
} }
</style> </style>

View File

@ -16,5 +16,5 @@ export const TOOLTIP_MAP = {
ARG_OF_PERICENTER_近地点幅角: "8位数字如'181.9338'表示近地点相对升交点的角度范围0°-360°", ARG_OF_PERICENTER_近地点幅角: "8位数字如'181.9338'表示近地点相对升交点的角度范围0°-360°",
MEAN_ANOMALY_平近点角: "8位数字如'171.6150'表示历元时的平近点角范围0°-360°", MEAN_ANOMALY_平近点角: "8位数字如'171.6150'表示历元时的平近点角范围0°-360°",
MEAN_MOTION_平均运动: "11位数字如'2.21786616',表示卫星每天绕地球的圈数(圈/天)", MEAN_MOTION_平均运动: "11位数字如'2.21786616',表示卫星每天绕地球的圈数(圈/天)",
REV_AT_EPOCH_历元时的圈数: "5位数字如'13',表示卫星在历元时完成的轨道圈数最后以为是校验和共6位", REV_AT_EPOCH_历元时的圈数: "5位数字如'13',表示卫星在历元时完成的轨道圈数",
}; };

View File

@ -6,7 +6,9 @@ export const VIEWER_OPTIONS_FN = (): Viewer.ConstructorOptions => {
return { return {
animation: true, // .cesium-viewer-animationContainer https://cesium.com/learn/ion-sdk/ref-doc/Animation.html animation: true, // .cesium-viewer-animationContainer https://cesium.com/learn/ion-sdk/ref-doc/Animation.html
baseLayer: Cesium.ImageryLayer.fromProviderAsync( baseLayer: Cesium.ImageryLayer.fromProviderAsync(
Cesium.TileMapServiceImageryProvider.fromUrl(Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')), Cesium.TileMapServiceImageryProvider.fromUrl(
Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII'),
),
), ),
baseLayerPicker: false, baseLayerPicker: false,
fullscreenButton: !true, // 全屏按钮 fullscreenButton: !true, // 全屏按钮

View File

@ -20,18 +20,30 @@ export function configureCesium() {
// Animation 的时间日期格式化 // Animation 的时间日期格式化
Cesium.AnimationViewModel.defaultDateFormatter = function (date) { Cesium.AnimationViewModel.defaultDateFormatter = function (date) {
const dataZone8 = Cesium.JulianDate.addMinutes(date, minutes, new Cesium.JulianDate()); const dataZone8 = Cesium.JulianDate.addMinutes(
date,
minutes,
new Cesium.JulianDate(),
);
return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 10); return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 10);
}; };
Cesium.AnimationViewModel.defaultTimeFormatter = function (time) { Cesium.AnimationViewModel.defaultTimeFormatter = function (time) {
const dataZone8 = Cesium.JulianDate.addMinutes(time, minutes, new Cesium.JulianDate()); const dataZone8 = Cesium.JulianDate.addMinutes(
time,
minutes,
new Cesium.JulianDate(),
);
return Cesium.JulianDate.toIso8601(dataZone8).slice(11, 19); return Cesium.JulianDate.toIso8601(dataZone8).slice(11, 19);
}; };
// Timeline 的时间日期格式化 // Timeline 的时间日期格式化
// @ts-expect-error node_modules/@cesium/widgets/Source/Timeline/Timeline.js // @ts-expect-error node_modules/@cesium/widgets/Source/Timeline/Timeline.js
Cesium.Timeline.prototype.makeLabel = function (time) { Cesium.Timeline.prototype.makeLabel = function (time) {
const dataZone8 = Cesium.JulianDate.addMinutes(time, minutes, new Cesium.JulianDate()); const dataZone8 = Cesium.JulianDate.addMinutes(
time,
minutes,
new Cesium.JulianDate(),
);
return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19); return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19);
}; };
} }

View File

@ -19,8 +19,11 @@ export function configureMapTile(viewer: Cesium.Viewer) {
tooltip: '高德地图', tooltip: '高德地图',
}); });
// 设置高德地图为默认图层 // 设置高德地图为默认图层
viewer.baseLayerPicker.viewModel.imageryProviderViewModels.unshift(customLayerViewModel); viewer.baseLayerPicker.viewModel.imageryProviderViewModels.unshift(
const selectedViewModel = viewer.baseLayerPicker.viewModel.imageryProviderViewModels[0]; customLayerViewModel,
);
const selectedViewModel =
viewer.baseLayerPicker.viewModel.imageryProviderViewModels[0];
if (!selectedViewModel) { if (!selectedViewModel) {
console.error('未找到默认底图'); console.error('未找到默认底图');
return; return;

View File

@ -2,9 +2,16 @@ import * as Cesium from 'cesium';
const = 2 * 60 * 60; // 2小时 const = 2 * 60 * 60; // 2小时
export function configureTimeLine(viewer: Cesium.Viewer, totalSeconds = ) { export function configureTimeLine(
viewer: Cesium.Viewer,
totalSeconds = ,
) {
const start = Cesium.JulianDate.fromIso8601(new Date().toISOString()); const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());
const stop = Cesium.JulianDate.addSeconds(start, totalSeconds, new Cesium.JulianDate()); const stop = Cesium.JulianDate.addSeconds(
start,
totalSeconds,
new Cesium.JulianDate(),
);
// 设置时钟范围 // 设置时钟范围
viewer.clock.startTime = start.clone(); viewer.clock.startTime = start.clone();

View File

@ -1,4 +1,7 @@
import type { GroundStationOptions, SatelliteOptions } from './h-cesium-viewer-class'; import type {
GroundStationOptions,
SatelliteOptions,
} from './h-cesium-viewer-class';
/** /**
* 地面站状态接口 * 地面站状态接口
@ -7,8 +10,8 @@ import type { GroundStationOptions, SatelliteOptions } from './h-cesium-viewer-c
export interface GroundStationState { export interface GroundStationState {
/** 地面站配置数组 */ /** 地面站配置数组 */
groundStations: GroundStationOptions[]; groundStations: GroundStationOptions[];
/** 选中的地面站 ID 数组 */ /** 选中的地面站 ID 集合 */
selectedIds: string[]; selectedIds: Set<string>;
} }
/** /**
@ -18,6 +21,6 @@ export interface GroundStationState {
export interface SatelliteState { export interface SatelliteState {
/** 卫星配置数组 */ /** 卫星配置数组 */
satellites: SatelliteOptions[]; satellites: SatelliteOptions[];
/** 选中的卫星 ID 数组 */ /** 选中的卫星 ID 集合 */
selectedIds: string[]; selectedIds: Set<string>;
} }

View File

@ -1,5 +1,6 @@
// src/utils/useHCesiumViewerCls.ts // src/utils/useHCesiumViewerCls.ts
import { HCesiumViewerCls } from '@/components/h-cesium-viewer/h-cesium-viewer-class';
import { HCesiumViewerCls } from './h-cesium-viewer-class';
/** /**
* 管理 HCesiumViewerCls 实例的生命周期。 * 管理 HCesiumViewerCls 实例的生命周期。

View File

@ -1,17 +1,22 @@
// src/utils/useHCesiumViewerClsGroundStation.ts // src/utils/useHCesiumViewerClsGroundStation.ts
import type { GroundStationOptions, HCesiumViewerCls } from '@/components/h-cesium-viewer/h-cesium-viewer-class';
import type { MaybeRefOrGetter } from 'vue'; import type { MaybeRefOrGetter } from 'vue';
import type {
GroundStationOptions,
HCesiumViewerCls,
} from './h-cesium-viewer-class';
/** /**
* 管理 Cesium Viewer 中的地面站实体,根据选中的 ID 列表进行同步。 * 管理 Cesium Viewer 中的地面站实体,根据选中的 ID 列表进行同步。
* @param hCesiumViewerInst - HCesiumViewerCls 实例或其 getter。 * @param hCesiumViewerInst - HCesiumViewerCls 实例或其 getter。
* @param groundStationList - 包含所有可用地面站选项的数组或 getter。 * @param groundStationList - 包含所有可用地面站选项的数组或 getter。
* @param selectedStationIds - 包含当前选中地面站 ID 的数组或 getter。 * @param selectedStationIds - 包含当前选中地面站 ID 的 Set 或 getter。
*/ */
export function useHCesiumViewerClsGroundStation( export function useHCesiumViewerClsGroundStation(
hCesiumViewerInst: MaybeRefOrGetter<HCesiumViewerCls | null>, hCesiumViewerInst: MaybeRefOrGetter<HCesiumViewerCls | null>,
groundStationList: MaybeRefOrGetter<Array<GroundStationOptions> | undefined>, groundStationList: MaybeRefOrGetter<Array<GroundStationOptions> | undefined>,
selectedStationIds: MaybeRefOrGetter<string[] | undefined>, selectedStationIds: MaybeRefOrGetter<Set<string> | undefined>,
) { ) {
// 创建一个从 ID 到站点选项的映射,方便查找 // 创建一个从 ID 到站点选项的映射,方便查找
const stationMap = computed(() => { const stationMap = computed(() => {
@ -31,9 +36,10 @@ export function useHCesiumViewerClsGroundStation(
return; return;
} }
const selectedIds = toValue(selectedStationIds) ?? []; const selectedIdsSet = toValue(selectedStationIds) ?? new Set<string>(); // 直接获取 Set如果为 undefined 则创建空 Set
const selectedIdsSet = new Set(selectedIds); // 需要显示的站点 ID const currentEntityIds = new Set(
const currentEntityIds = new Set(viewerInstance.currentStationEntities.keys()); // 当前已显示的站点 ID viewerInstance.currentStationEntities.keys(),
); // 当前已显示的站点 ID
// 1. 移除不再选中的站点 // 1. 移除不再选中的站点
for (const entityId of currentEntityIds) { for (const entityId of currentEntityIds) {
@ -52,7 +58,9 @@ export function useHCesiumViewerClsGroundStation(
viewerInstance.addGroundStation(stationToAdd); viewerInstance.addGroundStation(stationToAdd);
} else { } else {
// 如果在 groundStationList 中找不到对应的站点信息,发出警告 // 如果在 groundStationList 中找不到对应的站点信息,发出警告
consola.warn(`无法找到 ID 为 "${selectedId}" 的站点信息,无法添加到地图。`); console.warn(
`无法找到 ID 为 "${selectedId}" 的站点信息,无法添加到地图。`,
);
} }
} }
} }

View File

@ -1,17 +1,22 @@
// src/components/h-cesium-viewer/useHCesiumViewerClsSatellite.ts // src/components/h-cesium-viewer/useHCesiumViewerClsSatellite.ts
import type { HCesiumViewerCls, SatelliteOptions } from '@/components/h-cesium-viewer/h-cesium-viewer-class';
import type { MaybeRefOrGetter } from 'vue'; import type { MaybeRefOrGetter } from 'vue';
import type {
HCesiumViewerCls,
SatelliteOptions,
} from './h-cesium-viewer-class';
/** /**
* 管理 Cesium Viewer 中的卫星实体,根据选中的 ID 列表进行同步。 * 管理 Cesium Viewer 中的卫星实体,根据选中的 ID 列表进行同步。
* @param hCesiumViewerInst - HCesiumViewerCls 实例或其 getter。 * @param hCesiumViewerInst - HCesiumViewerCls 实例或其 getter。
* @param satelliteList - 包含所有可用卫星选项的数组或 getter。 * @param satelliteList - 包含所有可用卫星选项的数组或 getter。
* @param selectedSatelliteIds - 包含当前选中卫星 ID 的数组或 getter。 * @param selectedSatelliteIds - 包含当前选中卫星 ID 的 Set 或 getter。
*/ */
export function useHCesiumViewerClsSatellite( export function useHCesiumViewerClsSatellite(
hCesiumViewerInst: MaybeRefOrGetter<HCesiumViewerCls | null>, hCesiumViewerInst: MaybeRefOrGetter<HCesiumViewerCls | null>,
satelliteList: MaybeRefOrGetter<Array<SatelliteOptions> | undefined>, satelliteList: MaybeRefOrGetter<Array<SatelliteOptions> | undefined>,
selectedSatelliteIds: MaybeRefOrGetter<string[] | undefined>, selectedSatelliteIds: MaybeRefOrGetter<Set<string> | undefined>,
) { ) {
// 创建一个从 ID 到卫星选项的映射,方便查找 // 创建一个从 ID 到卫星选项的映射,方便查找
const satelliteMap = computed(() => { const satelliteMap = computed(() => {
@ -31,9 +36,10 @@ export function useHCesiumViewerClsSatellite(
return; return;
} }
const selectedIds = toValue(selectedSatelliteIds) ?? []; const selectedIdsSet = toValue(selectedSatelliteIds) ?? new Set<string>(); // 直接获取 Set如果为 undefined 则创建空 Set
const selectedIdsSet = new Set(selectedIds); // 需要显示的卫星 ID const currentEntityIds = new Set(
const currentEntityIds = new Set(viewerInstance.currentSatelliteEntities.keys()); // 当前已显示的卫星 ID viewerInstance.currentSatelliteEntities.keys(),
); // 当前已显示的卫星 ID
// 1. 移除不再选中的卫星 // 1. 移除不再选中的卫星
for (const entityId of currentEntityIds) { for (const entityId of currentEntityIds) {
@ -49,10 +55,15 @@ export function useHCesiumViewerClsSatellite(
// 如果选中的 ID 对应的实体当前未显示,则添加 // 如果选中的 ID 对应的实体当前未显示,则添加
const satelliteToAdd = satelliteMap.value.get(selectedId); // 从映射中查找卫星信息 const satelliteToAdd = satelliteMap.value.get(selectedId); // 从映射中查找卫星信息
if (satelliteToAdd) { if (satelliteToAdd) {
console.debug(
`添加卫星 "${satelliteToAdd.id}" 到地图TLE: ${satelliteToAdd.tle}`,
);
viewerInstance.addSatellite(satelliteToAdd); viewerInstance.addSatellite(satelliteToAdd);
} else { } else {
// 如果在 satelliteList 中找不到对应的卫星信息,发出警告 // 如果在 satelliteList 中找不到对应的卫星信息,发出警告
consola.warn(`无法找到 ID 为 "${selectedId}" 的卫星信息,无法添加到地图。`); console.warn(
`无法找到 ID 为 "${selectedId}" 的卫星信息,无法添加到地图。`,
);
} }
} }
} }

View File

@ -9,7 +9,7 @@ import type { GroundStationState, SatelliteState } from '@/components/h-cesium-v
// 地面站和选中状态 // 地面站和选中状态
const groundStationState = reactive<GroundStationState>({ const groundStationState = reactive<GroundStationState>({
groundStations: [], groundStations: [],
selectedIds: [], selectedIds: new Set<string>(),
}); });
groundStationState.groundStations = [ groundStationState.groundStations = [
{ height: 50, id: 'gs-bj', latitude: 39.9042, longitude: 116.4074, name: '北京站' }, { height: 50, id: 'gs-bj', latitude: 39.9042, longitude: 116.4074, name: '北京站' },
@ -20,7 +20,7 @@ groundStationState.groundStations = [
// >>>>>>>>> 卫星状态管理 >>>>>>>>> // >>>>>>>>> 卫星状态管理 >>>>>>>>>
const satelliteState = reactive<SatelliteState>({ const satelliteState = reactive<SatelliteState>({
satellites: [], satellites: [],
selectedIds: [], selectedIds: new Set<string>(),
}); });
// 初始化卫星列表 // 初始化卫星列表
@ -51,6 +51,14 @@ const satelliteCheckboxOptions = computed(() =>
})), })),
); );
// 为卫星 a-checkbox-group 创建计算属性,处理 Set 和 Array 的转换
const selectedSatelliteIdsArray = computed({
get: () => [...satelliteState.selectedIds], // 从 Set 转换为 Array
set: (val: string[]) => {
satelliteState.selectedIds = new Set(val); // 从 Array 转换回 Set
},
});
// <<<<<<<<< 卫星状态管理 <<<<<<<<< // <<<<<<<<< 卫星状态管理 <<<<<<<<<
// 计算 Checkbox Group 的 options // 计算 Checkbox Group 的 options
@ -71,7 +79,7 @@ const addRandomStation = () => {
longitude: randomLon, longitude: randomLon,
name: `随机站 ${randomId.slice(-4)}`, name: `随机站 ${randomId.slice(-4)}`,
}); });
groundStationState.selectedIds.push(randomId); // 同时将新站点 ID 添加到选中项 groundStationState.selectedIds.add(randomId); // 同时将新站点 ID 添加到选中项
consola.info('添加随机站点:', groundStationState.groundStations.at(-1)); // 使用 .at() 访问最后一个元素 consola.info('添加随机站点:', groundStationState.groundStations.at(-1)); // 使用 .at() 访问最后一个元素
}; };
@ -82,7 +90,7 @@ const removeLastStation = () => {
if (removedStation) { if (removedStation) {
consola.info('移除站点:', removedStation); consola.info('移除站点:', removedStation);
// 同时从选中项中移除 // 同时从选中项中移除
groundStationState.selectedIds = groundStationState.selectedIds.filter((id) => id !== removedStation.id); groundStationState.selectedIds.delete(removedStation.id);
} }
} }
}; };
@ -90,9 +98,17 @@ const removeLastStation = () => {
// 清空所有选中项 // 清空所有选中项
const clearAllStations = () => { const clearAllStations = () => {
groundStationState.groundStations = []; groundStationState.groundStations = [];
groundStationState.selectedIds = []; // 清空选中项 groundStationState.selectedIds.clear(); // 清空选中项
consola.info('清空所有站点'); consola.info('清空所有站点');
}; };
// 为 a-checkbox-group 创建计算属性,处理 Set 和 Array 的转换
const selectedStationIdsArray = computed({
get: () => [...groundStationState.selectedIds], // 从 Set 转换为 Array
set: (val: string[]) => {
groundStationState.selectedIds = new Set(val); // 从 Array 转换回 Set
},
});
</script> </script>
<template> <template>
@ -113,22 +129,22 @@ const clearAllStations = () => {
>清空所有</a-button >清空所有</a-button
> >
<span>当前站点数: {{ groundStationState.groundStations.length }}</span> <span>当前站点数: {{ groundStationState.groundStations.length }}</span>
<span> | 选中站点数: {{ groundStationState.selectedIds.length }}</span> <span> | 选中站点数: {{ groundStationState.selectedIds.size }}</span>
</div> </div>
<!-- 站点选择 --> <!-- 站点选择 -->
<div mt-2 v-if="groundStationState.groundStations.length > 0"> <div mt-2 v-if="groundStationState.groundStations.length > 0">
<span class="mr-2">选择要显示的站点:</span> <span class="mr-2">选择要显示的站点:</span>
<a-checkbox-group v-model:value="groundStationState.selectedIds" :options="stationCheckboxOptions" /> <a-checkbox-group v-model:value="selectedStationIdsArray" :options="stationCheckboxOptions" />
</div> </div>
</a-card> </a-card>
<!-- 卫星控制 --> <!-- 卫星控制 -->
<a-card title="卫星控制" size="small"> <a-card title="卫星控制" size="small">
<span>当前卫星数: {{ satelliteState.satellites.length }}</span> <span>当前卫星数: {{ satelliteState.satellites.length }}</span>
<span> | 选中卫星数: {{ satelliteState.selectedIds.length }}</span> <span> | 选中卫星数: {{ satelliteState.selectedIds.size }}</span>
<div v-if="satelliteState.satellites.length > 0" class="mt-2"> <div v-if="satelliteState.satellites.length > 0" class="mt-2">
<span class="mr-2">选择要显示的卫星:</span> <span class="mr-2">选择要显示的卫星:</span>
<a-checkbox-group v-model:value="satelliteState.selectedIds" :options="satelliteCheckboxOptions" /> <a-checkbox-group v-model:value="selectedSatelliteIdsArray" :options="satelliteCheckboxOptions" />
</div> </div>
</a-card> </a-card>
</div> </div>