322 lines
7.8 KiB
JavaScript
322 lines
7.8 KiB
JavaScript
|
|
// 🎤 语音消息组件逻辑
|
||
|
|
const voiceMessageManager = require('../../utils/voice-message-manager.js');
|
||
|
|
|
||
|
|
Component({
|
||
|
|
properties: {
|
||
|
|
// 语音消息数据
|
||
|
|
voiceData: {
|
||
|
|
type: Object,
|
||
|
|
value: {},
|
||
|
|
observer: 'onVoiceDataChange'
|
||
|
|
},
|
||
|
|
|
||
|
|
// 是否为自己发送的消息
|
||
|
|
isSelf: {
|
||
|
|
type: Boolean,
|
||
|
|
value: false
|
||
|
|
},
|
||
|
|
|
||
|
|
// 消息ID
|
||
|
|
messageId: {
|
||
|
|
type: String,
|
||
|
|
value: ''
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
data: {
|
||
|
|
// 播放状态
|
||
|
|
isPlaying: false,
|
||
|
|
isLoading: false,
|
||
|
|
hasError: false,
|
||
|
|
|
||
|
|
// 播放进度
|
||
|
|
currentTime: 0,
|
||
|
|
duration: 0,
|
||
|
|
playProgress: 0,
|
||
|
|
|
||
|
|
// 波形数据
|
||
|
|
waveformData: [],
|
||
|
|
currentWaveIndex: 0,
|
||
|
|
|
||
|
|
// 语音信息
|
||
|
|
voiceUrl: '',
|
||
|
|
voiceDuration: 0
|
||
|
|
},
|
||
|
|
|
||
|
|
lifetimes: {
|
||
|
|
attached() {
|
||
|
|
console.log('🎤 语音消息组件加载');
|
||
|
|
this.initComponent();
|
||
|
|
},
|
||
|
|
|
||
|
|
detached() {
|
||
|
|
console.log('🎤 语音消息组件卸载');
|
||
|
|
this.cleanup();
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
methods: {
|
||
|
|
// 初始化组件
|
||
|
|
initComponent() {
|
||
|
|
// 注册语音管理器事件
|
||
|
|
this.registerVoiceEvents();
|
||
|
|
|
||
|
|
// 生成波形数据
|
||
|
|
this.generateWaveform();
|
||
|
|
|
||
|
|
// 检查当前播放状态
|
||
|
|
this.checkPlayingState();
|
||
|
|
},
|
||
|
|
|
||
|
|
// 语音数据变化处理
|
||
|
|
onVoiceDataChange(newData, oldData) {
|
||
|
|
if (!newData || JSON.stringify(newData) === JSON.stringify(oldData)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('🎤 语音数据更新:', newData);
|
||
|
|
|
||
|
|
this.setData({
|
||
|
|
voiceUrl: newData.url || '',
|
||
|
|
voiceDuration: newData.duration || 0,
|
||
|
|
duration: newData.duration || 0
|
||
|
|
});
|
||
|
|
|
||
|
|
// 重新生成波形
|
||
|
|
this.generateWaveform();
|
||
|
|
|
||
|
|
// 检查播放状态
|
||
|
|
this.checkPlayingState();
|
||
|
|
},
|
||
|
|
|
||
|
|
// 注册语音管理器事件
|
||
|
|
registerVoiceEvents() {
|
||
|
|
// 播放开始事件
|
||
|
|
voiceMessageManager.on('playStart', () => {
|
||
|
|
this.checkPlayingState();
|
||
|
|
});
|
||
|
|
|
||
|
|
// 播放结束事件
|
||
|
|
voiceMessageManager.on('playEnd', () => {
|
||
|
|
this.setData({
|
||
|
|
isPlaying: false,
|
||
|
|
currentTime: 0,
|
||
|
|
playProgress: 0,
|
||
|
|
currentWaveIndex: 0
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// 播放进度更新事件
|
||
|
|
voiceMessageManager.on('playTimeUpdate', (data) => {
|
||
|
|
if (this.isCurrentMessage()) {
|
||
|
|
this.updatePlayProgress(data.currentTime, data.duration);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// 播放错误事件
|
||
|
|
voiceMessageManager.on('playError', (error) => {
|
||
|
|
if (this.isCurrentMessage()) {
|
||
|
|
console.error('🎤 语音播放错误:', error);
|
||
|
|
this.setData({
|
||
|
|
isPlaying: false,
|
||
|
|
isLoading: false,
|
||
|
|
hasError: true
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// 播放可以开始事件
|
||
|
|
voiceMessageManager.on('playCanplay', () => {
|
||
|
|
if (this.isCurrentMessage()) {
|
||
|
|
this.setData({
|
||
|
|
isLoading: false,
|
||
|
|
hasError: false
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
// 检查是否为当前播放的消息
|
||
|
|
isCurrentMessage() {
|
||
|
|
const currentMessageId = voiceMessageManager.getCurrentPlayingMessageId();
|
||
|
|
return currentMessageId === this.properties.messageId;
|
||
|
|
},
|
||
|
|
|
||
|
|
// 检查播放状态
|
||
|
|
checkPlayingState() {
|
||
|
|
const isCurrentlyPlaying = this.isCurrentMessage() && voiceMessageManager.isPlaying();
|
||
|
|
|
||
|
|
this.setData({
|
||
|
|
isPlaying: isCurrentlyPlaying
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
// 切换播放状态
|
||
|
|
async togglePlay() {
|
||
|
|
if (this.data.hasError) {
|
||
|
|
return this.retryPlay();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this.data.isLoading) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
if (this.data.isPlaying) {
|
||
|
|
// 暂停播放
|
||
|
|
voiceMessageManager.pausePlaying();
|
||
|
|
this.setData({ isPlaying: false });
|
||
|
|
} else {
|
||
|
|
// 开始播放
|
||
|
|
await this.startPlay();
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error('🎤 切换播放状态失败:', error);
|
||
|
|
this.setData({
|
||
|
|
hasError: true,
|
||
|
|
isLoading: false,
|
||
|
|
isPlaying: false
|
||
|
|
});
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
// 开始播放
|
||
|
|
async startPlay() {
|
||
|
|
if (!this.data.voiceUrl) {
|
||
|
|
console.error('🎤 语音URL为空');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
this.setData({
|
||
|
|
isLoading: true,
|
||
|
|
hasError: false
|
||
|
|
});
|
||
|
|
|
||
|
|
// 播放语音消息
|
||
|
|
await voiceMessageManager.playVoiceMessage(
|
||
|
|
this.data.voiceUrl,
|
||
|
|
this.properties.messageId
|
||
|
|
);
|
||
|
|
|
||
|
|
this.setData({
|
||
|
|
isPlaying: true,
|
||
|
|
isLoading: false
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log('🎤 开始播放语音消息');
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('🎤 播放语音消息失败:', error);
|
||
|
|
this.setData({
|
||
|
|
hasError: true,
|
||
|
|
isLoading: false,
|
||
|
|
isPlaying: false
|
||
|
|
});
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
// 重试播放
|
||
|
|
async retryPlay() {
|
||
|
|
console.log('🎤 重试播放语音消息');
|
||
|
|
|
||
|
|
this.setData({
|
||
|
|
hasError: false,
|
||
|
|
isLoading: false,
|
||
|
|
isPlaying: false
|
||
|
|
});
|
||
|
|
|
||
|
|
await this.startPlay();
|
||
|
|
},
|
||
|
|
|
||
|
|
// 更新播放进度
|
||
|
|
updatePlayProgress(currentTime, duration) {
|
||
|
|
if (!duration || duration <= 0) return;
|
||
|
|
|
||
|
|
const progress = (currentTime / duration) * 100;
|
||
|
|
const waveIndex = Math.floor((currentTime / duration) * this.data.waveformData.length);
|
||
|
|
|
||
|
|
this.setData({
|
||
|
|
currentTime: currentTime,
|
||
|
|
duration: duration,
|
||
|
|
playProgress: progress,
|
||
|
|
currentWaveIndex: Math.max(0, waveIndex)
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
// 生成波形数据
|
||
|
|
generateWaveform() {
|
||
|
|
const duration = this.data.voiceDuration || this.data.duration || 1000;
|
||
|
|
const barCount = Math.min(Math.max(Math.floor(duration / 200), 8), 30); // 8-30个波形条
|
||
|
|
|
||
|
|
const waveformData = [];
|
||
|
|
for (let i = 0; i < barCount; i++) {
|
||
|
|
// 生成随机高度,模拟真实波形
|
||
|
|
const height = Math.random() * 60 + 20; // 20-80%的高度
|
||
|
|
waveformData.push(height);
|
||
|
|
}
|
||
|
|
|
||
|
|
this.setData({
|
||
|
|
waveformData: waveformData,
|
||
|
|
currentWaveIndex: 0
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log('🌊 生成波形数据:', waveformData.length, '个波形条');
|
||
|
|
},
|
||
|
|
|
||
|
|
// 格式化时长显示
|
||
|
|
formatDuration(duration) {
|
||
|
|
if (!duration || duration <= 0) return '0"';
|
||
|
|
|
||
|
|
const seconds = Math.floor(duration / 1000);
|
||
|
|
const minutes = Math.floor(seconds / 60);
|
||
|
|
const remainingSeconds = seconds % 60;
|
||
|
|
|
||
|
|
if (minutes > 0) {
|
||
|
|
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
|
||
|
|
} else {
|
||
|
|
return `${remainingSeconds}"`;
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
// 格式化时间显示
|
||
|
|
formatTime(time) {
|
||
|
|
if (!time || time <= 0) return '0:00';
|
||
|
|
|
||
|
|
const totalSeconds = Math.floor(time);
|
||
|
|
const minutes = Math.floor(totalSeconds / 60);
|
||
|
|
const seconds = totalSeconds % 60;
|
||
|
|
|
||
|
|
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
||
|
|
},
|
||
|
|
|
||
|
|
// 获取语音文件大小描述
|
||
|
|
getFileSizeDescription(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`;
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
// 清理资源
|
||
|
|
cleanup() {
|
||
|
|
// 如果当前正在播放这个消息,停止播放
|
||
|
|
if (this.isCurrentMessage() && voiceMessageManager.isPlaying()) {
|
||
|
|
voiceMessageManager.stopPlaying();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 移除事件监听器
|
||
|
|
voiceMessageManager.off('playStart');
|
||
|
|
voiceMessageManager.off('playEnd');
|
||
|
|
voiceMessageManager.off('playTimeUpdate');
|
||
|
|
voiceMessageManager.off('playError');
|
||
|
|
voiceMessageManager.off('playCanplay');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|