2026-03-06 13:59:22 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 聊天室管理器
|
|
|
|
|
|
* 封装聊天室相关操作,包括进入房间、离开房间、发送消息、接收消息、管理未读数等
|
|
|
|
|
|
*/
|
|
|
|
|
|
import { chatConfig } from '@/config/chat.js';
|
|
|
|
|
|
import { sendWebSocketMessage, isWebSocketConnected } from '@/utils/ws/initWebSocket.js';
|
2026-05-14 14:29:51 +08:00
|
|
|
|
import { getChatRegisterInfoApi, getMessagesByRoomIdApi } from '@/api/chat.js';
|
|
|
|
|
|
import { getMessagePreview } from '@/utils/chat/messagePreview.js';
|
|
|
|
|
|
|
|
|
|
|
|
function unwrapMessagesPayload(res) {
|
|
|
|
|
|
if (res == null) return null;
|
|
|
|
|
|
if (res.result !== undefined && res.result !== null) return res.result;
|
|
|
|
|
|
if (res.data && res.data.result !== undefined && res.data.result !== null) return res.data.result;
|
|
|
|
|
|
if (res.data && typeof res.data === 'object') return res.data;
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 房间 ID 归一化,便于 WS 与列表接口字段比较 */
|
|
|
|
|
|
export function normalizeRoomId(id) {
|
|
|
|
|
|
return String(id == null ? '' : id).trim();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 仅在工作台 / 在线接诊列表为栈顶页时派发列表增量,减少后台页无意义合并 */
|
|
|
|
|
|
function shouldEmitDoctorImListUpdate() {
|
|
|
|
|
|
const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
|
|
|
|
const cur = pages && pages.length ? pages[pages.length - 1] : null;
|
|
|
|
|
|
const route = cur && cur.route ? cur.route : '';
|
|
|
|
|
|
return (
|
|
|
|
|
|
route === 'pages/workbench/index' ||
|
|
|
|
|
|
route === 'subPackages/sub_online_reception/pages/list'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-03-06 13:59:22 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 聊天室管理器类
|
|
|
|
|
|
*/
|
|
|
|
|
|
class ChatRoomManager {
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
// 当前房间ID
|
|
|
|
|
|
this.currentRoomId = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 最后一条消息ID(用于分页加载)
|
|
|
|
|
|
this.lastMessageId = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 未读数(按房间ID存储)
|
|
|
|
|
|
this.unreadCounts = {};
|
|
|
|
|
|
|
|
|
|
|
|
// 消息缓存(按房间ID存储)
|
|
|
|
|
|
this.roomMessages = {};
|
|
|
|
|
|
|
|
|
|
|
|
// 消息处理器列表
|
|
|
|
|
|
this.messageHandlers = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 进入聊天室
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* 职责:设置当前房间,重置未读数,保存到本地存储
|
|
|
|
|
|
*/
|
|
|
|
|
|
enterRoom(roomId) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const id = normalizeRoomId(roomId);
|
|
|
|
|
|
if (!id) {
|
2026-03-06 13:59:22 +08:00
|
|
|
|
console.warn('房间ID不能为空');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
this.currentRoomId = id;
|
|
|
|
|
|
uni.setStorageSync('currentRoomId', id);
|
|
|
|
|
|
this.resetUnreadCount(id);
|
|
|
|
|
|
|
|
|
|
|
|
console.log('进入聊天室:', id);
|
2026-03-06 13:59:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 离开聊天室
|
|
|
|
|
|
* 职责:清空当前房间,移除本地存储
|
|
|
|
|
|
*/
|
|
|
|
|
|
leaveRoom() {
|
|
|
|
|
|
this.currentRoomId = null;
|
|
|
|
|
|
uni.removeStorageSync('currentRoomId');
|
|
|
|
|
|
console.log('离开聊天室');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取当前房间ID
|
|
|
|
|
|
* @returns {string|null} 当前房间ID
|
|
|
|
|
|
*/
|
|
|
|
|
|
getCurrentRoomId() {
|
|
|
|
|
|
return this.currentRoomId || uni.getStorageSync('currentRoomId');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 增加未读数
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* 职责:如果房间不是当前房间,则增加未读数并通知
|
|
|
|
|
|
*/
|
|
|
|
|
|
increaseUnreadCount(roomId) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const key = normalizeRoomId(roomId);
|
|
|
|
|
|
if (!key) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (normalizeRoomId(this.getCurrentRoomId()) === key) {
|
2026-03-06 13:59:22 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
this.unreadCounts[key] = (this.unreadCounts[key] || 0) + 1;
|
2026-03-06 13:59:22 +08:00
|
|
|
|
this.notifyUnreadChange();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 重置未读数
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* 职责:将指定房间的未读数重置为0并通知
|
|
|
|
|
|
*/
|
|
|
|
|
|
resetUnreadCount(roomId) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const key = normalizeRoomId(roomId);
|
|
|
|
|
|
if (this.unreadCounts[key]) {
|
|
|
|
|
|
this.unreadCounts[key] = 0;
|
2026-03-06 13:59:22 +08:00
|
|
|
|
this.notifyUnreadChange();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取未读数
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* @returns {number} 未读数
|
|
|
|
|
|
*/
|
|
|
|
|
|
getUnreadCount(roomId) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const key = normalizeRoomId(roomId);
|
|
|
|
|
|
return this.unreadCounts[key] || 0;
|
2026-03-06 13:59:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取所有未读数总和
|
|
|
|
|
|
* @returns {number} 总未读数
|
|
|
|
|
|
*/
|
|
|
|
|
|
getAllUnreadCount() {
|
|
|
|
|
|
return Object.values(this.unreadCounts).reduce((sum, count) => sum + count, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 格式化未读数显示
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* @returns {string} 格式化后的未读数
|
|
|
|
|
|
*/
|
|
|
|
|
|
getFormattedUnreadCount(roomId) {
|
|
|
|
|
|
const count = this.getUnreadCount(roomId);
|
|
|
|
|
|
return chatConfig.formatUnreadCount(count);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 通知未读数变化
|
|
|
|
|
|
* 职责:触发未读数更新事件
|
|
|
|
|
|
*/
|
|
|
|
|
|
notifyUnreadChange() {
|
|
|
|
|
|
uni.$emit('unread-message-update', {
|
|
|
|
|
|
total: this.getAllUnreadCount(),
|
|
|
|
|
|
byRoom: { ...this.unreadCounts }
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 添加消息到房间
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* @param {Object} message - 消息对象
|
|
|
|
|
|
* 职责:将消息添加到指定房间的消息列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
addMessageToRoom(roomId, message) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const key = normalizeRoomId(roomId);
|
|
|
|
|
|
if (!key || !message) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.roomMessages[key]) {
|
|
|
|
|
|
this.roomMessages[key] = [];
|
2026-03-06 13:59:22 +08:00
|
|
|
|
}
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
// 检查消息是否已存在(避免重复)
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const existingIndex = this.roomMessages[key].findIndex(m => m.id === message.id);
|
2026-03-06 13:59:22 +08:00
|
|
|
|
if (existingIndex !== -1) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
this.roomMessages[key][existingIndex] = message;
|
2026-03-06 13:59:22 +08:00
|
|
|
|
} else {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
this.roomMessages[key].push(message);
|
2026-03-06 13:59:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取房间消息列表
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* @returns {Array} 消息列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
getRoomMessages(roomId) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const key = normalizeRoomId(roomId);
|
|
|
|
|
|
return this.roomMessages[key] || [];
|
2026-03-06 13:59:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加载房间消息
|
|
|
|
|
|
* @param {string} roomId - 房间ID
|
|
|
|
|
|
* @param {number} lastMessageId - 最后一条消息ID(可选,用于分页)
|
|
|
|
|
|
* @returns {Promise<Array>} 消息列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
async loadRoomMessages(roomId, lastMessageId = 0) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const key = normalizeRoomId(roomId);
|
|
|
|
|
|
if (!key) {
|
2026-03-06 13:59:22 +08:00
|
|
|
|
console.warn('房间ID不能为空');
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
try {
|
|
|
|
|
|
const res = await getMessagesByRoomIdApi({
|
2026-05-14 14:29:51 +08:00
|
|
|
|
room_id: key,
|
2026-03-06 13:59:22 +08:00
|
|
|
|
last_message_id: lastMessageId || 0
|
|
|
|
|
|
});
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
const payload = unwrapMessagesPayload(res);
|
|
|
|
|
|
if (payload && typeof payload === 'object') {
|
|
|
|
|
|
const rawList = payload.list;
|
|
|
|
|
|
const list = Array.isArray(rawList) ? rawList : rawList != null ? [rawList] : [];
|
|
|
|
|
|
const messages = this.processMessages(list);
|
|
|
|
|
|
this.lastMessageId = payload.last_message_id || 0;
|
|
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
// 如果是首次加载,替换消息列表;否则追加到前面
|
|
|
|
|
|
if (lastMessageId === 0) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
this.roomMessages[key] = messages;
|
2026-03-06 13:59:22 +08:00
|
|
|
|
} else {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
this.roomMessages[key] = [...messages, ...(this.roomMessages[key] || [])];
|
2026-03-06 13:59:22 +08:00
|
|
|
|
}
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
uni.$emit('load-room-message', lastMessageId === 0 ? 1 : 0);
|
|
|
|
|
|
return messages;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载房间消息失败:', error);
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 处理消息数据
|
|
|
|
|
|
* @param {Array|Object} messages - 消息数据(数组或单个消息)
|
|
|
|
|
|
* @returns {Array|Object} 处理后的消息
|
|
|
|
|
|
*/
|
|
|
|
|
|
processMessages(messages) {
|
|
|
|
|
|
if (!Array.isArray(messages)) {
|
|
|
|
|
|
return this.processSingleMessage(messages);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return messages.map((item) => {
|
|
|
|
|
|
const result = {
|
|
|
|
|
|
id: item.id,
|
|
|
|
|
|
sender_user_id: item.sender_user_id,
|
|
|
|
|
|
receiver_user_id: item.receiver_user_id,
|
|
|
|
|
|
message_type: item.message_type,
|
|
|
|
|
|
message_content: item.message_content,
|
|
|
|
|
|
duration: item.duration,
|
|
|
|
|
|
room_id: item.room_id,
|
|
|
|
|
|
created_at: item.created_at || item.send_time,
|
|
|
|
|
|
created_at_text: item.created_at_text || this.formatTime(item.send_time || item.created_at),
|
|
|
|
|
|
timestamp: item.send_time || item.created_at
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是挂号消息(type=10),异步加载详细信息
|
|
|
|
|
|
if (item.message_type === 10) {
|
|
|
|
|
|
this.loadRegisterInfo(result);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 处理单个消息
|
|
|
|
|
|
* @param {Object} message - 消息对象
|
|
|
|
|
|
* @returns {Object} 处理后的消息
|
|
|
|
|
|
*/
|
|
|
|
|
|
processSingleMessage(message) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
id: message.id,
|
|
|
|
|
|
sender_user_id: message.sender_user_id,
|
|
|
|
|
|
receiver_user_id: message.receiver_user_id,
|
|
|
|
|
|
message_type: message.message_type,
|
|
|
|
|
|
message_content: message.message_content,
|
|
|
|
|
|
duration: message.duration,
|
|
|
|
|
|
room_id: message.room_id,
|
|
|
|
|
|
created_at: message.created_at || message.send_time,
|
|
|
|
|
|
created_at_text: message.created_at_text || this.formatTime(message.send_time || message.created_at),
|
|
|
|
|
|
timestamp: message.send_time || message.created_at
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-05-14 14:29:51 +08:00
|
|
|
|
* 格式化时间(HH:mm),时间戳支持秒或毫秒
|
|
|
|
|
|
* @param {number} timestamp
|
|
|
|
|
|
* @returns {string}
|
2026-03-06 13:59:22 +08:00
|
|
|
|
*/
|
|
|
|
|
|
formatTime(timestamp) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
if (timestamp === undefined || timestamp === null || timestamp === '') return '';
|
|
|
|
|
|
const n = Number(timestamp);
|
|
|
|
|
|
if (Number.isNaN(n)) return '';
|
|
|
|
|
|
const ms = n > 1e12 ? n : n * 1000;
|
|
|
|
|
|
const date = new Date(ms);
|
2026-03-06 13:59:22 +08:00
|
|
|
|
const hours = date.getHours().toString().padStart(2, '0');
|
|
|
|
|
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
|
|
|
|
return `${hours}:${minutes}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加载挂号信息(异步)
|
|
|
|
|
|
* @param {Object} message - 消息对象
|
|
|
|
|
|
* 职责:为挂号消息加载详细信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
loadRegisterInfo(message) {
|
|
|
|
|
|
const parsedContent = this.parseMessageContent(message.message_content);
|
|
|
|
|
|
if (parsedContent._loaded || !parsedContent.id) return;
|
|
|
|
|
|
|
|
|
|
|
|
getChatRegisterInfoApi({
|
|
|
|
|
|
id: parsedContent.id,
|
|
|
|
|
|
message_id: message.id || ''
|
|
|
|
|
|
}).then((res) => {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const info = res && (res.result != null ? res.result : res.data && res.data.result);
|
|
|
|
|
|
if (res && info) {
|
|
|
|
|
|
const resultWithFlag = { ...info, _loaded: true };
|
2026-03-06 13:59:22 +08:00
|
|
|
|
const roomId = message.room_id;
|
|
|
|
|
|
const roomMessages = this.roomMessages[roomId];
|
|
|
|
|
|
|
|
|
|
|
|
if (roomMessages) {
|
|
|
|
|
|
const index = roomMessages.findIndex(m => m.id === message.id);
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
roomMessages[index].message_content = JSON.stringify(resultWithFlag);
|
|
|
|
|
|
uni.$emit('message-updated', { roomId, messageId: message.id });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch(error => {
|
|
|
|
|
|
console.error('加载挂号信息失败:', error);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 解析消息内容
|
|
|
|
|
|
* @param {string|Object} content - 消息内容
|
|
|
|
|
|
* @returns {Object|string} 解析后的内容
|
|
|
|
|
|
*/
|
|
|
|
|
|
parseMessageContent(content) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
return typeof content === 'object' ? content : JSON.parse(content);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return content;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-05-14 14:29:51 +08:00
|
|
|
|
* 通过 WebSocket 发送消息(request_type: send_message)。
|
|
|
|
|
|
* 在线接诊聊天页(sub_online_reception/pages/chat.vue)主路径已改为 Go IM `POST /api/send-to-user`(与 websocket 配置同基址),
|
|
|
|
|
|
* 此处保留供其它仍走 WS 直发的场景;新页面发聊天消息请优先使用 HTTP API。
|
2026-03-06 13:59:22 +08:00
|
|
|
|
* @param {Object} messageData - 消息数据
|
|
|
|
|
|
* @param {string} messageData.room_id - 房间ID
|
|
|
|
|
|
* @param {string} messageData.sender_user_id - 发送者ID
|
|
|
|
|
|
* @param {string} messageData.receiver_user_id - 接收者ID
|
|
|
|
|
|
* @param {number|string} messageData.message_type - 消息类型
|
|
|
|
|
|
* @param {string} messageData.message_content - 消息内容
|
|
|
|
|
|
* @param {number} messageData.duration - 语音时长(可选)
|
|
|
|
|
|
* @returns {boolean} 是否发送成功
|
|
|
|
|
|
*/
|
|
|
|
|
|
sendMessage(messageData) {
|
|
|
|
|
|
if (!isWebSocketConnected()) {
|
|
|
|
|
|
console.error('WebSocket未连接,无法发送消息');
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 确保消息类型是数字
|
|
|
|
|
|
let messageType = messageData.message_type;
|
|
|
|
|
|
if (typeof messageType === 'string') {
|
|
|
|
|
|
messageType = chatConfig.getMessageType(messageType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const message = {
|
|
|
|
|
|
request_type: 'send_message',
|
|
|
|
|
|
room_id: messageData.room_id,
|
|
|
|
|
|
sender_user_id: messageData.sender_user_id,
|
|
|
|
|
|
receiver_user_id: messageData.receiver_user_id,
|
|
|
|
|
|
message_type: messageType,
|
|
|
|
|
|
message_content: messageData.message_content || '',
|
|
|
|
|
|
duration: messageData.duration || 0
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return sendWebSocketMessage(message);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 注册消息处理器
|
|
|
|
|
|
* @param {Function} handler - 消息处理函数
|
|
|
|
|
|
* 职责:注册消息处理器,当收到WebSocket消息时调用
|
|
|
|
|
|
*/
|
|
|
|
|
|
onMessage(handler) {
|
|
|
|
|
|
if (typeof handler !== 'function') {
|
|
|
|
|
|
console.warn('消息处理器必须是函数');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.messageHandlers.push(handler);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 移除消息处理器
|
|
|
|
|
|
* @param {Function} handler - 消息处理函数
|
|
|
|
|
|
*/
|
|
|
|
|
|
offMessage(handler) {
|
|
|
|
|
|
const index = this.messageHandlers.indexOf(handler);
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
this.messageHandlers.splice(index, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 处理收到的WebSocket消息
|
|
|
|
|
|
* @param {Object} data - WebSocket消息数据
|
|
|
|
|
|
* 职责:处理收到的消息,更新未读数,调用注册的处理器
|
|
|
|
|
|
*/
|
|
|
|
|
|
handleWebSocketMessage(data) {
|
|
|
|
|
|
// 只处理聊天消息
|
|
|
|
|
|
if (data.request_type !== 'receive_message' && !data.room_id) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
const roomId = normalizeRoomId(data.room_id);
|
2026-03-06 13:59:22 +08:00
|
|
|
|
if (!roomId) return;
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
const dataNorm = { ...data, room_id: roomId };
|
|
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
// 处理消息
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const message = this.processSingleMessage(dataNorm);
|
|
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
// 添加到房间消息列表
|
|
|
|
|
|
this.addMessageToRoom(roomId, message);
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
const currentNorm = normalizeRoomId(this.getCurrentRoomId());
|
|
|
|
|
|
const incrementUnread = currentNorm !== roomId;
|
|
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
// 如果不是当前房间,增加未读数
|
2026-05-14 14:29:51 +08:00
|
|
|
|
if (incrementUnread) {
|
2026-03-06 13:59:22 +08:00
|
|
|
|
this.increaseUnreadCount(roomId);
|
|
|
|
|
|
}
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
2026-03-06 13:59:22 +08:00
|
|
|
|
// 调用所有注册的处理器
|
|
|
|
|
|
this.messageHandlers.forEach(handler => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
handler(message, roomId);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('消息处理器执行失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-05-14 14:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
const lastMessageTime =
|
|
|
|
|
|
dataNorm.send_time != null && dataNorm.send_time !== ''
|
|
|
|
|
|
? dataNorm.send_time
|
|
|
|
|
|
: dataNorm.created_at != null && dataNorm.created_at !== ''
|
|
|
|
|
|
? dataNorm.created_at
|
|
|
|
|
|
: message.timestamp != null && message.timestamp !== ''
|
|
|
|
|
|
? message.timestamp
|
|
|
|
|
|
: message.created_at;
|
|
|
|
|
|
|
|
|
|
|
|
const unreadForRoom = this.getUnreadCount(roomId);
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldEmitDoctorImListUpdate()) {
|
|
|
|
|
|
uni.$emit('doctor-im-room-update', {
|
|
|
|
|
|
roomId,
|
|
|
|
|
|
last_message_preview: getMessagePreview(dataNorm),
|
|
|
|
|
|
last_message_time: lastMessageTime,
|
|
|
|
|
|
incrementUnread,
|
|
|
|
|
|
unreadForRoom
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-03-06 13:59:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 清空房间消息缓存
|
|
|
|
|
|
* @param {string} roomId - 房间ID(可选,不传则清空所有)
|
|
|
|
|
|
*/
|
|
|
|
|
|
clearRoomCache(roomId = null) {
|
|
|
|
|
|
if (roomId) {
|
2026-05-14 14:29:51 +08:00
|
|
|
|
const key = normalizeRoomId(roomId);
|
|
|
|
|
|
if (key) delete this.roomMessages[key];
|
2026-03-06 13:59:22 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
this.roomMessages = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 导出单例
|
|
|
|
|
|
export const chatRoomManager = new ChatRoomManager();
|