From 9f4c8128cc2525bba0134c6ce32911564c018b6d Mon Sep 17 00:00:00 2001
From: jiang teng <1348746268@qq.com>
Date: Sun, 29 Sep 2024 15:18:03 +0800
Subject: [PATCH] =?UTF-8?q?feat(*):=20=E4=BB=A3=E7=A0=81=E6=A2=B3=E7=90=86?=
 =?UTF-8?q?=E4=B8=8E=E7=B2=BE=E7=AE=80|=E5=88=A0=E9=99=A4=E5=86=97?=
 =?UTF-8?q?=E4=BD=99=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/http/index.js                            |   4 -
 src/js/SatelliteEntity.js                    |  11 +-
 src/utils/index.js                           |  22 ++
 src/views/satellite-track/SatelliteTrack.vue | 210 ++-----------------
 src/views/satellite-track/satelliteType.js   | 100 ++++-----
 5 files changed, 100 insertions(+), 247 deletions(-)
 create mode 100644 src/utils/index.js

diff --git a/src/http/index.js b/src/http/index.js
index 7192a0b..2744f42 100644
--- a/src/http/index.js
+++ b/src/http/index.js
@@ -6,8 +6,6 @@ function getTleDataFromExternal(path = "") {
     let uri = `${BASE_URL}/NORAD/elements/gp.php?GROUP=${path}&FORMAT=tle`;
     return axios.get(uri).then(res => {
         if (res.status === 200) {
-            ElMessage.success('获取TLE成功');
-            localStorage.setItem(path, res.data);  // 缓存TLE数据,减轻数据服务压力
             return Promise.resolve(res.data);
         } else {
             ElMessage.error('获取TLE失败');
@@ -16,6 +14,4 @@ function getTleDataFromExternal(path = "") {
     });
 }
 
-
-
 export { getTleDataFromExternal };
\ No newline at end of file
diff --git a/src/js/SatelliteEntity.js b/src/js/SatelliteEntity.js
index 14486ae..49a42a6 100644
--- a/src/js/SatelliteEntity.js
+++ b/src/js/SatelliteEntity.js
@@ -51,6 +51,7 @@ class SatelliteEntity {
     createSatelliteEntity() {
         const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());
         const stop = Cesium.JulianDate.addSeconds(start, this.totalSeconds, new Cesium.JulianDate());
+        const color = Cesium.Color.fromRandom({ alpha: 1.0 });
         let satelliteEntity = {
             name: this.name,
             description: this.name,
@@ -58,15 +59,15 @@ class SatelliteEntity {
             position: this._getPositionProperty(),
             point: {
                 pixelSize: 8,
-                color: Cesium.Color.fromRandom({ alpha: 1.0 }),
+                color: color,
                 // scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1, 8.0e8, 0.5),
             },
             path: new Cesium.PathGraphics({
-                width: 1,
-                show: false,
+                width: 0.5,
+                show: true,
                 leadTime: this.leadTime,
                 trailTime: this.trailTime,
-                material: Cesium.Color.LIME,
+                material: color,
             }),
             label: {
                 text: this.name,
@@ -79,7 +80,7 @@ class SatelliteEntity {
                 horizontalOrigin: Cesium.VerticalOrigin.LEFT,
                 pixelOffset: new Cesium.Cartesian2(0, 5),
                 fillColor: Cesium.Color.WHITE,
-                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 5000000),
+                // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 50000000),
             }
         }
         return satelliteEntity;
diff --git a/src/utils/index.js b/src/utils/index.js
new file mode 100644
index 0000000..6d24326
--- /dev/null
+++ b/src/utils/index.js
@@ -0,0 +1,22 @@
+/**
+ * 比较两个数组之间的差异
+ * 
+ * @param {Array} oldArray - 旧的数组
+ * @param {Array} newArray - 新的数组
+ * @throws {Error} 如果oldArray或newArray不是数组,则抛出错误
+ * @returns {Object} 返回一个对象,包含两个属性:addedItems(新数组中新增的元素)和removedItems(旧数组中被移除的元素)
+ */
+function compareArrays(oldArray, newArray) {
+    // 验证参数类型,确保oldArray和newArray都是数组
+    if (!Array.isArray(oldArray) || !Array.isArray(newArray)) {
+        throw new Error('Both oldArray and newArray must be arrays.');
+    }
+    // 使用filter方法找出newArray中oldArray不包含的元素,即新增的元素
+    const addedItems = newArray.filter(x => !oldArray.includes(x));
+    // 使用filter方法找出oldArray中newArray不包含的元素,即被移除的元素
+    const removedItems = oldArray.filter(x => !newArray.includes(x));
+    // 返回新增的元素和被移除的元素
+    return { addedItems, removedItems };
+}
+
+export { compareArrays };
\ No newline at end of file
diff --git a/src/views/satellite-track/SatelliteTrack.vue b/src/views/satellite-track/SatelliteTrack.vue
index 59e06e1..84e2cc3 100644
--- a/src/views/satellite-track/SatelliteTrack.vue
+++ b/src/views/satellite-track/SatelliteTrack.vue
@@ -4,17 +4,8 @@
         <div class="menu_button" @click="drawer = !drawer" title="卫星星座选择">
             <img src="../../assets/menu.svg" width="28" height="28" alt="卫星星座选择">
         </div>
-        <div class="menu_button" @click="drawerImport = !drawerImport" title="自定义导入TLE数据">
-            <img src="../../assets/import.svg" width="28" height="28" alt="自定义导入TLE数据">
-        </div>
-        <div class="menu_button" @click="handleClearTLECache" title="清除TLE缓存">
-            <img src="../../assets/clean.svg" width="24" height="24" alt="清除TLE缓存">
-        </div>
-        <div class="menu_button" @click="clearSatelliteOrbit" title="清除轨道">
-            <img src="../../assets/hide.svg" width="24" height="24" alt="清除轨道">
-        </div>
     </div>
-    <!-- 抽屉1 -->
+
     <el-drawer v-model="drawer" title="卫星星座选择" direction="ltr">
         <el-checkbox-group v-model="checked" @change="handleSatelliteChange" :max=5>
             <template v-for="(item, index) in allSatellite" :key="index">
@@ -23,24 +14,6 @@
             </template>
         </el-checkbox-group>
     </el-drawer>
-    <!-- 抽屉2 -->
-    <el-drawer v-model="drawerImport" title="自定义卫星数据" direction="ltr">
-        <el-input v-model="tleData" type="textarea" placeholder="Please input tle data" :rows="20" />
-        <el-row class="add_satellite">
-            <el-button type="primary" @click="handleAddSatellite">
-                添加
-            </el-button>
-            <el-upload class="upload_button" :on-change="handleImportSatellite" :show-file-list="false" accept="txt" :limit="1" :auto-upload="false" ref="upload">
-                <template #trigger>
-                    <el-button type="default">导入</el-button>
-                </template>
-            </el-upload>
-            <el-button type="danger" @click="handleClearSatellite">
-                清空
-            </el-button>
-        </el-row>
-
-    </el-drawer>
 </template>
 
 <script setup>
@@ -48,45 +21,29 @@
 
 import * as Cesium from 'cesium';
 import "cesium/Build/Cesium/Widgets/widgets.css";
-
 import { onMounted, ref, watch } from 'vue';
-
 import "./SatelliteTrack.scss"
-
 import { getTleDataFromExternal } from '@/http/index'
-
 import SatelliteEntity from '@/js/SatelliteEntity';
-
 import { specialSatellite, weatherSatellite, communicationSatellite, navigationSatellite, scientificSatellite, miscellaneousSatellite } from "./satelliteType"
+import { compareArrays } from '@/utils';
 
-let allSatellite = [...specialSatellite, ...weatherSatellite, ...communicationSatellite, ...navigationSatellite, ...scientificSatellite, ...miscellaneousSatellite];
-
+const allSatellite = [...specialSatellite, ...weatherSatellite, ...communicationSatellite, ...navigationSatellite, ...scientificSatellite, ...miscellaneousSatellite];
 
 window.CESIUM_BASE_URL = import.meta.env.MODE === 'development' ? '/cesium' : '/satellite-track/cesium';
 
 let viewer;
+// 默认场景的时间跨度
 const totalSeconds = 86400;
-// 保存所有的卫星实例 
+// 保存分组的卫星实例 
 const satelliteMap = new Map();
-// 自定义的卫星
-const customSatelliteMap = new Map();
 // 响应式数据
 const drawer = ref(false);
+// 默认勾选
+const checked = ref(["last-30-days"]);
+// TLE缓存
+const tleCache = new Map();
 
-const drawerImport = ref(false);
-
-const checked = ref([1]);
-
-const clickedSatelliteArray = [];
-
-const upload = ref(null);
-
-let tleData = ref(`BEIDOU-3 G2             
-1 45344U 20017A   23037.82027362 -.00000136  00000+0  00000+0 0  9994
-2 45344   1.9879   4.6761 0000950 328.7503 178.5761  1.00272999 10962
-BEIDOU-3 G3             
-1 45807U 20040A   23037.85365455 -.00000347  00000+0  00000+0 0  9999
-2 45807   0.9369 314.6571 0008244 342.4957 257.2704  1.00264764  9772`);
 
 
 Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiYjZmMWM4Ny01YzQ4LTQ3MzUtYTI5Mi1hNTgyNjdhMmFiMmMiLCJpZCI6NjIwMjgsImlhdCI6MTYyNjY3MTMxNX0.5SelYUyzXWRoMyjjFvmFIAoPtWlJPQMjsVl2e_jQe-c';
@@ -99,12 +56,6 @@ function initCesium() {
         return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19);
     }
 
-    // mapBox 卫星地图
-    let mapBoxImgLayer = new Cesium.MapboxImageryProvider({
-        mapId: 'mapbox.satellite',
-        accessToken: 'pk.eyJ1Ijoiamlhbmd0ZW5nIiwiYSI6ImNqbGhhcDhzMjAxdncza294c2ZqcHFxNGIifQ.rjSmtZ5QzE2sJ-qDANh3WQ'
-    });
-
     //高德卫星地图
     let gaoDeSatelliteImgLayer = new Cesium.UrlTemplateImageryProvider({
         url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
@@ -113,13 +64,6 @@ function initCesium() {
         tilingScheme: new Cesium.WebMercatorTilingScheme(),
     });
 
-    // 高德地图路网图层
-    let gaoDeImageryProvider = new Cesium.UrlTemplateImageryProvider({
-        url: "http://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
-        minimumLevel: 3,
-        maximumLevel: 18,
-    })
-
     viewer = new Cesium.Viewer('cesiumContainer', {
         baseLayerPicker: true,
         geocoder: false,
@@ -191,23 +135,6 @@ function parseTle(data = "") {
     return tles;
 }
 
-function parseTleWithSimpleSplit(data = "") {
-    if (data.length === 0) return;
-    let result = data.split("\n");
-    console.log(result)
-    let tles = [], i = 0, tem = [];
-    result.forEach(item => {
-        i++;
-        tem.push(item)
-        if (i === 3) {
-            tles.push(tem.join("\r\n"));
-            tem = [];
-            i = 0;
-        }
-    });
-    return tles;
-}
-
 function addCesiumEventListener() {
     let callback = viewer.screenSpaceEventHandler.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
     viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
@@ -218,9 +145,7 @@ function addCesiumEventListener() {
 
         }
         if (pickedFeature) {
-            pickedFeature.id.path.show = new Cesium.ConstantProperty(true);
-            pickedFeature.id.label.distanceDisplayCondition = undefined;
-            clickedSatelliteArray.push(pickedFeature);
+
         }
 
     }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
@@ -231,106 +156,18 @@ function handleSatelliteChange(e) {
 
 }
 
-function handleClearTLECache() {
-    ElMessageBox.confirm("清空TLE缓存后手动刷新页面将重新下载TLE数据,是否继续?", "提示", {
-        distinguishCancelAndClose: true,
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-    }).then(() => {
-        clearTLECache();
-    }).catch(() => {
-        console.log('取消');
-    })
-}
-
-function clearTLECache() {
-    // satelliteMap.forEach(satelliteSet => satelliteSet.forEach(sate => viewer.entities.remove(sate)));
-    // satelliteMap.clear();  // 一级缓存
-    localStorage.clear(); // 二级缓存
-    ElMessage.success('清除成功')
-}
-
-function clearSatelliteOrbit() {
-    if (clickedSatelliteArray.length) {
-        clickedSatelliteArray.forEach(item => {
-            item.id ? item.id.path.show = false : '';
-        })
-    }
-}
-
-function checkTleData(data) {
-    try {
-        if (!data.length) {
-            return false;
-        }
-        let dataArray = data.split('\n');
-        if (dataArray.length % 3 !== 0) {
-            return false;
-        }
-        dataArray.forEach((item, index) => {
-            if (index % 3 === 0 && !item) throw new Error(false);
-            if (index % 3 === 1 && item.length < 69) throw new Error(false);
-            if (index % 3 === 2 && item.length < 69) throw new Error(false);
-        })
-        return true;
-    } catch (error) {
-        console.log(error);
-        return false;
-    }
-}
-
-// 添加自定义卫星实例
-function handleAddSatellite() {
-    if (!checkTleData(tleData.value)) {
-        ElMessage.error('wrong TLE data');
-        return;
-    }
-    clearCustomSatelliteMap();
-    let result = parseTleWithSimpleSplit(tleData.value);
-    result.forEach(tle => {
-        let satellite = new SatelliteEntity(tle);
-        let cesiumSateEntity = satellite.createSatelliteEntity();
-        let result = viewer.entities.add(cesiumSateEntity);
-        customSatelliteMap.set(satellite.name, result)
-    });
-    viewer.zoomTo(viewer.entities);
-
-}
-
-async function handleImportSatellite(uploadFiles) {
-    upload.value.clearFiles();
-    if (uploadFiles.raw.type !== "text/plain") {
-        ElMessage.warning('请上传TXT格式的TLE数据');
-        return;
-    }
-    let data = await uploadFiles.raw.text();
-    tleData.value = data;
-}
-
-// 清空所有状态,输入框和cesium实例
-function handleClearSatellite() {
-    clearCustomSatelliteMap();
-    tleData.value = "";
-    upload.value.clearFiles();
-}
-
-// 清空卫星实例;
-function clearCustomSatelliteMap() {
-    customSatelliteMap.forEach(item => viewer.entities.remove(item));
-    customSatelliteMap.clear();
-}
-
-
-// 获取tle数据,从缓存中获取,若无请求数据
 
+// 获取tle数据,从缓存中获取,若无则请求数据
 async function getTleData(path) {
-    let data = localStorage.getItem(path);
+    let data = tleCache.get(path);
     if (data) {
         console.log(`%c 命中缓存,key值为${path}`, 'color:#0f0;');
         return data;
     } else {
         console.warn("未命中缓存,开始下载TLE数据");
-        return await getTleDataFromExternal(path);
+        const res = await getTleDataFromExternal(path);
+        tleCache.set(path, res);
+        return res;
     }
 }
 
@@ -362,16 +199,14 @@ function removeSatellite(path) {
     }
 }
 
-// 侦听器
 watch(checked, (newValue, oldValue) => {
-    let filterValue = newValue.concat(oldValue).filter((item, index, arr) => arr.indexOf(item) === arr.lastIndexOf(item));
-    let satelliteClassify = allSatellite.find(item => item.value === filterValue[0]);
-    // 勾选了卫星
-    if (newValue.length > oldValue.length) {
-        addSatellite(satelliteClassify.group);
-    } else {
-        //取消了勾选
-        removeSatellite(satelliteClassify.group);
+    const { addedItems, removedItems } = compareArrays(oldValue, newValue);
+    if (addedItems.length) {
+        // 默认只会有一次操作,也就是说addedItems, removedItems数组中的元素只会有一个,可以直接取第一个元素
+        addSatellite(addedItems[0]);
+    }
+    if (removedItems.length) {
+        removeSatellite(removedItems[0]);
     }
 })
 
@@ -381,7 +216,6 @@ onMounted(async () => {
     initCesium();
     initTimeLine();
     addCesiumEventListener();
-    addSatellite('last-30-days');
 })
 
 
diff --git a/src/views/satellite-track/satelliteType.js b/src/views/satellite-track/satelliteType.js
index 15b8af0..8f27c06 100644
--- a/src/views/satellite-track/satelliteType.js
+++ b/src/views/satellite-track/satelliteType.js
@@ -7,27 +7,27 @@ let specialSatellite = [
     },
     {
         label: "Last 30 Days' Launches",
-        value: 1,
+        value: 'last-30-days',
         group: 'last-30-days'
     },
     {
         label: 'Space Stations',
-        value: 2,
+        value: 'stations',
         group: 'stations'
     },
     {
         label: '100 (or so) Brightest',
-        value: 3,
+        value: 'visual',
         group: 'visual'
     },
     {
         label: 'Active Satellites',
-        value: 4,
+        value: 'active',
         group: 'active'
     },
     {
         label: 'Analyst Satellites ',
-        value: 5,
+        value: 'analyst',
         group: 'analyst'
     }
 ];
@@ -41,52 +41,52 @@ let weatherSatellite = [
     },
     {
         label: 'Weather',
-        value: 6,
+        value: 'weather',
         group: 'weather'
     },
     {
         label: 'NOAA',
-        value: 7,
+        value: 'noaa',
         group: 'noaa'
     },
     {
         label: 'GOES',
-        value: 8,
+        value: 'goes',
         group: 'goes'
     },
     {
         label: 'Earth Resources',
-        value: 9,
+        value: 'resource',
         group: 'resource'
     },
     {
         label: 'Search & Rescue (SARSAT) ',
-        value: 10,
+        value: 'sarsat',
         group: 'sarsat'
     },
     {
         label: 'Disaster Monitoring',
-        value: 11,
+        value: 'dmc',
         group: 'dmc'
     },
     {
         label: 'TDRSS',
-        value: 12,
+        value: 'tdrss',
         group: 'tdrss'
     },
     {
         label: 'ARGOS Data Collection System',
-        value: 13,
+        value: 'argos',
         group: 'argos'
     },
     {
         label: 'Planet',
-        value: 14,
+        value: 'planet',
         group: 'planet'
     },
     {
         label: 'Spire',
-        value: 15,
+        value: 'spire',
         group: 'spire'
     }
 ];
@@ -100,97 +100,97 @@ let communicationSatellite = [
     },
     {
         label: 'Active Geosynchronous',
-        value: 16,
+        value: 'geo',
         group: 'geo'
     },
     {
         label: 'GEO Protected Zone',
-        value: 17,
+        value: 'gpz',
         group: 'gpz'
     },
     {
         label: 'GEO Protected Zone Plus',
-        value: 18,
+        value: 'gpz-plus',
         group: 'gpz-plus'
     },
     {
         label: 'Intelsat',
-        value: 19,
+        value: 'intelsat',
         group: 'intelsat'
     },
     {
         label: 'SES',
-        value: 20,
+        value: 'ses',
         group: 'ses'
     },
     {
         label: 'Iridium',
-        value: 21,
+        value: 'iridium',
         group: 'iridium'
     },
     {
         label: 'Iridium NEXT',
-        value: 22,
+        value: 'iridium-NEXT',
         group: 'iridium-NEXT'
     },
     {
         label: 'Starlink',
-        value: 23,
+        value: 'starlink',
         group: 'starlink'
     },
     {
         label: 'OneWeb',
-        value: 24,
+        value: 'oneweb',
         group: 'oneweb'
     },
     {
         label: 'Orbcomm',
-        value: 25,
+        value: 'orbcomm',
         group: 'orbcomm'
     },
     {
         label: 'Globalstar',
-        value: 26,
+        value: 'globalstar',
         group: 'globalstar'
     },
     {
         label: 'Swarm',
-        value: 27,
+        value: 'swarm',
         group: 'swarm'
     },
     {
         label: 'Amateur Radio',
-        value: 28,
+        value: 'amateur',
         group: 'amateur'
     },
     {
         label: 'Experimental Comm',
-        value: 29,
+        value: 'x-comm',
         group: 'x-comm'
     },
     {
         label: 'Other Comm',
-        value: 30,
+        value: 'other-comm',
         group: 'other-comm'
     },
     {
         label: 'SatNOGS',
-        value: 31,
+        value: 'satnogs',
         group: 'satnogs'
     },
     {
         label: 'Gorizont',
-        value: 32,
+        value: 'gorizont',
         group: 'gorizont'
     },
     {
         label: 'Raduga',
-        value: 33,
+        value: 'raduga',
         group: 'raduga'
     },
     {
         label: 'Molniya',
-        value: 34,
+        value: 'molniya',
         group: 'molniya'
     },
 ];
@@ -204,42 +204,42 @@ let navigationSatellite = [
     },
     {
         label: 'GNSS',
-        value: 35,
+        value: 'gnss',
         group: 'gnss'
     },
     {
         label: 'GPS Operational',
-        value: 36,
+        value: 'gps-ops',
         group: 'gps-ops'
     },
     {
         label: 'GLONASS Operational',
-        value: 37,
+        value: 'glo-ops',
         group: 'glo-ops'
     },
     {
         label: 'Galileo',
-        value: 38,
+        value: 'galileo',
         group: 'galileo'
     },
     {
         label: 'Beidou',
-        value: 39,
+        value: 'beidou',
         group: 'beidou'
     },
     {
         label: 'Satellite-Based Augmentation System',
-        value: 40,
+        value: 'sbas',
         group: 'sbas'
     },
     {
         label: 'Navy Navigation Satellite System (NNSS)',
-        value: 41,
+        value: 'nnss',
         group: 'nnss'
     },
     {
         label: 'Russian LEO Navigation',
-        value: 42,
+        value: 'musson',
         group: 'musson'
     },
 ];
@@ -253,22 +253,22 @@ let scientificSatellite = [
     },
     {
         label: 'Space & Earth Science',
-        value: 43,
+        value: 'science',
         group: 'science'
     },
     {
         label: 'Geodetic',
-        value: 44,
+        value: 'geodetic',
         group: 'geodetic'
     },
     {
         label: 'Engineering',
-        value: 45,
+        value: 'engineering',
         group: 'engineering'
     },
     {
         label: 'Education',
-        value: 46,
+        value: 'education',
         group: 'education'
     }
 ];
@@ -282,22 +282,22 @@ let miscellaneousSatellite = [
     },
     {
         label: 'Miscellaneous Military',
-        value: 47,
+        value: 'military',
         group: 'military'
     },
     {
         label: 'Radar Calibration',
-        value: 48,
+        value: 'radar',
         group: 'radar'
     },
     {
         label: 'CubeSats',
-        value: 49,
+        value: 'cubesat',
         group: 'cubesat'
     },
     {
         label: 'Other Satellites',
-        value: 50,
+        value: 'other',
         group: 'other'
     }
 ]