修复导览与讲解位置预览逻辑
This commit is contained in:
@@ -29,14 +29,14 @@
|
||||
:layer-mode="indoorLayerMode"
|
||||
:active-floor="activeGuideFloor"
|
||||
layer-mode-toggle-top="154px"
|
||||
floor-bottom="185px"
|
||||
floor-bottom="153px"
|
||||
floor-max-height="206px"
|
||||
floor-side="left"
|
||||
show-floor-header
|
||||
:show-layer-mode-toggle="false"
|
||||
:show-floor="is3DMode"
|
||||
show-zoom-controls
|
||||
zoom-controls-top="calc(100vh - 284px)"
|
||||
zoom-controls-top="calc(100vh - 252px)"
|
||||
:route-preview="activeRoutePreview"
|
||||
:show-route="Boolean(activeRoutePreview)"
|
||||
:disable-auto-exit="disableIndoorAutoExit"
|
||||
@@ -71,7 +71,7 @@
|
||||
<view v-if="isPoiCardCollapsed" class="poi-card-collapsed" @tap="expandPoiCard">
|
||||
<view class="poi-card-copy">
|
||||
<text class="poi-card-title">{{ selectedGuidePoi.name }}</text>
|
||||
<text class="poi-card-subtitle">位置预览 · 点按展开操作</text>
|
||||
<text class="poi-card-subtitle">{{ selectedGuidePoiCollapsedSubtitle }}</text>
|
||||
</view>
|
||||
<view class="poi-card-mini-action">
|
||||
<text class="poi-card-mini-text">展开</text>
|
||||
@@ -92,15 +92,12 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="poi-card-actions">
|
||||
<view class="poi-action primary" @tap="handlePreviewSelectedPoi">
|
||||
<text class="poi-action-text">查看位置</text>
|
||||
</view>
|
||||
<view class="poi-action" @tap="handleSetSelectedPoiAsStart">
|
||||
<text class="poi-action-text">从这里出发</text>
|
||||
</view>
|
||||
<view class="poi-action" @tap="handleSetSelectedPoiAsEnd">
|
||||
<text class="poi-action-text">去这里</text>
|
||||
<view
|
||||
v-if="selectedGuidePoiIsHall"
|
||||
class="poi-card-actions"
|
||||
>
|
||||
<view class="poi-action primary" @tap="handleViewSelectedHall">
|
||||
<text class="poi-action-text">查看展厅</text>
|
||||
</view>
|
||||
<view class="poi-action" @tap="handleSelectedPoiRelated">
|
||||
<text class="poi-action-text">相关讲解</text>
|
||||
@@ -248,7 +245,8 @@ import type {
|
||||
GuideRouteResult,
|
||||
GuideRouteTarget,
|
||||
MuseumExhibit,
|
||||
MuseumFloor
|
||||
MuseumFloor,
|
||||
MuseumHall
|
||||
} from '@/domain/museum'
|
||||
import { MUSEUM_LOCATION, type TravelMode } from '@/config/museum'
|
||||
import {
|
||||
@@ -400,13 +398,27 @@ const selectedGuidePoiSubtitle = computed(() => {
|
||||
return `${floorLabel} · ${poi.primaryCategoryZh || '位置预览'}`
|
||||
})
|
||||
|
||||
const selectedGuidePoiIsHall = computed(() => {
|
||||
const poi = selectedGuidePoi.value
|
||||
return Boolean(
|
||||
poi
|
||||
&& (
|
||||
poi.kind === 'hall'
|
||||
|| poi.primaryCategory === 'touring_poi'
|
||||
|| poi.primaryCategory === 'exhibition_hall'
|
||||
|| poi.primaryCategory === 'exhibition_hall_entrance'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
const selectedGuidePoiCollapsedSubtitle = computed(() => (
|
||||
selectedGuidePoiIsHall.value ? '已定位展厅 · 点按展开操作' : '已定位点位'
|
||||
))
|
||||
|
||||
const routeSimulationStepText = computed(() => {
|
||||
if (!activeRoutePreview.value) return routeReady.value ? '馆内导览 · 查看路线' : '馆内导览 · 查看位置'
|
||||
if (!activeRoutePreview.value) return '位置预览 · 查看位置关系'
|
||||
const hasConnector = activeRoutePreview.value.connectorPoints.length > 0
|
||||
if (routeReady.value) {
|
||||
return hasConnector ? '馆内导览 · 跨楼层路线' : '馆内导览 · 同层路线'
|
||||
}
|
||||
return hasConnector ? '馆内导览 · 跨楼层位置关系' : '馆内导览 · 同层位置关系'
|
||||
return hasConnector ? '位置预览 · 跨楼层位置关系' : '位置预览 · 同层位置关系'
|
||||
})
|
||||
|
||||
const explainHallItems = ref<ExplainHallSelectItem[]>([])
|
||||
@@ -667,12 +679,12 @@ const handleIndoorToolClick = (tool: string) => {
|
||||
|
||||
const handleGuidePoiClick = (poi: GuideRenderPoi) => {
|
||||
selectedGuidePoi.value = poi
|
||||
isPoiCardCollapsed.value = false
|
||||
isPoiCardCollapsed.value = !selectedGuidePoiIsHall.value
|
||||
indoorView.value = 'floor'
|
||||
isSimulatingRoute.value = false
|
||||
const matchedFloor = guideFloors.value.find((floor) => floor.id === poi.floorId)
|
||||
activeGuideFloor.value = matchedFloor?.label || poi.floorId
|
||||
showIndoorHint('已选中标记,可查看位置预览', 3200)
|
||||
showIndoorHint('已在当前楼层标出点位', 3000)
|
||||
}
|
||||
|
||||
const handleGuideSelectionClear = () => {
|
||||
@@ -692,55 +704,84 @@ const togglePoiCardCollapsed = () => {
|
||||
isPoiCardCollapsed.value = !isPoiCardCollapsed.value
|
||||
}
|
||||
|
||||
const findRouteOptionForPoi = async (poi: GuideRenderPoi) => {
|
||||
if (!routePointOptions.value.length) {
|
||||
await loadRouteTargets()
|
||||
const normalizeHallMatchText = (value?: string) => (value || '')
|
||||
.trim()
|
||||
.replace(/[\s()()【】[\]_-]/g, '')
|
||||
.toLowerCase()
|
||||
|
||||
const resolveSelectedPoiHall = async (): Promise<MuseumHall | null> => {
|
||||
const poi = selectedGuidePoi.value
|
||||
if (!poi) return null
|
||||
|
||||
const halls = await explainUseCase.listHalls()
|
||||
const hallId = poi.hallId
|
||||
if (hallId) {
|
||||
const matchedById = halls.find((hall) => hall.id === hallId || hall.poiId === hallId)
|
||||
if (matchedById) return matchedById
|
||||
}
|
||||
|
||||
return routePointOptions.value.find((option) => option.poiId === poi.id) || null
|
||||
const matchedByPoiId = halls.find((hall) => (
|
||||
hall.poiId === poi.id
|
||||
|| hall.location?.poiId === poi.id
|
||||
|| (poi.entrances || []).some((entrance) => hall.poiId === entrance.sourcePlaceId)
|
||||
))
|
||||
if (matchedByPoiId) return matchedByPoiId
|
||||
|
||||
const poiHallName = normalizeHallMatchText(poi.hallName || poi.name)
|
||||
return halls.find((hall) => {
|
||||
const hallName = normalizeHallMatchText(hall.name)
|
||||
return hallName && poiHallName && (hallName.includes(poiHallName) || poiHallName.includes(hallName))
|
||||
}) || null
|
||||
}
|
||||
|
||||
const setSelectedPoiAsRoutePoint = async (mode: 'start' | 'end') => {
|
||||
if (!selectedGuidePoi.value) return
|
||||
const navigateToHallDetail = (hallId: string) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hall/detail?id=${encodeURIComponent(hallId)}&tab=explain`
|
||||
})
|
||||
}
|
||||
|
||||
const option = await findRouteOptionForPoi(selectedGuidePoi.value)
|
||||
if (!option) {
|
||||
const handleViewSelectedHall = async () => {
|
||||
const hall = await resolveSelectedPoiHall()
|
||||
if (!hall) {
|
||||
uni.showToast({
|
||||
title: '该点位暂无线路数据,可先查看三维位置',
|
||||
title: '该展厅详情暂未接入',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (mode === 'start') {
|
||||
routeStartPoint.value = option
|
||||
} else {
|
||||
routeEndPoint.value = option
|
||||
navigateToHallDetail(hall.id)
|
||||
}
|
||||
|
||||
const handleSelectedPoiRelated = async () => {
|
||||
if (!selectedGuidePoi.value) return
|
||||
|
||||
const hall = await resolveSelectedPoiHall()
|
||||
if (hall) {
|
||||
navigateToHallDetail(hall.id)
|
||||
return
|
||||
}
|
||||
|
||||
clearRoutePreviewState()
|
||||
openRoutePlanner()
|
||||
}
|
||||
const keyword = selectedGuidePoi.value.hallName || selectedGuidePoi.value.name
|
||||
const results = await explainUseCase.searchExplain(keyword)
|
||||
const firstHall = results.find((item) => item.type === 'hall' && item.hallId)
|
||||
const firstExhibit = results.find((item) => item.type === 'exhibit' && item.exhibitId)
|
||||
|
||||
const handlePreviewSelectedPoi = () => {
|
||||
if (!selectedGuidePoi.value) return
|
||||
indoorView.value = 'floor'
|
||||
showRoutePlanner.value = false
|
||||
isSimulatingRoute.value = false
|
||||
}
|
||||
if (firstHall?.hallId) {
|
||||
navigateToHallDetail(firstHall.hallId)
|
||||
return
|
||||
}
|
||||
|
||||
const handleSetSelectedPoiAsStart = () => {
|
||||
void setSelectedPoiAsRoutePoint('start')
|
||||
}
|
||||
if (firstExhibit?.exhibitId) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/exhibit/detail?id=${encodeURIComponent(firstExhibit.exhibitId)}&tab=explain`
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const handleSetSelectedPoiAsEnd = () => {
|
||||
void setSelectedPoiAsRoutePoint('end')
|
||||
}
|
||||
|
||||
const handleSelectedPoiRelated = () => {
|
||||
if (!selectedGuidePoi.value) return
|
||||
uni.navigateTo({
|
||||
url: `/pages/search/index?keyword=${encodeURIComponent(selectedGuidePoi.value.name)}`
|
||||
uni.showToast({
|
||||
title: '该展厅暂无对应讲解',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -769,15 +810,16 @@ const refreshRouteReadinessState = async () => {
|
||||
routeReady.value = readiness.ready
|
||||
routePreviewUnavailableMessage.value = readiness.ready
|
||||
? ''
|
||||
: readiness.message || '当前暂不支持正式导航,可查看位置预览和路线示意'
|
||||
: readiness.message || '当前可查看位置预览和位置关系,暂不提供正式室内导航'
|
||||
} catch (error) {
|
||||
console.warn('读取路线能力状态失败:', error)
|
||||
routeReady.value = false
|
||||
routePreviewUnavailableMessage.value = '当前暂不支持正式导航,可查看位置预览和路线示意'
|
||||
routePreviewUnavailableMessage.value = '当前可查看位置预览和位置关系,暂不提供正式室内导航'
|
||||
}
|
||||
}
|
||||
|
||||
const openRoutePlanner = () => {
|
||||
closeOutdoorNavPanel()
|
||||
showRoutePlanner.value = true
|
||||
is3DMode.value = true
|
||||
indoorView.value = indoorView.value === 'overview' ? 'floor' : indoorView.value
|
||||
@@ -898,6 +940,7 @@ const handleRouteSimulate = () => {
|
||||
// 进入 3D 馆内模式
|
||||
const handleEnter3DMode = () => {
|
||||
console.log('进入 3D 馆内模式')
|
||||
closeOutdoorNavPanel()
|
||||
indoorView.value = 'overview'
|
||||
is3DMode.value = true
|
||||
guideOutdoorState.value = 'home'
|
||||
@@ -919,6 +962,7 @@ const handleModeChange = (mode: '2d' | '3d') => {
|
||||
isSimulatingRoute.value = false
|
||||
clearRoutePreviewState()
|
||||
} else {
|
||||
closeOutdoorNavPanel()
|
||||
indoorView.value = 'overview'
|
||||
showIndoorHint()
|
||||
if (!routePointOptions.value.length) {
|
||||
@@ -970,18 +1014,21 @@ const clearOutdoorNavState = () => {
|
||||
outdoorNavManualMode.value = false
|
||||
}
|
||||
|
||||
const closeOutdoorNavPanel = () => {
|
||||
showOutdoorNavPanel.value = false
|
||||
clearOutdoorNavState()
|
||||
}
|
||||
|
||||
const handleMoreOutdoorNav = () => {
|
||||
openOutdoorNavPanel()
|
||||
}
|
||||
|
||||
const handleOutdoorNavClose = () => {
|
||||
showOutdoorNavPanel.value = false
|
||||
clearOutdoorNavState()
|
||||
closeOutdoorNavPanel()
|
||||
}
|
||||
|
||||
const handleOutdoorNavBack = () => {
|
||||
showOutdoorNavPanel.value = false
|
||||
clearOutdoorNavState()
|
||||
closeOutdoorNavPanel()
|
||||
}
|
||||
|
||||
const handleOutdoorNavGpsStart = () => {
|
||||
@@ -1291,7 +1338,7 @@ const handleExplainBack = () => {
|
||||
.poi-card-actions {
|
||||
margin-top: 12px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user