From 1d552a3bad95caae4af15322df28e6240b797693 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Thu, 13 Aug 2026 15:32:06 +0800
Subject: [PATCH] feat: app视频封面图

---
 applications/mobile-web-view/src/appComponents/workMap/index.vue |  482 +++++++++++++++++++----------------------------------
 1 files changed, 175 insertions(+), 307 deletions(-)

diff --git a/applications/mobile-web-view/src/appComponents/workMap/index.vue b/applications/mobile-web-view/src/appComponents/workMap/index.vue
index a037fca..71bf4e0 100644
--- a/applications/mobile-web-view/src/appComponents/workMap/index.vue
+++ b/applications/mobile-web-view/src/appComponents/workMap/index.vue
@@ -1,77 +1,34 @@
 <template>
 	<div class="page-container">
 		<div class="map" id="map"></div>
-
-		<div class="weather-box" v-show="weatherShow">
-			<div class="icon">
-				<van-image :src="WEATHER?.[weather] || ''" width="100%" height="100%"></van-image>
-			</div>
-
-			<div class="content">
-				<span class="tq">{{ weather }} {{ temperature }}</span>
-				<span class="tq">风速:{{ windVelocity }}</span>
-			</div>
-		</div>
-		<div class="back-btn" @click="goBackWork" v-show="workNavigationShow">
-			<van-image width="20" height="20" :src="backIcon" />
-			<div class="label">返回</div>
-		</div>
-		<div class="layer-btn" @click="layerChangePopupShow = true" v-show="layerShow">
-			<van-image width="20" height="20" :src="layerIcon" />
-			<div class="label">图层</div>
-		</div>
-
-		<div class="location-btn" @click="setMapLocation" v-show="locationShow">
-			<van-image width="20" height="20" :src="locationIcon" />
-			<div class="label">定位</div>
-		</div>
-		<!-- 事件导航按钮 -->
-		<div class="work-btn" v-show="workNavigationShow">
-			<van-button round block type="primary" color="#1D6FE9" @click="openAmap">事件导航</van-button>
-		</div>
-		<slot name="searchBar"></slot>
-		<slot name="eventNav"></slot>
-
-		<van-popup v-model:show="layerChangePopupShow" position="bottom" round>
-			<div class="popup-container">
-				<div class="category-content">
-					<div class="header">
-						<div class="title">底图切换</div>
-					</div>
-
-					<div class="content">
-						<div
-							class="layer-box"
-							:class="{ on: setSelectMapLayerKey === item.key }"
-							v-for="(item, ind) in layers"
-							:key="ind"
-							@click="setMapLayer(item)"
-						>
-							<div class="image">
-								<van-image :src="item.src" width="100%" height="100%"></van-image>
-							</div>
-							<div class="label">{{ item.name }}</div>
-						</div>
-					</div>
+				<div class="location-btn" @click="setMapLocation" v-show="locationShow">
+					<van-image width="20" height="20" :src="locationIcon" />
+					<div class="label">定位</div>
 				</div>
-			</div>
-		</van-popup>
+				<div class="nav-btn" @click="openNavigation" v-show="navigationTarget">
+					<van-image width="20" height="20" :src="mapnavIcon" />
+					<div class="label">导航</div>
+				</div>
+				<van-action-sheet
+					v-model:show="navigationSheetShow"
+					:actions="navigationActions"
+					cancel-text="取消"
+					@select="handleNavigationSelect"
+				/>
+
+
+				
 	</div>
 </template>
 
 <script setup>
 import { searchGeocoder } from '@/utils/util'
+import { showToast } from 'vant'
 import mapnavIcon from '@/appDataSource/appwork/mapnav.svg'
-import backIcon from '@/appDataSource/leafletMapIcon/back-icon.svg'
-import incidentPoint from '@/appDataSource/appwork/positioning.svg'
-import droneIcon from '@/appDataSource/leafletMapIcon/drone-icon.svg'
+import incidentPoint from '@/appDataSource/appwork/positioning1.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 { getDroneSuggest } from '@/api/home/common'
-import DroneMarkerPopup from '@/appComponents/DroneMarkerPopup/index.vue'
-import EventMarkerPopup from '@/appComponents/EventMarkerPopup/index.vue'
 import { basemapLayer0, basemapLayer1, basemapLayer2, basemapLayer3 } from '@/const/leafletConst'
 
 import L from 'leaflet'
