import TIM from 'tim-wx-sdk'; class TIMManager { constructor() { this.tim = null; this.isLogin = false; this.userId = null; this.messageCallbacks = []; } /** * 初始化 TIM SDK */ init(sdkAppID) { // 创建 SDK 实例 this.tim = TIM.create({ SDKAppID: sdkAppID }); // 设置日志级别(开发时设为 0,生产设为 1) this.tim.setLogLevel(0); // 注册监听事件 this.registerEvents(); console.log('✅ TIM SDK 初始化完成'); } /** * 注册事件监听 */ registerEvents() { // SDK 进入 ready 状态 this.tim.on(TIM.EVENT.SDK_READY, this.onSdkReady.bind(this)); // SDK 未 ready this.tim.on(TIM.EVENT.SDK_NOT_READY, this.onSdkNotReady.bind(this)); // 收到新消息 this.tim.on(TIM.EVENT.MESSAGE_RECEIVED, this.onMessageReceived.bind(this)); // 会话列表更新 this.tim.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, this.onConversationListUpdated.bind(this)); // 被踢下线 this.tim.on(TIM.EVENT.KICKED_OUT, this.onKickedOut.bind(this)); // 网络状态变化 this.tim.on(TIM.EVENT.NET_STATE_CHANGE, this.onNetStateChange.bind(this)); } /** * SDK Ready */ onSdkReady() { console.log('✅ TIM SDK Ready'); this.isLogin = true; } /** * SDK Not Ready */ onSdkNotReady() { console.log('⚠️ TIM SDK Not Ready'); this.isLogin = false; } /** * 收到新消息 */ onMessageReceived(event) { const messageList = event.data; console.log('📥 收到新消息:', messageList.length, '条'); // 同步接收到的消息到MySQL(双重保障) messageList.forEach(message => { this.syncReceivedMessageToMySQL(message); }); // 触发回调 this.messageCallbacks.forEach(callback => { callback(messageList); }); } /** * 同步接收到的消息到MySQL */ async syncReceivedMessageToMySQL(timMessage) { try { // 获取消息类型 const getMessageType = (msg) => { const typeMap = { 'TIMTextElem': 1, 'TIMImageElem': 2, 'TIMSoundElem': 3, 'TIMVideoFileElem': 4, 'TIMFileElem': 5 }; return typeMap[msg.type] || 1; }; // 获取消息内容 const getMessageContent = (msg) => { switch (msg.type) { case 'TIMTextElem': return msg.payload.text || ''; case 'TIMImageElem': return '[图片]'; case 'TIMSoundElem': return '[语音]'; case 'TIMVideoFileElem': return '[视频]'; case 'TIMFileElem': return '[文件]'; default: return '[未知消息]'; } }; const syncData = { messageId: timMessage.ID, fromUserId: timMessage.from, toUserId: timMessage.to, messageType: getMessageType(timMessage), content: getMessageContent(timMessage), sendTime: timMessage.time }; // 调用后端同步接口 const res = await uni.request({ url: 'http://localhost:1004/api/chat/syncTIMMessage', method: 'POST', data: syncData, header: { 'Content-Type': 'application/json' } }); if (res[1].data.code === 200) { console.log('✅ 接收消息已同步到MySQL:', timMessage.ID); } } catch (error) { console.error('❌ 同步接收消息失败:', error); // 同步失败不影响主流程 } } /** * 会话列表更新 */ onConversationListUpdated(event) { console.log('📋 会话列表更新:', event.data.length, '个'); } /** * 被踢下线 */ onKickedOut(event) { console.log('❌ 被踢下线:', event.data.type); uni.showModal({ title: '下线通知', content: '您的账号在其他设备登录', showCancel: false }); } /** * 网络状态变化 */ onNetStateChange(event) { console.log('🌐 网络状态:', event.data.state); } /** * 登录 */ async login(userID, userSig) { try { console.log('📱 开始登录 TIM, userID:', userID); const res = await this.tim.login({ userID: String(userID), userSig: userSig }); console.log('✅ TIM 登录成功'); this.userId = userID; return res; } catch (error) { console.error('❌ TIM 登录失败:', error); throw error; } } /** * 登出 */ async logout() { try { await this.tim.logout(); console.log('✅ TIM 登出成功'); this.isLogin = false; this.userId = null; } catch (error) { console.error('❌ TIM 登出失败:', error); } } /** * 发送文本消息 */ async sendTextMessage(toUserId, text) { try { // 验证参数 if (!toUserId || toUserId === 'undefined' || toUserId === 'null') { console.error('❌ 接收者ID无效:', toUserId); throw new Error('接收者ID无效: ' + toUserId); } if (!this.userId || this.userId === 'undefined' || this.userId === 'null') { console.error('❌ 发送者ID无效:', this.userId); throw new Error('发送者ID未登录或无效'); } const toUserIdStr = String(toUserId); console.log('📤 准备发送消息:'); console.log(' - 发送者ID:', this.userId, '(类型:', typeof this.userId, ')'); console.log(' - 接收者ID:', toUserIdStr, '(类型:', typeof toUserIdStr, ')'); console.log(' - 消息内容:', text); // 创建文本消息 const message = this.tim.createTextMessage({ to: toUserIdStr, conversationType: TIM.TYPES.CONV_C2C, // 单聊 payload: { text: text } }); console.log('📤 消息已创建,准备发送...'); // 发送消息 const res = await this.tim.sendMessage(message); console.log('✅ 消息发送成功:', res.data.message); return res.data.message; } catch (error) { console.error('❌ 消息发送失败:', error); console.error(' - 错误详情:', error.message || error); console.error(' - 错误代码:', error.code || 'N/A'); throw error; } } /** * 发送图片消息 */ async sendImageMessage(toUserId, filePath) { try { const message = this.tim.createImageMessage({ to: String(toUserId), conversationType: TIM.TYPES.CONV_C2C, payload: { file: filePath }, onProgress: (percent) => { console.log('📊 上传进度:', percent); } }); const res = await this.tim.sendMessage(message); console.log('✅ 图片发送成功'); return res.data.message; } catch (error) { console.error('❌ 图片发送失败:', error); throw error; } } /** * 获取会话列表 */ async getConversationList() { try { const res = await this.tim.getConversationList(); console.log('📋 会话列表:', res.data.conversationList.length, '个'); return res.data.conversationList; } catch (error) { console.error('❌ 获取会话列表失败:', error); throw error; } } /** * 获取聊天记录 */ async getMessageList(conversationID, count = 15) { try { const res = await this.tim.getMessageList({ conversationID: conversationID, count: count }); console.log('💬 聊天记录:', res.data.messageList.length, '条'); return res.data.messageList; } catch (error) { console.error('❌ 获取聊天记录失败:', error); throw error; } } /** * 将消息设为已读 */ async setMessageRead(conversationID) { try { await this.tim.setMessageRead({ conversationID }); console.log('✅ 消息已读'); } catch (error) { console.error('❌ 设置已读失败:', error); } } /** * 撤回消息 */ async revokeMessage(message) { try { await this.tim.revokeMessage(message); console.log('✅ 消息已撤回'); } catch (error) { console.error('❌ 撤回失败:', error); throw error; } } /** * 监听消息 */ onMessage(callback) { this.messageCallbacks.push(callback); } /** * 移除监听 */ offMessage(callback) { const index = this.messageCallbacks.indexOf(callback); if (index > -1) { this.messageCallbacks.splice(index, 1); } } } // 导出单例 const timManager = new TIMManager(); export default timManager;