/** * 音频相关工具方法 * 从 AudioControls.vue 抽离的通用工具方法 */ /** * 智能分割文本,按句号和逗号分割中英文文本 * @param {string} text - 要分割的文本 * @returns {Array} 分割后的文本段落数组 */ export function splitTextIntelligently(text) { if (!text || typeof text !== 'string') { return [text]; } // 判断是否为中文文本(包含中文字符) const isChinese = /[\u4e00-\u9fa5]/.test(text); const maxLength = isChinese ? 100 : 200; // 如果文本长度不超过限制,直接返回 if (text.length <= maxLength) { return [{ text: text, startIndex: 0, endIndex: text.length - 1 }]; } const segments = []; let currentText = text; let globalStartIndex = 0; while (currentText.length > 0) { if (currentText.length <= maxLength) { // 剩余文本不超过限制,直接添加 segments.push({ text: currentText, startIndex: globalStartIndex, endIndex: globalStartIndex + currentText.length - 1 }); break; } // 在限制长度内寻找最佳分割点 let splitIndex = maxLength; let bestSplitIndex = -1; // 优先寻找句号 for (let i = Math.min(maxLength, currentText.length - 1); i >= Math.max(0, maxLength - 50); i--) { const char = currentText[i]; if (char === '。' || char === '.') { bestSplitIndex = i + 1; // 包含句号 break; } } // 如果没找到句号,寻找逗号 if (bestSplitIndex === -1) { for (let i = Math.min(maxLength, currentText.length - 1); i >= Math.max(0, maxLength - 50); i--) { const char = currentText[i]; if (char === ',' || char === ',' || char === ';' || char === ';') { bestSplitIndex = i + 1; // 包含标点符号 break; } } } // 如果还是没找到合适的分割点,使用默认长度 if (bestSplitIndex === -1) { bestSplitIndex = maxLength; } // 提取当前段落 const segment = currentText.substring(0, bestSplitIndex).trim(); if (segment.length > 0) { segments.push({ text: segment, startIndex: globalStartIndex, endIndex: globalStartIndex + segment.length - 1 }); } // 更新剩余文本和全局索引 currentText = currentText.substring(bestSplitIndex).trim(); globalStartIndex += bestSplitIndex; } return segments; } /** * 格式化时间显示 * @param {number} seconds - 秒数 * @returns {string} 格式化后的时间字符串 (mm:ss) */ export function formatTime(seconds) { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } /** * 生成音频缓存键 * @param {string} courseId - 课程ID * @param {number} pageNumber - 页面号码 * @param {string} voiceId - 音色ID * @returns {string} 缓存键 */ export function generateCacheKey(courseId, pageNumber, voiceId) { return `${courseId}_${pageNumber}_${voiceId}`; } /** * 验证缓存数据的有效性 * @param {Object} cachedData - 缓存的音频数据 * @param {number} expectedPage - 期望的页面号码 * @returns {boolean} 缓存数据是否有效 */ export function validateCacheData(cachedData, expectedPage) { if (!cachedData || !cachedData.audios || cachedData.audios.length === 0) { return false; } // 检查页面号码匹配 if (expectedPage !== null && cachedData.pageNumber && cachedData.pageNumber !== expectedPage) { return false; } // 检查音频URL有效性 const firstAudio = cachedData.audios[0]; if (!firstAudio || !firstAudio.url) { return false; } return true; } /** * 查找第一个非导语音频的索引 * @param {Array} audioArray - 音频数组 * @returns {number} 第一个非导语音频的索引,如果没有找到返回-1 */ export function findFirstNonLeadAudio(audioArray) { if (!audioArray || audioArray.length === 0) { return -1; } // 从第一个音频开始查找非导语音频 for (let i = 0; i < audioArray.length; i++) { const audioData = audioArray[i]; if (audioData && !audioData.isLead) { return i; } } // 如果所有音频都是导语,返回 -1 表示不播放 return -1; } /** * 限制缓存大小,保留最近访问的页面 * @param {Object} audioCache - 音频缓存对象 * @param {number} maxSize - 最大缓存数量,默认10 * @returns {Object} 清理后的缓存对象 */ export function limitCacheSize(audioCache, maxSize = 10) { const cacheKeys = Object.keys(audioCache); if (cacheKeys.length > maxSize) { // 删除最旧的缓存项 const keysToDelete = cacheKeys.slice(0, cacheKeys.length - maxSize); keysToDelete.forEach(key => { delete audioCache[key]; }); } return audioCache; } /** * 清理音频缓存 * @param {Object} audioCache - 音频缓存对象 * @returns {Object} 清空的缓存对象 */ export function clearAudioCache(audioCache) { return {}; } /** * 音频状态重置工具 * @param {Object} audioState - 音频状态对象 * @param {boolean} clearHighlight - 是否清除高亮索引,默认true * @returns {Object} 重置后的状态对象 */ export function resetAudioState(audioState, clearHighlight = true) { const resetState = { ...audioState, isPlaying: false, currentTime: 0, sliderValue: 0 }; if (clearHighlight) { resetState.currentHighlightIndex = -1; } return resetState; } /** * 检查音频数据是否属于当前页面 * @param {Object} audioData - 音频数据 * @param {string} expectedCacheKey - 期望的缓存键 * @returns {boolean} 是否属于当前页面 */ export function isAudioDataForCurrentPage(audioData, expectedCacheKey) { if (!audioData || !audioData.cacheKey) { return false; } return audioData.cacheKey === expectedCacheKey; }