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 }}
-
+
停止播放
+
+
+
+ 关闭播放器
+
+
+ ×
+
-
+
+
+ ×
+
@@ -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
}
}
)