@@ -79,24 +36,12 @@
 import sl from '@/appDataSource/leafletMapIcon/sl.svg'
 import yx from '@/appDataSource/leafletMapIcon/yx.svg'
 import EventBus from '@/utils/eventBus'
-import { polygonTransformScale } from '@/utils/turfFunc'
-import { getEventImage } from '@/utils/stateToImageMap/event'
-import { getDroneStatusImage } from '@/utils/stateToImageMap/drone'
-import { WEATHER } from '@/const/weather'
+
 import { wgs84ToGcj02 } from '@/utils/coordinateTransformation'
 const emit = defineEmits(['location-selected'])
 import _ from 'lodash'
-import { useAreaBoundary } from '@/hooks/useAreaBoundary'
-const { weatherShow, layerShow, locationShow, createWorkShow, workNavigationShow, mapCurrentDetail, clearMarker } =
+const {  locationShow, createWorkShow, workNavigationShow, mapCurrentDetail, clearMarker } =
 	defineProps({
-		weatherShow: {
-			type: Boolean,
-			default: false,
-		},
-		layerShow: {
-			type: Boolean,
-			default: false,
-		},
 		locationShow: {
 			type: Boolean,
 			default: false,
@@ -119,6 +64,21 @@
 	})
 const currentAddress = ref('')
 const AMAP_KEY = '5b8ba312d053e4bdb44911733ece7d63'
+const navigationSheetShow = ref(false)
+const navigationActions = [{ name: '高德地图' }, { name: '百度地图' }, { name: '腾讯地图' }]
+const navigationTarget = computed(() => {
+	if (!workNavigationShow || !mapCurrentDetail?.longitude || !mapCurrentDetail?.latitude) return null
+
+	const lat = parseFloat(mapCurrentDetail.latitude)
+	const lng = parseFloat(mapCurrentDetail.longitude)
+	if (Number.isNaN(lat) || Number.isNaN(lng)) return null
+
+	return {
+		lat,
+		lng,
+		name: mapCurrentDetail.eventLocation || mapCurrentDetail.address || '工单位置',
+	}
+})
 
 const basemap0 = L.layerGroup([basemapLayer0, basemapLayer1])
 const basemap1 = L.layerGroup([basemapLayer2, basemapLayer3])
@@ -140,9 +100,7 @@
 	},
 ]
 
-const layerChangePopupShow = ref(false)
 const setSelectMapLayerKey = ref(1) // 选择的地图图层
-let boundaryInstance = useAreaBoundary({ initFly: true })
 let markersLayer = null
 const initMap = () => {
 	if (map) return
@@ -155,7 +113,6 @@
 		doubleClickZoom: false,
 		editable: true, //绘制控件
 	}).setView([25.992338, 114.823254], 13)
