import store from '@/config/store'; import base from '@/config/baseUrl'; class IMWebSocket { constructor() { this.socketUrl = base.socketUrl || "ws://q.sjqqzc.top:8586"; this.socket = null; this.isConnected = false; this.reconnectCount = 0; this.maxReconnectCount = 5; this.reconnectTimer = null; this.heartbeatTimer = null; this.messageHandlers = new Set(); // 存储联系人列表 this.contactList = new Map(); // key: contact_id, value: contact_info // 存储未读消息数 this.unreadCount = new Map(); // key: contact_id, value: unread_count // 存储最后一条消息 this.lastMessage = new Map(); // key: contact_id, value: last_message // 绑定方法到实例 this.connect = this.connect.bind(this); this.disconnect = this.disconnect.bind(this); this.reconnect = this.reconnect.bind(this); this.send = this.send.bind(this); this.startHeartbeat = this.startHeartbeat.bind(this); this.stopHeartbeat = this.stopHeartbeat.bind(this); } // 初始化连接 init() { if (!this.socketUrl) { console.warn('WebSocket URL not configured'); return; } this.connect(); } // 建立连接 connect() { if (this.socket) { this.disconnect(); } this.socket = uni.connectSocket({ url: this.socketUrl, success: () => { console.log('WebSocket连接创建成功'); }, fail: (err) => { console.error('WebSocket连接创建失败:', err); this.reconnect(); } }); // 监听连接打开 uni.onSocketOpen(() => { console.log('WebSocket连接已打开'); this.isConnected = true; this.reconnectCount = 0; this.sendAuth(); this.startHeartbeat(); }); // 监听消息 uni.onSocketMessage((res) => { try { const message = JSON.parse(res.data); this.handleMessage(message); } catch (e) { console.error('消息解析错误:', e); } }); // 监听连接关闭 uni.onSocketClose(() => { console.log('WebSocket连接已关闭'); this.isConnected = false; this.stopHeartbeat(); this.reconnect(); }); // 监听错误 uni.onSocketError((err) => { console.error('WebSocket错误:', err); this.isConnected = false; this.reconnect(); }); } // 断开连接 disconnect() { this.stopHeartbeat(); if (this.socket) { uni.closeSocket(); this.socket = null; } this.isConnected = false; } // 重连机制 reconnect() { if (this.reconnectCount >= this.maxReconnectCount) { console.log('达到最大重连次数'); return; } if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); } this.reconnectTimer = setTimeout(() => { this.reconnectCount++; console.log(`第${this.reconnectCount}次重连`); this.connect(); }, 3000); } // 发送认证信息 sendAuth() { if (store.state.userInfo.token) { this.send({ type: 'auth', token: store.state.userInfo.token }); } } // 发送消息 send(data) { if (!this.isConnected) { console.warn('WebSocket未连接'); return false; } if (typeof data === 'object') { data = JSON.stringify(data); } return new Promise((resolve, reject) => { uni.sendSocketMessage({ data, success: () => resolve(true), fail: (err) => { console.error('发送消息失败:', err); reject(err); } }); }); } // 启动心跳 startHeartbeat() { this.stopHeartbeat(); this.heartbeatTimer = setInterval(() => { this.send({ type: 'ping' }).catch(() => { this.reconnect(); }); }, 30000); } // 停止心跳 stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } } // 处理接收到的消息 handleMessage(message) { if(!message.type || message.type == "ok" || message.type == "pong"){ return ; } console.log(message) // 更新联系人列表 this.updateContactList(message); // 更新未读消息数 this.updateUnreadCount(message); // 更新最后一条消息 this.updateLastMessage(message); // 发送通知 this.sendNotification(message); // 通知所有注册的消息处理器 this.messageHandlers.forEach(handler => { try { handler(message); } catch (e) { console.error('消息处理错误:', e); } }); } // 更新联系人列表 async updateContactList(message) { const contactId = message.from_user.uid; const contactType = message.target_type; const contactKey = `${contactType}_${contactId}`; // 如果联系人不在列表中,获取联系人信息 if (!this.contactList.has(contactKey)) { try { const res = await uni.$http.get('/api/chat/contact_info', { contact_id: contactId, contact_type: contactType }); if (res.data) { this.contactList.set(contactKey, { ...res.data, type: contactType, id: contactId }); // 触发联系人列表更新事件 this.emitContactListUpdate(); } } catch (error) { console.error('获取联系人信息失败:', error); } } } // 更新未读消息数 updateUnreadCount(message) { const contactId = message.from_user.id; const contactType = message.target_type; const contactKey = `${contactType}_${contactId}`; // 如果当前不在聊天页面,增加未读数 const currentPage = getCurrentPages(); const isInChatPage = currentPage.some(page => page.route === 'pages/im/chat' && page.$page.options.target_id === contactId+'' && page.$page.options.target_type === contactType ); console.warn(isInChatPage); if (!isInChatPage) { const currentCount = this.unreadCount.get(contactKey) || 0; this.unreadCount.set(contactKey, currentCount + 1); // 触发未读消息更新事件 this.emitUnreadCountUpdate(); } } // 更新最后一条消息 updateLastMessage(message) { const contactId = message.from_user.uid; const contactType = message.target_type; const contactKey = `${contactType}_${contactId}`; this.lastMessage.set(contactKey, { content: message.content, type: message.type, create_time: message.create_time }); // 触发最后消息更新事件 this.emitLastMessageUpdate(); } // 发送通知 sendNotification(message) { // #ifdef APP-PLUS const currentPage = getCurrentPages(); const isInChatPage = currentPage.some(page => page.route === 'pages/im/chat' && page.$page.options.target_id === message.from_user.uid.toString() && page.$page.options.target_type === message.target_type ); // 如果不在聊天页面,发送通知 if (!isInChatPage) { const contact = this.contactList.get(`${message.target_type}_${message.from_user.uid}`); const title = contact ? contact.username : '新消息'; let content = ''; // 根据消息类型设置通知内容 switch (message.type) { case 'text': content = message.content; break; case 'image': content = '[图片]'; break; default: content = '[新消息]'; } // 创建通知 plus.push.createMessage(content, { title: title, payload: { type: 'chat', target_id: message.from_user.uid, target_type: message.target_type } }, { sound: 'system', cover: true }); } // #endif } // 获取联系人列表 getContactList() { return Array.from(this.contactList.values()); } // 获取未读消息数 getUnreadCount(contactId, contactType) { return this.unreadCount.get(`${contactType}_${contactId}`) || 0; } // 获取最后一条消息 getLastMessage(contactId, contactType) { return this.lastMessage.get(`${contactType}_${contactId}`); } // 清除未读消息数 clearUnreadCount(contactId, contactType) { const contactKey = `${contactType}_${contactId}`; this.unreadCount.delete(contactKey); this.emitUnreadCountUpdate(); } // 事件发射器 emitContactListUpdate() { uni.$emit('im:contactListUpdate', this.getContactList()); } emitUnreadCountUpdate() { uni.$emit('im:unreadCountUpdate', Object.fromEntries(this.unreadCount)); } emitLastMessageUpdate() { uni.$emit('im:lastMessageUpdate', Object.fromEntries(this.lastMessage)); } // 注册联系人列表更新监听 onContactListUpdate(callback) { uni.$on('im:contactListUpdate', callback); } // 注册未读消息数更新监听 onUnreadCountUpdate(callback) { uni.$on('im:unreadCountUpdate', callback); } // 注册最后消息更新监听 onLastMessageUpdate(callback) { uni.$on('im:lastMessageUpdate', callback); } // 移除监听器 offContactListUpdate(callback) { uni.$off('im:contactListUpdate', callback); } offUnreadCountUpdate(callback) { uni.$off('im:unreadCountUpdate', callback); } offLastMessageUpdate(callback) { uni.$off('im:lastMessageUpdate', callback); } // 注册消息处理器 onMessage(handler) { if (typeof handler === 'function') { this.messageHandlers.add(handler); } } // 移除消息处理器 offMessage(handler) { this.messageHandlers.delete(handler); } } // 创建单例 const im = new IMWebSocket(); export default im;