修复播放器关闭入口逻辑
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>
</view>
<view class="expanded-actions">
<view class="expanded-actions" :class="{ 'with-close': closable }">
<view class="action-btn collapse-action" @tap.stop="handleCollapse">
<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"/>
@@ -77,11 +77,21 @@
</svg>
<text class="action-text">停止播放</text>
</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 v-else-if="displayMode === 'floating'" class="floating-player" @tap="handleExpand">
<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">
<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"/>
@@ -96,7 +106,7 @@
</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">
<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"/>
@@ -143,6 +153,9 @@
<path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</view>
<view v-if="closable" class="mini-close" @tap.stop="handleClose">
<text class="mini-close-text">×</text>
</view>
</view>
</view>
</view>
@@ -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<AudioDisplayMode>(() => 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;

View File

@@ -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()

View File

@@ -35,6 +35,7 @@
<GlobalAudioPlayerHost
:avoid-bottom-nav="audioPlayerAvoidBottomNav"
:display-mode="audioPlayerMode"
:closable="audioPlayerClosable"
/>
</view>
</template>
@@ -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<{

View File

@@ -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
}
}
)