chore: freeze guide and explain update

This commit is contained in:
lyf
2026-06-24 18:00:25 +08:00
parent feb7310a46
commit 67c6609ae6
104 changed files with 3203572 additions and 40713 deletions

View File

@@ -2,9 +2,11 @@
<GuidePageFrame
:active-tab="activeTopTab"
variant="static"
show-back
@tab-change="handleTopTabChange"
@back="handleBack"
>
<view class="detail-page">
<view class="detail-page" :class="{ 'with-audio-player': showAudioPlayer }">
<scroll-view class="content" scroll-y>
<view class="detail-hero">
<image
@@ -59,7 +61,7 @@
</view>
<view v-if="exhibit.audio.status !== 'playable'" class="audio-note">
<text class="audio-note-title">音频待同步</text>
<text class="audio-note-title">{{ audioNoteTitle }}</text>
<text class="audio-note-desc">
{{ exhibit.audio.unavailableReason || '当前仅提供图文讲解,正式音频接入后将显示播放入口。' }}
</text>
@@ -107,7 +109,7 @@
<view v-if="exhibit.location" class="location-note">
<text class="location-title">位置说明</text>
<text class="location-desc">当前支持三维位置预览馆内路线规划待开放</text>
<text class="location-desc">{{ locationDescription }}</text>
</view>
</view>
</scroll-view>
@@ -143,14 +145,27 @@
<text class="btn-text">分享</text>
</view>
</view>
<AudioPlayer
ref="audioPlayerRef"
:visible="showAudioPlayer"
:audio="currentAudio"
:auto-play="true"
@update:visible="handleAudioVisibleChange"
@play="handleAudioPlay"
@pause="handleAudioPause"
@ended="handleAudioEnded"
@error="handleAudioError"
/>
</view>
</GuidePageFrame>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, nextTick, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import AudioPlayer, { type AudioItem } from '@/components/audio/AudioPlayer.vue'
import {
explainUseCase
} from '@/usecases/explainUseCase'
@@ -174,17 +189,25 @@ const defaultDetail: ExplainDetailPageViewModel = {
subtitle: '位置待补充',
contentType: 'exhibit',
coverImages: ['/static/exhibit-placeholder.jpg'],
summary: '该讲解内容待 SGS 场景设置或 CMS 内容补充。',
body: '该讲解内容待 SGS 场景设置或 CMS 内容补充。',
summary: '该讲解内容待补充。',
body: '该讲解内容待补充。',
audio: {
status: 'unavailable',
unavailableReason: 'SGS 场景设置音频资源尚未同步到当前 H5 项目'
unavailableReason: '该展项暂无已发布音频,当前提供图文讲解。'
},
chapters: [],
relatedItems: []
}
interface AudioPlayerExpose {
play: (audio: AudioItem) => void
pause: () => void
}
const exhibit = ref<ExplainDetailPageViewModel>(defaultDetail)
const audioPlayerRef = ref<AudioPlayerExpose | null>(null)
const showAudioPlayer = ref(false)
const currentAudio = ref<AudioItem | null>(null)
const isPlaying = ref(false)
const isCollected = ref(false)
const activeTopTab = ref<GuideTopTab>('guide')
@@ -197,9 +220,15 @@ const audioStatusText = computed(() => {
if (exhibit.value.audio.status === 'none') {
return '图文讲解'
}
return exhibit.value.audio.unavailableReason?.includes('包含音频地址') ? '音频待同步' : '图文讲解'
return '图文讲解'
})
const audioNoteTitle = computed(() => (
exhibit.value.audio.status === 'playable'
? '音频讲解'
: '图文讲解'
))
const contentTypeText = computed(() => {
const map: Record<ExplainContentType, string> = {
hall: '空间讲解',
@@ -210,6 +239,10 @@ const contentTypeText = computed(() => {
return map[exhibit.value.contentType]
})
const locationDescription = computed(() => (
exhibit.value.location?.note || '当前支持三维位置预览。'
))
onLoad(async (options: any) => {
if (options.id) {
const exhibitData = await explainUseCase.getExhibitById(options.id)
@@ -231,6 +264,31 @@ const formatChapterTime = (seconds: number) => {
}
const handlePlayAudio = async () => {
if (exhibit.value.audio.url) {
const audio: AudioItem = {
id: `media-${exhibit.value.id}`,
name: exhibit.value.title,
audioUrl: exhibit.value.audio.url,
image: heroImage.value,
duration: undefined
}
const isSameAudio = currentAudio.value?.id === audio.id
if (showAudioPlayer.value && isSameAudio && isPlaying.value) {
audioPlayerRef.value?.pause()
return
}
showAudioPlayer.value = true
currentAudio.value = audio
await nextTick()
if (!isPlaying.value) {
audioPlayerRef.value?.play(audio)
}
return
}
const selection = exhibit.value.id
? await explainUseCase.selectAudioForExhibit(exhibit.value.id)
: null
@@ -243,7 +301,56 @@ const handlePlayAudio = async () => {
return
}
isPlaying.value = !isPlaying.value
const audio: AudioItem = {
id: selection.media.id,
name: selection.track?.title || selection.exhibit.name,
audioUrl: selection.media.url,
image: selection.exhibit.image || heroImage.value,
duration: selection.media.duration
}
const isSameAudio = currentAudio.value?.id === audio.id
if (showAudioPlayer.value && isSameAudio && isPlaying.value) {
audioPlayerRef.value?.pause()
return
}
showAudioPlayer.value = true
currentAudio.value = audio
await nextTick()
if (!isPlaying.value) {
audioPlayerRef.value?.play(audio)
}
}
const handleAudioVisibleChange = (visible: boolean) => {
showAudioPlayer.value = visible
if (!visible) {
isPlaying.value = false
currentAudio.value = null
}
}
const handleAudioPlay = () => {
isPlaying.value = true
}
const handleAudioPause = () => {
isPlaying.value = false
}
const handleAudioEnded = () => {
isPlaying.value = false
showAudioPlayer.value = false
currentAudio.value = null
}
const handleAudioError = (_audio: AudioItem | null, message: string) => {
console.warn('详情音频不可播放:', message)
isPlaying.value = false
showAudioPlayer.value = false
currentAudio.value = null
}
const handleNavigate = async () => {
@@ -284,6 +391,17 @@ const handleShare = () => {
const handleTopTabChange = (tab: GuideTopTab) => {
navigateToGuideTopTab(tab)
}
const handleBack = () => {
uni.navigateBack({
delta: 1,
fail: () => {
uni.reLaunch({
url: '/pages/index/index?tab=explain'
})
}
})
}
</script>
<style scoped lang="scss">
@@ -530,6 +648,10 @@ const handleTopTabChange = (tab: GuideTopTab) => {
border-top: 1px solid #e7e9e0;
}
.detail-page.with-audio-player .action-bar {
margin-bottom: 88px;
}
.action-btn {
height: 46px;
display: flex;

221
src/pages/explain/list.vue Normal file
View File

@@ -0,0 +1,221 @@
<template>
<GuidePageFrame
active-tab="explain"
variant="static"
show-back
back-label="讲解首页"
@tab-change="handleTopTabChange"
@back="handleBack"
>
<view class="explain-all-page">
<ExplainList
:cards="explainExhibits"
:loading="explainLoading"
:error="explainError"
list-title="全部讲解"
page-mode="all"
:initial-render-limit="48"
:page-size="48"
@exhibit-click="handleExplainExhibitClick"
@featured-click="handleExplainFeaturedClick"
@audio-click="handleAudioClick"
@location-click="handleExplainLocationClick"
@hall-click="handleExplainHallClick"
/>
<AudioPlayer
:visible="showAudioPlayer"
:audio="currentAudio"
:auto-play="true"
@update:visible="handleAudioVisibleChange"
@play="handleAudioPlay"
@pause="handleAudioPause"
@ended="handleAudioEnded"
@error="handleAudioError"
/>
</view>
</GuidePageFrame>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import ExplainList, { type Exhibit } from '@/components/explain/ExplainList.vue'
import AudioPlayer, { type AudioItem } from '@/components/audio/AudioPlayer.vue'
import {
explainUseCase
} from '@/usecases/explainUseCase'
import {
guideUseCase
} from '@/usecases/guideUseCase'
import {
toExplainCardViewModel
} from '@/view-models/explainViewModels'
import {
navigateToGuideTopTab,
type GuideTopTab
} from '@/utils/guideTopTabs'
const explainExhibits = ref<Exhibit[]>([])
const explainLoading = ref(false)
const explainError = ref('')
const showAudioPlayer = ref(false)
const isAudioPlaying = ref(false)
const currentAudio = ref<AudioItem | null>(null)
let explainLoadPromise: Promise<void> | null = null
const loadExplainExhibits = async () => {
if (explainExhibits.value.length) return
if (explainLoadPromise) return explainLoadPromise
explainLoading.value = true
explainError.value = ''
explainLoadPromise = (async () => {
try {
const exhibits = await explainUseCase.listExplainExhibits()
explainExhibits.value = exhibits.map(toExplainCardViewModel)
} catch (error) {
console.error('加载全部讲解内容失败:', error)
explainError.value = '讲解内容加载失败,请稍后重试'
explainExhibits.value = []
} finally {
explainLoading.value = false
explainLoadPromise = null
}
})()
return explainLoadPromise
}
onLoad(() => {
void loadExplainExhibits()
})
const handleBack = () => {
uni.navigateBack({
delta: 1,
fail: () => {
uni.reLaunch({
url: '/pages/index/index?tab=explain'
})
}
})
}
const handleTopTabChange = (tab: GuideTopTab) => {
navigateToGuideTopTab(tab)
}
const handleExplainExhibitClick = (exhibit: Exhibit) => {
uni.navigateTo({
url: `/pages/exhibit/detail?id=${exhibit.id}&tab=explain`
})
}
const handleExplainFeaturedClick = async (exhibit: Exhibit) => {
await handleAudioClick(exhibit)
}
const handleExplainHallClick = (hallId: string) => {
uni.navigateTo({
url: `/pages/hall/detail?id=${encodeURIComponent(hallId)}&tab=explain`
})
}
const handleAudioClick = async (exhibit: Exhibit) => {
if (exhibit.audioUrl) {
currentAudio.value = {
id: `media-${exhibit.id}`,
name: exhibit.title,
audioUrl: exhibit.audioUrl,
image: exhibit.coverImage,
duration: exhibit.audioDuration
}
showAudioPlayer.value = true
return
}
const selection = await explainUseCase.selectAudioForExhibit(exhibit.id)
if (!selection?.playable || !selection.media?.url) {
uni.showToast({
title: selection?.unavailableMessage || exhibit.audioStatusText || '该讲解暂无可播放音频',
icon: 'none'
})
return
}
currentAudio.value = {
id: selection.media.id,
name: selection.track?.title || selection.exhibit.name,
audioUrl: selection.media.url,
image: selection.exhibit.image,
duration: selection.media.duration
}
showAudioPlayer.value = true
}
const clearAudioState = () => {
showAudioPlayer.value = false
isAudioPlaying.value = false
currentAudio.value = null
}
const handleAudioVisibleChange = (visible: boolean) => {
showAudioPlayer.value = visible
if (!visible) {
isAudioPlaying.value = false
currentAudio.value = null
}
}
const handleAudioPlay = () => {
isAudioPlaying.value = true
}
const handleAudioPause = () => {
isAudioPlaying.value = false
}
const handleAudioEnded = () => {
clearAudioState()
}
const handleAudioError = (_audio: AudioItem | null, message: string) => {
console.warn('全部讲解音频不可播放:', message)
clearAudioState()
}
const handleExplainLocationClick = async (exhibit: Exhibit) => {
if (!exhibit.poiId) {
uni.showToast({
title: '该讲解暂无三维位置数据',
icon: 'none'
})
return
}
const matchedPoi = await guideUseCase.getPoiById(exhibit.poiId)
if (!matchedPoi) {
uni.showToast({
title: '该讲解位置尚未映射到当前三维导览资源',
icon: 'none'
})
return
}
uni.navigateTo({
url: `/pages/route/detail?facilityId=${encodeURIComponent(exhibit.poiId)}&target=${encodeURIComponent(exhibit.title)}&state=preview`
})
}
</script>
<style scoped lang="scss">
.explain-all-page {
position: absolute;
inset: 0;
background: #edf0ea;
}
</style>

View File

@@ -13,8 +13,11 @@
search-top="60px"
mode-top="104px"
floor-top="208px"
tools-top="450px"
:tools="['回正', '2D']"
tools-top="176px"
:active-mode="activeMode"
:active-floor="activeFloor"
:map-type="activeMode === '2d' ? 'outdoor' : 'indoor'"
:tools="mapTools"
:indoor-model-source="indoorModelSource"
:floors="guideFloors"
:normalize-floor-id="normalizeGuideFloorId"
@@ -31,7 +34,7 @@
<view class="detail-lines">
<text class="detail-line">所在区域{{ facility.location }}</text>
<text class="detail-line">最近垂直交通{{ facility.traffic }}</text>
<text class="detail-line">能力说明{{ facility.traffic }}</text>
<text v-if="confirmedStart" class="detail-line">预览起点{{ confirmedStart.label }}</text>
</view>
@@ -67,7 +70,7 @@
@tap.stop=""
>
<text class="start-select-title">选择预览起点</text>
<text class="start-select-desc">当前仅用于位置预览不生成真实馆内路线</text>
<text class="start-select-desc">当前支持选择预览起点用于三维位置预览</text>
<view class="start-chip-section">
<text class="start-chip-label">楼层</text>
@@ -141,20 +144,23 @@ interface ConfirmedStart {
const indoorModelSource = guideUseCase.getModelSource()
const guideFloors = ref<MuseumFloor[]>([])
const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloorId(labelOrId)
const activeMode = ref<'2d' | '3d'>('3d')
const activeFloor = ref('1F')
const facility = ref<FacilityDetailViewModel>({
id: '',
name: '目标位置',
status: '可预览',
location: 'clean 导览数据点位',
traffic: guideUseCase.getRouteReadiness().message,
tags: ['三维位置', 'clean 数据']
location: '中心线路网导览点位',
traffic: guideUseCase.getRouteReadinessSnapshot().message,
tags: ['三维位置', '中心线路网']
})
const isStartPanelOpen = ref(false)
const selectedStartFloor = ref('1F')
const selectedStartArea = ref('服务台附近')
const confirmedStart = ref<ConfirmedStart | null>(null)
const startFloors = computed(() => guideFloors.value.map((floor) => floor.label))
const mapTools = computed(() => ['重置', activeMode.value === '2d' ? '3D' : '2D'])
const startAreas = ['主入口', '服务台附近', '停车场入口']
const pendingStartLabel = computed(() => `${selectedStartFloor.value} ${selectedStartArea.value}`)
@@ -179,10 +185,13 @@ const loadGuideFloors = async () => {
try {
const floors = await guideUseCase.getFloors()
guideFloors.value = floors
selectedStartFloor.value = floors.find((floor) => floor.label === selectedStartFloor.value)?.label
const defaultFloor = floors.find((floor) => floor.label === selectedStartFloor.value)?.label
|| floors.find((floor) => floor.id === 'L1')?.label
|| floors[0]?.label
|| selectedStartFloor.value
selectedStartFloor.value = defaultFloor
activeFloor.value = floors.find((floor) => floor.label === activeFloor.value)?.label
|| defaultFloor
} catch (error) {
console.error('加载导览楼层失败:', error)
guideFloors.value = []
@@ -203,15 +212,16 @@ onLoad(async (options: any) => {
if (!facility.value.id) return
try {
const routeReadiness = await guideUseCase.getRouteReadiness()
const poi = await guideUseCase.getPoiById(facility.value.id)
if (!poi) return
facility.value = toFacilityDetailViewModel(
poi,
guideUseCase.getRouteReadiness().message
routeReadiness.message
)
} catch (error) {
console.error('加载 clean 设施详情失败:', error)
console.error('加载中心线路网设施详情失败:', error)
}
})
@@ -271,15 +281,36 @@ const handleStartNavigation = () => {
}
const handleModeChange = (mode: '2d' | '3d') => {
console.log('设施详情切换导览模式:', mode)
activeMode.value = mode
uni.showToast({
title: mode === '2d' ? '已切换室外入口参考' : '已切换室内三维位置',
icon: 'none'
})
}
const handleFloorChange = (floor: string) => {
console.log('设施详情切换楼层:', floor)
activeFloor.value = floor
}
const handleToolClick = (tool: string) => {
console.log('设施详情工具:', tool)
if (tool === '2D') {
handleModeChange('2d')
return
}
if (tool === '3D') {
handleModeChange('3d')
return
}
if (tool === '重置') {
activeMode.value = '3d'
}
uni.showToast({
title: tool === '重置' ? '已回到三维位置预览' : '该工具暂未开放',
icon: 'none'
})
}
const handleTopTabChange = (tab: GuideTopTab) => {

View File

@@ -2,7 +2,9 @@
<GuidePageFrame
:active-tab="activeTopTab"
variant="static"
show-back
@tab-change="handleTopTabChange"
@back="handleBack"
>
<view class="detail-page">
<scroll-view class="content" scroll-y>
@@ -47,8 +49,12 @@
<!-- 底部操作栏 -->
<view class="action-bar">
<view class="action-btn primary" @tap="handleNavigate">
<text class="btn-text">查看三维位置</text>
<view
class="action-btn primary"
:class="{ disabled: !hall.location?.poiId }"
@tap="handleNavigate"
>
<text class="btn-text">{{ hall.location?.actionText || '暂无位置' }}</text>
</view>
</view>
</view>
@@ -84,7 +90,7 @@ const hall = ref<HallDetailViewModel>({
id: '',
name: '展厅内容',
floorLabel: '楼层待补充',
description: '该空间介绍待 SGS 场景设置或 CMS 内容补充。',
description: '该展厅暂无介绍文案。',
image: '/static/hall-placeholder.jpg',
exhibitCount: 0,
area: '待补充'
@@ -140,6 +146,17 @@ const handleNavigate = async () => {
const handleTopTabChange = (tab: GuideTopTab) => {
navigateToGuideTopTab(tab)
}
const handleBack = () => {
uni.navigateBack({
delta: 1,
fail: () => {
uni.reLaunch({
url: '/pages/index/index?tab=explain'
})
}
})
}
</script>
<style scoped lang="scss">

File diff suppressed because it is too large Load Diff

View File

@@ -106,7 +106,7 @@
<view v-else-if="routeViewState === 'outdoor-preview'" class="outdoor-preview-card">
<text class="outdoor-preview-title">室外地图预览{{ route.target }}</text>
<text class="outdoor-preview-desc">
当前仅展示室外地图参考真实馆内路线需等待 route_graph/nav_data 接入
室外地图仅作入口参考馆内当前支持三维位置预览
</text>
<view class="outdoor-preview-actions">
<view class="outdoor-preview-btn secondary" @tap="handleReturnToPreview">
@@ -142,6 +142,7 @@ import type {
} from '@/domain/museum'
import {
navigateToGuideTopTab,
saveLastGuideLocationPreviewUrl,
type GuideTopTab
} from '@/utils/guideTopTabs'
@@ -269,7 +270,7 @@ const shellConfig = computed(() => {
}
return {
searchText: `${route.value.target}`,
searchText: `位置预览:${route.value.target}`,
searchTop: '60px',
activeMode: '3d' as GuideMode,
activeFloor: activeFloor.value,
@@ -297,6 +298,40 @@ const normalizeStringOption = (value: unknown) => {
return typeof normalizedValue === 'string' ? safeDecode(normalizedValue).trim() : ''
}
const setLocationPreviewTitle = () => {
if (typeof uni !== 'undefined') {
uni.setNavigationBarTitle({
title: '位置预览'
})
}
if (typeof document !== 'undefined') {
document.title = '位置预览'
}
}
const saveCurrentLocationPreviewUrl = () => {
if (!route.value.facilityId) return
const params = new URLSearchParams({
facilityId: route.value.facilityId,
target: route.value.target,
state: routeViewState.value
})
if (route.value.startLocation?.label) {
params.set('startLabel', route.value.startLocation.label)
}
if (route.value.startLocation?.floor) {
params.set('startFloor', route.value.startLocation.floor)
}
if (route.value.startLocation?.source) {
params.set('startSource', route.value.startLocation.source)
}
saveLastGuideLocationPreviewUrl(`/pages/route/detail?${params.toString()}`)
}
const createStartLocationFromOptions = (options: Record<string, unknown>) => {
const label = normalizeStringOption(options.startLabel)
@@ -385,10 +420,14 @@ const applyRouteOptions = async (options: Record<string, unknown> = {}) => {
activeFloor.value = matchedPoi.floorLabel || guideFloorLabel(matchedPoi.floorId)
}
setLocationPreviewTitle()
saveCurrentLocationPreviewUrl()
return true
}
onLoad((options: any) => {
setLocationPreviewTitle()
void applyRouteOptions(options)
})
@@ -441,6 +480,7 @@ const handleSearchTap = () => {
const handleViewOutdoorMap = () => {
isManualLocationPanelOpen.value = false
routeViewState.value = 'outdoor-preview'
saveCurrentLocationPreviewUrl()
}
const handleShowTargetLocation = (target: Partial<RouteTargetLocation> | null) => {
@@ -451,7 +491,13 @@ const handleShowTargetLocation = (target: Partial<RouteTargetLocation> | null) =
title: '目标暂无三维位置数据',
icon: 'none'
})
return
}
uni.showToast({
title: '已显示三维位置',
icon: 'none'
})
}
const handleTargetFocus = (result: TargetPoiFocusResult) => {
@@ -467,6 +513,7 @@ const handleReturnToPreview = () => {
isManualLocationPanelOpen.value = false
routeViewState.value = 'preview'
requestTargetFocus(route.value.targetLocation)
saveCurrentLocationPreviewUrl()
}
const handleRelocate = () => {
@@ -508,17 +555,20 @@ const handleConfirmLocation = async () => {
isManualLocationPanelOpen.value = false
routeViewState.value = 'preview'
requestTargetFocus(route.value.targetLocation)
saveCurrentLocationPreviewUrl()
}
const handleModeChange = (mode: GuideMode) => {
if (routeViewState.value === 'outdoor-preview' && mode === '3d') {
routeViewState.value = 'preview'
requestTargetFocus(route.value.targetLocation)
saveCurrentLocationPreviewUrl()
return
}
if (routeViewState.value !== 'outdoor-preview' && mode === '2d') {
routeViewState.value = 'outdoor-preview'
saveCurrentLocationPreviewUrl()
return
}
@@ -537,7 +587,7 @@ const handleToolClick = (tool: string) => {
}
uni.showToast({
title: tool === '回正' ? '已回到三维总览' : guideUseCase.getRouteReadiness().message,
title: tool === '回正' ? '已回到三维总览' : guideUseCase.getRouteReadinessSnapshot().message,
icon: 'none'
})
}

View File

@@ -13,12 +13,18 @@
search-top="60px"
mode-top="104px"
floor-top="208px"
tools-top="176px"
:active-mode="activeMode"
:active-floor="activeFloor"
:map-type="activeMode === '2d' ? 'outdoor' : 'indoor'"
:tools="mapTools"
:indoor-model-source="indoorModelSource"
:floors="guideFloors"
:normalize-floor-id="normalizeGuideFloorId"
@search-tap="handleSearchTap"
@mode-change="handleModeChange"
@floor-change="handleFloorChange"
@tool-click="handleToolClick"
>
<template #overlay>
<view
@@ -124,10 +130,12 @@ interface FilterItem {
interface FacilityResult extends FacilityResultViewModel {}
const searchKeyword = ref('卫生间')
const searchKeyword = ref('')
const indoorModelSource = guideUseCase.getModelSource()
const guideFloors = ref<MuseumFloor[]>([])
const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloorId(labelOrId)
const activeMode = ref<'2d' | '3d'>('3d')
const activeFloor = ref('1F')
const searchDraftKeyword = ref('')
const currentFilter = ref<FilterItem['id']>('all')
const isLoading = ref(false)
@@ -140,6 +148,7 @@ const filters: FilterItem[] = [
{ id: 'accessible', label: '无障碍' },
{ id: 'floor', label: '1F 点位' }
]
const mapTools = computed(() => ['重置', activeMode.value === '2d' ? '3D' : '2D'])
const facilities = ref<FacilityResult[]>([])
@@ -154,7 +163,7 @@ const visibleFacilities = computed(() => {
})
const resultTitle = computed(() => {
if (isLoading.value) return '正在读取 clean 导览数据'
if (isLoading.value) return '正在读取中心线路网导览数据'
return `${searchKeyword.value || '设施'} ${visibleFacilities.value.length} 个结果`
})
@@ -166,7 +175,7 @@ const loadFacilityResults = async () => {
.filter((poi) => poi.primaryCategory.id !== 'touring_poi')
.map(toFacilityResultViewModel)
} catch (error) {
console.error('加载 clean 导览搜索结果失败:', error)
console.error('加载中心线路网导览搜索结果失败:', error)
facilities.value = []
uni.showToast({
title: '导览数据读取失败',
@@ -179,7 +188,12 @@ const loadFacilityResults = async () => {
const loadGuideFloors = async () => {
try {
guideFloors.value = await guideUseCase.getFloors()
const floors = await guideUseCase.getFloors()
guideFloors.value = floors
activeFloor.value = floors.find((floor) => floor.label === activeFloor.value)?.label
|| floors.find((floor) => floor.id === 'L1')?.label
|| floors[0]?.label
|| activeFloor.value
} catch (error) {
console.error('加载导览楼层失败:', error)
guideFloors.value = []
@@ -250,11 +264,36 @@ const handleResultAction = (facility: FacilityResult) => {
}
const handleModeChange = (mode: '2d' | '3d') => {
console.log('切换搜索页导览模式:', mode)
activeMode.value = mode
uni.showToast({
title: mode === '2d' ? '已切换室外入口参考' : '已切换室内三维位置',
icon: 'none'
})
}
const handleFloorChange = (floor: string) => {
console.log('搜索页切换楼层:', floor)
activeFloor.value = floor
}
const handleToolClick = (tool: string) => {
if (tool === '2D') {
handleModeChange('2d')
return
}
if (tool === '3D') {
handleModeChange('3d')
return
}
if (tool === '重置') {
activeMode.value = '3d'
}
uni.showToast({
title: tool === '重置' ? '已回到三维位置预览' : '该工具暂未开放',
icon: 'none'
})
}
const handleTopTabChange = (tab: GuideTopTab) => {