From 7eba2b62447a89bf186df15a015896f5d132e37f Mon Sep 17 00:00:00 2001 From: lyf <2514544224@qq.com> Date: Wed, 8 Jul 2026 23:04:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=92=AD=E6=94=BE=E5=99=A8?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=85=A5=E5=8F=A3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/audio/AudioPlayer.vue | 91 ++++++++++++++++++- .../audio/GlobalAudioPlayerHost.vue | 6 +- src/components/navigation/GuidePageFrame.vue | 5 +- src/pages/exhibit/detail.vue | 4 +- 4 files changed, 101 insertions(+), 5 deletions(-) diff --git a/src/components/audio/AudioPlayer.vue b/src/components/audio/AudioPlayer.vue index 838ecde..0f312b3 100644 --- a/src/components/audio/AudioPlayer.vue +++ b/src/components/audio/AudioPlayer.vue @@ -63,7 +63,7 @@ {{ formattedDuration }} - + @@ -77,11 +77,21 @@ 停止播放 + + + + + + 关闭播放器 + + + × + @@ -96,7 +106,7 @@ - + @@ -143,6 +153,9 @@ + + × + @@ -176,6 +189,7 @@ const props = defineProps<{ currentTime?: number durationValue?: number pendingLanguage?: AudioLanguage | '' + closable?: boolean }>() const emit = defineEmits<{ @@ -230,6 +244,7 @@ const displayLoading = computed(() => props.controlled ? props.loading === true const displayPlaybackError = computed(() => props.controlled ? props.playbackError || '' : localPlaybackError.value) const displayCurrentTime = computed(() => props.controlled ? props.currentTime || 0 : localCurrentTime.value) const displayMode = computed(() => props.mode || 'mini') +const closable = computed(() => props.closable !== false) const audioLanguageOptions: Array<{ value: AudioLanguage; label: string; shortLabel: string }> = [ { value: 'zh-CN', label: '中文', shortLabel: '中文' }, { value: 'en-US', label: 'English', shortLabel: 'EN' } @@ -569,6 +584,17 @@ const handleStop = () => { emit('stop') } +const handleClose = () => { + if (props.controlled) { + emit('close') + return + } + + stopAudio() + emit('update:visible', false) + emit('close') +} + const handleH5LoadedMetadata = () => { const audio = h5AudioElement.value if (!audio) return @@ -936,6 +962,10 @@ defineExpose({ border-top: 1px solid rgba(255, 255, 255, 0.14); } +.expanded-actions.with-close { + grid-template-columns: 1fr 1px 1fr 1px 1fr; +} + .action-btn { min-width: 0; height: 42px; @@ -950,6 +980,10 @@ defineExpose({ color: rgba(255, 255, 255, 0.92); } +.close-action { + color: rgba(255, 255, 255, 0.78); +} + .action-divider { width: 1px; height: 26px; @@ -979,6 +1013,14 @@ defineExpose({ border-radius: 30px; } +.mini-player.with-close { + grid-template-columns: 56px minmax(0, 1fr) auto auto auto; + grid-template-areas: + "play spacer language expand close" + "copy copy copy copy copy" + "progress progress progress progress progress"; +} + .mini-play { grid-area: play; width: 56px; @@ -1097,6 +1139,23 @@ defineExpose({ color: #ffffff; } +.mini-close { + grid-area: close; + width: 34px; + height: 42px; + display: flex; + align-items: center; + justify-content: center; + color: rgba(255, 255, 255, 0.82); +} + +.mini-close-text { + display: block; + font-size: 28px; + line-height: 28px; + color: currentColor; +} + .expand-text { font-size: 18px; line-height: 22px; @@ -1120,6 +1179,26 @@ defineExpose({ border-radius: 50%; } +.floating-close { + position: absolute; + z-index: 2; + top: 5px; + right: 7px; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + color: rgba(255, 255, 255, 0.82); +} + +.floating-close-text { + display: block; + font-size: 24px; + line-height: 24px; + color: currentColor; +} + .floating-ring::before { content: ''; position: absolute; @@ -1205,6 +1284,14 @@ defineExpose({ row-gap: 6px; } + .mini-player.with-close { + grid-template-columns: 50px minmax(0, 1fr) auto auto; + grid-template-areas: + "play language expand close" + "copy copy copy copy" + "progress progress progress progress"; + } + .mini-play { width: 50px; height: 50px; diff --git a/src/components/audio/GlobalAudioPlayerHost.vue b/src/components/audio/GlobalAudioPlayerHost.vue index 48d7d6e..741de72 100644 --- a/src/components/audio/GlobalAudioPlayerHost.vue +++ b/src/components/audio/GlobalAudioPlayerHost.vue @@ -10,11 +10,13 @@ :current-time="currentTime" :duration-value="duration" :pending-language="pendingLanguage" + :closable="closable" :avoid-bottom-nav="avoidBottomNav" :mode="currentDisplayMode" @toggle="handleToggle" @collapse="handleCollapse" @stop="handleStop" + @close="player.close" @seek="player.seekToPercent" @expand="handleExpand" @language-change="handleLanguageChange" @@ -34,9 +36,11 @@ import { useGlobalAudioPlayer } from '@/composables/useGlobalAudioPlayer' const props = withDefaults(defineProps<{ avoidBottomNav?: boolean displayMode?: AudioDisplayMode + closable?: boolean }>(), { avoidBottomNav: true, - displayMode: 'mini' + displayMode: 'mini', + closable: true }) const player = useGlobalAudioPlayer() diff --git a/src/components/navigation/GuidePageFrame.vue b/src/components/navigation/GuidePageFrame.vue index ca919ac..e808767 100644 --- a/src/components/navigation/GuidePageFrame.vue +++ b/src/components/navigation/GuidePageFrame.vue @@ -35,6 +35,7 @@ @@ -57,6 +58,7 @@ withDefaults(defineProps<{ cancelLabel?: string audioPlayerAvoidBottomNav?: boolean audioPlayerMode?: AudioDisplayMode + audioPlayerClosable?: boolean }>(), { activeTab: 'guide', variant: 'overlay', @@ -68,7 +70,8 @@ withDefaults(defineProps<{ backLabel: '返回', cancelLabel: '取消', audioPlayerAvoidBottomNav: true, - audioPlayerMode: 'mini' + audioPlayerMode: 'mini', + audioPlayerClosable: true }) const emit = defineEmits<{ diff --git a/src/pages/exhibit/detail.vue b/src/pages/exhibit/detail.vue index 7202efd..d82104c 100644 --- a/src/pages/exhibit/detail.vue +++ b/src/pages/exhibit/detail.vue @@ -4,6 +4,7 @@ variant="static" :show-top-tabs="false" :audio-player-avoid-bottom-nav="false" + :audio-player-closable="false" audio-player-mode="expanded" @back="handleBack" > @@ -505,7 +506,8 @@ watch( && closedSource.targetId === currentAudioTarget.value.targetId && (!closedSource.lang || closedSource.lang === selectedAudioLanguage.value) ) { - detailAudioDockDismissed.value = true + // 关闭全局播放器后,详情页需要恢复本地播放入口,避免用户无法重新播放。 + detailAudioDockDismissed.value = false } } )