同步 sgs-frontend-mobile 源码
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-27 11:26:01 +08:00
parent 575dca430f
commit 9ea1bfab71
181 changed files with 24395 additions and 5212 deletions

View File

@@ -15,6 +15,8 @@ export interface GlobalAudioSource {
targetType?: AudioPlayTargetType
targetId?: string
lang?: AudioLanguage | string
channelCode?: string
voiceGender?: 'male' | 'female'
detailRoute?: string
title?: string
}
@@ -37,14 +39,12 @@ const error = ref('')
const currentTime = ref(0)
const duration = ref(0)
const displayMode = ref<AudioDisplayMode>('mini')
const playbackRate = ref(1)
const muted = ref(false)
const pendingLanguage = ref<AudioLanguage | ''>('')
const activeHostId = ref('')
const lastClosedSource = ref<GlobalAudioSource | null>(null)
const closeVersion = ref(0)
const playbackRate = ref(1)
const muted = ref(false)
const PLAYBACK_RATES = [1, 1.25, 1.5, 2] as const
let audioElement: HTMLAudioElement | null = null
let retryOnError: GlobalAudioRetryHandler | null = null
@@ -78,17 +78,13 @@ const syncAudioDuration = () => {
: currentAudio.value?.duration || 0
}
const applyAudioPreferences = (audio: HTMLAudioElement) => {
audio.playbackRate = playbackRate.value
audio.muted = muted.value
}
const ensureAudioElement = () => {
if (audioElement || typeof window === 'undefined' || !window.Audio) return audioElement
const audio = new window.Audio()
audio.preload = 'metadata'
applyAudioPreferences(audio)
audio.playbackRate = playbackRate.value
audio.muted = muted.value
audio.addEventListener('loadedmetadata', syncAudioDuration)
audio.addEventListener('play', () => {
playing.value = true
@@ -123,6 +119,25 @@ const ensureAudioElement = () => {
return audioElement
}
const setPlaybackRate = (rate: number) => {
const nextRate = Math.max(0.5, Math.min(2, Number.isFinite(rate) ? rate : 1))
playbackRate.value = nextRate
if (audioElement) {
audioElement.playbackRate = nextRate
}
}
const setMuted = (nextMuted: boolean) => {
muted.value = nextMuted
if (audioElement) {
audioElement.muted = nextMuted
}
}
const toggleMute = () => {
setMuted(!muted.value)
}
const resetState = () => {
currentAudio.value = null
currentSource.value = null
@@ -134,11 +149,6 @@ const resetState = () => {
duration.value = 0
displayMode.value = 'mini'
pendingLanguage.value = ''
playbackRate.value = 1
muted.value = false
if (audioElement) {
applyAudioPreferences(audioElement)
}
retryOnError = null
retrying = false
retryUsed = false
@@ -242,7 +252,8 @@ const play = async (audio: AudioItem, options: GlobalAudioPlayOptions = {}) => {
element.src = audio.audioUrl
element.load()
}
applyAudioPreferences(element)
element.playbackRate = playbackRate.value
element.muted = muted.value
try {
await element.play()
@@ -275,7 +286,7 @@ const resume = () => {
})
}
const switchLanguage = async (lang: AudioLanguage, localAudio?: AudioItem | null) => {
const switchLanguage = async (lang: AudioLanguage) => {
if (pendingLanguage.value) {
return false
}
@@ -307,35 +318,6 @@ const switchLanguage = async (lang: AudioLanguage, localAudio?: AudioItem | null
}
try {
if (localAudio?.audioUrl) {
currentSource.value = nextSource
return await play(localAudio, {
source: nextSource,
retryOnError: retryOnError || undefined,
displayMode: preservedMode
})
}
if (localAudio) {
stopAudioElement()
currentSource.value = nextSource
currentAudio.value = {
...localAudio,
audioUrl: '',
duration: 0,
language: lang
}
visible.value = true
displayMode.value = preservedMode
playing.value = false
loading.value = false
currentTime.value = 0
duration.value = 0
error.value = '当前语言暂无语音讲解'
showToast(error.value)
return false
}
const playInfo = await audioPlayInfoRepository.getPlayInfo({
targetType: source.targetType,
targetId: source.targetId,
@@ -464,22 +446,6 @@ const seekToPercent = (percent: number) => {
currentTime.value = targetTime
}
const cyclePlaybackRate = () => {
const currentIndex = PLAYBACK_RATES.indexOf(playbackRate.value as typeof PLAYBACK_RATES[number])
const nextIndex = currentIndex >= 0 ? (currentIndex + 1) % PLAYBACK_RATES.length : 0
playbackRate.value = PLAYBACK_RATES[nextIndex]
if (audioElement) {
audioElement.playbackRate = playbackRate.value
}
}
const toggleMuted = () => {
muted.value = !muted.value
if (audioElement) {
audioElement.muted = muted.value
}
}
const registerHost = () => {
hostSequence += 1
const hostId = `global-audio-host-${hostSequence}`
@@ -496,7 +462,7 @@ const unregisterHost = (hostId: string) => {
}
}
const isCurrentSource = (source: Pick<GlobalAudioSource, 'targetType' | 'targetId' | 'lang'>) => {
const isCurrentSource = (source: Pick<GlobalAudioSource, 'targetType' | 'targetId' | 'lang' | 'channelCode'>) => {
if (!currentAudio.value || !currentSource.value) return false
return Boolean(
@@ -505,6 +471,7 @@ const isCurrentSource = (source: Pick<GlobalAudioSource, 'targetType' | 'targetI
&& currentSource.value.targetType === source.targetType
&& currentSource.value.targetId === source.targetId
&& (!source.lang || !currentSource.value.lang || currentSource.value.lang === source.lang)
&& (!source.channelCode || currentSource.value.channelCode === source.channelCode)
)
}
@@ -518,12 +485,12 @@ export const useGlobalAudioPlayer = () => ({
currentTime,
duration,
displayMode,
playbackRate,
muted,
pendingLanguage,
activeHostId,
lastClosedSource,
closeVersion,
playbackRate,
muted,
hasAudio: computed(() => Boolean(currentAudio.value)),
play,
pause,
@@ -531,13 +498,14 @@ export const useGlobalAudioPlayer = () => ({
stop,
close,
setDisplayMode,
setPlaybackRate,
setMuted,
toggleMute,
collapse,
switchLanguage,
handleEnded,
handleError,
seekToPercent,
cyclePlaybackRate,
toggleMuted,
registerHost,
activateHost,
unregisterHost,