修复播放器关闭入口逻辑
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-08 23:04:43 +08:00
parent 180d3e7c96
commit 7eba2b6244
4 changed files with 101 additions and 5 deletions

View File

@@ -63,7 +63,7 @@
<text class="time-text">{{ formattedDuration }}</text> <text class="time-text">{{ formattedDuration }}</text>
</view> </view>
<view class="expanded-actions"> <view class="expanded-actions" :class="{ 'with-close': closable }">
<view class="action-btn collapse-action" @tap.stop="handleCollapse"> <view class="action-btn collapse-action" @tap.stop="handleCollapse">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path d="M6 15L12 9L18 15" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M6 15L12 9L18 15" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
@@ -77,11 +77,21 @@
</svg> </svg>
<text class="action-text">停止播放</text> <text class="action-text">停止播放</text>
</view> </view>
<view v-if="closable" class="action-divider"></view>
<view v-if="closable" class="action-btn close-action" @tap.stop="handleClose">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
<path d="M7 7L17 17M17 7L7 17" stroke="currentColor" stroke-width="2.1" stroke-linecap="round"/>
</svg>
<text class="action-text">关闭播放器</text>
</view>
</view> </view>
</view> </view>
<view v-else-if="displayMode === 'floating'" class="floating-player" @tap="handleExpand"> <view v-else-if="displayMode === 'floating'" class="floating-player" @tap="handleExpand">
<view class="floating-ring" :style="{ '--progress': progressPercent + '%' }"> <view class="floating-ring" :style="{ '--progress': progressPercent + '%' }">
<view v-if="closable" class="floating-close" @tap.stop="handleClose">
<text class="floating-close-text">×</text>
</view>
<view class="control-btn floating-play" @tap.stop="togglePlay"> <view class="control-btn floating-play" @tap.stop="togglePlay">
<svg v-if="displayPlaying" width="24" height="24" viewBox="0 0 24 24" fill="none"> <svg v-if="displayPlaying" width="24" height="24" viewBox="0 0 24 24" fill="none">
<rect x="6" y="5" width="4" height="14" rx="1" fill="currentColor"/> <rect x="6" y="5" width="4" height="14" rx="1" fill="currentColor"/>
@@ -96,7 +106,7 @@
</view> </view>
</view> </view>
<view v-else class="mini-player" @tap="handleExpand"> <view v-else class="mini-player" :class="{ 'with-close': closable }" @tap="handleExpand">
<view class="control-btn play-btn mini-play" @tap.stop="togglePlay"> <view class="control-btn play-btn mini-play" @tap.stop="togglePlay">
<svg v-if="displayPlaying" width="26" height="26" viewBox="0 0 24 24" fill="none"> <svg v-if="displayPlaying" width="26" height="26" viewBox="0 0 24 24" fill="none">
<rect x="6" y="5" width="4" height="14" rx="1" fill="currentColor"/> <rect x="6" y="5" width="4" height="14" rx="1" fill="currentColor"/>
@@ -143,6 +153,9 @@
<path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
</view> </view>
<view v-if="closable" class="mini-close" @tap.stop="handleClose">
<text class="mini-close-text">×</text>
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -176,6 +189,7 @@ const props = defineProps<{
currentTime?: number currentTime?: number
durationValue?: number durationValue?: number
pendingLanguage?: AudioLanguage | '' pendingLanguage?: AudioLanguage | ''
closable?: boolean
}>() }>()
const emit = defineEmits<{ 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 displayPlaybackError = computed(() => props.controlled ? props.playbackError || '' : localPlaybackError.value)
const displayCurrentTime = computed(() => props.controlled ? props.currentTime || 0 : localCurrentTime.value) const displayCurrentTime = computed(() => props.controlled ? props.currentTime || 0 : localCurrentTime.value)
const displayMode = computed<AudioDisplayMode>(() => props.mode || 'mini') const displayMode = computed<AudioDisplayMode>(() => props.mode || 'mini')
const closable = computed(() => props.closable !== false)
const audioLanguageOptions: Array<{ value: AudioLanguage; label: string; shortLabel: string }> = [ const audioLanguageOptions: Array<{ value: AudioLanguage; label: string; shortLabel: string }> = [
{ value: 'zh-CN', label: '中文', shortLabel: '中文' }, { value: 'zh-CN', label: '中文', shortLabel: '中文' },
{ value: 'en-US', label: 'English', shortLabel: 'EN' } { value: 'en-US', label: 'English', shortLabel: 'EN' }
@@ -569,6 +584,17 @@ const handleStop = () => {
emit('stop') emit('stop')
} }
const handleClose = () => {
if (props.controlled) {
emit('close')
return
}
stopAudio()
emit('update:visible', false)
emit('close')
}
const handleH5LoadedMetadata = () => { const handleH5LoadedMetadata = () => {
const audio = h5AudioElement.value const audio = h5AudioElement.value
if (!audio) return if (!audio) return
@@ -936,6 +962,10 @@ defineExpose({
border-top: 1px solid rgba(255, 255, 255, 0.14); border-top: 1px solid rgba(255, 255, 255, 0.14);
} }
.expanded-actions.with-close {
grid-template-columns: 1fr 1px 1fr 1px 1fr;
}
.action-btn { .action-btn {
min-width: 0; min-width: 0;
height: 42px; height: 42px;
@@ -950,6 +980,10 @@ defineExpose({
color: rgba(255, 255, 255, 0.92); color: rgba(255, 255, 255, 0.92);
} }
.close-action {
color: rgba(255, 255, 255, 0.78);
}
.action-divider { .action-divider {
width: 1px; width: 1px;
height: 26px; height: 26px;
@@ -979,6 +1013,14 @@ defineExpose({
border-radius: 30px; 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 { .mini-play {
grid-area: play; grid-area: play;
width: 56px; width: 56px;
@@ -1097,6 +1139,23 @@ defineExpose({
color: #ffffff; 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 { .expand-text {
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
@@ -1120,6 +1179,26 @@ defineExpose({
border-radius: 50%; 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 { .floating-ring::before {
content: ''; content: '';
position: absolute; position: absolute;
@@ -1205,6 +1284,14 @@ defineExpose({
row-gap: 6px; 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 { .mini-play {
width: 50px; width: 50px;
height: 50px; height: 50px;

View File

@@ -10,11 +10,13 @@
:current-time="currentTime" :current-time="currentTime"
:duration-value="duration" :duration-value="duration"
:pending-language="pendingLanguage" :pending-language="pendingLanguage"
:closable="closable"
:avoid-bottom-nav="avoidBottomNav" :avoid-bottom-nav="avoidBottomNav"
:mode="currentDisplayMode" :mode="currentDisplayMode"
@toggle="handleToggle" @toggle="handleToggle"
@collapse="handleCollapse" @collapse="handleCollapse"
@stop="handleStop" @stop="handleStop"
@close="player.close"
@seek="player.seekToPercent" @seek="player.seekToPercent"
@expand="handleExpand" @expand="handleExpand"
@language-change="handleLanguageChange" @language-change="handleLanguageChange"
@@ -34,9 +36,11 @@ import { useGlobalAudioPlayer } from '@/composables/useGlobalAudioPlayer'
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
avoidBottomNav?: boolean avoidBottomNav?: boolean
displayMode?: AudioDisplayMode displayMode?: AudioDisplayMode
closable?: boolean
}>(), { }>(), {
avoidBottomNav: true, avoidBottomNav: true,
displayMode: 'mini' displayMode: 'mini',
closable: true
}) })
const player = useGlobalAudioPlayer() const player = useGlobalAudioPlayer()

View File

@@ -35,6 +35,7 @@
<GlobalAudioPlayerHost <GlobalAudioPlayerHost
:avoid-bottom-nav="audioPlayerAvoidBottomNav" :avoid-bottom-nav="audioPlayerAvoidBottomNav"
:display-mode="audioPlayerMode" :display-mode="audioPlayerMode"
:closable="audioPlayerClosable"
/> />
</view> </view>
</template> </template>
@@ -57,6 +58,7 @@ withDefaults(defineProps<{
cancelLabel?: string cancelLabel?: string
audioPlayerAvoidBottomNav?: boolean audioPlayerAvoidBottomNav?: boolean
audioPlayerMode?: AudioDisplayMode audioPlayerMode?: AudioDisplayMode
audioPlayerClosable?: boolean
}>(), { }>(), {
activeTab: 'guide', activeTab: 'guide',
variant: 'overlay', variant: 'overlay',
@@ -68,7 +70,8 @@ withDefaults(defineProps<{
backLabel: '返回', backLabel: '返回',
cancelLabel: '取消', cancelLabel: '取消',
audioPlayerAvoidBottomNav: true, audioPlayerAvoidBottomNav: true,
audioPlayerMode: 'mini' audioPlayerMode: 'mini',
audioPlayerClosable: true
}) })
const emit = defineEmits<{ const emit = defineEmits<{

View File

@@ -4,6 +4,7 @@
variant="static" variant="static"
:show-top-tabs="false" :show-top-tabs="false"
:audio-player-avoid-bottom-nav="false" :audio-player-avoid-bottom-nav="false"
:audio-player-closable="false"
audio-player-mode="expanded" audio-player-mode="expanded"
@back="handleBack" @back="handleBack"
> >
@@ -505,7 +506,8 @@ watch(
&& closedSource.targetId === currentAudioTarget.value.targetId && closedSource.targetId === currentAudioTarget.value.targetId
&& (!closedSource.lang || closedSource.lang === selectedAudioLanguage.value) && (!closedSource.lang || closedSource.lang === selectedAudioLanguage.value)
) { ) {
detailAudioDockDismissed.value = true // 关闭全局播放器后,详情页需要恢复本地播放入口,避免用户无法重新播放。
detailAudioDockDismissed.value = false
} }
} }
) )