From d8833c91930bbffcbbe75b8fa7fdbd84d12c9229 Mon Sep 17 00:00:00 2001 From: wang <3202024218@qq.com> Date: Wed, 9 Jul 2025 12:07:35 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A8=B3=E5=AE=9A=E6=B5=8B=E8=AF=95=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../node_modules/.cache/eslint/123ee647.json | 2 +- .../frontend/src/components/ChatRoom.vue | 158 ++++++------------ 2 files changed, 49 insertions(+), 111 deletions(-) diff --git a/goldminer/frontend/node_modules/.cache/eslint/123ee647.json b/goldminer/frontend/node_modules/.cache/eslint/123ee647.json index 1d262cd8..df3e8f6e 100644 --- a/goldminer/frontend/node_modules/.cache/eslint/123ee647.json +++ b/goldminer/frontend/node_modules/.cache/eslint/123ee647.json @@ -1 +1 @@ -[{"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\main.js":"1","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\App.vue":"2","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\router.js":"3","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Home.vue":"4","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Register.vue":"5","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Game.vue":"6","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Login.vue":"7","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\UserProfile.vue":"8","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\ChatRoom.vue":"9","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Leaderboard.vue":"10","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Header.vue":"11","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Admin.vue":"12","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\AdminSetup.vue":"13"},{"size":2756,"mtime":1751556761222,"results":"14","hashOfConfig":"15"},{"size":1004,"mtime":1750128639386,"results":"16","hashOfConfig":"15"},{"size":2623,"mtime":1751556546605,"results":"17","hashOfConfig":"15"},{"size":5735,"mtime":1750209720346,"results":"18","hashOfConfig":"15"},{"size":4492,"mtime":1750147385471,"results":"19","hashOfConfig":"15"},{"size":53697,"mtime":1752025017871,"results":"20","hashOfConfig":"15"},{"size":7100,"mtime":1751556546604,"results":"21","hashOfConfig":"15"},{"size":11652,"mtime":1750381631833,"results":"22","hashOfConfig":"15"},{"size":62702,"mtime":1752032799816,"results":"23","hashOfConfig":"15"},{"size":13225,"mtime":1752025017873,"results":"24","hashOfConfig":"15"},{"size":4886,"mtime":1751556546600,"results":"25","hashOfConfig":"15"},{"size":18677,"mtime":1751677918715,"results":"26","hashOfConfig":"15"},{"size":4836,"mtime":1750303858491,"results":"27","hashOfConfig":"15"},{"filePath":"28","messages":"29","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"30"},"i331ru",{"filePath":"31","messages":"32","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"34","messages":"35","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"30"},{"filePath":"36","messages":"37","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"38","messages":"39","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"40","messages":"41","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"42","messages":"43","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"44","messages":"45","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"46","messages":"47","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"48","messages":"49","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"50","messages":"51","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"52","messages":"53","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"54","messages":"55","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\main.js",[],[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\App.vue",[],[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\router.js",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Home.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Register.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Game.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Login.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\UserProfile.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\ChatRoom.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Leaderboard.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Header.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Admin.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\AdminSetup.vue",[]] \ No newline at end of file +[{"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\main.js":"1","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\App.vue":"2","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\router.js":"3","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Home.vue":"4","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Register.vue":"5","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Game.vue":"6","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Login.vue":"7","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\UserProfile.vue":"8","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\ChatRoom.vue":"9","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Leaderboard.vue":"10","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Header.vue":"11","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Admin.vue":"12","D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\AdminSetup.vue":"13"},{"size":2756,"mtime":1751556761222,"results":"14","hashOfConfig":"15"},{"size":1004,"mtime":1750128639386,"results":"16","hashOfConfig":"15"},{"size":2623,"mtime":1751556546605,"results":"17","hashOfConfig":"15"},{"size":5735,"mtime":1750209720346,"results":"18","hashOfConfig":"15"},{"size":4492,"mtime":1750147385471,"results":"19","hashOfConfig":"15"},{"size":53697,"mtime":1752025017871,"results":"20","hashOfConfig":"15"},{"size":7100,"mtime":1751556546604,"results":"21","hashOfConfig":"15"},{"size":11652,"mtime":1750381631833,"results":"22","hashOfConfig":"15"},{"size":60164,"mtime":1752033607652,"results":"23","hashOfConfig":"15"},{"size":13225,"mtime":1752025017873,"results":"24","hashOfConfig":"15"},{"size":4886,"mtime":1751556546600,"results":"25","hashOfConfig":"15"},{"size":18677,"mtime":1751677918715,"results":"26","hashOfConfig":"15"},{"size":4836,"mtime":1750303858491,"results":"27","hashOfConfig":"15"},{"filePath":"28","messages":"29","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"30"},"i331ru",{"filePath":"31","messages":"32","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"34","messages":"35","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"30"},{"filePath":"36","messages":"37","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"38","messages":"39","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"40","messages":"41","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"42","messages":"43","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"44","messages":"45","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"46","messages":"47","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"48","messages":"49","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"50","messages":"51","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"52","messages":"53","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},{"filePath":"54","messages":"55","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"33"},"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\main.js",[],[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\App.vue",[],[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\router.js",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Home.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Register.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Game.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Login.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\UserProfile.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\ChatRoom.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Leaderboard.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Header.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\Admin.vue",[],"D:\\学习\\网络应用程序开发\\pdf\\goldminer\\frontend\\src\\components\\AdminSetup.vue",[]] \ No newline at end of file diff --git a/goldminer/frontend/src/components/ChatRoom.vue b/goldminer/frontend/src/components/ChatRoom.vue index a9f0c354..a71dbfb5 100644 --- a/goldminer/frontend/src/components/ChatRoom.vue +++ b/goldminer/frontend/src/components/ChatRoom.vue @@ -606,86 +606,47 @@ export default { // 开始录音 const startRecording = async () => { try { - // 请求用户的麦克风权限 const stream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true } - }) - - // 检测浏览器支持的音频格式 - let options = {}; - let mimeType = ''; + }); - // 按优先级检测支持的格式 + let mimeType = 'audio/webm'; if (MediaRecorder.isTypeSupported('audio/webm;codecs=opus')) { mimeType = 'audio/webm;codecs=opus'; - console.log('使用 audio/webm;codecs=opus 格式录音'); - } - else if (MediaRecorder.isTypeSupported('audio/webm')) { - mimeType = 'audio/webm'; - console.log('使用 audio/webm 格式录音'); - } - else if (MediaRecorder.isTypeSupported('audio/ogg;codecs=opus')) { - mimeType = 'audio/ogg;codecs=opus'; - console.log('使用 audio/ogg;codecs=opus 格式录音'); - } - else if (MediaRecorder.isTypeSupported('audio/mp4')) { - mimeType = 'audio/mp4'; - console.log('使用 audio/mp4 格式录音'); - } - else { - console.log('使用默认音频格式录音'); } - // 设置录音选项 - if (mimeType) { - options = { - mimeType: mimeType, - audioBitsPerSecond: 32000 // 降低比特率以减小文件大小 - }; - } + const options = { + mimeType: mimeType, + audioBitsPerSecond: 32000 + }; - // 创建媒体录制器 - mediaRecorder.value = new MediaRecorder(stream, options) - audioChunks.value = [] + mediaRecorder.value = new MediaRecorder(stream, options); + audioChunks.value = []; - // 记录开始时间 - recordingStartTime.value = Date.now() - recordingDuration.value = 0 + recordingStartTime.value = Date.now(); - // 监听数据可用事件 mediaRecorder.value.addEventListener('dataavailable', event => { if (event.data.size > 0) { - audioChunks.value.push(event.data) + audioChunks.value.push(event.data); } - }) + }); - // 监听录制完成事件 mediaRecorder.value.addEventListener('stop', () => { - // 如果没有录制数据或录制被取消,直接返回 - if (audioChunks.value.length === 0 || !isRecording.value) { - isRecording.value = false - recordingDuration.value = 0 - stopMediaTracks(stream) - return + const actualDuration = (Date.now() - recordingStartTime.value) / 1000; + if (audioChunks.value.length === 0 || actualDuration < 0.5) { + stopMediaTracks(stream); + return; } - // 计算实际录制时长(秒) - const actualDuration = (Date.now() - recordingStartTime.value) / 1000 - console.log('录音实际时长:', actualDuration, '秒') - - // 将录制的音频块转换为Blob - const audioBlob = new Blob(audioChunks.value, { type: mimeType || 'audio/webm' }) - - // 添加本地预览消息,减少感知延迟 - const tempId = 'temp-' + Date.now() - const localAudioUrl = URL.createObjectURL(audioBlob) + const audioBlob = new Blob(audioChunks.value, { type: mimeType }); + const localAudioUrl = URL.createObjectURL(audioBlob); messages.value.push({ - id: tempId, + id: `temp-${Date.now()}`, user_id: currentUser.id, username: currentUser.username, message: localAudioUrl, @@ -693,81 +654,58 @@ export default { audio_duration: actualDuration, created_at: new Date().toISOString(), isLocal: true - }) - - scrollToBottom() + }); + scrollToBottom(); - // 将Blob转换为Base64 - const reader = new FileReader() - reader.readAsDataURL(audioBlob) + const reader = new FileReader(); + reader.readAsDataURL(audioBlob); reader.onloadend = () => { - const base64Audio = reader.result - console.log('音频格式:', mimeType || 'unknown', '数据前缀:', base64Audio.substring(0, 50)) - - // 发送语音消息 + const base64Audio = reader.result; socket.emit('send_audio_message', { room_id: currentRoom.value.id, audio_data: base64Audio, audio_duration: actualDuration, - audio_mime_type: mimeType || 'audio/webm' - }) - - // 重置录音状态 - isRecording.value = false - recordingDuration.value = 0 - recordingStartTime.value = null - } + audio_mime_type: mimeType + }); + }; - // 停止所有媒体轨道 - stopMediaTracks(stream) - }) + stopMediaTracks(stream); + }); - // 开始录音,设置较短的时间片以便更快获取数据 - mediaRecorder.value.start(100) - isRecording.value = true + mediaRecorder.value.start(100); + isRecording.value = true; - // 启动计时器 - 用于界面显示 + recordingDuration.value = 0; // Reset duration display recordingTimer.value = setInterval(() => { - // 使用实际经过的时间而不是自增计数 - recordingDuration.value = (Date.now() - recordingStartTime.value) / 1000 - - // 限制最大录音时间为60秒 + recordingDuration.value = (Date.now() - recordingStartTime.value) / 1000; if (recordingDuration.value >= 60) { - stopRecording() + stopRecording(); } - }, 100) // 更新频率提高到100ms一次,使显示更平滑 + }, 100); } catch (err) { - console.error('无法访问麦克风:', err) - alert('无法访问麦克风,请检查浏览器权限设置。') + console.error('无法访问麦克风:', err); + alert('无法访问麦克风,请检查浏览器权限设置。'); } - } - - // 切换录音状态 + }; + + // 修复:恢复 toggleRecording 函数 const toggleRecording = () => { if (isRecording.value) { - stopRecording() + stopRecording(); } else { - startRecording() + startRecording(); } - } - - // 停止录音 - const stopRecording = (forceStop = false) => { + }; + + const stopRecording = () => { if (mediaRecorder.value && isRecording.value) { - mediaRecorder.value.stop() - isRecording.value = false + mediaRecorder.value.stop(); + isRecording.value = false; if (recordingTimer.value) { - clearInterval(recordingTimer.value) - } - - // 如果不是强制停止(即用户正常完成录音),则处理音频数据 - if (!forceStop) { - // onstop事件会处理后续逻辑 - } else { - audioChunks.value = [] // 强制停止时清空数据 + clearInterval(recordingTimer.value); } } - } + }; // 播放音频 const playAudio = (message) => {