-	boundaryInstance.initBoundary(map)
 
 	markersLayer = L.layerGroup().addTo(map) // 创建一个标注层,便于管理和移除
 	if (createWorkShow) {
@@ -174,9 +131,9 @@
 let locationFlag = false
 let watchId = null
 let userLocationMarker = null
-const setMapLocation = () => {
-	locationFlag = true
 
+// 初始化实时位置监听
+const initLocationWatch = () => {
 	// 在WebView加载的网页中
 	// 检查浏览器是否支持 geolocation
 	if (navigator.geolocation) {
@@ -184,7 +141,6 @@
 			// 停止监听位置
 			navigator.geolocation.clearWatch(watchId)
 		}
-
 		// 开始持续获取用户的位置
 		watchId = navigator.geolocation.watchPosition(
 			function (position) {
@@ -192,27 +148,27 @@
 				const lat = position.coords.latitude // 纬度
 				const lng = position.coords.longitude // 经度
 
+				// 确保位置标记存在并更新位置
 				if (userLocationMarker) {
 					userLocationMarker.setLatLng([lat, lng])
-				}
-
-				if (locationFlag) {
+				} else {
 					userLocationMarker = L.marker([lat, lng], {
 						icon: L.icon({
 							iconUrl: userLocationIcon, // 图片路径
-							iconSize: [24, 24], // 图标尺寸
-							iconAnchor: [12, 12], // 锚点位置
-						}),
+								iconSize: [24, 24], // 图标尺寸
+								iconAnchor: [12, 12], // 锚点位置
+							}),
 					}).addTo(map)
+				}
 
+				// 如果是点击定位按钮触发的,将地图视图定位到当前位置
+				if (locationFlag) {
 					mapSetView({
 						lat,
 						lng,
 					})
-
 					locationFlag = false
 				}
-				// 可以根据位置更新地图或界面
 			},
 			function (error) {
 				// 如果获取位置失败,执行回调
@@ -225,20 +181,62 @@
 			}
 		)
 	} else {
-		console.log('Geolocation is not supported by this browser.')
+		console.log('该浏览器不支持地理定位功能。')
+	}
+}
+
+const setMapLocation = () => {
+	locationFlag = true
+	// 如果还没有开始监听位置,先初始化监听
+	if (!watchId) {
+		initLocationWatch()
+	} else {
+		// 已经在监听位置,会自动定位到当前位置
+		// 可以添加一个视觉反馈,比如位置标记闪烁效果
+		if (userLocationMarker) {
+			// 添加闪烁效果
+			userLocationMarker.getElement().classList.add('location-blink')
+			setTimeout(() => {
+				userLocationMarker.getElement().classList.remove('location-blink')
+			}, 1000)
+		}
+	}
+}
+
+function openNavigation() {
+	if (!navigationTarget.value) {
+		showToast('暂无可导航的位置')
+		return
 	}
 
-	// 获取定位信息
-	// uni.getLocation({
-	// 	type: 'wgs84', // 返回的经纬度是 WGS84 坐标系(适合地图定位)
-	// 	isHighAccuracy: true,
-	// 	success: function (res) {
-	// 		location.value = res
-	// 	},
-	// 	fail: function (err) {
-	// 		console.log('定位失败:', err)
-	// 	},
-	// })
+	navigationSheetShow.value = true
+}
+
+function handleNavigationSelect(action) {
+	navigationSheetShow.value = false
+	const url = getNavigationUrl(action.name, navigationTarget.value)
+	if (url) {
+		window.location.href = url
+	}
+}
+
+function getNavigationUrl(type, target) {
+	const [gcjLng, gcjLat] = wgs84ToGcj02(target.lng, target.lat)
+	const name = encodeURIComponent(target.name)
+
+	if (type === '高德地图') {
+		return `https://uri.amap.com/navigation?to=${gcjLng},${gcjLat},${name}&mode=car&policy=1&coordinate=gaode&callnative=1`
+	}
+
+	if (type === '百度地图') {
+		return `https://api.map.baidu.com/direction?destination=latlng:${gcjLat},${gcjLng}|name:${name}&mode=driving&coord_type=gcj02&output=html&src=ja-web`
+	}
+
+	if (type === '腾讯地图') {
+		return `https://apis.map.qq.com/uri/v1/routeplan?type=drive&tocoord=${gcjLat},${gcjLng}&to=${name}&referer=ja-web`
+	}
+
+	return ''
 }
 
 let lastLocationMarker = null
@@ -311,31 +309,13 @@
 const store = useStore()
 const selectedAreaCode = computed(() => store.state.user.selectedAreaCode)
 
-const weather = ref('')
-// 风速
-const windVelocity = ref('')
-const temperature = ref('')
-// 获取天气建议
-const getWeatherSuggest = () => {
-	getDroneSuggest({ areaCode: selectedAreaCode.value }).then(res => {
-		if (res.data.code !== 0) return
-		weather.value = res.data.data.weather
-		windVelocity.value = res.data.data.windPower
-		temperature.value = res.data.data.temperature
-	})
-}
-const goBackWork = () => {
-	const transmitData = { data: { type: 'workDetailback' } }
-	wx.miniProgram.navigateBack({
-      delta: 1,
-    })
-	wx.miniProgram.postMessage(transmitData)
-	uni.postMessage(transmitData)
-
-	markersLayer.removeLayer(incidentMarker)
-}
 // 存储事件点标记实例,用于后续更新或移除
 let incidentMarker = null
