feat: wire guide data source and POI focus UI
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
:map-type="guideMapType"
|
||||
:outdoor-variant="guideOutdoorVariant"
|
||||
:indoor-asset-base-url="indoorNavAssetBaseUrl"
|
||||
:indoor-model-source="indoorModelSource"
|
||||
:floors="guideFloors"
|
||||
:normalize-floor-id="normalizeGuideFloorId"
|
||||
indoor-initial-view="overview"
|
||||
:indoor-view="indoorView"
|
||||
:active-floor="activeGuideFloor"
|
||||
@@ -80,6 +83,7 @@
|
||||
|
||||
<view v-else-if="currentTab === 'explain'" class="explain-page">
|
||||
<ExplainList
|
||||
:exhibits="explainExhibits"
|
||||
@exhibit-click="handleExplainExhibitClick"
|
||||
@featured-click="handleExplainFeaturedClick"
|
||||
@audio-click="handleAudioClick"
|
||||
@@ -109,7 +113,7 @@ import { computed, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
|
||||
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
|
||||
import ExplainList from '@/components/explain/ExplainList.vue'
|
||||
import ExplainList, { type Exhibit } from '@/components/explain/ExplainList.vue'
|
||||
import FloatingAudioButton from '@/components/audio/FloatingAudioButton.vue'
|
||||
import AudioPlayer, { type AudioItem } from '@/components/audio/AudioPlayer.vue'
|
||||
import {
|
||||
@@ -117,9 +121,20 @@ import {
|
||||
type GuideTopTab
|
||||
} from '@/utils/guideTopTabs'
|
||||
import {
|
||||
NAV_ASSET_BASE_URL,
|
||||
NAV_ROUTE_UNAVAILABLE_MESSAGE
|
||||
} from '@/services/navAssets'
|
||||
} from '@/domain/guideReadiness'
|
||||
import {
|
||||
guideUseCase
|
||||
} from '@/usecases/guideUseCase'
|
||||
import {
|
||||
explainUseCase
|
||||
} from '@/usecases/explainUseCase'
|
||||
import {
|
||||
toExplainExhibitViewModel
|
||||
} from '@/view-models/explainViewModels'
|
||||
import type {
|
||||
MuseumFloor
|
||||
} from '@/domain/museum'
|
||||
|
||||
// 3D 模式状态
|
||||
const is3DMode = ref(false)
|
||||
@@ -135,7 +150,10 @@ const showMarkerDetail = ref(false)
|
||||
const showAreaSelector = ref(false)
|
||||
const selectedAreaId = ref('service')
|
||||
|
||||
const indoorNavAssetBaseUrl = NAV_ASSET_BASE_URL
|
||||
const indoorNavAssetBaseUrl = guideUseCase.getAssetBaseUrl()
|
||||
const indoorModelSource = guideUseCase.getModelSource()
|
||||
const guideFloors = ref<MuseumFloor[]>([])
|
||||
const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloorId(labelOrId)
|
||||
|
||||
const shortcutItems = [
|
||||
{ id: 'toilet', name: '卫生间', abbr: '卫' },
|
||||
@@ -149,6 +167,7 @@ const shortcutItems = [
|
||||
const showAudioPlayer = ref(false)
|
||||
const isAudioPlaying = ref(false)
|
||||
const currentAudio = ref<AudioItem | null>(null)
|
||||
const explainExhibits = ref<Exhibit[]>([])
|
||||
|
||||
// 选中的标记详情
|
||||
interface MarkerDetail {
|
||||
@@ -188,8 +207,35 @@ onLoad((options: any = {}) => {
|
||||
if (isGuideTopTab(tab)) {
|
||||
currentTab.value = tab
|
||||
}
|
||||
|
||||
void loadGuideFloors()
|
||||
void loadExplainExhibits()
|
||||
})
|
||||
|
||||
const loadGuideFloors = async () => {
|
||||
try {
|
||||
const floors = await guideUseCase.getFloors()
|
||||
guideFloors.value = floors
|
||||
activeGuideFloor.value = floors.find((floor) => floor.label === activeGuideFloor.value)?.label
|
||||
|| floors.find((floor) => floor.id === 'L1')?.label
|
||||
|| floors[0]?.label
|
||||
|| activeGuideFloor.value
|
||||
} catch (error) {
|
||||
console.error('加载导览楼层失败:', error)
|
||||
guideFloors.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const loadExplainExhibits = async () => {
|
||||
try {
|
||||
const exhibits = await explainUseCase.listExhibits()
|
||||
explainExhibits.value = exhibits.map(toExplainExhibitViewModel)
|
||||
} catch (error) {
|
||||
console.error('加载讲解内容失败:', error)
|
||||
explainExhibits.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearchFocus = () => {
|
||||
searchBarFocused.value = true
|
||||
@@ -391,13 +437,23 @@ const guideSearchText = computed(() => {
|
||||
})
|
||||
|
||||
// 音频相关处理
|
||||
const handleAudioClick = (exhibit: any) => {
|
||||
console.log('点击音频播放:', exhibit)
|
||||
const handleAudioClick = async (exhibit: Exhibit) => {
|
||||
const selection = await explainUseCase.selectAudioForExhibit(exhibit.id)
|
||||
|
||||
if (!selection?.playable || !selection.media?.url) {
|
||||
uni.showToast({
|
||||
title: selection?.unavailableMessage || exhibit.audioUnavailableReason || '该展项暂无讲解音频',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
currentAudio.value = {
|
||||
id: exhibit.id,
|
||||
name: exhibit.name,
|
||||
audioUrl: exhibit.audioUrl || 'https://example.com/audio.mp3',
|
||||
image: exhibit.image
|
||||
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
|
||||
}
|
||||
@@ -431,30 +487,14 @@ const handleAudioEnded = (audio: AudioItem) => {
|
||||
}
|
||||
|
||||
// 讲解页面处理
|
||||
const handleExplainExhibitClick = (exhibit: any) => {
|
||||
console.log('点击讲解展品:', exhibit)
|
||||
const handleExplainExhibitClick = (exhibit: Exhibit) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/exhibit/detail?id=${exhibit.id}&tab=explain`
|
||||
})
|
||||
}
|
||||
|
||||
const handleExplainFeaturedClick = (exhibit: any) => {
|
||||
console.log('点击推荐讲解:', exhibit)
|
||||
// 播放音频讲解
|
||||
if (exhibit.hasAudio) {
|
||||
currentAudio.value = {
|
||||
id: exhibit.id,
|
||||
name: exhibit.name,
|
||||
audioUrl: exhibit.audioUrl || 'https://example.com/audio.mp3',
|
||||
image: exhibit.image
|
||||
}
|
||||
showAudioPlayer.value = true
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '该展品暂无讲解音频',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
const handleExplainFeaturedClick = async (exhibit: Exhibit) => {
|
||||
await handleAudioClick(exhibit)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user