|
|
|
@ -401,6 +401,18 @@ export default { |
|
|
|
checkAndLoadPreloadedAudio() { |
|
|
|
// 只在需要加载音频的页面检查 |
|
|
|
if (!this.shouldLoadAudio) { |
|
|
|
// 非文本页面,确保音频状态为空 |
|
|
|
this.currentPageAudios = []; |
|
|
|
this.totalTime = 0; |
|
|
|
this.hasAudioData = false; |
|
|
|
this.isAudioLoading = false; |
|
|
|
|
|
|
|
// 通知父组件音频状态变化 |
|
|
|
this.$emit('audio-state-change', { |
|
|
|
hasAudioData: false, |
|
|
|
isLoading: false, |
|
|
|
currentHighlightIndex: -1 |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
@ -414,10 +426,21 @@ export default { |
|
|
|
this.totalTime = cachedAudio.totalDuration || 0; |
|
|
|
this.hasAudioData = true; |
|
|
|
this.isAudioLoading = false; |
|
|
|
|
|
|
|
this.currentAudioIndex = 0; |
|
|
|
this.currentTime = 0; |
|
|
|
this.currentHighlightIndex = -1; |
|
|
|
|
|
|
|
console.log(`🎵 checkAndLoadPreloadedAudio: 从缓存加载音频,页面=${this.currentPage}, 音频数量=${this.currentPageAudios.length}`); |
|
|
|
|
|
|
|
// 通知父组件音频状态变化 |
|
|
|
this.$emit('audio-state-change', { |
|
|
|
hasAudioData: true, |
|
|
|
isLoading: false, |
|
|
|
currentHighlightIndex: -1 |
|
|
|
}); |
|
|
|
} else { |
|
|
|
// 没有缓存:自动开始加载音频 |
|
|
|
|
|
|
|
console.log(`🎵 checkAndLoadPreloadedAudio: 无缓存,开始加载音频,页面=${this.currentPage}`); |
|
|
|
this.getCurrentPageAudio(); |
|
|
|
} |
|
|
|
}, |
|
|
|
@ -955,37 +978,17 @@ export default { |
|
|
|
this.currentHighlightIndex = -1; |
|
|
|
this.playSpeed = 1.0; |
|
|
|
|
|
|
|
// 如果不需要加载音频,直接重置为初始状态 |
|
|
|
if (!this.shouldLoadAudio) { |
|
|
|
|
|
|
|
this.currentPageAudios = []; |
|
|
|
this.totalTime = 0; |
|
|
|
this.hasAudioData = false; |
|
|
|
} else { |
|
|
|
// 文本页面:检查是否有缓存的音频数据 |
|
|
|
const pageKey = `${this.courseId}_${this.currentPage}_${this.localVoiceId}`; |
|
|
|
const cachedAudio = this.audioCache[pageKey]; |
|
|
|
|
|
|
|
if (cachedAudio && cachedAudio.audios && cachedAudio.audios.length > 0) { |
|
|
|
// 有缓存:直接显示控制栏 |
|
|
|
this.currentPageAudios = cachedAudio.audios; |
|
|
|
this.totalTime = cachedAudio.totalDuration || 0; |
|
|
|
this.hasAudioData = true; |
|
|
|
|
|
|
|
} else { |
|
|
|
// 没有缓存:重置为初始状态,但不立即加载(由checkAndLoadPreloadedAudio处理) |
|
|
|
this.currentPageAudios = []; |
|
|
|
this.totalTime = 0; |
|
|
|
this.hasAudioData = false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
// 页面切换时,始终清空当前音频数据,避免数据错乱 |
|
|
|
// 音频数据的加载由checkAndLoadPreloadedAudio方法统一处理 |
|
|
|
this.currentPageAudios = []; |
|
|
|
this.totalTime = 0; |
|
|
|
this.hasAudioData = false; |
|
|
|
|
|
|
|
// 通知父组件音频状态变化 |
|
|
|
this.$emit('audio-state-change', { |
|
|
|
hasAudioData: this.hasAudioData, |
|
|
|
isLoading: this.isAudioLoading, |
|
|
|
currentHighlightIndex: this.currentHighlightIndex |
|
|
|
hasAudioData: false, |
|
|
|
isLoading: false, |
|
|
|
currentHighlightIndex: -1 |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
@ -1206,13 +1209,37 @@ export default { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.currentPageAudios.length === 0) return; |
|
|
|
// 检查音频数据有效性 |
|
|
|
if (!this.currentPageAudios || this.currentPageAudios.length === 0) { |
|
|
|
console.warn('🎵 playAudio: 没有音频数据'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.currentAudioIndex < 0 || this.currentAudioIndex >= this.currentPageAudios.length) { |
|
|
|
console.error('🎵 playAudio: 音频索引无效', this.currentAudioIndex); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const currentAudioData = this.currentPageAudios[this.currentAudioIndex]; |
|
|
|
if (!currentAudioData || !currentAudioData.url) { |
|
|
|
console.error('🎵 playAudio: 音频数据无效', currentAudioData); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查音频数据是否属于当前页面 |
|
|
|
const audioCacheKey = `${this.courseId}_${this.currentPage}_${this.localVoiceId}`; |
|
|
|
const currentPageCache = this.audioCache[audioCacheKey]; |
|
|
|
|
|
|
|
if (!currentPageCache || !currentPageCache.audios.includes(currentAudioData)) { |
|
|
|
console.error('🎵 playAudio: 音频数据与当前页面不匹配,停止播放'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 🎯 全局音频管理:停止单词音频播放,确保只有一个音频播放 |
|
|
|
this.stopWordAudio(); |
|
|
|
|
|
|
|
// 如果没有当前音频实例或者需要切换音频 |
|
|
|
if (!this.currentAudio || this.currentAudio.src !== this.currentPageAudios[this.currentAudioIndex].url) { |
|
|
|
if (!this.currentAudio || this.currentAudio.src !== currentAudioData.url) { |
|
|
|
this.createAudioInstance(); |
|
|
|
// 创建实例后稍等一下再播放,确保音频准备就绪 |
|
|
|
setTimeout(() => { |
|
|
|
@ -1632,6 +1659,32 @@ export default { |
|
|
|
|
|
|
|
// 创建音频实例 |
|
|
|
createAudioInstance() { |
|
|
|
// 检查音频数据有效性 |
|
|
|
if (!this.currentPageAudios || this.currentPageAudios.length === 0) { |
|
|
|
console.error('🎵 createAudioInstance: 没有音频数据'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.currentAudioIndex < 0 || this.currentAudioIndex >= this.currentPageAudios.length) { |
|
|
|
console.error('🎵 createAudioInstance: 音频索引无效', this.currentAudioIndex); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const currentAudioData = this.currentPageAudios[this.currentAudioIndex]; |
|
|
|
if (!currentAudioData || !currentAudioData.url) { |
|
|
|
console.error('🎵 createAudioInstance: 音频数据无效', currentAudioData); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查音频数据是否属于当前页面 |
|
|
|
const audioCacheKey = `${this.courseId}_${this.currentPage}_${this.localVoiceId}`; |
|
|
|
const currentPageCache = this.audioCache[audioCacheKey]; |
|
|
|
|
|
|
|
if (!currentPageCache || !currentPageCache.audios.includes(currentAudioData)) { |
|
|
|
console.error('🎵 createAudioInstance: 音频数据与当前页面不匹配'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 销毁之前的音频实例 |
|
|
|
if (this.currentAudio) { |
|
|
|
this.currentAudio.pause(); |
|
|
|
@ -1657,13 +1710,12 @@ export default { |
|
|
|
// audio = uni.createInnerAudioContext(); |
|
|
|
// } |
|
|
|
// } |
|
|
|
const audioUrl = this.currentPageAudios[this.currentAudioIndex].url; |
|
|
|
const audioUrl = currentAudioData.url; |
|
|
|
audio.src = audioUrl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log('🎵 创建音频实例 - 音频文本:', this.currentPageAudios[this.currentAudioIndex].text?.substring(0, 50) + '...'); |
|
|
|
console.log('🎵 创建音频实例 - 页面:', this.currentPage, '音频索引:', this.currentAudioIndex); |
|
|
|
console.log('🎵 创建音频实例 - 音频URL:', audioUrl); |
|
|
|
console.log('🎵 创建音频实例 - 音频文本:', currentAudioData.text?.substring(0, 50) + '...'); |
|
|
|
|
|
|
|
// 在音頻可以播放時檢測playbackRate支持 |
|
|
|
audio.onCanplay(() => { |
|
|
|
@ -1763,6 +1815,11 @@ export default { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查是否正在页面切换中,如果是则不更新高亮 |
|
|
|
if (this.isPageChanging) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 获取当前播放的音频数据 |
|
|
|
const currentAudio = this.currentPageAudios[this.currentAudioIndex]; |
|
|
|
if (!currentAudio) { |
|
|
|
@ -1771,6 +1828,16 @@ export default { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查音频数据是否属于当前页面,防止页面切换时的数据错乱 |
|
|
|
const audioCacheKey = `${this.courseId}_${this.currentPage}_${this.localVoiceId}`; |
|
|
|
const currentPageCache = this.audioCache[audioCacheKey]; |
|
|
|
|
|
|
|
// 如果当前音频数据不属于当前页面,则不更新高亮 |
|
|
|
if (!currentPageCache || !currentPageCache.audios.includes(currentAudio)) { |
|
|
|
console.warn('🎵 updateHighlightIndex: 音频数据与当前页面不匹配,跳过高亮更新'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 如果是分段音频,需要计算正确的高亮索引 |
|
|
|
if (currentAudio.isSegmented && typeof currentAudio.originalTextIndex !== 'undefined') { |
|
|
|
// 使用原始文本项的索引作为高亮索引 |
|
|
|
@ -1784,6 +1851,9 @@ export default { |
|
|
|
|
|
|
|
// 使用辅助方法发送高亮变化事件 |
|
|
|
this.emitHighlightChange(this.currentHighlightIndex); |
|
|
|
|
|
|
|
// 发送滚动事件,让页面滚动到当前高亮的文本 |
|
|
|
this.emitScrollToText(this.currentHighlightIndex); |
|
|
|
}, |
|
|
|
|
|
|
|
// 发送高亮变化事件的辅助方法 |
|
|
|
@ -1814,6 +1884,40 @@ export default { |
|
|
|
this.$emit('highlight-change', highlightData); |
|
|
|
}, |
|
|
|
|
|
|
|
// 发送滚动到文本事件的辅助方法 |
|
|
|
emitScrollToText(highlightIndex = -1) { |
|
|
|
if (highlightIndex === -1) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 获取当前播放的音频数据 |
|
|
|
const audioData = this.currentPageAudios[this.currentAudioIndex]; |
|
|
|
if (!audioData) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查音频数据是否属于当前页面,防止页面切换时的数据错乱 |
|
|
|
const audioCacheKey = `${this.courseId}_${this.currentPage}_${this.localVoiceId}`; |
|
|
|
const currentPageCache = this.audioCache[audioCacheKey]; |
|
|
|
|
|
|
|
// 如果当前音频数据不属于当前页面,则不发送滚动事件 |
|
|
|
if (!currentPageCache || !currentPageCache.audios.includes(audioData)) { |
|
|
|
console.warn('🎵 emitScrollToText: 音频数据与当前页面不匹配,跳过滚动事件'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const scrollData = { |
|
|
|
highlightIndex: audioData.originalTextIndex !== undefined ? audioData.originalTextIndex : highlightIndex, |
|
|
|
isSegmented: audioData.isSegmented || false, |
|
|
|
segmentIndex: audioData.segmentIndex || 0, |
|
|
|
currentText: audioData.text || '', |
|
|
|
currentPage: this.currentPage |
|
|
|
}; |
|
|
|
|
|
|
|
// 发送滚动事件 |
|
|
|
this.$emit('scroll-to-text', scrollData); |
|
|
|
}, |
|
|
|
|
|
|
|
// 音频播放结束处理 |
|
|
|
onAudioEnded() { |
|
|
|
if (this.currentAudioIndex < this.currentPageAudios.length - 1) { |
|
|
|
|