miniprogramme/utils/chat-message-handler.js
2025-09-12 16:08:17 +08:00

300 lines
8.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 聊天消息处理器
* 专门处理WebSocket接收到的聊天相关消息
*/
class ChatMessageHandler {
constructor() {
this.messageListeners = new Map();
this.statusListeners = new Map();
this.conversationListeners = new Map();
}
// 处理WebSocket消息
handleMessage(message) {
console.log('🔄 聊天消息处理器收到消息:', message.type);
switch (message.type) {
case 'new_message':
this.handleNewMessage(message.data);
break;
case 'message_status_update':
this.handleMessageStatusUpdate(message.data);
break;
case 'message_recalled':
this.handleMessageRecalled(message.data);
break;
case 'conversation_update':
this.handleConversationUpdate(message.data);
break;
case 'typing_status':
this.handleTypingStatus(message.data);
break;
case 'read_receipt':
this.handleReadReceipt(message.data);
break;
default:
console.log('未处理的聊天消息类型:', message.type);
}
}
// 处理新消息
handleNewMessage(messageData) {
console.log('📨 收到新消息:', messageData);
// 格式化消息数据
const formattedMessage = this.formatMessage(messageData);
// 通知所有监听器
this.notifyMessageListeners('new_message', formattedMessage);
// 更新会话信息
this.updateConversationLastMessage(formattedMessage);
}
// 处理消息状态更新
handleMessageStatusUpdate(statusData) {
console.log('📊 消息状态更新:', statusData);
this.notifyStatusListeners('status_update', statusData);
}
// 处理消息撤回
handleMessageRecalled(recallData) {
console.log('↩️ 消息被撤回:', recallData);
this.notifyMessageListeners('message_recalled', recallData);
}
// 处理会话更新
handleConversationUpdate(conversationData) {
console.log('💬 会话更新:', conversationData);
this.notifyConversationListeners('conversation_update', conversationData);
}
// 处理输入状态
handleTypingStatus(typingData) {
console.log('⌨️ 输入状态:', typingData);
this.notifyMessageListeners('typing_status', typingData);
}
// 处理已读回执
handleReadReceipt(readData) {
console.log('✅ 已读回执:', readData);
this.notifyStatusListeners('read_receipt', readData);
}
// 格式化消息数据
formatMessage(messageData) {
return {
messageId: messageData.messageId,
senderId: messageData.senderId,
receiverId: messageData.receiverId,
conversationId: messageData.conversationId || this.generateConversationId(messageData.senderId, messageData.receiverId),
chatType: messageData.chatType || 0,
msgType: messageData.msgType || 1,
content: messageData.content || '',
status: messageData.status || 1,
sendTime: messageData.sendTime || new Date().toISOString(),
senderName: messageData.senderName || '',
senderAvatar: messageData.senderAvatar || '',
replyTo: messageData.replyTo || '',
atUsers: messageData.atUsers || [],
extra: messageData.extra || '',
// 客户端扩展字段
isOwn: false, // 需要在使用时设置
displayTime: this.formatDisplayTime(messageData.sendTime),
contentType: this.getContentType(messageData.msgType),
parsedContent: this.parseContent(messageData.content, messageData.msgType)
};
}
// 生成会话ID
generateConversationId(senderId, receiverId) {
// 单聊会话ID生成规则较小的ID在前
const ids = [senderId, receiverId].sort();
return `conv_${ids[0]}_${ids[1]}`;
}
// 格式化显示时间
formatDisplayTime(timeString) {
if (!timeString) return '';
const messageTime = new Date(timeString);
const now = new Date();
const diffMs = now - messageTime;
const diffMinutes = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffMinutes < 1) {
return '刚刚';
} else if (diffMinutes < 60) {
return `${diffMinutes}分钟前`;
} else if (diffHours < 24) {
return messageTime.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
} else if (diffDays < 7) {
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
return weekdays[messageTime.getDay()];
} else {
return messageTime.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' });
}
}
// 获取内容类型
getContentType(msgType) {
const typeMap = {
1: 'text',
2: 'image',
3: 'voice',
4: 'video',
5: 'file',
6: 'emoji',
7: 'location',
8: 'system',
9: 'recall',
10: 'redpacket'
};
return typeMap[msgType] || 'text';
}
// 解析消息内容
parseContent(content, msgType) {
try {
switch (msgType) {
case 2: // 图片
return { url: content, type: 'image' };
case 3: // 语音
const voiceData = JSON.parse(content);
return { url: voiceData.url, duration: voiceData.duration, type: 'voice' };
case 4: // 视频
const videoData = JSON.parse(content);
return { url: videoData.url, duration: videoData.duration, thumbnail: videoData.thumbnail, type: 'video' };
case 5: // 文件
const fileData = JSON.parse(content);
return { url: fileData.url, name: fileData.name, size: fileData.size, type: 'file' };
case 7: // 位置
const locationData = JSON.parse(content);
return { latitude: locationData.latitude, longitude: locationData.longitude, address: locationData.address, type: 'location' };
default:
return { text: content, type: 'text' };
}
} catch (error) {
console.warn('解析消息内容失败:', error);
return { text: content, type: 'text' };
}
}
// 更新会话最后消息
updateConversationLastMessage(message) {
const conversationUpdate = {
conversationId: message.conversationId,
lastMessage: {
content: this.getDisplayContent(message),
sendTime: message.sendTime,
senderId: message.senderId,
senderName: message.senderName
},
unreadCount: message.isOwn ? 0 : 1 // 如果是自己发的消息未读数为0
};
this.notifyConversationListeners('last_message_update', conversationUpdate);
}
// 获取显示内容
getDisplayContent(message) {
switch (message.msgType) {
case 1: return message.content;
case 2: return '[图片]';
case 3: return '[语音]';
case 4: return '[视频]';
case 5: return '[文件]';
case 6: return '[表情]';
case 7: return '[位置]';
case 8: return message.content;
case 9: return '撤回了一条消息';
case 10: return '[红包]';
default: return message.content;
}
}
// 注册消息监听器
onMessage(event, listener) {
if (!this.messageListeners.has(event)) {
this.messageListeners.set(event, []);
}
this.messageListeners.get(event).push(listener);
}
// 注册状态监听器
onStatus(event, listener) {
if (!this.statusListeners.has(event)) {
this.statusListeners.set(event, []);
}
this.statusListeners.get(event).push(listener);
}
// 注册会话监听器
onConversation(event, listener) {
if (!this.conversationListeners.has(event)) {
this.conversationListeners.set(event, []);
}
this.conversationListeners.get(event).push(listener);
}
// 通知消息监听器
notifyMessageListeners(event, data) {
const listeners = this.messageListeners.get(event);
if (listeners) {
listeners.forEach(listener => {
try {
listener(data);
} catch (error) {
console.error(`消息监听器错误 [${event}]:`, error);
}
});
}
}
// 通知状态监听器
notifyStatusListeners(event, data) {
const listeners = this.statusListeners.get(event);
if (listeners) {
listeners.forEach(listener => {
try {
listener(data);
} catch (error) {
console.error(`状态监听器错误 [${event}]:`, error);
}
});
}
}
// 通知会话监听器
notifyConversationListeners(event, data) {
const listeners = this.conversationListeners.get(event);
if (listeners) {
listeners.forEach(listener => {
try {
listener(data);
} catch (error) {
console.error(`会话监听器错误 [${event}]:`, error);
}
});
}
}
// 清理监听器
removeAllListeners() {
this.messageListeners.clear();
this.statusListeners.clear();
this.conversationListeners.clear();
}
}
// 创建全局实例
const chatMessageHandler = new ChatMessageHandler();
module.exports = chatMessageHandler;