From 2f991d893492f5257856a4076f22ad642861dfd5 Mon Sep 17 00:00:00 2001 From: air <30444667+sszdot@users.noreply.github.com> Date: Thu, 18 Sep 2025 16:24:51 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E7=B1=BB=20=20=E5=9E=8B=E3=80=91?= =?UTF-8?q?=EF=BC=9Afeat=20=E3=80=90=E5=8E=9F=20=20=E5=9B=A0=E3=80=91?= =?UTF-8?q?=EF=BC=9A=E5=9C=B0=E5=9B=BE=E7=BB=84=E4=BB=B6=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E9=A3=9E=E6=9C=BA=E5=9B=BE=E6=A0=87=20=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=9C=A8=E7=BA=BF=E7=8A=B6=E6=80=81=20?= =?UTF-8?q?=E9=87=8D=E9=87=8F=E7=8A=B6=E6=80=81=20=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=9B=BE=E6=A0=87=20=E3=80=90=E8=BF=87=20=20?= =?UTF-8?q?=E7=A8=8B=E3=80=91=EF=BC=9Amapbox=E5=8A=A0=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E6=9B=B4=E6=96=B0updatePlaneIcon=E5=87=BD=E6=95=B0=20=20?= =?UTF-8?q?=E6=A6=82=E5=86=B5=20=E9=A3=9E=E6=9C=BA=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=20=E7=9B=91=E6=B5=8B=E9=A3=9E=E6=9C=BA?= =?UTF-8?q?=E7=8A=B6=E6=80=81=20=E8=B0=83=E7=94=A8=E6=9B=B4=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E5=87=BD=E6=95=B0=20=E3=80=90=E5=BD=B1=20=20=E5=93=8D?= =?UTF-8?q?=E3=80=91=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 类型 包含: # feat:新功能(feature) # fix:修补bug # docs:文档(documentation) # style: 格式(不影响代码运行的变动) # refactor:重构(即不是新增功能,也不是修改bug的代码变动) # test:增加测试 # chore:构建过程或辅助工具的变动 --- src/assets/svg/plane_run.svg | 2028 ++++------------- src/assets/svg/plane_unline.svg | 1626 ++++--------- src/components/MapBox.vue | 87 +- .../layout/components/main/home/index.vue | 29 + .../layout/components/main/planes/index.vue | 24 + 5 files changed, 978 insertions(+), 2816 deletions(-) diff --git a/src/assets/svg/plane_run.svg b/src/assets/svg/plane_run.svg index f9da02e..41d2403 100644 --- a/src/assets/svg/plane_run.svg +++ b/src/assets/svg/plane_run.svg @@ -1,1707 +1,537 @@ - - - + - - - - - - - - - - - - - - - + + - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + diff --git a/src/assets/svg/plane_unline.svg b/src/assets/svg/plane_unline.svg index 051479f..3079cda 100644 --- a/src/assets/svg/plane_unline.svg +++ b/src/assets/svg/plane_unline.svg @@ -1,1261 +1,503 @@ - - + - + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + + + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/MapBox.vue b/src/components/MapBox.vue index 363719b..13bb900 100644 --- a/src/components/MapBox.vue +++ b/src/components/MapBox.vue @@ -8,7 +8,8 @@ import mapboxgl from 'mapbox-gl' import { MapboxStyleSwitcherControl, FollowControl, CustomFullscreenControl, NoFlyControl, RestrictflyControl, SaveToFileControl, PolygonToggleControl } from '@/utils/mapboxgl_plugs' import planeIcon from '@/assets/svg/plane.svg' -// import unlineIcon from '@/assets/svg/plane_unline.svg' +import planeRunIcon from '@/assets/svg/plane_run.svg' +import unlineIcon from '@/assets/svg/plane_unline.svg' import civilIcon from '@/assets/svg/civil.svg' export default { @@ -87,22 +88,6 @@ export default { } }, watch: { - /** 动态开关地图样式切换控件 */ - enableSwitch (val) { - if (!this.map) return - if (val) { - if (!this.styleSwitcherControlRef) { - const control = new MapboxStyleSwitcherControl(this.mapStyleList, 'iconfont icon-duozhang f-s-20', this.currentStyleIndex) - this.map.addControl(control, 'top-right') - this.styleSwitcherControlRef = control - } - } else { - if (this.styleSwitcherControlRef) { - try { this.map.removeControl(this.styleSwitcherControlRef) } catch (e) { /* noop */ } - this.styleSwitcherControlRef = null - } - } - }, /** 动态开关全屏控件(enableZoom) */ enableZoom (val) { if (!this.map) return @@ -118,6 +103,22 @@ export default { this.fullscreenControlRef = null } } + }, + /** 动态开关地图样式切换控件 */ + enableSwitch (val) { + if (!this.map) return + if (val) { + if (!this.styleSwitcherControlRef) { + const control = new MapboxStyleSwitcherControl(this.mapStyleList, 'iconfont icon-duozhang f-s-20', this.currentStyleIndex) + this.map.addControl(control, 'top-right') + this.styleSwitcherControlRef = control + } + } else { + if (this.styleSwitcherControlRef) { + try { this.map.removeControl(this.styleSwitcherControlRef) } catch (e) { /* noop */ } + this.styleSwitcherControlRef = null + } + } } }, async mounted () { @@ -253,13 +254,6 @@ export default { this.map.addControl(this.fullscreenControlRef, 'top-right') } - // 地图样式选择控件 - // 自定义地图样式列表 - if (this.enableSwitch) { - this.styleSwitcherControlRef = new MapboxStyleSwitcherControl(this.mapStyleList, 'iconfont icon-duozhang f-s-20', this.currentStyleIndex) - this.map.addControl(this.styleSwitcherControlRef, 'top-right') - } - // 飞机跟随 if (this.enableFollow) { this.map.addControl(new FollowControl({ @@ -349,6 +343,13 @@ export default { } }), 'top-right') } + + // 地图样式选择控件 + // 自定义地图样式列表 + if (this.enableSwitch) { + this.styleSwitcherControlRef = new MapboxStyleSwitcherControl(this.mapStyleList, 'iconfont icon-duozhang f-s-20', this.currentStyleIndex) + this.map.addControl(this.styleSwitcherControlRef, 'top-right') + } }, /** * @description 通用地图图层和数据源清除方法 @@ -917,7 +918,17 @@ export default { makePlane (plane, index = 0) { const customIcon = document.createElement('div') customIcon.className = 'custom-marker' - customIcon.style.backgroundImage = `url(${planeIcon})` + // 根据在线状态与载重显示不同图标,空值安全处理 + // 约定: online === false 才判定为离线;其他(包括 undefined/null) 默认为在线 + const isOnline = !((plane && plane.planeState && plane.planeState.online) === false) + const lwRaw0 = plane && plane.planeState ? plane.planeState.loadweight : 0 + const lwNum0 = Number(lwRaw0) + const loadWeight = Number.isFinite(lwNum0) ? lwNum0 : 0 + const iconToUse = !isOnline ? unlineIcon : (loadWeight > 300 ? planeRunIcon : planeIcon) + // 使用 important 确保覆盖样式表中的背景图设置 + customIcon.style.setProperty('background-image', `url(${iconToUse})`, 'important') + customIcon.style.setProperty('background-repeat', 'no-repeat', 'important') + customIcon.style.setProperty('background-size', 'contain', 'important') customIcon.style.width = '64px' customIcon.style.height = '64px' @@ -1088,6 +1099,32 @@ export default { popup.setHTML(popupContent) } }, + /** + * @description 实时根据在线状态与载重更新指定飞机的图标 + * @param {Object} stateObj 飞机状态对象(需包含 online, loadweight) + * @param {number} index 对应的飞机索引 + */ + updatePlaneIcon (stateObj, index = 0) { + const marker = this.planes[index] + if (!marker) return + const el = marker.getElement() + if (!el) return + // 约定: online === false 才判定为离线;其他(包括 undefined/null) 默认为在线 + const isOnline = !((stateObj && stateObj.online) === false) + const lwRaw = stateObj ? stateObj.loadweight : 0 + const lwNum = Number(lwRaw) + const loadWeight = Number.isFinite(lwNum) ? lwNum : 0 + const iconToUse = !isOnline ? unlineIcon : (loadWeight > 300 ? planeRunIcon : planeIcon) + // 使用 important 确保覆盖样式表中的背景图设置 + el.style.setProperty('background-image', `url(${iconToUse})`, 'important') + el.style.setProperty('background-repeat', 'no-repeat', 'important') + el.style.setProperty('background-size', 'contain', 'important') + // 调试信息,观察状态与最终图标选择 + try { + el.dataset.icon = !isOnline ? 'unline' : (loadWeight > 300 ? 'run' : 'normal') + console.debug('[updatePlaneIcon]', { index, online: stateObj && stateObj.online, loadweight: lwRaw, parsedLoad: loadWeight, chosen: el.dataset.icon }) + } catch (e) { /* noop */ } + }, /** * @description: 镜头跳转 * @param {obj} lonLat {lon:lon,lat:lat} 经纬度 diff --git a/src/views/layout/components/main/home/index.vue b/src/views/layout/components/main/home/index.vue index c321d91..d88254c 100644 --- a/src/views/layout/components/main/home/index.vue +++ b/src/views/layout/components/main/home/index.vue @@ -43,6 +43,20 @@ export default { return Array.isArray(posArr) ? posArr : [] }) }, + /** + * @description: 派生出与“图标选择”强相关的轻量状态,供独立 watcher 监控 + * offline: 是否离线;run: 载重是否超过阈值(>300) + */ + planeIconStates () { + return this.planeList.map(plane => { + const s = plane.planeState || {} + const n = Number(s.loadweight) + return { + offline: s.online === false, + run: Number.isFinite(n) && n > 300 + } + }) + }, /** * @description: 侧边栏显隐 */ @@ -129,6 +143,21 @@ export default { }, deep: true }, + // 专门监听轻量图标状态,必要时才更新图标,避免不必要的 DOM 操作 + planeIconStates: { + handler (val, oldVal) { + val.forEach((iconState, index) => { + const prev = Array.isArray(oldVal) ? oldVal[index] : undefined + const changed = !prev || prev.offline !== iconState.offline || prev.run !== iconState.run + if (changed) { + // 使用原始 planeState 作为数据源更新图标 + const stateObj = this.planeList[index].planeState || {} + this.$refs.mapbox.updatePlaneIcon(stateObj, index) + } + }) + }, + deep: true + }, /** * @description: 侧边栏缩进有变化时 地图重新自适应 */ diff --git a/src/views/layout/components/main/planes/index.vue b/src/views/layout/components/main/planes/index.vue index f53ea85..c0495fb 100644 --- a/src/views/layout/components/main/planes/index.vue +++ b/src/views/layout/components/main/planes/index.vue @@ -175,8 +175,20 @@ export default { */ isCollapse () { return this.$store.state.app.isCollapse + }, + /** + * @description: 与图标选择强相关的轻量状态(仅当前选中飞机) + */ + planeIconState () { + const s = this.planeState || {} + const n = Number(s.loadweight) + return { + offline: s.online === false, + run: Number.isFinite(n) && n > 300 + } } }, + methods: { /** 切换主视图 */ toggleMainView () { @@ -336,6 +348,18 @@ export default { }, deep: true }, + // 仅当离线/载重跨阈值状态发生变化时更新图标(当前选中飞机) + planeIconState: { + handler (val, oldVal) { + const changed = !oldVal || oldVal.offline !== val.offline || oldVal.run !== val.run + if (changed) { + const stateObj = this.planeState || {} + // 当前视图只有一架选中飞机,对应 MapBox 数组索引为 0 + this.$refs.mapbox.updatePlaneIcon(stateObj, 0) + } + }, + deep: false + }, /** * @description: 更新飞机位置 并画出轨迹 跟随飞机 */