From 6126b9d13775c8c47716bb700f1b57fc2a078027 Mon Sep 17 00:00:00 2001 From: szdot Date: Sun, 22 Jun 2025 15:05:06 +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=9Afactor=20=E3=80=90=E5=8E=9F=20=20=E5=9B=A0=E3=80=91?= =?UTF-8?q?=EF=BC=9A=E5=AE=8C=E5=96=84=20=E9=A3=9E=E8=A1=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=BB=9F=E8=AE=A1=E7=9A=841.=E6=9E=B6=E6=AC=A1?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=20=202.=E9=A3=9E=E8=A1=8C=E8=BD=A8=E8=BF=B9?= =?UTF-8?q?=E7=9A=84bug=E4=BF=AE=E5=A4=8D=20=E3=80=90=E8=BF=87=20=20?= =?UTF-8?q?=E7=A8=8B=E3=80=91=EF=BC=9A=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/components/DateRangePicker.vue | 13 +- src/components/MapBox.vue | 144 +++++++++++++++++- .../components/main/register/flyData.vue | 88 ++++++++--- 3 files changed, 217 insertions(+), 28 deletions(-) diff --git a/src/components/DateRangePicker.vue b/src/components/DateRangePicker.vue index 63f342d..2127a67 100644 --- a/src/components/DateRangePicker.vue +++ b/src/components/DateRangePicker.vue @@ -123,8 +123,17 @@ export default { }, methods: { onChange (val) { - this.$emit('input', val) - this.$emit('change', val) + if (Array.isArray(val) && val.length === 2) { + const start = val[0] + const end = new Date(val[1]) + end.setHours(23, 59, 59, 999) // 把结束时间改为当天最后一毫秒 + this.internalValue = [start, end] + this.$emit('input', [start, end]) + this.$emit('change', [start, end]) + } else { + this.$emit('input', val) + this.$emit('change', val) + } } } } diff --git a/src/components/MapBox.vue b/src/components/MapBox.vue index b1fbaa6..804dc4f 100644 --- a/src/components/MapBox.vue +++ b/src/components/MapBox.vue @@ -134,7 +134,7 @@ export default { // 判断地图开启了点飞功能 if (this.enableGuided) { - // 长按事件 传longPress到组件外部调用 + // 长按事件 传longPress到组件外部调用 let pressTimer = null let isLongPress = false // 标记是否为长按 let startPoint = null // 记录按下时的位置 @@ -605,7 +605,146 @@ export default { } }, /** - * @description: 创建飞机轨迹 ps:原理删除之前的轨迹 重新绘制 + * @description 清除历史轨迹所有轨迹线和轨迹点的图层与数据源 + * @param {Array} lineLayerIds - 轨迹线图层ID数组 + * @param {Array} pointLayerIds - 轨迹点图层ID数组 + */ + clearHistoryPaths (lineLayerIds = [], pointLayerIds = []) { + if (!this.map) return + + // 清除轨迹线图层及对应数据源 + lineLayerIds.forEach(id => { + if (this.map.getLayer(id)) { + this.map.removeLayer(id) + } + if (this.map.getSource(id)) { + this.map.removeSource(id) + } + }) + + // 清除轨迹点图层及对应数据源 + pointLayerIds.forEach(id => { + if (this.map.getLayer(id)) { + this.map.removeLayer(id) + } + if (this.map.getSource(id)) { + this.map.removeSource(id) + } + }) + }, + + /** + * @description 根据索引绘制一条历史轨迹的轨迹线和起点圆点 + * @param {Array>} pathArray - GPS坐标数组,格式为 [[lon, lat, ...], ...] + * @param {number} index - 用于生成图层ID的索引,确保每条轨迹ID唯一 + */ + drawHistoryPathByIndex (pathArray, index) { + if (!this.map) return + if (!pathArray || pathArray.length === 0) return + + const zoomThreshold = 12 // 缩放等级阈值,决定显示轨迹线还是起点圆点 + const pointRadius = 6 // 起点圆点半径 + + // 轨迹线GeoJSON对象 + const lineGeojson = { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: pathArray + } + } + + // 起点圆点GeoJSON对象,取轨迹的第一个坐标点 + const pointGeojson = { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: pathArray[0] + } + } + + // 图层ID,保证唯一 + const lineLayerId = `path${index}` + const pointLayerId = `path${index}-point` + + // 绘制轨迹线 + const drawLine = () => { + if (this.map.getSource(lineLayerId)) return + this.map.addSource(lineLayerId, { + type: 'geojson', + data: lineGeojson + }) + this.map.addLayer({ + id: lineLayerId, + type: 'line', + source: lineLayerId, + layout: { + 'line-join': 'round', + 'line-cap': 'round' + }, + paint: { + 'line-color': '#3388ff', + 'line-width': 3 + } + }) + } + + // 绘制起点圆点 + const drawPoint = () => { + if (this.map.getSource(pointLayerId)) return + this.map.addSource(pointLayerId, { + type: 'geojson', + data: pointGeojson + }) + this.map.addLayer({ + id: pointLayerId, + type: 'circle', + source: pointLayerId, + paint: { + 'circle-radius': pointRadius, + 'circle-color': '#3388ff', + 'circle-stroke-color': '#fff', + 'circle-stroke-width': 2 + } + }) + } + + // 根据缩放等级切换显示轨迹线还是起点圆点 + const updateDisplay = () => { + const zoom = this.map.getZoom() + + // 起点圆点一直显示,先确保点图层存在 + if (!this.map.getSource(pointLayerId)) { + drawPoint() + } + + // 轨迹线根据缩放决定显示或隐藏 + if (zoom >= zoomThreshold) { + // 放大,显示轨迹线 + if (!this.map.getSource(lineLayerId)) { + drawLine() + } + } else { + // 缩小时隐藏轨迹线 + if (this.map.getLayer(lineLayerId)) { + this.map.removeLayer(lineLayerId) + } + if (this.map.getSource(lineLayerId)) { + this.map.removeSource(lineLayerId) + } + } + } + + // 首次渲染轨迹显示 + updateDisplay() + + // 监听缩放事件,动态切换显示 + this.map.on('zoom', () => { + updateDisplay() + }) + }, + /** + * @description: 创建飞机轨迹 ps:原理删除之前的轨迹 重新绘制 用于实时轨迹 * @param {arr} coordinatesArray 飞机经纬高度数组 */ createPathWithArray (coordinatesArray) { @@ -842,6 +981,7 @@ export default { /** * @description: 镜头跳转 * @param {obj} lonLat {lon:lon,lat:lat} 经纬度 + * @param {Number} zoom 地图放大率 */ goto (lonLat, zoom = 18) { this.map.flyTo({ diff --git a/src/views/layout/components/main/register/flyData.vue b/src/views/layout/components/main/register/flyData.vue index bf0a19c..02e0ddc 100644 --- a/src/views/layout/components/main/register/flyData.vue +++ b/src/views/layout/components/main/register/flyData.vue @@ -4,6 +4,7 @@
+ @@ -13,7 +14,7 @@
- +
暂无数据
@@ -39,7 +40,7 @@ export default { flyDataList: [], selectedPlaneIdArr: this.$store.state.app.toFlyDataIdArr, dateRange: [start, end], - radioClass: '飞行时长', + radioClass: '作业架次', boxShow: true } }, @@ -88,6 +89,7 @@ export default { const groupedData = {} const keyMap = { + 作业架次: () => 1, 飞行时长: (item) => { if (!item.start_time || !item.end_time) return 0 return Math.round((item.end_time - item.start_time) / 60) @@ -199,41 +201,73 @@ export default { methods: { // 地图组件回调地图加载完成后 执行 onMapReady () { - this.drawAllPathsOnMap() + this.drawAllHistoricalPaths() }, - // 地图轨迹绘制 - drawAllPathsOnMap () { + // 地图组件 历史轨迹绘制 + drawAllHistoricalPaths () { if (!this.$refs.mapbox) return + if (this.flyDataList.length === 0) return - // 清理旧轨迹 - this.$refs.mapbox.clearMapElements(['path'], ['path']) + // 准备要清除的所有轨迹图层和点图层id + const lineLayerIds = [] + const pointLayerIds = [] - // 遍历所有飞行数据,绘制轨迹 - this.flyDataList.forEach(item => { - if (!item.gps_path) return + // 解析所有轨迹 + this.flyDataList.forEach((item, index) => { + let pathArray = item.gps_path try { - const pathArray = JSON.parse(item.gps_path) - if (Array.isArray(pathArray) && pathArray.length > 0) { - this.$refs.mapbox.createPathWithArray(pathArray) + if (typeof pathArray === 'string') { + pathArray = JSON.parse(pathArray) } } catch (e) { - console.warn('gps_path 解析失败', item.gps_path) + console.warn(`第${index + 1}条轨迹 gps_path 解析失败`, e) + return + } + + // 添加图层id + lineLayerIds.push(`path${index}`) + pointLayerIds.push(`path${index}-point`) + }) + + // 清除所有轨迹图层和数据源 + this.$refs.mapbox.clearHistoryPaths(lineLayerIds, pointLayerIds) + + // 逐条绘制轨迹 + this.flyDataList.forEach((item, index) => { + let pathArray = item.gps_path + if (typeof pathArray === 'string') { + try { + pathArray = JSON.parse(pathArray) + } catch (e) { + console.warn(`第${index + 1}条轨迹 gps_path 解析失败`, e) + return + } + } + if (Array.isArray(pathArray) && pathArray.length > 0) { + this.$refs.mapbox.drawHistoryPathByIndex(pathArray, index) } }) - // 跳转到第一个轨迹的起点(经纬度) - if (this.flyDataList.length > 0 && this.flyDataList[0].gps_path) { - try { - const firstPath = JSON.parse(this.flyDataList[0].gps_path) - if (Array.isArray(firstPath) && firstPath.length > 0) { - const [lon, lat] = firstPath[0] - this.$refs.mapbox.goto({ lon, lat }) + // 跳转到第一条轨迹的第一个点 + const firstPath = this.flyDataList[0]?.gps_path + let firstPoint = null + if (firstPath) { + if (typeof firstPath === 'string') { + try { + firstPoint = JSON.parse(firstPath)[0] + } catch { + firstPoint = null } - } catch (e) { - // 解析失败不跳转 + } else if (Array.isArray(firstPath)) { + firstPoint = firstPath[0] } } + if (firstPoint && Array.isArray(firstPoint) && firstPoint.length >= 2) { + const [lon, lat] = firstPoint + this.$refs.mapbox.goto({ lon, lat }) + } }, + // 获取飞行数据 async loadFlyData () { if (this.selectedPlaneIdArr.length === 0) { @@ -280,7 +314,13 @@ export default { xAxis: { type: 'category' }, yAxis: { gridIndex: 0, - name: this.radioClass === '飞行时长' ? '分钟' : this.radioClass === '飞行距离' ? '米' : '毫安' + name: this.radioClass === '飞行时长' + ? '分钟' + : this.radioClass === '飞行距离' + ? '米' + : this.radioClass === '消耗电量' + ? '毫安' + : '架次' }, grid: { top: '55%' }, series: [