diff --git a/src/audioManager.js b/src/audioManager.js index 33ba885..f8608a5 100644 --- a/src/audioManager.js +++ b/src/audioManager.js @@ -126,6 +126,8 @@ class AudioManager { this.readyMap = new Map(); // 新增:首轮失败的音频集合与重试阶段标识 this.failedLoadKeys = new Set(); + // 加载代数,用于 reloadAll 时作废旧的加载循环 + this.loadGeneration = 0; this.initAudios(); } @@ -141,9 +143,15 @@ class AudioManager { this.currentLoadingIndex = 0; this.failedLoadKeys.clear(); + // 增加代数,使得旧的加载循环失效 + this.loadGeneration = (this.loadGeneration || 0) + 1; + const currentGen = this.loadGeneration; + this.loadingPromise = new Promise((resolve) => { const finalize = () => { + if (currentGen !== this.loadGeneration) return; const runRounds = (round) => { + if (currentGen !== this.loadGeneration) return; // 达到最大轮次或没有失败项,收尾 if (this.failedLoadKeys.size === 0 || round > this.maxRetryRounds) { this.isLoading = false; @@ -155,30 +163,40 @@ class AudioManager { this.failedLoadKeys.clear(); debugLog(`开始第 ${round} 轮串行加载,共 ${retryKeys.length} 个`); - this.loadKeysSequentially(retryKeys, () => { - // 如仍有失败项,继续下一轮;否则结束 - if (this.failedLoadKeys.size > 0 && round < this.maxRetryRounds) { - setTimeout(() => runRounds(round + 1), this.retryRoundIntervalMs); - } else { - this.isLoading = false; - resolve(); - } - }); + this.loadKeysSequentially( + retryKeys, + () => { + if (currentGen !== this.loadGeneration) return; + // 如仍有失败项,继续下一轮;否则结束 + if (this.failedLoadKeys.size > 0 && round < this.maxRetryRounds) { + setTimeout( + () => runRounds(round + 1), + this.retryRoundIntervalMs + ); + } else { + this.isLoading = false; + resolve(); + } + }, + currentGen + ); }; // 启动第 1 轮重试(如有失败项) runRounds(1); }; - this.loadNextAudio(finalize); + this.loadNextAudio(finalize, currentGen); }); return this.loadingPromise; } // 按自定义列表串行加载音频(避免并发过多) - loadKeysSequentially(keys, onComplete) { + loadKeysSequentially(keys, onComplete, gen) { + if (gen !== undefined && gen !== this.loadGeneration) return; let idx = 0; const list = Array.from(keys); const next = () => { + if (gen !== undefined && gen !== this.loadGeneration) return; if (idx >= list.length) { if (onComplete) onComplete(); return; @@ -206,7 +224,8 @@ class AudioManager { } // 串行加载下一个音频(首轮) - loadNextAudio(onComplete) { + loadNextAudio(onComplete, gen) { + if (gen !== undefined && gen !== this.loadGeneration) return; if (this.currentLoadingIndex >= this.audioKeys.length) { debugLog("首轮加载遍历完成", this.currentLoadingIndex); if (onComplete) onComplete(); @@ -220,7 +239,7 @@ class AudioManager { ); this.createAudio(key, () => { setTimeout(() => { - this.loadNextAudio(onComplete); + this.loadNextAudio(onComplete, gen); }, 100); }); } @@ -530,6 +549,38 @@ class AudioManager { } return Number((loaded / total).toFixed(2)); } + + + // 手动重置并重新加载所有音频(用于卡住时恢复) + reloadAll() { + // 1. 停止所有播放 + this.stopAll(); + + // 2. 销毁现有音频实例 + for (const audio of this.audioMap.values()) { + try { + audio.destroy(); + } catch (_) {} + } + this.audioMap.clear(); + + // 3. 重置状态 + this.readyMap.clear(); + this.failedLoadKeys.clear(); + this.allowPlayMap.clear(); + this.currentPlayingKey = null; + this.sequenceQueue = []; + this.sequenceIndex = 0; + this.isSequenceRunning = false; + + // 4. 强制重置加载锁 + this.isLoading = false; + this.loadingPromise = null; + this.currentLoadingIndex = 0; + + // 5. 重新初始化 (initAudios 会自增 loadGeneration,从而终止之前的任何异步循环) + return this.initAudios(); + } } // 导出单例 diff --git a/src/components/Container.vue b/src/components/Container.vue index 698eb1a..0221d30 100644 --- a/src/components/Container.vue +++ b/src/components/Container.vue @@ -66,9 +66,7 @@ const checkAudioProgress = async () => { if (audioInitProgress.value === 1) return resolve(); audioTimer.value = setInterval(() => { const result = AudioManager.getLoadProgress(); - if (result > audioProgress.value) { - audioProgress.value = result; - } + audioProgress.value = result; if (audioProgress.value === 1) { setTimeout(() => { audioInitProgress.value = 1; @@ -227,7 +225,12 @@ const goCalibration = async () => { mode="widthFix" /> - 资源加载中... + + + 若加载时间过长,请 + @@ -321,11 +324,21 @@ const goCalibration = async () => { width: 46rpx; height: 26rpx; } -.audio-progress > view:nth-child(2) > text { - width: 100%; +.audio-progress > view:nth-child(3) { + display: flex; + align-items: center; + justify-content: center; + margin-top: 20rpx; +} +.audio-progress > view:nth-child(3) > text { font-size: 22rpx; color: #a2a2a2; text-align: center; - margin-top: 10rpx; + line-height: 32rpx; +} +.audio-progress > view:nth-child(3) > button { + font-size: 22rpx; + color: #ffe431; + line-height: 32rpx; } diff --git a/src/components/UserHeader.vue b/src/components/UserHeader.vue index 7f50fa8..e9196f9 100644 --- a/src/components/UserHeader.vue +++ b/src/components/UserHeader.vue @@ -66,7 +66,7 @@ watch( :onClick="toUserPage" :size="42" /> - + {{ user.nickName }} 段位积分 - text { text-align: center; + word-break: keep-all; + width: 83px; } .rank-number { display: block;