简化来馆面板并优化地图点位展示
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user