fix: 修复导览按钮文案与三维路线显示联动

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
lyf
2026-06-26 04:17:03 +08:00
parent d4b97379bb
commit a7413ee037
5 changed files with 592 additions and 93 deletions

View File

@@ -3,25 +3,14 @@
<view class="map-layer" :class="`map-${mapType}`">
<template v-if="mapType === 'indoor'">
<!-- #ifdef H5 -->
<SgsMapRenderer
v-if="useSgsMapRenderer"
ref="indoorRendererRef"
class="indoor-three-map"
:initial-floor-id="activeFloorId"
:initial-view="indoorInitialView"
:floors="props.floors"
:target-focus="targetFocusRequest"
@target-focus="handleTargetFocus"
@floor-change="handleSdkFloorChange"
/>
<ThreeMap
v-else-if="indoorModelSource"
v-if="effectiveIndoorModelSource"
ref="indoorRendererRef"
class="indoor-three-map"
:asset-base-url="indoorAssetBaseUrl"
:model-source="indoorModelSource"
:model-source="effectiveIndoorModelSource"
:initial-floor-id="activeFloorId"
:initial-view="indoorInitialView"
:initial-view="indoorView"
:show-controls="false"
:show-poi="shouldShowIndoorPois"
:target-focus="targetFocusRequest"
@@ -50,6 +39,8 @@
class="outdoor-map"
:active-floor="activeFloor"
:floors="props.floors"
:polylines="outdoorNavPolylines"
@map-tap="handleMapTap"
/>
</view>
<view v-if="dimmed" class="dim-layer"></view>
@@ -170,11 +161,6 @@
</view>
</view>
<view v-if="showLocationControl" class="location-control" :style="locationControlStyle" @tap="handleResetView">
<view class="location-ring"></view>
<view class="location-dot"></view>
</view>
<view v-if="showMoreControl" class="more-control" :style="moreControlStyle" @tap="handleMoreTap">
<text class="more-control-text">更多</text>
</view>
@@ -195,14 +181,10 @@
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, ref, watch } from 'vue'
import TencentMap from '@/components/map/TencentMap.vue'
// #ifdef H5
import ThreeMap from '@/components/map/ThreeMap.vue'
import SgsMapRenderer from '@/components/map/SgsMapRenderer.vue'
import {
isSgsSdkMode
} from '@/config/dataSource'
// #endif
import type {
GuideModelSource,
@@ -217,6 +199,14 @@ interface GuideFloorOption {
label: string
}
interface OutdoorNavPolyline {
points: Array<{ latitude: number; longitude: number }>
color: string
width: number
}
type CameraViewMode = 'reset' | 'top' | 'oblique'
interface TargetPoiFocusRequest {
requestId: number | string
poiId: string
@@ -253,6 +243,7 @@ const props = withDefaults(defineProps<{
layerModeToggleTop?: string
toolsTop?: string
tools?: string[]
cameraView?: CameraViewMode
searchVariant?: 'default' | 'home'
showVoiceIcon?: boolean
showModeRow?: boolean
@@ -260,9 +251,9 @@ const props = withDefaults(defineProps<{
showZoomControls?: boolean
showLocationControl?: boolean
showMoreControl?: boolean
toolsBottom?: string
floorSide?: 'left' | 'right'
zoomControlsTop?: string
locationControlBottom?: string
moreControlBottom?: string
showSearch?: boolean
showFloor?: boolean
@@ -285,6 +276,7 @@ const props = withDefaults(defineProps<{
showRoute?: boolean
autoSwitchThresholdLow?: number
autoSwitchThresholdHigh?: number
outdoorNavPolylines?: OutdoorNavPolyline[]
}>(), {
searchText: '请输入地点进行搜索',
activeMode: '3d',
@@ -297,7 +289,9 @@ const props = withDefaults(defineProps<{
floorMaxHeight: '',
layerModeToggleTop: '154px',
toolsTop: '406px',
toolsBottom: '',
tools: () => [] as string[],
cameraView: 'reset',
searchVariant: 'default',
showVoiceIcon: false,
showModeRow: true,
@@ -307,7 +301,6 @@ const props = withDefaults(defineProps<{
showMoreControl: false,
floorSide: 'right',
zoomControlsTop: '520px',
locationControlBottom: '34px',
moreControlBottom: '34px',
showSearch: true,
showFloor: true,
@@ -329,7 +322,8 @@ const props = withDefaults(defineProps<{
routePreview: null,
showRoute: false,
autoSwitchThresholdLow: 1.0,
autoSwitchThresholdHigh: 1.3
autoSwitchThresholdHigh: 1.3,
outdoorNavPolylines: () => [] as OutdoorNavPolyline[]
})
const emit = defineEmits<{
@@ -344,8 +338,23 @@ const emit = defineEmits<{
selectionClear: []
targetFocus: [result: TargetPoiFocusResult]
autoSwitch: [event: { from: 'overview' | 'floor'; to: 'overview' | 'floor'; trigger: string; distance: number }]
mapTap: [location: { latitude: number; longitude: number }]
}>()
// 监听视角切换循环切换reset -> top -> oblique -> reset
watch(() => props.cameraView, (view) => {
if (props.mapType !== 'indoor') return
indoorRendererRef.value?.disableAutoSwitchTemporarily?.(10000)
if (view === 'reset') {
indoorRendererRef.value?.resetCamera?.()
} else if (view === 'top') {
indoorRendererRef.value?.setCameraPreset?.('top')
} else if (view === 'oblique') {
indoorRendererRef.value?.setCameraPreset?.('oblique')
}
})
const indoorRendererRef = ref<{
switchFloor?: (floorId: string) => Promise<void> | void
showOverview?: () => Promise<void> | void
@@ -354,19 +363,30 @@ const indoorRendererRef = ref<{
setCameraPreset?: (preset: 'top' | 'oblique') => void
zoomCamera?: (direction: 'in' | 'out') => void
clearSelection?: (shouldEmit?: boolean) => void
clearRoute?: () => Promise<void> | void
disableAutoSwitchTemporarily?: (durationMs: number) => void
} | null>(null)
const floorLabels = computed(() => props.floors.map((floor) => floor.label))
const indoorModelSource = computed(() => props.indoorModelSource)
// #ifdef H5
const useSgsMapRenderer = computed(() => isSgsSdkMode())
const effectiveIndoorModelSource = computed(() => props.indoorModelSource)
// #endif
const showIndoorRightControls = computed(() => (
props.mapType === 'indoor' && props.indoorView !== 'overview'
))
const activeFloorId = computed(() => props.normalizeFloorId(props.activeFloor))
const activeFloorId = computed(() => {
const matchedFloor = props.floors.find((floor) => (
floor.id === props.activeFloor || floor.label === props.activeFloor
))
if (matchedFloor) return matchedFloor.id
const normalizedFloorId = props.normalizeFloorId(props.activeFloor)
const normalizedFloor = props.floors.find((floor) => (
floor.id === normalizedFloorId || floor.label === normalizedFloorId
))
return normalizedFloor?.id || normalizedFloorId
})
const searchFieldStyle = computed(() => ({
top: props.searchTop
@@ -386,17 +406,15 @@ const modeRowStyle = computed(() => ({
}))
const toolStackStyle = computed(() => ({
top: props.toolsTop
...(props.toolsTop ? { top: props.toolsTop } : {}),
...(props.toolsBottom ? { bottom: props.toolsBottom } : {}),
left: '18px'
}))
const zoomControlsStyle = computed(() => ({
top: props.zoomControlsTop
}))
const locationControlStyle = computed(() => ({
bottom: props.locationControlBottom
}))
const moreControlStyle = computed(() => ({
bottom: props.moreControlBottom
}))
@@ -469,11 +487,6 @@ const handleToolClick = (tool: string) => {
emit('toolClick', tool)
}
const handleResetView = () => {
indoorRendererRef.value?.resetCamera?.()
emit('toolClick', '重置')
}
const handleZoomClick = (direction: 'in' | 'out') => {
indoorRendererRef.value?.zoomCamera?.(direction)
emit('toolClick', direction === 'in' ? '放大' : '缩小')
@@ -502,16 +515,23 @@ const handleTargetFocus = (result: TargetPoiFocusResult) => {
emit('targetFocus', result)
}
const handleSdkFloorChange = (floorId: string) => {
const floor = props.floors.find((item) => item.id === floorId)
if (floor) {
emit('floorChange', floor.label)
}
}
const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' | 'floor'; trigger: string; distance: number }) => {
emit('autoSwitch', event)
}
const handleMapTap = (location: { latitude?: number; longitude?: number }) => {
const { latitude, longitude } = location
if (latitude !== undefined && longitude !== undefined) {
emit('mapTap', { latitude, longitude })
}
}
// 暴露 clearRoute 方法供父组件显式调用路线清除
defineExpose({
clearRoute: () => {
indoorRendererRef.value?.clearRoute?.()
}
})
</script>
<style scoped lang="scss">
@@ -958,7 +978,7 @@ const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' |
.tool-stack {
position: absolute;
left: 16px;
left: 18px;
display: flex;
flex-direction: column;
gap: 8px;

View File

@@ -67,7 +67,7 @@
<view v-if="startPoint && endPoint" class="route-options">
<view class="route-options-header">
<text class="route-options-title">线路预览</text>
<text class="route-options-title">{{ routeOptionsTitle }}</text>
<text class="route-options-note">偏好选择</text>
</view>
<view class="route-option-list">
@@ -84,7 +84,7 @@
</view>
<view v-if="loading || error || summary" class="panel-status">
<text v-if="loading" class="panel-status-text">线路预览生成中</text>
<text v-if="loading" class="panel-status-text">{{ loadingText }}</text>
<text v-else-if="error" class="panel-status-text error">{{ error }}</text>
<text v-else class="panel-status-text">{{ summary }}</text>
</view>
@@ -136,6 +136,7 @@ const props = withDefaults(defineProps<{
pickerLoading?: boolean
pickerError?: string
pickerEmptyText?: string
routeReady?: boolean
}>(), {
visible: true,
startPoint: null,
@@ -147,7 +148,8 @@ const props = withDefaults(defineProps<{
summary: '',
pickerLoading: false,
pickerError: '',
pickerEmptyText: '暂无匹配地点'
pickerEmptyText: '暂无匹配地点',
routeReady: false
})
const emit = defineEmits<{
@@ -194,7 +196,15 @@ const canViewRoute = computed(() => Boolean(
const canPrimaryAction = computed(() => canViewRoute.value && !props.error)
const primaryActionText = computed(() => (
props.hasRoutePreview ? '模拟导览' : '线路预览'
props.hasRoutePreview
? '开始导览'
: (props.routeReady ? '查看路线' : '查看位置关系')
))
const routeOptionsTitle = computed(() => '室内导览')
const loadingText = computed(() => (
props.routeReady ? '正在规划室内导览路线' : '正在生成室内位置关系'
))
const collapsedSummary = computed(() => {
@@ -207,26 +217,32 @@ const collapsedSummary = computed(() => {
const routeOptions = computed(() => {
const unavailable = Boolean(props.error)
const summaryText = props.summary || '选择后查看位置关系'
const summaryText = props.summary || (props.routeReady ? '选择后规划真实路线' : '选择后查看位置关系')
return [
{
id: 'recommended',
title: '推荐路线',
meta: unavailable ? '当前为路线示意状态' : props.hasRoutePreview ? summaryText : '优先展示位置关系',
meta: unavailable
? '当前暂不可用'
: props.hasRoutePreview
? summaryText
: props.routeReady
? '调用 SGS SDK 路线规划'
: '查看起点终点位置关系',
active: !unavailable,
disabled: unavailable
},
{
id: 'stairs',
title: '少走楼梯',
meta: '偏好预览,待路线数据验证',
meta: props.routeReady ? '偏好能力待接入' : '偏好预览,待路线数据验证',
active: false,
disabled: true
},
{
id: 'elevator',
title: '电梯优先',
meta: '偏好预览,待路线数据验证',
meta: props.routeReady ? '偏好能力待接入' : '偏好预览,待路线数据验证',
active: false,
disabled: true
}