300 lines
8.9 KiB
JavaScript
300 lines
8.9 KiB
JavaScript
/**
|
||
* 聊天消息处理器
|
||
* 专门处理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;
|