+
+function formatCoordinate(value) {
+	const numberValue = Number(value)
+	return Number.isNaN(numberValue) ? value : numberValue.toFixed(6)
+}
 
 // 添加事件点标记
 function addIncidentMarker(data) {
@@ -373,6 +353,19 @@
 
 	// 存储关联数据
 	incidentMarker.options.customData = data
+	incidentMarker.bindTooltip(
+		`<div class="coordinate-label">
+			<div>经度:${formatCoordinate(lng)}</div>
+			<div>纬度:${formatCoordinate(lat)}</div>
+		</div>`,
+		{
+			permanent: true,
+			direction: 'top',
+			offset: L.point(0, -16),
+			opacity: 1,
+			className: 'incident-coordinate-tooltip',
+		}
+	)
 
 	// 定位到该标记点
 	mapSetView({
@@ -385,10 +378,11 @@
 watch(
 	() => mapCurrentDetail,
 	newVal => {
+const newDataMap=newVal
 		// 只有 workNavigationShow 为 true 且有经纬度时才添加标记
-		if (workNavigationShow && newVal?.longitude && newVal?.latitude) {
-			addIncidentMarker(newVal)
-			mapCurrentDetailData.value = newVal
+		if (workNavigationShow && newDataMap?.longitude && newDataMap?.latitude) {
+			addIncidentMarker(newDataMap)
+			mapCurrentDetailData.value = newDataMap
 		} else if (!workNavigationShow && incidentMarker) {
 			// 当 workNavigationShow 变为 false 时,移除已添加的标记
 			markersLayer.removeLayer(incidentMarker)
@@ -398,37 +392,31 @@
 	{ immediate: true, deep: true }
 )
 
-const openAmap = () => {
-	if (!mapCurrentDetailData.value.longitude || !mapCurrentDetailData.value.latitude) {
-		showToast('未获取到事件坐标')
-		return
-	}
-	// wgs84ToGcj02(Number(item.longitude), Number(item.latitude))
-	// wgs84ToGcj02(mapCurrentDetailData.value.longitude, mapCurrentDetailData.value.latitude)
-	const [gcjLng, gcjLat] = wgs84ToGcj02(
-		Number(mapCurrentDetailData.value.longitude),
-		Number(mapCurrentDetailData.value.latitude)
-	)
 
-	// 高德地图URL Scheme
-	const url = `https://uri.amap.com/marker?position=${gcjLng},${gcjLat}&name=%E4%BA%8B%E4%BB%B6%E7%82%B9&from='ztzf'`
-
-	const transmitData = { data: { type: 'browser', data: { url: url } } }
-	wx.miniProgram.navigateTo({ url: `/subPackages/browser/index?url=${encodeURIComponent(url)}` })
-	wx.miniProgram.postMessage(transmitData)
-	uni.postMessage(transmitData)
-}
 onMounted(async () => {
-	getWeatherSuggest()
 
 	await nextTick()
 	initMap()
 	map.addLayer(layers[0].map)
 
+	// 初始化实时位置监听
+	initLocationWatch()
+
 	EventBus.on('mapSetView', mapSetView)
 })
 
 onUnmounted(() => {
+	// 清理位置监听
+	if (watchId) {
+		navigator.geolocation.clearWatch(watchId)
+		watchId = null
+	}
+	// 移除位置标记
+	if (userLocationMarker) {
+		map.removeLayer(userLocationMarker)
+		userLocationMarker = null
+	}
+	
 	EventBus.off('mapSetView', mapSetView)
 	if (map) {
 		map.remove()
@@ -453,83 +441,8 @@
 		width: 100%;
 		height: 100%;
 	}
-	// 事件导航按钮
-	.work-btn {
-		position: absolute;
-		bottom: 80px;
-		left: 0;
-		right: 0;
-		z-index: 996;
-		padding: 0 16px;
-		display: flex;
-		justify-content: center;
-	}
-
-	.work-btn :deep(.van-button) {
-		width: 100%;
-		max-width: 194px;
-		height: 38px;
-	}
-
-	.weather-box {
-		padding: 4px 0;
-		padding-right: 6px;
-		display: flex;
-		justify-content: center;
-		align-items: center;
-		position: absolute;
-		top: 12px;
-		left: 12px;
-
-		height: 48px;
-		background: #fff;
-		z-index: 996;
-
-		box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.18);
-		border-radius: 6px 6px 6px 6px;
-
-		.icon {
-			margin-left: 10px;
-			width: 24px;
-			height: 24px;
-		}
-
-		.content {
-			height: 100%;
-			margin-left: 4px;
-			display: flex;
-			flex-direction: column;
-			justify-content: space-around;
-
-			font-family: Source Han Sans CN, Source Han Sans CN;
-			font-weight: 400;
-			font-size: 12px;
-			color: #757575;
-			text-align: left;
-			font-style: normal;
-			text-transform: none;
-		}
-
-		.tq {
-			margin: 0 5px;
-		}
-		.qk {
-			margin-left: 5px;
-			color: #04f043;
-		}
-		.yellowqk {
-			margin-left: 5px;
-			color: yellow;
-		}
-		.redqk {
-			margin-left: 5px;
-			color: red;
-		}
-	}
-
 	.location-btn,
-	.layer-btn,
-	.back-btn {
+	.nav-btn{
 		display: flex;
 		flex-direction: column;
 		justify-content: center;
@@ -547,99 +460,54 @@
 			font-size: 10px;
 		}
 	}
-	.back-btn {
-		bottom: 185px;
-	}
-	.layer-btn {
-		bottom: 130px;
-	}
-
 	.location-btn {
 		bottom: 76px;
 	}
+	.nav-btn {
+		bottom: 28px;
+	}
 }
 
-.popup-container {
-	padding: 10px 22px;
-	background: #fff;
-	border-radius: 12px 12px 0 0;
+// 位置标记闪烁效果
+.location-blink {
+	animation: blink 1s ease-in-out;
+}
 
-	.category-content {
-		.header {
-			height: 20px;
-			font-family: Source Han Sans CN, Source Han Sans CN;
-			font-weight: bold;
-			font-size: 16px;
-			color: #222324;
-			line-height: 20px;
-			text-align: left;
-			font-style: normal;
-			text-transform: none;
-		}
+:deep(.incident-coordinate-tooltip) {
+	padding: 0;
+	border: 0;
+	background: transparent;
+	box-shadow: none;
 
-		.content {
-			padding: 12px;
-			display: flex;
-			background: #fff;
-			border-radius: 16px;
+	&::before {
+		display: none;
+	}
+}
 
-			.layer-box {
-				margin-left: calc((100% / 3 - 84px) * 3 / 2);
+:deep(.coordinate-label) {
+	padding: 4px 7px;
+	background: rgba(255, 255, 255, 0.95);
+	border: 1px solid rgba(76, 133, 255, 0.35);
+	border-radius: 4px;
+	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
+	font-size: 11px;
+	line-height: 16px;
+	color: #222324;
+	white-space: nowrap;
+}
 
-				&:first-child {
-					margin-left: 0;
-				}
-
-				&.on {
-					.image {
-						position: relative;
-
-						&::after {
-							content: '';
-							position: absolute;
-							top: 0;
-							left: 0;
-							width: 100%;
-							height: 100%;
-							border-radius: 4px 4px 4px 4px;
-							border: 4px solid #1d6fe9;
-							z-index: 1;
-							box-sizing: border-box;
-						}
-					}
-
-					.label {
-						color: #1d6fe9;
-					}
-				}
-
-				.image {
-					width: 84px;
-					height: 82px;
-					border-radius: 4px 4px 4px 4px;
-					overflow: hidden;
-					box-sizing: border-box;
-					border: none;
-				}
-
-				.label {
-					margin-top: 6px;
-					height: 20px;
-					font-family: Source Han Sans CN, Source Han Sans CN;
-					font-weight: 400;
-					font-size: 14px;
-					color: #222324;
-					line-height: 20px;
-					text-align: center;
-					font-style: normal;
-					text-transform: none;
-				}
-			}
-
-			.layer-box:nth-child(3n + 1) {
-				margin-left: 0;
-			}
-		}
+@keyframes blink {
+	0% {
+		transform: scale(1);
+		opacity: 1;
+	}
+	50% {
+		transform: scale(1.2);
+		opacity: 0.8;
+	}
+	100% {
+		transform: scale(1);
+		opacity: 1;
 	}
 }
 </style>

--
Gitblit v1.9.3