From a67c8402eb8fd055f49a83441d54891060cc41dd Mon Sep 17 00:00:00 2001
From: chenyao <1219716595@qq.com>
Date: Wed, 14 Jan 2026 10:17:49 +0800
Subject: [PATCH] feat:更新小程序

---
 applications/mobile-web-view/src/appComponents/LeafletMap/index.vue |  184 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 183 insertions(+), 1 deletions(-)

diff --git a/applications/mobile-web-view/src/appComponents/LeafletMap/index.vue b/applications/mobile-web-view/src/appComponents/LeafletMap/index.vue
index d2fda5d..b6add64 100644
--- a/applications/mobile-web-view/src/appComponents/LeafletMap/index.vue
+++ b/applications/mobile-web-view/src/appComponents/LeafletMap/index.vue
@@ -39,12 +39,14 @@
 </template>
 
 <script setup>
+	import * as turf from '@turf/turf'
 import addressLocationIcon from '@/appDataSource/leafletMapIcon/address-location.svg'
 import droneIcon from '@/appDataSource/leafletMapIcon/drone-icon.svg'
 import userLocationIcon from '@/appDataSource/leafletMapIcon/user-location.svg'
 import layerIcon from '@/appDataSource/leafletMapIcon/layer-icon.svg'
 import locationIcon from '@/appDataSource/leafletMapIcon/location-icon.svg'
 import { useStore } from 'vuex'
+import { showToast } from 'vant'
 import L from 'leaflet'
 import 'leaflet/dist/leaflet.css'
 import sl from '@/appDataSource/leafletMapIcon/sl.svg'
@@ -102,6 +104,7 @@
 let droneMarkersLayer = null
 let eventMarkersLayer = null
 let addressMarkersLayer = null
