简化来馆面板并优化地图点位展示

This commit is contained in:
lyf
2026-07-09 18:46:56 +08:00
parent 5b4fe19ce3
commit 3f9c64a36e
5 changed files with 587 additions and 221 deletions

View File

@@ -59,7 +59,7 @@
</template>
<script setup lang="ts">
import { computed, ref, onBeforeUnmount, onMounted, nextTick } from 'vue'
import { computed, ref, onBeforeUnmount, onMounted, nextTick, watch } from 'vue'
import { getMuseumEntranceLocation } from '@/services/tencent/TencentMapService'
const isH5 = typeof window !== 'undefined'
@@ -103,6 +103,14 @@ interface Polyline {
dottedLine?: boolean
}
export interface OutdoorMapMarker {
id: string
title: string
subtitle?: string
latitude: number
longitude: number
}
interface MapFloor {
id: string
label: string
@@ -112,14 +120,21 @@ const props = withDefaults(defineProps<{
activeFloor?: string
floors?: MapFloor[]
polylines?: Polyline[]
outdoorMarkers?: OutdoorMapMarker[]
activeOutdoorMarkerId?: string
outdoorFocusOffsetY?: number
}>(), {
activeFloor: '1F',
floors: () => [] as MapFloor[],
polylines: () => [] as Polyline[]
polylines: () => [] as Polyline[],
outdoorMarkers: () => [] as OutdoorMapMarker[],
activeOutdoorMarkerId: '',
outdoorFocusOffsetY: 0
})
const emit = defineEmits<{
markerClick: [markerId: number]
outdoorMarkerClick: [markerId: string]
floorChange: [floor: string]
enter3DMode: []
mapTap: [location: { latitude: number; longitude: number }]
@@ -138,9 +153,11 @@ const mapScale = ref(17)
// 当前楼层
const currentFloor = ref(props.activeFloor)
const mapComponentRef = ref<unknown>(null)
const userLocationMarker = ref<Marker | null>(null)
let mapAuthErrorObserver: MutationObserver | null = null
let mapAuthErrorLogged = false
const mapAuthErrorText = '鉴权失败请传入正确的key'
const OUTDOOR_MARKER_ID_BASE = 20000
// 楼层列表
const floors = computed(() => props.floors)
@@ -213,8 +230,46 @@ const entranceMarker = ref<Marker>({
}
})
const outdoorMarkerIdMap = computed(() => {
const markerMap = new Map<number, string>()
props.outdoorMarkers.forEach((marker, index) => {
markerMap.set(OUTDOOR_MARKER_ID_BASE + index, marker.id)
})
return markerMap
})
const outdoorDisplayMarkers = computed<Marker[]>(() => (
props.outdoorMarkers.map((marker, index) => {
const isActive = marker.id === props.activeOutdoorMarkerId
return {
id: OUTDOOR_MARKER_ID_BASE + index,
latitude: marker.latitude,
longitude: marker.longitude,
iconPath: '/static/icons/marker-location.svg',
width: isActive ? 42 : 32,
height: isActive ? 42 : 32,
title: marker.title,
callout: {
content: marker.subtitle ? `${marker.title}\n${marker.subtitle}` : marker.title,
display: isActive ? 'ALWAYS' : 'BYCLICK',
padding: 10,
borderRadius: 6,
bgColor: isActive ? '#262421' : '#FFFFFF',
color: isActive ? '#E0E100' : '#262421',
fontSize: 12
}
}
})
))
// 地图标记点列表
const markers = computed(() => [museumMarker.value, entranceMarker.value])
const markers = computed(() => [
museumMarker.value,
entranceMarker.value,
...outdoorDisplayMarkers.value,
...(userLocationMarker.value ? [userLocationMarker.value] : [])
])
// 显示的路线列表(转换格式以适配 uni-app map 组件)
const displayPolylines = computed(() => {
@@ -233,8 +288,7 @@ const displayPolylines = computed(() => {
* 更新用户位置标记
*/
const updateUserLocation = (location: { latitude: number; longitude: number }) => {
const userMarkerIndex = markers.value.findIndex((m) => m.id === 999)
const userMarker: Marker = {
userLocationMarker.value = {
id: 999,
latitude: location.latitude,
longitude: location.longitude,
@@ -252,22 +306,13 @@ const updateUserLocation = (location: { latitude: number; longitude: number }) =
fontSize: 12
}
}
if (userMarkerIndex >= 0) {
markers.value[userMarkerIndex] = userMarker
} else {
markers.value.push(userMarker)
}
}
/**
* 清除用户位置标记
*/
const clearUserLocation = () => {
const userMarkerIndex = markers.value.findIndex((m) => m.id === 999)
if (userMarkerIndex >= 0) {
markers.value.splice(userMarkerIndex, 1)
}
userLocationMarker.value = null
}
/**
@@ -280,6 +325,31 @@ const moveTo = (location: { latitude: number; longitude: number }) => {
}
}
const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value))
const getLatitudeDegreesPerPixel = (latitude: number, scale: number) => {
const latitudeRadians = latitude * Math.PI / 180
const worldPixelSize = 256 * (2 ** scale)
return 360 * Math.cos(latitudeRadians) / worldPixelSize
}
const moveToWithVerticalOffset = (
location: { latitude: number; longitude: number },
offsetY: number
) => {
const effectiveOffsetY = clamp(offsetY, 0, 360)
if (effectiveOffsetY <= 0) {
moveTo(location)
return
}
const latitudeOffset = getLatitudeDegreesPerPixel(location.latitude, mapScale.value) * effectiveOffsetY
mapCenter.value = {
latitude: location.latitude - latitudeOffset,
longitude: location.longitude
}
}
// 暴露方法给父组件
defineExpose({
updateUserLocation,
@@ -289,8 +359,12 @@ defineExpose({
// 处理标记点点击
const handleMarkerTap = (e: any) => {
const markerId = e.detail.markerId || e.markerId
const markerId = Number(e.detail?.markerId ?? e.markerId)
console.log('点击标记点:', markerId)
const outdoorMarkerId = outdoorMarkerIdMap.value.get(markerId)
if (outdoorMarkerId) {
emit('outdoorMarkerClick', outdoorMarkerId)
}
emit('markerClick', markerId)
}
@@ -328,8 +402,7 @@ const handleLocation = () => {
}
// 添加或更新用户位置标记
const userMarkerIndex = markers.value.findIndex(m => m.id === 999)
const userMarker: Marker = {
userLocationMarker.value = {
id: 999,
latitude: res.latitude,
longitude: res.longitude,
@@ -348,12 +421,6 @@ const handleLocation = () => {
}
}
if (userMarkerIndex >= 0) {
markers.value[userMarkerIndex] = userMarker
} else {
markers.value.push(userMarker)
}
console.log('定位成功:', res)
},
fail: (err) => {
@@ -388,6 +455,23 @@ const handleEnter3D = () => {
emit('enter3DMode')
}
watch(
() => [props.activeOutdoorMarkerId, props.outdoorMarkers, props.outdoorFocusOffsetY] as const,
([activeOutdoorMarkerId, outdoorMarkers, outdoorFocusOffsetY]) => {
if (!activeOutdoorMarkerId) return
const activeMarker = outdoorMarkers.find((marker) => marker.id === activeOutdoorMarkerId)
if (!activeMarker) return
moveToWithVerticalOffset(
{
latitude: activeMarker.latitude,
longitude: activeMarker.longitude
},
outdoorFocusOffsetY
)
},
{ immediate: true }
)
const getMapComponentElement = () => {
const rawRef = mapComponentRef.value
if (rawRef instanceof HTMLElement) return rawRef