// 🎤 语音录制组件逻辑 const voiceMessageManager = require('../../utils/voice-message-manager.js'); Component({ properties: { // 是否显示录音界面 visible: { type: Boolean, value: false, observer: 'onVisibleChange' }, // 最大录音时长(毫秒) maxDuration: { type: Number, value: 60000 }, // 最小录音时长(毫秒) minDuration: { type: Number, value: 1000 } }, data: { // 录音状态:idle, recording, paused, completed, error recordingState: 'idle', // 状态文本 statusText: '准备录音', // 录音时长 recordingDuration: 0, // 实时波形数据 realtimeWaveform: [], // 最终波形数据 finalWaveform: [], // 录音文件信息 tempFilePath: '', fileSize: 0, // 播放状态 isPlaying: false, // 错误信息 errorMessage: '', // 权限引导 showPermissionGuide: false, // 定时器 durationTimer: null, waveformTimer: null }, lifetimes: { attached() { console.log('🎤 语音录制组件加载'); this.initComponent(); }, detached() { console.log('🎤 语音录制组件卸载'); this.cleanup(); } }, methods: { // 事件阻断占位 noop() {}, // 初始化组件 initComponent() { // 注册语音管理器事件 this.registerVoiceEvents(); // 初始化波形数据 this.initWaveform(); }, // 可见性变化处理 onVisibleChange(visible) { if (visible) { this.resetRecorder(); } else { this.cleanup(); } }, // 注册语音管理器事件 registerVoiceEvents() { // 录音开始事件 voiceMessageManager.on('recordStart', () => { this.setData({ recordingState: 'recording', statusText: '正在录音...', recordingDuration: 0 }); this.startDurationTimer(); this.startWaveformAnimation(); }); // 录音停止事件 voiceMessageManager.on('recordStop', (data) => { this.setData({ recordingState: 'completed', statusText: '录音完成', recordingDuration: data.duration, tempFilePath: data.tempFilePath, fileSize: data.fileSize }); this.stopTimers(); this.generateFinalWaveform(); }); // 录音暂停事件 voiceMessageManager.on('recordPause', () => { this.setData({ recordingState: 'paused', statusText: '录音已暂停' }); this.stopTimers(); }); // 录音恢复事件 voiceMessageManager.on('recordResume', () => { this.setData({ recordingState: 'recording', statusText: '正在录音...' }); this.startDurationTimer(); this.startWaveformAnimation(); }); // 录音错误事件 voiceMessageManager.on('recordError', (error) => { console.error('🎤 录音错误:', error); this.setData({ recordingState: 'error', statusText: '录音失败', errorMessage: this.getErrorMessage(error) }); this.stopTimers(); }); // 录音帧数据事件 voiceMessageManager.on('recordFrame', (data) => { this.updateRealtimeWaveform(data.frameBuffer); }); }, // 🎤 ===== 录音控制 ===== // 开始录音 async startRecording() { console.log('🎤 开始录音'); try { await voiceMessageManager.startRecording({ duration: this.properties.maxDuration, format: 'mp3' }); } catch (error) { console.error('🎤 开始录音失败:', error); if (error.message.includes('权限')) { this.setData({ showPermissionGuide: true }); } else { this.setData({ recordingState: 'error', statusText: '录音失败', errorMessage: this.getErrorMessage(error) }); } } }, // 停止录音 stopRecording() { console.log('🎤 停止录音'); try { // 检查最小录音时长 if (this.data.recordingDuration < this.properties.minDuration) { wx.showToast({ title: `录音时长不能少于${this.properties.minDuration / 1000}秒`, icon: 'none' }); return; } voiceMessageManager.stopRecording(); } catch (error) { console.error('🎤 停止录音失败:', error); this.setData({ recordingState: 'error', statusText: '停止录音失败', errorMessage: this.getErrorMessage(error) }); } }, // 暂停录音 pauseRecording() { console.log('🎤 暂停录音'); try { voiceMessageManager.pauseRecording(); } catch (error) { console.error('🎤 暂停录音失败:', error); } }, // 恢复录音 resumeRecording() { console.log('🎤 恢复录音'); try { voiceMessageManager.resumeRecording(); } catch (error) { console.error('🎤 恢复录音失败:', error); } }, // 取消录音 cancelRecording() { console.log('🎤 取消录音'); try { voiceMessageManager.cancelRecording(); this.resetRecorder(); } catch (error) { console.error('🎤 取消录音失败:', error); } }, // 丢弃录音 discardRecording() { console.log('🎤 丢弃录音'); this.resetRecorder(); }, // 🔊 ===== 播放控制 ===== // 播放预览 async playPreview() { if (!this.data.tempFilePath) { return; } try { if (this.data.isPlaying) { voiceMessageManager.stopPlaying(); this.setData({ isPlaying: false }); } else { await voiceMessageManager.playVoiceMessage(this.data.tempFilePath); this.setData({ isPlaying: true }); // 监听播放结束 const onPlayEnd = () => { this.setData({ isPlaying: false }); voiceMessageManager.off('playEnd', onPlayEnd); }; voiceMessageManager.on('playEnd', onPlayEnd); } } catch (error) { console.error('🎤 播放预览失败:', error); wx.showToast({ title: '播放失败', icon: 'none' }); } }, // 📤 ===== 发送录音 ===== // 发送录音 async sendRecording() { if (!this.data.tempFilePath || !this.data.recordingDuration) { return; } console.log('📤 发送录音'); try { wx.showLoading({ title: '上传中...', mask: true }); // 上传语音文件 const uploadResult = await voiceMessageManager.uploadVoiceFile( this.data.tempFilePath, this.data.recordingDuration ); wx.hideLoading(); if (uploadResult.success) { // 触发发送事件 this.triggerEvent('send', { type: 'voice', url: uploadResult.url, duration: uploadResult.duration, size: uploadResult.size, tempFilePath: this.data.tempFilePath }); // 关闭录音界面 this.closeRecorder(); wx.showToast({ title: '发送成功', icon: 'success' }); } else { throw new Error('上传失败'); } } catch (error) { wx.hideLoading(); console.error('📤 发送录音失败:', error); wx.showToast({ title: '发送失败', icon: 'none' }); } }, // 🎨 ===== 界面控制 ===== // 关闭录音界面 closeRecorder() { console.log('❌ 关闭录音界面'); // 如果正在录音,先停止 if (this.data.recordingState === 'recording') { this.cancelRecording(); } // 如果正在播放,先停止 if (this.data.isPlaying) { voiceMessageManager.stopPlaying(); } // 先自隐,再通知父级,提升关闭成功率 this.setData({ visible: false }); this.triggerEvent('close'); }, // 遮罩点击 onOverlayTap() { // 点击遮罩关闭 this.closeRecorder(); }, // 🔐 ===== 权限处理 ===== // 取消权限申请 cancelPermission() { this.setData({ showPermissionGuide: false }); }, // 打开设置页面 openSettings() { wx.openSetting({ success: (res) => { if (res.authSetting['scope.record']) { this.setData({ showPermissionGuide: false }); wx.showToast({ title: '权限已开启', icon: 'success' }); } } }); }, // 🔧 ===== 工具方法 ===== // 重置录音器 resetRecorder() { this.setData({ recordingState: 'idle', statusText: '准备录音', recordingDuration: 0, tempFilePath: '', fileSize: 0, isPlaying: false, errorMessage: '', showPermissionGuide: false }); this.stopTimers(); this.initWaveform(); }, // 初始化波形 initWaveform() { const waveform = Array(20).fill(0).map(() => Math.random() * 30 + 10); this.setData({ realtimeWaveform: waveform, finalWaveform: [] }); }, // 开始时长计时器 startDurationTimer() { this.stopTimers(); this.data.durationTimer = setInterval(() => { const duration = this.data.recordingDuration + 100; this.setData({ recordingDuration: duration }); // 检查最大时长 if (duration >= this.properties.maxDuration) { this.stopRecording(); } }, 100); }, // 开始波形动画 startWaveformAnimation() { this.data.waveformTimer = setInterval(() => { const waveform = Array(20).fill(0).map(() => Math.random() * 80 + 20); this.setData({ realtimeWaveform: waveform }); }, 150); }, // 停止定时器 stopTimers() { if (this.data.durationTimer) { clearInterval(this.data.durationTimer); this.data.durationTimer = null; } if (this.data.waveformTimer) { clearInterval(this.data.waveformTimer); this.data.waveformTimer = null; } }, // 更新实时波形 updateRealtimeWaveform(frameBuffer) { if (!frameBuffer) return; // 简化的波形数据处理 const waveform = Array(20).fill(0).map(() => Math.random() * 80 + 20); this.setData({ realtimeWaveform: waveform }); }, // 生成最终波形 generateFinalWaveform() { const duration = this.data.recordingDuration; const barCount = Math.min(Math.max(Math.floor(duration / 200), 15), 40); const waveform = Array(barCount).fill(0).map(() => Math.random() * 70 + 15); this.setData({ finalWaveform: waveform }); }, // 格式化时长 formatDuration(duration) { if (!duration || duration <= 0) return '00:00'; const totalSeconds = Math.floor(duration / 1000); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; }, // 获取文件大小文本 getFileSizeText(fileSize) { if (!fileSize || fileSize <= 0) return ''; if (fileSize < 1024) { return `${fileSize}B`; } else if (fileSize < 1024 * 1024) { return `${(fileSize / 1024).toFixed(1)}KB`; } else { return `${(fileSize / (1024 * 1024)).toFixed(1)}MB`; } }, // 获取质量文本 getQualityText(duration) { if (!duration || duration <= 0) return ''; const seconds = Math.floor(duration / 1000); if (seconds < 3) return '音质:一般'; if (seconds < 10) return '音质:良好'; return '音质:优秀'; }, // 获取错误消息 getErrorMessage(error) { if (error.message) { if (error.message.includes('权限')) { return '需要录音权限'; } else if (error.message.includes('timeout')) { return '录音超时'; } else if (error.message.includes('fail')) { return '录音失败'; } return error.message; } return '未知错误'; }, // 清理资源 cleanup() { this.stopTimers(); // 如果正在录音,取消录音 if (this.data.recordingState === 'recording') { voiceMessageManager.cancelRecording(); } // 如果正在播放,停止播放 if (this.data.isPlaying) { voiceMessageManager.stopPlaying(); } // 移除事件监听器 voiceMessageManager.off('recordStart'); voiceMessageManager.off('recordStop'); voiceMessageManager.off('recordPause'); voiceMessageManager.off('recordResume'); voiceMessageManager.off('recordError'); voiceMessageManager.off('recordFrame'); } } });