+let mapLayerSourceLayer = null // 空域信息
 
 const initMap = () => {
 	if (map) return
@@ -112,7 +115,7 @@
 		attributionControl: false,
 		doubleClickZoom: false,
 		editable: true, //绘制控件
-	}).setView([25.992338, 114.823254], 3)
+	}).setView([27.117445, 114.984917], 10)
 
 	map.whenReady(() => {
 		isMapReady.value = true
@@ -121,6 +124,8 @@
 	droneMarkersLayer = L.layerGroup([], { pane: 'drones' }).addTo(map) // 创建一个标注层,便于管理和移除
 	eventMarkersLayer = L.layerGroup([], { pane: 'events' }).addTo(map) // 创建一个标注层,便于管理和移除
 	addressMarkersLayer = L.layerGroup([], { pane: 'addresses' }).addTo(map) // 创建一个标注层,便于管理和移除
+	// 空域信息
+	mapLayerSourceLayer = L.layerGroup([], { pane: 'mapLayerSource' }).addTo(map)
 
 	map.on('zoomend', function () {
 		var currentZoom = map.getZoom()
@@ -260,6 +265,177 @@
 	L.marker([lat, lng], { icon: droneHtmlIcon }).addTo(addressMarkersLayer)
 }
 
+// 吉安项目-空域信息
+// 统一的飞行函数
+function flyVisual(coordinates) {
+	console.log(coordinates, '0000')
+	// 确保map对象存在且坐标有效
+	if (!map || !coordinates || !coordinates.length) return;
+	
+	try {
+		// 改进坐标格式判断
+		let isSinglePoint = false;
+		let latLng;
+		let bounds;
+		
+		// 处理不同格式的坐标输入
+		if (Array.isArray(coordinates[0])) {
+			if (coordinates[0].length === 2) {
+				// 格式: [[lng, lat]] - 单个点
+				isSinglePoint = true;
+				latLng = [coordinates[0][1], coordinates[0][0]]; // 转换为 [lat, lng]
+			} else if (coordinates[0].length > 2 && Array.isArray(coordinates[0][0])) {
+				// 格式: [[[lng, lat], [lng, lat], ...]] - 多边形
+				const polygonCoords = coordinates[0].map(coord => [coord[1], coord[0]]);
+				bounds = L.latLngBounds(polygonCoords);
+			} else {
+				// 格式: [[lng, lat], [lng, lat], ...] - 多个点或线
+				if (coordinates.length === 1) {
+					// 单个点
+					isSinglePoint = true;
+					latLng = [coordinates[0][1], coordinates[0][0]];
+				} else {
+					// 多个点
+					const leafletCoords = coordinates.map(coord => [coord[1], coord[0]]);
+					bounds = L.latLngBounds(leafletCoords);
+				}
+			}
+		} else if (coordinates.length === 2) {
+			// 格式: [lng, lat] - 单个点
+			isSinglePoint = true;
+			latLng = [coordinates[1], coordinates[0]];
+		}
+		
+		if (isSinglePoint && latLng) {
+			// 单个坐标点
+			map.flyTo(latLng, 10, {
+				duration: 1,
+				easeLinearity: 0.2
+			});
+		} else if (bounds) {
+			// 多边形或多个点
+			map.flyToBounds(bounds, {
+				padding: [30, 30],
+				duration: 2,
+				maxZoom: 13
+			});
+		}
+	} catch (error) {
+		console.error('flyVisual 函数执行错误:', error);
+	}
+}
+// 点击单个飞行
+function signFlyToMarker(item) {
+	const positionsData = JSON.parse(item.content);
+	const coordinates = positionsData.coordinates;
+	console.log('coordinates数据:', coordinates, '类型:', typeof coordinates, '长度:', coordinates?.length);
+	
+	// 更全面的空值检查
+	let hasValidCoordinates = false;
+	
+	// 检查不同格式的坐标数据
+	if (Array.isArray(coordinates)) {
+		if (coordinates.length > 0) {
+			// 检查是否有有效的坐标点
+			if (Array.isArray(coordinates[0])) {
+				if (coordinates[0].length === 2 || coordinates[0].length === 3) {
+					// 格式: [lng, lat] 或 [lng, lat, alt]
+					hasValidCoordinates = true;
+				} else if (Array.isArray(coordinates[0][0])) {
+					// 格式: [[lng, lat], [lng, lat], ...]
+					hasValidCoordinates = coordinates[0].length > 0;
+				} else if (Array.isArray(coordinates[0][0][0])) {
+					// 格式: [[[lng, lat], [lng, lat], ...]]
+					hasValidCoordinates = coordinates[0][0].length > 0;
+				}
+			}
+		}
+	}
+	
+	if (!hasValidCoordinates) {
+		console.log('没有有效的坐标数据,显示提示');
+		return showToast('暂无区域数据');
+	}
+	
+	// 单个位置飞行
+	flyVisual(coordinates);
+}
+// 清空所有空域信息
+function mapClearAirMarker() {
+	if (!map) return
+	// 清空所有图层
+	if (mapLayerSourceLayer) {
+		mapLayerSourceLayer.clearLayers();
+	}
+}
+function mapAddAirMarker(data) {
+	// 清空所有图层
+	mapClearAirMarker()
+
+	data
+		.filter(item => item.content)
+		.forEach(item => {
+			const parseParsed = JSON.parse(item.content); // 转为数组
+			if (parseParsed.type !== 'Polygon') return
+			const parsed = parseParsed.coordinates[0]
+			
+			const grouped = parsed.flat(); // 再展开
+			
+			// 3. 计算多边形质心
+			const turfPolygon = turf.polygon([parsed]);
+			const center = turf.centerOfMass(turfPolygon);
+			const centerLatLng = [center.geometry.coordinates[1], center.geometry.coordinates[0]];
+
+			const labelMarker = L.marker(centerLatLng, {
+				icon: L.divIcon({
+					className: 'polygon-label',
+					html: `
+                            <div style="
+                                color: ${item.airspaceType === '0' ? '#008013' : '#ff0000'};
+                                font-weight: bold;
+                                font-size: 12px;
+                                font-family: 'Source Han Sans CN', 'Source Han Sans CN';
+                                white-space: nowrap;
+                            ">
+                                ${item.airspaceType === '1' ? '禁飞区' : item.airspaceType === '2' ? '危险区' : item.airspaceType === '3' ? '限制区' : item.airspaceType === '0' ? '适飞区' : '未知'}
+                            </div>
+                        `,
+					iconSize: null,    // 让div决定大小
+					iconAnchor: null   // 不需要锚点,用CSS transform居中
+				}),
+				interactive: false,    // 标签不参与交互
+				// zIndexOffset: 1000     // 确保标签在最上层
+			});
+
+			// 将坐标数组转换为 Leaflet 格式 [lat, lng, lat, lng...] -> [[lat, lng], [lat, lng]...]
+			const latLngs = [];
+			for (let i = 0; i < grouped.length; i += 2) {
+				latLngs.push([grouped[i + 1], grouped[i]]); // 注意:Leaflet 是 [lat, lng] 顺序
+			}
+
+			// 创建多边形(填充区域)
+			const polygon = L.polygon(latLngs, {
+				color: item.airspaceType === '0' ? '#00ff06' : '#ff0000',
+				fillColor: item.airspaceType === '0' ? '#00ff06' : '#ff0000',
+				fillOpacity: 0.5,
+				weight: 0, // 隐藏多边形边框,使用折线作为边框
+			});
+
+			// 创建折线(边框)
+			const polyline = L.polyline([...latLngs, latLngs[0]], { // 闭合多边形
+				color: item.airspaceType === '0' ? '#00ff06' : '#ff0000',
+				weight: 1.5,
+				opacity: 1,
+				fill: false
+			});
+
+			// 将两个图层组合在一起
+			const group = L.featureGroup([polygon, polyline, labelMarker]);
+			// 添加到图层组
+			mapLayerSourceLayer.addLayer(group);
+		});
+}
+
 const mapClearMarker = () => {
 	addressMarkersLayer.clearLayers()
 }
@@ -276,6 +452,9 @@
 
 	EventBus.on('mapSetView', mapSetView)
 	EventBus.on('mapAddMarker', mapAddMarker)
+	EventBus.on('mapAddAirMarker', mapAddAirMarker)
+	EventBus.on('signFlyToMarker', signFlyToMarker)
+	EventBus.on('mapClearAirMarker', mapClearAirMarker)
 	EventBus.on('mapClearMarker', mapClearMarker)
 
 	// L.circle([24, 112], {
@@ -289,6 +468,9 @@
 onUnmounted(() => {
 	EventBus.off('mapSetView', mapSetView)
 	EventBus.off('mapAddMarker', mapAddMarker)
+	EventBus.off('mapAddAirMarker', mapAddAirMarker)
+	EventBus.off('signFlyToMarker', signFlyToMarker)
+	EventBus.off('mapClearAirMarker', mapClearAirMarker)
 	EventBus.off('mapClearMarker', mapClearMarker)
 })
 

--
Gitblit v1.9.3