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/api/map/address.js                 |   14 ++
 uniapps/work-wx/src/pages.json                                      |   11 +
 applications/mobile-web-view/src/appComponents/LeafletMap/index.vue |  184 ++++++++++++++++++++++++++++++
 uniapps/work-wx/src/subPackages/airspaceInformation/index.vue       |   93 ++++++++++++++-
 applications/mobile-web-view/src/router/page/index.js               |    6 +
 5 files changed, 299 insertions(+), 9 deletions(-)

diff --git a/applications/mobile-web-view/src/api/map/address.js b/applications/mobile-web-view/src/api/map/address.js
index 200b7d1..8129be0 100644
--- a/applications/mobile-web-view/src/api/map/address.js
+++ b/applications/mobile-web-view/src/api/map/address.js
@@ -14,3 +14,17 @@
     data
   })
 }
+/**
+ * @description: 获取空域详情 吉安项目
+ * @param {*} data :{
+ *  id:string 空域id
+ * }
+ * @return {*} Promise
+ */
+export const getAirspaceDetail = (data) => {
+  return request({
+    url: `/webservice/flightAirspace/pageInfo`,
+    method: 'post',
+    data
+  })
+}
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)
 })
 
diff --git a/applications/mobile-web-view/src/router/page/index.js b/applications/mobile-web-view/src/router/page/index.js
index eb93a61..4406f9c 100644
--- a/applications/mobile-web-view/src/router/page/index.js
+++ b/applications/mobile-web-view/src/router/page/index.js
@@ -54,6 +54,12 @@
 				},
 			},
 			{
+				path: 'airMap',
+				name: '地图',
+				component: () => import('@/appPages/AirMap/index.vue'),
+				meta: { title: '地图'},
+			},
+			{
 				path: 'QrCodeScanner',
 				name: '扫码',
 				component: () => import('@/appPages/QrCodeScanner/index.vue'),
diff --git a/uniapps/work-wx/src/pages.json b/uniapps/work-wx/src/pages.json
index 2f49cea..98d5c7d 100644
--- a/uniapps/work-wx/src/pages.json
+++ b/uniapps/work-wx/src/pages.json
@@ -18,7 +18,7 @@
 		{
 			"path": "pages/register/index",
 			"style": {
-				"navigationBarTitleText": "注册",
+				"navigationBarTitleText": "注册"
 			}
 		},
 		{
@@ -43,6 +43,13 @@
 				"navigationStyle": "custom"
 			}
 		},
+    {
+      "path": "pages/map/index",
+      "style": {
+        "navigationBarTitleText": "地图",
+        "navigationStyle": "custom"
+      }
+    },
 		{
 			"path": "pages/login/index",
 			"style": {
@@ -62,7 +69,7 @@
 						"navigationStyle": "custom"
 					}
 				},
-				
+
 				{
 					"path": "airspaceInformation/index",
 					"style": {
diff --git a/uniapps/work-wx/src/subPackages/airspaceInformation/index.vue b/uniapps/work-wx/src/subPackages/airspaceInformation/index.vue
index 56500b2..2838ca6 100644
--- a/uniapps/work-wx/src/subPackages/airspaceInformation/index.vue
+++ b/uniapps/work-wx/src/subPackages/airspaceInformation/index.vue
@@ -1,10 +1,91 @@
+<!--
+ * @Author       : yuan
+ * @Date         : 2025-12-03 14:20:57
+ * @LastEditors  : yuan
+ * @LastEditTime : 2025-12-20 16:49:02
+ * @FilePath     : \src\pages\map\index.vue
+ * @Description  :
+ * Copyright 2025 OBKoro1, All Rights Reserved.
+ * 2025-12-03 14:20:57
+-->
 <template>
-<view class="airspaceInformation">
-    <view class="title">
-        空域信息
-    </view>
-</view>
+  <view class="page-wrap">
+    <WebViewPlus :src="`${viewUrl}`" @webMessage="onPostMessage" />
+  </view>
 </template>
+
 <script setup>
-import { ref } from 'vue'
+import { getWebViewUrl } from "@/utils/index.js";
+import WebViewPlus from "@/components/WebViewPlus.vue";
+import { onHide, onShow } from "@dcloudio/uni-app";
+// const viewUrl = getWebViewUrl("/defaultMap");
+
+let envParam = "";
+// #ifdef WEB
+envParam = "true";
+// #endif
+// #ifdef APP-PLUS
+envParam = "false";
+// #endif
+
+const updateKey = ref(0);
+const viewUrl = computed(() => {
+  return getWebViewUrl("/airMap", {
+    isWeb: envParam,
+    updateKey: updateKey.value,
+  });
+});
+
+const onPostMessage = (data) => {
+  // #ifdef MP-WEIXIN
+  if (data.type === "scanCode") {
+  } else if (data.type === "jumpAddWork") {
+  } else if (data.type === "jumpMapNav") {
+    //事件导航
+  } else if (data.type === "workid") {
+    //事件详情
+  }
+  // #endif
+
+  // #ifndef MP-WEIXIN
+  if (data.type === "scanCode") {
+    uni.navigateTo({
+      url: "/subPackages/qrCode/index",
+    });
+  } else if (data.type === "jumpAddWork") {
+    //新建任务
+    const encodedData = encodeURIComponent(JSON.stringify(data.rowItem));
+    uni.setStorageSync("webview_params", encodedData);
+    uni.navigateTo({
+      url: `/subPackages/taskDetail/addTask/index`,
+    });
+  } else if (data.type === "jumpMapNav") {
+    //事件导航
+    uni.navigateTo({
+      url: `/subPackages/workDetail/mapWork/index?currentItem=${data.eventNum}`,
+    });
+  } else if (data.type === "workid") {
+    //事件详情
+    uni.navigateTo({
+      url: `/subPackages/workDetail/index?eventNum=${data.eventNum}`,
+    });
+  }
+  // #endif
+};
+
+onShow(() => {
+  // #ifndef MP-WEIXIN
+
+  // #endif
+});
+
+onHide(() => {
+  updateKey.value = updateKey.value + 1;
+});
 </script>
+
+<style scoped lang="scss">
+.page-wrap {
+  font-size: 20px;
+}
+</style>

--
Gitblit v1.9.3