import {getChatRegisterInfoApi, getMessagesByRoomIdApi} from "@/request/api/im"; /** * 聊天消息管理器 * @type {{currentRoomId: null, lastMessageId: null, unreadCounts: {}, messageCache: {}, roomMessages: {}, enterRoom(*): void, leaveRoom(): void, getCurrentRoomId(): *, increaseUnreadCount(*): void, resetUnreadCount(*): void, getUnreadCount(*): *, getAllUnreadCount(): *, loadHistory(): *, getMessageType(): *, notifyUnreadChange(): void,, addMessageToRoom(*, *): void, getRoomMessages(*): *, handleIncomingMessage(*): void}} */ const ChatManager = { // 当前房间ID currentRoomId: null, lastMessageId: 0, // 存储未读消息数 { roomId: count } unreadCounts: {}, // 消息缓存 { roomId: [message1, message2, ...] } messageCache: {}, // 房间消息存储 { roomId: [message1, message2, ...] } roomMessages: {}, // 进入聊天室 enterRoom(roomId) { this.currentRoomId = roomId; uni.setStorageSync('currentRoomId', roomId); // 重置当前房间的未读消息 this.resetUnreadCount(roomId); }, // 离开聊天室 leaveRoom() { this.currentRoomId = null; uni.removeStorageSync('currentRoomId'); }, // 获取当前房间ID getCurrentRoomId() { return this.currentRoomId || uni.getStorageSync('currentRoomId'); }, // 增加未读消息数 increaseUnreadCount(roomId) { // 如果当前不在该房间,才增加未读计数 if (this.getCurrentRoomId() !== roomId) { this.unreadCounts[roomId] = (this.unreadCounts[roomId] || 0) + 1; this.notifyUnreadChange(); } }, // 重置未读消息数 resetUnreadCount(roomId) { if (this.unreadCounts[roomId]) { this.unreadCounts[roomId] = 0; this.notifyUnreadChange(); } }, // 获取未读消息数 getUnreadCount(roomId) { return this.unreadCounts[roomId] || 0; }, // 获取所有未读消息数 getAllUnreadCount() { return Object.values(this.unreadCounts).reduce((sum, count) => sum + count, 0); }, // 通知未读消息变化 notifyUnreadChange() { uni.$emit('unread-message-update', { total: this.getAllUnreadCount(), byRoom: {...this.unreadCounts} }); }, // 添加消息到房间 addMessageToRoom(roomId, message) { if (!this.roomMessages[roomId]) { this.roomMessages[roomId] = []; } this.roomMessages[roomId].push(message); }, // 获取房间消息 getRoomMessages(roomId) { let that = this; this.roomMessages[roomId] = []; getMessagesByRoomIdApi({ room_id: roomId, last_message_id: 0, }).then((res) => { that.roomMessages[roomId] = that.checkMessage(res.data.result.list); that.lastMessageId = res.data.result.last_message_id; uni.$emit('load-room-message', 1); return this.roomMessages[roomId] || []; }) return this.roomMessages[roomId] || []; }, checkMessage(message, type = 0) { if (type === 1) { // 直接返回数据库字段,不进行转换 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 }; } return message.map((item, index) => { // 直接返回数据库字段,不进行转换 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 }; // 对于挂号消息,仍然需要异步获取详细信息 if (item.message_type === 10) { this.getChatRegisterInfo(result, index) } return result; }); }, // 根据消息类型ID获取类型名称(辅助函数,不转换字段名) getMessageTypeName(typeId) { const types = { 0: 'text', 1: 'image', 2: 'audio', 3: 'video', 4: 'prescription', 5: 'file', 6: 'video-call', 7: 'audio-call', 8: 'file', 9: 'system', 10: 'register', 11: 'patient-experience', 12: 'product-card', 13: 'end-consultation', }; return types[typeId] || 'unknown'; }, // 按需解析消息内容(辅助函数) getParsedContent(messageType, messageContent) { // 对于需要 JSON 解析的消息类型:4, 10, 11, 12, 13 if ([4, 10, 11, 12, 13].includes(messageType)) { try { return JSON.parse(messageContent); } catch (e) { console.error('解析消息内容失败:', e); return messageContent; } } return messageContent; }, /** * 获取挂号信息卡片 * @param item * @param index * @returns {*} */ getChatRegisterInfo(item, index) { let that = this; getChatRegisterInfoApi({ id: item.id }).then((res) => { that.roomMessages[that.currentRoomId][index].content = res.data.result; }) }, // 格式化时间 formatTime(timestamp) { let date; // 处理不同输入类型 if (typeof timestamp === 'number') { // 数字直接作为时间戳处理 date = new Date(timestamp); } else if (timestamp instanceof Date) { // Date对象直接使用 date = timestamp; } else if (typeof timestamp === 'string') { // 字符串类型:尝试转换为时间戳 const parsed = Date.parse(timestamp); if (isNaN(parsed)) { // 转换失败则使用当前时间 date = new Date(); } else { date = new Date(parsed); } } else { // 其他类型使用当前时间 date = new Date(); } const now = new Date(); const diff = now - date; // 时间差(毫秒) const seconds = Math.floor(diff / 1000); // 定义星期几的名称 const weekdays = ['日', '一', '二', '三', '四', '五', '六']; const currentWeekday = date.getDay(); // 0=周日,1=周一,...,6=周六 // 格式化时间函数 (补零) const formatTime = (num) => num.toString().padStart(2, '0'); const formattedTime = `${formatTime(date.getHours())}:${formatTime(date.getMinutes())}`; if (seconds < 60) { return '刚刚'; } else if (seconds < 3600) { return Math.floor(seconds / 60) + '分钟前'; } else if (seconds < 7200) { // 1-2小时 return Math.floor(seconds / 3600) + '小时前'; } else if (seconds < 86400) { // 2-24小时 return formattedTime; } else if (seconds < 172800) { // 1-2天(昨天) return `昨天 ${formattedTime}`; } else if (seconds < 259200) { // 2-3天(前天) return `前天 ${formattedTime}`; } else if (seconds < 604800) { // 3-7天内(本周X) return `周${weekdays[currentWeekday]} ${formattedTime}`; } else if (seconds < 1209600) { // 7-14天(上周X) return `上周${weekdays[currentWeekday]} ${formattedTime}`; } else if (seconds < 2592000) { // 14天-1个月 return Math.floor(seconds / 86400) + '天前'; } else if (seconds < 31536000) { // 1个月-1年 return Math.floor(seconds / 2592000) + '个月前'; } else { // 超过1年 return `${date.getFullYear()}-${formatTime(date.getMonth() + 1)}-${formatTime(date.getDate())}`; } }, loadHistory(roomId) { let that = this; getMessagesByRoomIdApi({ room_id: roomId, last_message_id: that.lastMessageId, }).then((res) => { if (res.data.result.list?.length === 0) { // 没有更多历史消息 uni.$emit('no-more-history'); return; } that.roomMessages[roomId] = [...that.checkMessage(res.data.result.list), ...that.roomMessages[roomId]]; that.lastMessageId = res.data.result.last_message_id; uni.$emit('load-room-message'); return res.data.result.list }) }, // 处理收到的消息 handleIncomingMessage(message) { const roomId = message.room_id; const currentRoomId = this.getCurrentRoomId(); // 添加消息到房间 this.addMessageToRoom(roomId, this.checkMessage(message, 1)); // 如果当前在消息所属的房间,直接显示 if (currentRoomId === roomId) { // 通知聊天页面显示消息 uni.$emit('new-room-message', this.checkMessage(message, 1)); } else { // 不在当前房间,缓存消息并增加未读消息数 this.increaseUnreadCount(roomId); // 触发顶部通知(传递原始消息,由 App.vue 处理通知显示) uni.$emit('show-global-notification', message); } // 通知聊天列表页刷新 uni.$emit('chat-list-update'); }, /** * 获取消息预览文本 * @param {Object} message 消息对象 * @returns {string} 预览文本 */ getMessagePreview(message) { const messageType = message.message_type; const content = message.message_content; switch (messageType) { case 0: // 文本 return content; case 1: // 图片 return '[图片]'; case 2: // 音频 return '[语音消息]'; case 3: // 视频 return '[视频]'; case 4: // 处方 return '[处方单]'; case 5: // 文件 return '[文件]'; case 6: // 视频通话 return '[视频通话]'; case 7: // 音频通话 return '[语音通话]'; case 9: // 系统消息 try { const parsed = JSON.parse(content); if (parsed.type === 'price_update') { return parsed.message || '[价格更新]'; } if (parsed.type === 'price_adjust') { return parsed.message || '[价格调整]'; } return '[系统消息]'; } catch (e) { return '[系统消息]'; } case 10: // 挂号 return '[挂号信息]'; case 11: // 患者就诊经历 return '[就诊信息]'; case 12: // 产品卡片 return '[商品推荐]'; case 13: // 结束问诊 return '[问诊已结束]'; default: return '您有一条新消息'; } } }; export { ChatManager };