接入H5讲解后端数据闭环

This commit is contained in:
lyf
2026-06-30 17:22:20 +08:00
parent 1c2cc788d1
commit e3682ed3ec
13 changed files with 815 additions and 68 deletions

View File

@@ -76,7 +76,7 @@
ref="audioPlayerRef"
:visible="showAudioPlayer"
:audio="currentAudio"
:auto-play="true"
:auto-play="false"
@update:visible="handleAudioVisibleChange"
@play="handleAudioPlay"
@pause="handleAudioPause"
@@ -189,6 +189,18 @@ onLoad(async (options: any = {}) => {
if (exhibitData.hallId) {
resolvedHallId.value = exhibitData.hallId
}
void explainUseCase.enrichExhibitDetailAudio(exhibitId)
.then((enrichedExhibit) => {
if (!enrichedExhibit || exhibit.value.id !== exhibitId) return
exhibit.value = toExplainDetailPageViewModel(enrichedExhibit)
if (enrichedExhibit.hallId) {
resolvedHallId.value = enrichedExhibit.hallId
}
})
.catch((error) => {
console.warn('讲解详情音频正文后台补充失败:', error)
})
}
})
@@ -210,11 +222,7 @@ const handlePlayAudio = async () => {
showAudioPlayer.value = true
currentAudio.value = audio
await nextTick()
if (!isPlaying.value) {
audioPlayerRef.value?.play(audio)
}
audioPlayerRef.value?.play(audio)
return
}
@@ -247,10 +255,10 @@ const handlePlayAudio = async () => {
showAudioPlayer.value = true
currentAudio.value = audio
await nextTick()
if (!isPlaying.value) {
audioPlayerRef.value?.play(audio)
}
uni.showToast({
title: '音频已准备好,请点击底部播放按钮',
icon: 'none'
})
}
const handleAudioVisibleChange = (visible: boolean) => {

View File

@@ -26,9 +26,10 @@
/>
<AudioPlayer
ref="audioPlayerRef"
:visible="showAudioPlayer"
:audio="currentAudio"
:auto-play="true"
:auto-play="false"
avoid-bottom-nav
@update:visible="handleAudioVisibleChange"
@play="handleAudioPlay"
@@ -66,8 +67,14 @@ const explainError = ref('')
const showAudioPlayer = ref(false)
const isAudioPlaying = ref(false)
const currentAudio = ref<AudioItem | null>(null)
const audioPlayerRef = ref<AudioPlayerExpose | null>(null)
let explainLoadPromise: Promise<void> | null = null
interface AudioPlayerExpose {
play: (audio: AudioItem) => void
pause: () => void
}
const loadExplainExhibits = async () => {
if (explainExhibits.value.length) return
if (explainLoadPromise) return explainLoadPromise
@@ -129,14 +136,23 @@ const handleExplainHallClick = (hallId: string) => {
const handleAudioClick = async (exhibit: Exhibit) => {
if (exhibit.audioUrl) {
currentAudio.value = {
const audio: AudioItem = {
id: `media-${exhibit.id}`,
name: exhibit.title,
audioUrl: exhibit.audioUrl,
image: exhibit.coverImage,
duration: exhibit.audioDuration
}
const isSameAudio = currentAudio.value?.id === audio.id
if (showAudioPlayer.value && isSameAudio && isAudioPlaying.value) {
audioPlayerRef.value?.pause()
return
}
currentAudio.value = audio
showAudioPlayer.value = true
audioPlayerRef.value?.play(audio)
return
}
@@ -158,6 +174,10 @@ const handleAudioClick = async (exhibit: Exhibit) => {
duration: selection.media.duration
}
showAudioPlayer.value = true
uni.showToast({
title: '音频已准备好,请点击底部播放按钮',
icon: 'none'
})
}
const clearAudioState = () => {

View File

@@ -125,6 +125,26 @@ const normalizePoiName = (value: string) => value
.toLowerCase()
// 展厅数据里可能没有直接写入 poiId优先走内容层映射再按展厅名称兜底匹配导览点位。
const applyMatchedHallPoi = (matchedPoi: Awaited<ReturnType<typeof guideUseCase.getPoiById>>) => {
if (!matchedPoi) return
resolvedHallPoiId.value = matchedPoi.id
hall.value = {
...hall.value,
poiId: matchedPoi.id,
location: hall.value.location || {
status: 'exact',
poiId: matchedPoi.id,
sourcePoiId: matchedPoi.id,
actionText: '查看三维位置',
previewOnly: true,
floorId: matchedPoi.floorId,
floorLabel: matchedPoi.floorLabel,
note: '已定位到该展厅的三维点位。'
}
}
}
const resolveHallGuidePoi = async () => {
const directPoiId = hall.value.location?.poiId || hall.value.poiId
if (directPoiId) {
@@ -148,6 +168,14 @@ const resolveHallGuidePoi = async () => {
}) || candidates[0] || null
}
const resolveHallGuidePoiInBackground = () => {
void resolveHallGuidePoi()
.then(applyMatchedHallPoi)
.catch((err) => {
console.warn('展厅三维位置后台匹配失败:', err)
})
}
onLoad(async (options: any = {}) => {
const tab = Array.isArray(options.tab) ? options.tab[0] : options.tab
if (isGuideTopTab(tab)) {
@@ -173,25 +201,8 @@ onLoad(async (options: any = {}) => {
hall.value = toHallDetailViewModel(hallData)
const hallExhibits = await explainUseCase.listExhibitsByHallId(hallData.id)
exhibits.value = hallExhibits.map(toExplainExhibitViewModel)
const matchedPoi = await resolveHallGuidePoi()
if (matchedPoi) {
resolvedHallPoiId.value = matchedPoi.id
hall.value = {
...hall.value,
poiId: matchedPoi.id,
location: hall.value.location || {
status: 'exact',
poiId: matchedPoi.id,
sourcePoiId: matchedPoi.id,
actionText: '查看三维位置',
previewOnly: true,
floorId: matchedPoi.floorId,
floorLabel: matchedPoi.floorLabel,
note: '已定位到该展厅的三维点位。'
}
}
}
loading.value = false
resolveHallGuidePoiInBackground()
} catch (err) {
console.error('加载展厅讲解失败:', err)
error.value = '展厅讲解加载失败,请稍后重试'
@@ -224,20 +235,7 @@ const handleNavigate = async () => {
}
resolvedHallPoiId.value = matchedPoi.id
hall.value = {
...hall.value,
poiId: matchedPoi.id,
location: hall.value.location || {
status: 'exact',
poiId: matchedPoi.id,
sourcePoiId: matchedPoi.id,
actionText: '查看三维位置',
previewOnly: true,
floorId: matchedPoi.floorId,
floorLabel: matchedPoi.floorLabel,
note: '已定位到该展厅的三维点位。'
}
}
applyMatchedHallPoi(matchedPoi)
uni.navigateTo({
url: `/pages/route/detail?facilityId=${encodeURIComponent(matchedPoi.id)}&target=${encodeURIComponent(hall.value.name)}&state=preview`