// 消息页面逻辑 - 完全基于 NIM SDK const app = getApp(); const apiClient = require('../../utils/api-client.js'); const nimConversationManager = require('../../utils/nim-conversation-manager.js'); const nimPresenceManager = require('../../utils/nim-presence-manager.js'); const { initPageSystemInfo } = require('../../utils/system-info-modern.js'); Page({ data: { //模拟数据 store:[{ avatar:'../../images/group/testImg.jpg', nickname:'Jianying Liu', text:'Heyyy', tiem:'16:30' }], searchKeyword: '', refreshing: false, loading: false, longPressing: false, // 长按标记,防止长按后触发单击 // 会话数据 conversations: [], pinnedConversations: [], normalConversations: [], totalUnreadCount: 0, filteredConversations: [], // NIM SDK 状态 nimReady: false, // 系统适配信息 systemInfo: {}, statusBarHeight: 0, menuButtonHeight: 0, menuButtonTop: 0, navBarHeight: 0, windowHeight: 0, safeAreaBottom: 0, showSearch: false, // 本地模糊搜索增强 searching: false, conversationSamples: {}, sampleLoading: {}, lastSearchKeyword: '' }, // 统一时间戳规范化 normalizeTimestamp(ts) { if (!ts && ts !== 0) return 0; if (typeof ts === 'number' && isFinite(ts)) return ts; if (typeof ts === 'string') { const s = ts.trim(); if (!s) return 0; if (/^\d+$/.test(s)) { const n = parseInt(s, 10); return s.length === 10 ? n * 1000 : n; } const d = Date.parse(s); return isNaN(d) ? 0 : d; } try { const d = new Date(ts).getTime(); return isNaN(d) ? 0 : d; } catch (_) { return 0; } }, /** * 从会话数据中提取真实的用户ID * @param {Object} conv - 会话对象 * @returns {string} - 用户ID */ extractUserIdFromConversation(conv) { let userId = conv.targetId || conv.userId || ''; // 如果 targetId 是 conversationId 格式(包含|符号),则解析 if (userId && typeof userId === 'string' && userId.includes('|')) { const parts = userId.split('|'); if (parts.length === 3) { userId = parts[2]; // 提取目标用户ID } } // 如果还是没有,尝试从 conversationId 解析 if (!userId && conv.conversationId && typeof conv.conversationId === 'string') { const parts = conv.conversationId.split('|'); if (parts.length === 3) { userId = parts[2]; } } return userId || ''; }, // 页面加载 onLoad: function (options) { const { store } = this.data; // 生成10次重复的数组(fill+flat 一行实现) const repeatedArr = Array(20).fill(store).flat(); // 响应式更新:必须用 setData,页面才会渲染新数组 this.setData({ repeatedArr }); this.initSystemInfo(); this.checkAuthAndInit(); wx.setNavigationBarTitle({ title: '消息' }); }, // 检查认证状态并初始化 async checkAuthAndInit() { try { const currentToken = apiClient.getToken(); const app = getApp(); const isLoggedIn = app?.globalData?.isLoggedIn || false; console.log('检查认证状态:', { hasToken: !!currentToken, isLoggedIn }); if (!currentToken || !isLoggedIn) { console.warn('⚠️ 用户未登录,跳转到登录页'); this.redirectToLogin('checkAuthAndInit'); return; } // 初始化 NIM 模式 await this.initNIMMode(); } catch (error) { console.error('认证检查失败:', error); wx.showToast({ title: `NIM初始化失败:${error}`, icon: 'none' }); } }, // 统一的登录页跳转方法 redirectToLogin(source) { if (this.redirecting) { console.log('已在跳转中,跳过'); return; } this.redirecting = true; console.log(`🔄 来自${source}的跳转请求,执行跳转...`); setTimeout(() => { wx.reLaunch({ url: '/pages/login/login', success: () => { console.log('✅ 跳转登录页成功'); this.redirecting = false; }, fail: (err) => { console.error('❌ 跳转登录页失败:', err); this.redirecting = false; } }); }, 1000); }, // 初始化系统信息 initSystemInfo() { const pageSystemInfo = initPageSystemInfo(); this.setData({ systemInfo: pageSystemInfo.systemInfo, statusBarHeight: pageSystemInfo.statusBarHeight, menuButtonHeight: pageSystemInfo.menuButtonHeight, menuButtonTop: pageSystemInfo.menuButtonTop, navBarHeight: pageSystemInfo.navBarHeight, windowHeight: pageSystemInfo.windowHeight, safeAreaBottom: pageSystemInfo.safeAreaBottom }); }, // 初始化 NIM 模式 initNIMMode() { try { console.log('📡 初始化 NIM 模式'); const app = getApp(); if (!app.globalData.nim) { console.error('❌ NIM 实例未初始化'); wx.showToast({ title: 'NIM未初始化', icon: 'none' }); return; } // 注册 NIM 事件监听器 nimConversationManager.on('conversation_created', this.handleNIMConversationCreated.bind(this)); nimConversationManager.on('conversation_deleted', this.handleNIMConversationDeleted.bind(this)); nimConversationManager.on('conversation_changed', this.handleNIMConversationChanged.bind(this)); nimConversationManager.on('new_message', this.handleNIMNewMessages.bind(this)); nimConversationManager.on('message_revoked', this.handleNIMMessageRevoked.bind(this)); // 🔥 注册在线状态变化监听 nimPresenceManager.on('presence_changed', this.handlePresenceChanged.bind(this)); this.setData({ nimReady: true }); // 加载会话列表 this.loadConversations(); console.log('✅ NIM 模式初始化完成'); } catch (error) { console.error('❌ 初始化 NIM 模式失败:', error); wx.showToast({ title: '初始化 NIM 模式失败', icon: 'none' }); } }, // 🔥 检查并重连 NIM(页面级别) async checkAndReconnectNim() { try { const app = getApp(); // 如果 NIM 未就绪,尝试初始化 if (!this.data.nimReady) { console.log('⚠️ 页面 NIM 未就绪,尝试初始化'); await this.checkAuthAndInit(); return; } // 触发全局 NIM 重连检查 if (app && typeof app.checkAndReconnectNim === 'function') { await app.checkAndReconnectNim(); } // 重新初始化会话管理器(确保事件监听器有效) if (app.globalData.nim) { const nim = app.globalData.nim; // 检查会话管理器是否已初始化 if (!nimConversationManager.getInitStatus()) { console.log('🔄 重新初始化会话管理器'); nimConversationManager.init(nim); } // 检查在线状态管理器是否已初始化 if (!nimPresenceManager.getInitStatus()) { console.log('🔄 重新初始化在线状态管理器'); nimPresenceManager.init(nim); } } } catch (error) { console.error('❌ 页面级 NIM 重连检查失败:', error); } }, // ===== NIM 事件处理方法 ===== // 处理 NIM 会话新增 handleNIMConversationCreated(conversation) { console.log('📝 处理NIM会话新增:', conversation); const conversations = [conversation, ...this.data.conversations]; this.processConversations(conversations); this.playMessageSound(); }, // 处理 NIM 会话删除 handleNIMConversationDeleted(conversationIds) { console.log('🗑️ 处理NIM会话删除:', conversationIds); const conversations = this.data.conversations.filter( conv => !conversationIds.includes(conv.conversationId) ); this.processConversations(conversations); }, // 处理 NIM 会话更新 handleNIMConversationChanged(changedConversations) { console.log('🔄 处理NIM会话更新,数量:', changedConversations?.length || 0); if (!Array.isArray(changedConversations) || changedConversations.length === 0) { return; } // 🔥 增量更新:只更新变化的会话,而不是替换整个列表 let conversations = [...this.data.conversations]; let hasChanges = false; changedConversations.forEach(changedConv => { const index = conversations.findIndex( conv => conv.conversationId === changedConv.conversationId ); if (index >= 0) { // 检查是否真的有变化(避免不必要的更新) const oldConv = conversations[index]; const hasRealChange = oldConv.unreadCount !== changedConv.unreadCount || oldConv.lastMessage !== changedConv.lastMessage || oldConv.isPinned !== changedConv.isPinned || oldConv.isMuted !== changedConv.isMuted; if (hasRealChange) { // 🔥 特殊处理:如果旧会话有未读数,新会话未读数为0,但最后消息没变 // 说明这可能是标记已读导致的更新,不应该覆盖可能正在到来的新消息未读数 if (oldConv.unreadCount > 0 && changedConv.unreadCount === 0 && oldConv.lastMessage === changedConv.lastMessage) { console.log('⚠️ 检测到可能的标记已读事件,保留当前未读数'); changedConv.unreadCount = oldConv.unreadCount; } conversations[index] = changedConv; hasChanges = true; } } else { // 新会话,添加到列表 conversations.unshift(changedConv); hasChanges = true; } }); // 只有真正有变化时才更新 UI if (hasChanges) { this.processConversations(conversations); } else { console.log('⚠️ 会话数据无实质变化,跳过更新'); } }, // 处理 NIM 新消息 async handleNIMNewMessages(messages) { console.log('📨 处理NIM新消息:', messages); if (!Array.isArray(messages)) return; let conversations = [...this.data.conversations]; let hasChanges = false; let needReloadConversations = false; messages.forEach(message => { const conversationId = message.conversationId; if (!conversationId) return; const index = conversations.findIndex( conv => conv.conversationId === conversationId ); if (index >= 0) { // 更新现有会话 // 🔥 使用消息的 createTime,如果没有则保持原时间 const messageTime = message.createTime || conversations[index].lastMsgTime || 0; conversations[index] = { ...conversations[index], lastMessage: nimConversationManager.getMessagePreview(message), lastMessageType: nimConversationManager.getMessageType(message), lastMessageTime: nimConversationManager.formatMessageTime(messageTime), lastMsgTime: messageTime, unreadCount: (conversations[index].unreadCount || 0) + 1 }; hasChanges = true; } else { // 新会话,需要重新加载 console.log('⚠️ 收到新会话消息,需要重新加载会话列表'); needReloadConversations = true; } }); if (hasChanges) { this.processConversations(conversations); this.playMessageSound(); } if (needReloadConversations) { this.loadConversations(); } }, // 处理 NIM 消息撤回 handleNIMMessageRevoked(revokeNotifications) { console.log('↩️ 处理NIM消息撤回:', revokeNotifications); if (!Array.isArray(revokeNotifications)) return; let conversations = [...this.data.conversations]; let hasChanges = false; revokeNotifications.forEach(notification => { const conversationId = notification.conversationId; if (!conversationId) return; const index = conversations.findIndex( conv => conv.conversationId === conversationId ); if (index >= 0) { conversations[index] = { ...conversations[index], lastMessage: '已撤回' }; hasChanges = true; } }); if (hasChanges) { this.processConversations(conversations); } }, // 🔥 处理用户在线状态变化 handlePresenceChanged(data) { const { userId, isOnline } = data; // 更新会话列表中对应用户的在线状态 let conversations = [...this.data.conversations]; let hasChanges = false; conversations.forEach(conv => { // 判断是否为单聊会话 const isSingleChat = conv.type === 'single' || conv.type === 0 || conv.chatType === 0; if (!isSingleChat) { return; } // 提取真实的用户ID进行匹配 let targetId = conv.targetId; // 如果 targetId 包含 | 符号,说明是 conversationId 格式,需要解析 if (targetId && typeof targetId === 'string' && targetId.includes('|')) { const parts = targetId.split('|'); if (parts.length === 3) { targetId = parts[2]; conv.targetId = targetId; // 更新为纯用户ID } } if (targetId === userId) { conv.isOnline = isOnline; hasChanges = true; } }); if (hasChanges) { this.processConversations(conversations); } }, // 加载会话列表 async loadConversations() { if (this.data.loading) return; const currentToken = apiClient.getToken(); if (!currentToken) { console.warn('⚠️ Token 丢失,无法加载会话列表'); return; } try { this.setData({ loading: true }); console.log('📋 从 NIM SDK 加载会话列表'); const conversations = await nimConversationManager.getConversationList(0, 100); console.log('✅ 加载会话列表成功,数量:', conversations.length); this.processConversations(conversations); } catch (error) { console.error('❌ 加载会话列表失败:', error); wx.showToast({ title: `加载会话列表失败:${error}`, icon: 'none' }); } finally { this.setData({ loading: false }); } }, // 播放消息提示音 playMessageSound() { try { const innerAudioContext = wx.createInnerAudioContext(); innerAudioContext.src = '/images/message-sound.mp3'; innerAudioContext.play(); } catch (error) { console.error('播放提示音失败:', error); } }, // 更新Tab角标 updateTabBadge() { const totalUnread = this.data.totalUnreadCount; if (totalUnread > 0) { wx.setTabBarBadge({ index: 1, text: totalUnread > 99 ? '99+' : totalUnread.toString() }); } else { wx.removeTabBarBadge({ index: 1 }); } // 自定义TabBar同步 try { if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setMessagesBadge(totalUnread); } } catch (_) { } }, // 处理会话数据 async processConversations(conversations) { // 过滤已删除项,并统一关键字段 const validList = (conversations || []) .filter(it => it && !it.deleted && !it._deleted) .map(it => ({ ...it, isPinned: !!(it.isPinned || it.isTop), _ts: this.normalizeTimestamp(it.lastMsgTime || it.lastMessageTimeTs || it.lastActiveAt || it.updatedAt) })); // 🔥 订阅会话中单聊用户的在线状态 try { await nimPresenceManager.subscribeConversations(validList); } catch (error) { console.error('订阅在线状态失败:', error); } // 🔥 从缓存中更新在线状态 validList.forEach(conv => { // 判断是否为单聊 const isSingleChat = conv.type === 'single' || conv.type === 0 || conv.chatType === 0; if (isSingleChat) { // 提取真实的用户ID(处理可能的 conversationId 格式) let targetId = conv.targetId; // 如果 targetId 包含 | 符号,说明是 conversationId 格式,需要解析 if (targetId && typeof targetId === 'string' && targetId.includes('|')) { const parts = targetId.split('|'); if (parts.length === 3) { targetId = parts[2]; conv.targetId = targetId; // 更新为纯用户ID } } if (!targetId) { return; } const presence = nimPresenceManager.getUserPresence(targetId); if (presence) { conv.isOnline = presence.online; } else { conv.isOnline = false; // 默认离线 } } }); // 置顶/非置顶分组并组内按时间降序 const pinnedConversations = validList .filter(item => item.isPinned) .sort((a, b) => b._ts - a._ts); const normalConversations = validList .filter(item => !item.isPinned) .sort((a, b) => b._ts - a._ts); let sortedAll = [...pinnedConversations, ...normalConversations]; // 应用来自聊天页的撤回提示 sortedAll = this.applyRecallHints(sortedAll); // 基于隐藏集合过滤呈现列表 const hiddenSet = this._getHiddenConversationSet(); const filteredSorted = (sortedAll || []).filter(item => !hiddenSet.has(String(item.conversationId || item.id || '')) ); const totalUnreadCount = filteredSorted.reduce((sum, item) => sum + (item.unreadCount || 0), 0); this.setData({ conversations: sortedAll, pinnedConversations: filteredSorted.filter(i => i.isPinned), normalConversations: filteredSorted.filter(i => !i.isPinned), totalUnreadCount, filteredConversations: filteredSorted }); // 更新角标 this.updateTabBadge(); }, // 应用撤回提示(来自 chat 页存储),TTL=2分钟 applyRecallHints(list) { try { const store = wx.getStorageSync('recallHints') || {}; const now = Date.now(); const TTL = 2 * 60 * 1000; // 2分钟 return list.map(conv => { const cid = conv.conversationId || conv.id; if (!cid) return conv; const hint = store[cid]; if (hint && (now - hint.timestamp < TTL)) { return { ...conv, lastMessage: '已撤回', lastMessageType: 'system' }; } return conv; }); } catch (e) { console.error('应用撤回提示失败:', e); return list; } }, // 刷新会话列表 async refreshConversations() { this.setData({ refreshing: true }); await this.loadConversations(); this.setData({ refreshing: false }); }, // 下拉刷新 onRefresh() { this.refreshConversations(); }, // 搜索输入 onSearchInput(e) { const keyword = (e.detail.value || '').trim(); this.setData({ searchKeyword: keyword, lastSearchKeyword: keyword, searching: !!keyword }); if (!keyword) { // 清空搜索结果 this.processConversations(this.data.conversations); return; } // 🔥 本地会话列表过滤(快速响应) this.fuzzyFilterConversations(keyword); }, // 清除搜索 clearSearch() { this.setData({ searchKeyword: '', lastSearchKeyword: '', searching: false }); this.processConversations(this.data.conversations); }, // 显示/隐藏搜索栏 showSearchBar() { this.setData({ showSearch: true }); }, hideSearchBar() { this.setData({ showSearch: false, searchKeyword: '', lastSearchKeyword: '', searching: false }); this.processConversations(this.data.conversations); }, // 🔥 带搜索关键词打开聊天 openChatWithSearchKeyword(conversation, searchKeyword) { if (!conversation.targetId) { wx.showToast({ title: '会话信息不完整', icon: 'none' }); return; } const chatType = conversation.chatType !== undefined ? conversation.chatType : 0; const params = { conversationId: conversation.conversationId, targetId: conversation.targetId, name: encodeURIComponent(conversation.name), chatType: chatType }; const kw = (searchKeyword || '').trim(); if (kw) { params.searchKeyword = encodeURIComponent(kw); } const queryString = Object.keys(params) .map(key => `${key}=${params[key]}`) .join('&'); wx.navigateTo({ url: `/pages/message/chat/chat?${queryString}` }); }, // 本地模糊过滤 fuzzyFilterConversations(keyword) { if (!keyword) { this.processConversations(this.data.conversations); return; } const q = (keyword || '').toLowerCase(); const subseqScore = (text, query) => { if (!text || !query) return 0; text = text.toLowerCase(); let ti = 0, qi = 0, matches = 0; while (ti < text.length && qi < query.length) { if (text[ti] === query[qi]) { matches++; qi++; } ti++; } return qi === query.length ? matches / text.length : 0; }; const samples = this.data.conversationSamples || {}; const list = this.data.conversations || []; const withScore = list.map(item => { const nameScore = subseqScore(item.name || '', q) * 3; const lastMsgScore = subseqScore(item.lastMessage || '', q) * 2; const sampleTexts = samples[item.conversationId] || []; const sampleScore = sampleTexts.reduce((acc, txt) => Math.max(acc, subseqScore(txt, q)), 0); const totalScore = nameScore + lastMsgScore + sampleScore; return { item, score: totalScore }; }).filter(x => x.score > 0); withScore.sort((a, b) => { if (Math.abs(a.score - b.score) < 0.01) { return b.item._ts - a.item._ts; } return b.score - a.score; }); let filtered = withScore.map(x => x.item); if (filtered.length === 0) { filtered = list.filter(item => { const n = (item.name || '').toLowerCase(); const m = (item.lastMessage || '').toLowerCase(); return n.includes(q) || m.includes(q); }); } const pinnedFiltered = filtered.filter(i => i.isPinned); const normalFiltered = filtered.filter(i => !i.isPinned); this.setData({ pinnedConversations: pinnedFiltered, normalConversations: normalFiltered, filteredConversations: filtered }); }, // 预取会话样本 async prefetchTopConversationSamples(keyword) { const q = (keyword || '').toLowerCase(); const list = this.data.conversations || []; const rough = list .map(item => ({ item, s: (String(item.name || '').toLowerCase().includes(q) ? 2 : 0) + (String(item.lastMessage || '').toLowerCase().includes(q) ? 1 : 0) })) .sort((a, b) => b.s - a.s) .slice(0, 8) .map(x => x.item); const tasks = []; for (const conv of rough) { const cid = conv.conversationId; const loading = this.data.sampleLoading[cid]; const existing = this.data.conversationSamples[cid]; if (!loading && !existing) { tasks.push(this.fetchConversationSample(conv)); } } if (tasks.length) { await Promise.allSettled(tasks); this.fuzzyFilterConversations(this.data.lastSearchKeyword); } }, async fetchConversationSample(conv) { const cid = conv.conversationId; try { this.setData({ [`sampleLoading.${cid}`]: true }); // 这里可以调用 NIM SDK 获取历史消息 // 暂时留空,等待实现 this.setData({ [`conversationSamples.${cid}`]: [], [`sampleLoading.${cid}`]: false }); } catch (e) { console.error('抓取会话样本失败:', e); this.setData({ [`sampleLoading.${cid}`]: false }); } }, // 打开聊天 openChat(e) { // 如果正在长按,忽略单击事件 if (this.data.longPressing) { console.log('长按中,忽略单击事件'); this.setData({ longPressing: false }); return; } const conversation = e.currentTarget.dataset.conversation; if (!conversation.targetId) { wx.showToast({ title: '会话信息不完整', icon: 'none' }); return; } const chatType = conversation.chatType !== undefined ? conversation.chatType : 0; const params = { conversationId: conversation.conversationId, targetId: conversation.targetId, name: encodeURIComponent(conversation.name), chatType: chatType }; const kw = (this.data.searchKeyword || '').trim(); if (kw) { params.searchKeyword = encodeURIComponent(kw); } const queryString = Object.keys(params) .map(key => `${key}=${params[key]}`) .join('&'); wx.navigateTo({ url: `/pages/message/chat/chat?${queryString}` }); }, // 显示会话选项 showConversationOptions(e) { // 设置长按标记,防止长按后触发单击 this.setData({ longPressing: true }); const conversation = e.currentTarget.dataset.conversation; const itemList = [ (conversation.isPinned || conversation.isTop) ? '取消置顶' : '置顶会话', conversation.isMuted ? '取消免打扰' : '免打扰', '不显示该聊天', '删除会话' ]; wx.showActionSheet({ itemList: itemList, success: (res) => { switch (res.tapIndex) { case 0: this.toggleConversationTop(conversation.conversationId); break; case 1: this.toggleConversationMute(conversation.conversationId); break; case 2: this.hideConversation(conversation.conversationId); break; case 3: this.deleteConversation(conversation.conversationId); break; } } }); }, // 标记会话已读 async markConversationRead(conversationId) { try { await nimConversationManager.markConversationRead(conversationId); const conversations = [...this.data.conversations]; const index = conversations.findIndex(c => c.conversationId === conversationId); if (index >= 0) { conversations[index].unreadCount = 0; this.processConversations(conversations); } } catch (error) { console.error('标记已读失败:', error); } }, // 全部标记为已读 markAllRead() { if (this._markingAll) return; const unreadIds = (this.data.conversations || []) .filter(c => (c.unreadCount || 0) > 0) .map(c => c.conversationId) .filter(Boolean); if (!unreadIds.length) { wx.showToast({ title: '没有未读消息', icon: 'none' }); return; } wx.showModal({ title: '确认操作', content: '将所有会话标记为已读?', success: async (res) => { if (!res.confirm) return; this._markingAll = true; wx.showLoading({ title: '处理中...' }); try { const tasks = unreadIds.map(id => this.markConversationRead(id)); await Promise.allSettled(tasks); wx.hideLoading(); wx.showToast({ title: '已全部标记为已读', icon: 'success' }); } catch (err) { console.error('批量标记已读失败:', err); wx.hideLoading(); wx.showToast({ title: '操作失败', icon: 'none' }); } finally { this._markingAll = false; } } }); }, // 发起聊天入口 startNewChat() { this.showMenu(); }, // ===== 隐藏会话 ===== _hiddenStorageKey: 'hiddenConversationIds', _getHiddenConversationSet() { try { const arr = wx.getStorageSync(this._hiddenStorageKey) || []; return new Set(arr); } catch (_) { return new Set(); } }, _saveHiddenConversationSet(set) { try { wx.setStorageSync(this._hiddenStorageKey, Array.from(set)); } catch (_) { } }, hideConversation(conversationId) { const cid = String(conversationId || ''); if (!cid) return; const set = this._getHiddenConversationSet(); if (!set.has(cid)) set.add(cid); this._saveHiddenConversationSet(set); this.processConversations(this.data.conversations || []); wx.showToast({ title: '已隐藏该聊天', icon: 'none' }); }, _unhideConversationId(conversationId) { const cid = String(conversationId || ''); if (!cid) return; const set = this._getHiddenConversationSet(); if (set.has(cid)) { set.delete(cid); this._saveHiddenConversationSet(set); } }, // ===== 会话操作 ===== // 置顶/取消置顶会话 async toggleConversationTop(conversationId) { const conversations = [...this.data.conversations]; const conv = conversations.find(c => c.conversationId === conversationId); if (!conv) return; const willPin = !conv.isPinned; try { wx.showLoading({ title: willPin ? '置顶中...' : '取消中...' }); await nimConversationManager.setConversationStickTop(conversationId, willPin); conv.isPinned = willPin; conv.isTop = willPin; this.processConversations(conversations); wx.hideLoading(); wx.showToast({ title: willPin ? '已置顶' : '已取消置顶', icon: 'success' }); } catch (error) { console.error('置顶操作失败:', error); wx.hideLoading(); wx.showToast({ title: '操作失败', icon: 'none' }); } }, // 静音/取消静音会话 async toggleConversationMute(conversationId) { const conversations = [...this.data.conversations]; const conv = conversations.find(c => c.conversationId === conversationId); if (!conv) return; const willMute = !conv.isMuted; conv.isMuted = willMute; this.processConversations(conversations); wx.showToast({ title: willMute ? '已设置免打扰' : '已取消免打扰', icon: 'success' }); }, // 删除会话 async deleteConversation(conversationId) { try { wx.showLoading({ title: '删除中...' }); await nimConversationManager.deleteConversation(conversationId); const conversations = this.data.conversations.filter( c => c.conversationId !== conversationId ); this.processConversations(conversations); wx.hideLoading(); wx.showToast({ title: '已删除', icon: 'success' }); } catch (error) { console.error('删除会话失败:', error); wx.hideLoading(); wx.showToast({ title: '删除失败', icon: 'none' }); } }, // 显示菜单 showMenu() { wx.showActionSheet({ itemList: ['创建群聊', '添加好友', '扫一扫', '设置'], success: (res) => { switch (res.tapIndex) { case 0: this.createGroup(); break; case 1: this.addFriend(); break; case 2: this.scanQRCode(); break; case 3: this.openSettings(); break; } } }); }, // 创建群聊 createGroup() { wx.navigateTo({ url: '/subpackages/group/create-group/create-group' }); }, // 添加好友 addFriend() { wx.navigateTo({ url: '/subpackages/social/search/search' }); }, // 扫一扫 scanQRCode() { wx.scanCode({ success: (res) => { this.handleScanResult(res.result); }, fail: (err) => { console.error('扫码失败:', err); if (err.errMsg && err.errMsg.includes('cancel')) { // 用户取消扫码,不显示错误提示 return; } wx.showToast({ title: '扫码失败', icon: 'none' }); } }); }, // 处理扫码结果 handleScanResult(result) { console.log('📱 扫码结果:', result); try { // 处理 FindMe 用户二维码格式: FINDME:{customId} if (result && result.startsWith('FINDME:')) { const customId = result.split(':')[1]; if (!customId) { wx.showToast({ title: '无效的用户二维码', icon: 'none' }); return; } // 检查是否是自己 const app = getApp(); const currentUser = app.globalData.userInfo?.user; if (currentUser && currentUser.customId === customId) { wx.showToast({ title: '这是你自己的二维码', icon: 'none' }); return; } // 跳转到用户预览页(该页面会自动处理好友/非好友状态) wx.navigateTo({ url: `/subpackages/social/user-preview/user-preview?customId=${customId}`, fail: (err) => { console.error('跳转用户预览页失败:', err); wx.showToast({ title: '打开用户资料失败', icon: 'none' }); } }); return; } // 尝试解析URL格式的二维码(兼容旧格式) try { const url = new URL(result); const type = url.searchParams.get('type'); const id = url.searchParams.get('id'); if (type === 'user' && id) { // 检查是否是自己 const app = getApp(); const currentUser = app.globalData.userInfo?.user; if (currentUser && currentUser.customId === id) { wx.showToast({ title: '这是你自己的二维码', icon: 'none' }); return; } wx.navigateTo({ url: `/subpackages/social/user-preview/user-preview?customId=${id}` }); } else if (type === 'group' && id) { this.joinGroupByQR(id); } else { wx.showToast({ title: '无效的二维码', icon: 'none' }); } } catch (urlError) { // 不是URL格式,显示无效二维码提示 wx.showToast({ title: '无法识别的二维码格式', icon: 'none' }); } } catch (error) { console.error('处理扫码结果失败:', error); wx.showToast({ title: '处理二维码失败', icon: 'none' }); } }, // 通过二维码加入群聊 async joinGroupByQR(groupId) { try { wx.showLoading({ title: '加入中...' }); // 调用加入群组API // await groupAPI.joinGroup(groupId); wx.hideLoading(); wx.showToast({ title: '已加入群聊', icon: 'success' }); setTimeout(() => { wx.navigateTo({ url: `/subpackages/group/group-info/group-info?groupId=${groupId}` }); }, 1500); } catch (error) { console.error('加入群聊失败:', error); wx.hideLoading(); wx.showToast({ title: '加入失败', icon: 'none' }); } }, // 打开设置 openSettings() { wx.navigateTo({ url: '/subpackages/settings/settingss/settingss' }); }, // 页面显示 onShow: function () { console.log('消息页面显示'); // 设置tabBar选中状态为"聊天"(索引2) try { if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ selected: 2 }); } } catch (_) {} const currentToken = apiClient.getToken(); const app = getApp(); const isLoggedIn = app?.globalData?.isLoggedIn || false; if (!currentToken) { console.warn('⚠️ onShow检测到用户未登录'); if (isLoggedIn) { this.redirectToLogin('onShow'); } return; } // 🔥 检查并重连 NIM(防止从后台恢复后 NIM 断开) this.checkAndReconnectNim(); // 刷新会话列表 this.refreshConversations(); }, // 页面隐藏 onHide: function () { console.log('消息页面隐藏'); }, // 页面卸载 onUnload: function () { console.log('消息页面卸载'); // 移除 NIM 监听器 if (this.data.nimReady) { nimConversationManager.off('conversation_created'); nimConversationManager.off('conversation_deleted'); nimConversationManager.off('conversation_changed'); nimConversationManager.off('new_message'); nimConversationManager.off('message_revoked'); } } });