diff --git a/src/pages/exhibit/detail.vue b/src/pages/exhibit/detail.vue index 58fce2d..f0eea27 100644 --- a/src/pages/exhibit/detail.vue +++ b/src/pages/exhibit/detail.vue @@ -225,9 +225,32 @@ const isDetailAudioDockVisible = computed(() => ( exhibit.value.audio.status === 'playable' )) const audioDockTitle = computed(() => exhibit.value.title || '讲解内容') +const formatDetailAudioTime = (seconds?: number) => { + const normalizedSeconds = Number.isFinite(seconds || 0) + ? Math.max(0, Math.floor(seconds || 0)) + : 0 + const minutes = Math.floor(normalizedSeconds / 60) + const remainSeconds = normalizedSeconds % 60 + + return `${minutes}:${remainSeconds.toString().padStart(2, '0')}` +} +const detailAudioDurationSeconds = computed(() => { + if (!isCurrentDetailAudioTarget.value) return exhibit.value.audio.duration || 0 + + return globalAudioPlayer.duration.value + || globalAudioPlayer.currentAudio.value?.duration + || exhibit.value.audio.duration + || 0 +}) +const detailAudioCurrentSeconds = computed(() => ( + isCurrentDetailAudioTarget.value ? globalAudioPlayer.currentTime.value : 0 +)) +const detailAudioTimeLabel = computed(() => ( + `${formatDetailAudioTime(detailAudioCurrentSeconds.value)} / ${formatDetailAudioTime(detailAudioDurationSeconds.value)}` +)) const audioDockSubtitle = computed(() => [ selectedAudioLanguage.value === 'en-US' ? 'English' : '中文', - exhibit.value.audio.durationLabel + detailAudioTimeLabel.value ].filter(Boolean).join(' · ') || '讲解') const detailAudioPlaying = computed(() => ( isCurrentDetailAudio.value @@ -236,10 +259,10 @@ const detailAudioPlaying = computed(() => ( const detailAudioProgressPercent = computed(() => { if (!isCurrentDetailAudioTarget.value) return 0 - const total = globalAudioPlayer.duration.value || globalAudioPlayer.currentAudio.value?.duration || 0 + const total = detailAudioDurationSeconds.value if (!total) return 0 - return Math.max(0, Math.min(100, (globalAudioPlayer.currentTime.value / total) * 100)) + return Math.max(0, Math.min(100, (detailAudioCurrentSeconds.value / total) * 100)) }) // 讲解详情页只定位到所属展厅,不再追踪具体展品点位。 const resolveHallGuidePoi = async () => {