// 消息列表页面 Page({ data: { messageList: [] }, onLoad: function() { this.loadChatList(); // 注册全局新消息处理函数 this.registerGlobalMessageHandler(); }, /** * 注册全局新消息处理函数 */ registerGlobalMessageHandler: function() { try { const app = getApp(); const that = this; // 保存原有的处理函数(如果有) this.originalMessageHandler = app.globalData.onNewMessage; // 注册新的处理函数 app.globalData.onNewMessage = function(message) { console.log('消息列表页面收到新消息:', message); // 重新加载聊天列表 that.loadChatList(); // 调用原始处理函数(如果有) if (that.originalMessageHandler && typeof that.originalMessageHandler === 'function') { that.originalMessageHandler(message); } }; console.log('已注册全局新消息处理函数'); } catch (e) { console.error('注册全局新消息处理函数失败:', e); } }, onShow: function() { console.log('消息列表页面显示,开始加载数据...'); // 每次显示页面时强制刷新聊天列表 this.loadChatList(); // 确保WebSocket连接已建立,用于接收实时消息 this.ensureWebSocketConnected(); }, /** * 确保WebSocket连接已建立 */ ensureWebSocketConnected: function() { try { const app = getApp(); if (typeof require === 'function') { const socketManager = require('../../utils/websocket.js').default; // 检查连接状态 if (!socketManager.getConnectionStatus()) { console.log('WebSocket未连接,尝试重新连接...'); // 使用正确的WebSocket服务器地址 const wsUrl = app.globalData.webSocketUrl || 'ws://localhost:3003'; socketManager.connect(wsUrl); } } } catch (e) { console.error('确保WebSocket连接失败:', e); } }, /** * 加载聊天列表 - 从服务器API获取数据 */ loadChatList: function() { wx.showLoading({ title: '加载中' }); try { // 从服务器获取真实的聊天列表数据 const app = getApp(); const token = app.globalData.token || wx.getStorageSync('token'); const currentUserId = app.globalData.userInfo?.userId || wx.getStorageSync('userId') || 'unknown'; const currentUserType = app.globalData.userType || wx.getStorageSync('userType') || ''; const isManager = app.globalData.isManager || currentUserType === 'manager' || currentUserType.includes('manager'); const isCustomer = app.globalData.isCustomer || (currentUserType.includes('buyer') || currentUserType.includes('seller') || currentUserType.includes('both')); console.log('当前用户类型:', currentUserType, 'isManager:', isManager, 'isCustomer:', isCustomer); // 使用正确的API配置,兼容开发环境 const baseUrl = app.globalData.baseUrl || 'http://localhost:3003'; console.log('使用API地址:', baseUrl); console.log('当前用户ID:', currentUserId); // 根据用户类型选择不同的API端点 let apiUrl; if (isManager) { // 客服类型使用专门的接口获取客户会话列表 const managerId = wx.getStorageSync('managerId') || currentUserId; apiUrl = `${baseUrl}/api/conversations/manager/${managerId}`; console.log('客服模式,使用manager API获取会话列表'); } else if (isCustomer || !isManager) { // 普通用户使用user API apiUrl = `${baseUrl}/api/conversations/user/${currentUserId}`; console.log('客户模式,使用user API获取会话列表'); } else { // 默认使用user API apiUrl = `${baseUrl}/api/conversations/user/${currentUserId}`; console.log('默认模式,使用user API获取会话列表'); } wx.request({ url: apiUrl, method: 'GET', header: { 'Authorization': token ? `Bearer ${token}` : '', 'content-type': 'application/json' }, success: (res) => { console.log('获取聊天列表成功:', res.data); // 处理不同的API响应格式 let chatData = []; if (res.data.code === 0 && res.data.data) { chatData = res.data.data; } else if (Array.isArray(res.data)) { // 如果直接返回数组 chatData = res.data; } else if (res.data) { // 如果返回的是对象但不是标准格式,尝试直接使用 chatData = [res.data]; } // 合理过滤聊天数据,保留有效的会话 const validChatData = chatData.filter(item => { // 确保item有效 if (!item || typeof item !== 'object') return false; // 获取显示的用户ID并验证其有效性 const displayUserId = item.userId === currentUserId ? item.managerId : item.userId || item.id; if (!displayUserId || displayUserId === 'undefined' || displayUserId === 'null' || String(displayUserId).trim() === '') { console.log('过滤掉无效的用户ID:', displayUserId, '的会话'); return false; } // 过滤掉临时用户ID(以temp_开头的ID) const safeUserId = String(displayUserId).trim(); if (safeUserId.startsWith('temp_')) { console.log('过滤掉临时用户ID:', safeUserId, '的会话'); return false; } return true; }); if (validChatData.length > 0) { // 格式化聊天列表数据 const formattedMessages = validChatData.map(item => { // 获取显示的用户ID和名称 let displayUserId, displayName; // 关键修复:根据用户类型和聊天对象类型确定显示的ID和名称 if (isManager) { // 客服模式:显示的是客户信息 displayUserId = item.userId; displayName = this.getUserNameById(displayUserId); } else { // 普通用户模式:显示的是客服信息 displayUserId = item.managerId || item.userId || item.id; displayName = this.getUserNameById(displayUserId); } return { userId: displayUserId, userName: displayName || item.userName || item.name || '未知用户', avatar: item.avatar || (displayName && displayName.charAt(0)) || '用', lastMessage: item.lastMessage || item.content || '', lastMessageTime: this.formatMessageTime(item.lastMessageTime || item.createdAt || Date.now()), messageCount: item.messageCount || 0, isRead: item.isRead || false, unreadCount: item.unreadCount || 0 }; }).filter(chat => { // 过滤掉客服之间的会话 if (isManager) { // 只过滤真正的客服聊天,保留所有用户消息 const isChatWithManager = (chat.userId && (chat.userId.includes('customer_service') || chat.userId.includes('manager'))) || (chat.userName && chat.userName.includes('客服') && !chat.userName.includes('用户')); console.log('过滤检查 - 用户ID:', chat.userId, '用户名:', chat.userName, '是否为客服聊天:', isChatWithManager); return !isChatWithManager; } return true; }); // 按最后消息时间排序(最新的在前) formattedMessages.sort((a, b) => { return new Date(b.lastMessageTime) - new Date(a.lastMessageTime); }); this.setData({ messageList: formattedMessages }); } else { console.log('暂无有效的聊天消息'); // 确保清空消息列表 this.setData({ messageList: [] }); // 尝试从本地存储加载数据作为备选,但现在本地加载逻辑也会严格验证 this.loadFromLocalStorage(); } }, fail: (err) => { console.error('网络请求失败:', err); wx.showToast({ title: '网络请求失败,尝试使用本地数据', icon: 'none', duration: 3000 }); // 失败时尝试从本地存储加载数据 this.loadFromLocalStorage(); }, complete: () => { wx.hideLoading(); } }); } catch (error) { console.error('加载聊天列表异常:', error); wx.hideLoading(); wx.showToast({ title: '加载异常', icon: 'none' }); // 异常时尝试从本地存储加载数据 this.loadFromLocalStorage(); } }, /** * 从本地存储加载聊天列表 - 作为备用方案 */ loadFromLocalStorage: function() { try { // 获取所有存储的聊天记录键 const storageInfo = wx.getStorageInfoSync(); const chatKeys = storageInfo.keys.filter(key => key.startsWith('chat_messages_')); const messageList = []; // 获取当前用户信息 const app = getApp(); const currentUserId = wx.getStorageSync('userId') || ''; const currentUserType = app.globalData.userType || wx.getStorageSync('userType') || 'customer'; console.log('从本地存储加载聊天列表 - 用户类型:', currentUserType, '聊天记录数量:', chatKeys.length); // 遍历每个聊天记录 chatKeys.forEach(key => { const chatUserId = key.replace('chat_messages_', ''); // 严格验证聊天用户ID if (!chatUserId || chatUserId === 'undefined' || chatUserId === 'null' || chatUserId.trim() === '') { console.log('跳过无效的聊天用户ID:', chatUserId); return; } // 过滤掉临时用户ID(以temp_开头的ID) if (chatUserId.trim().startsWith('temp_')) { console.log('跳过临时用户ID:', chatUserId, '的会话'); return; } // 获取消息列表 const messages = wx.getStorageSync(key); // 严格检查消息列表 if (!messages || !Array.isArray(messages) || messages.length === 0) { console.log('跳过无效或空的消息列表:', chatUserId); return; } // 避免处理自己与自己的聊天 if (chatUserId === currentUserId) { console.log('跳过自己与自己的聊天:', chatUserId); return; } // 过滤并验证每条消息 const validMessages = messages.filter(msg => { return msg && msg.content && typeof msg.content === 'string' && msg.content.trim() !== '' && msg.time; // 确保有时间戳 }); // 如果没有有效消息,跳过 if (validMessages.length === 0) { console.log('跳过没有有效消息的对话:', chatUserId); return; } // 放宽条件,只要有有效消息就显示会话,不再要求必须有对方发送的消息 // 这样可以显示用户主动发起的聊天会话 // 获取最后一条有效消息 const lastValidMessage = validMessages[validMessages.length - 1]; // 再次确认最后一条消息的有效性 if (!lastValidMessage || !lastValidMessage.content || lastValidMessage.content.trim() === '') { console.log('跳过最后消息无效的对话:', chatUserId); return; } // 统计未读消息数量 const unreadCount = validMessages.filter(msg => { return msg.sender !== 'me' && !msg.isRead; }).length; // 仅当不是客服之间的对话时添加 const userName = this.getUserNameById(chatUserId); if (!(isManager && userName && (userName.includes('客服') || userName.includes('manager')))) { messageList.push({ userId: chatUserId, userName: userName, avatar: '', lastMessage: this.formatMessagePreview(lastValidMessage), lastMessageTime: this.formatMessageTime(lastValidMessage.time), messageCount: validMessages.length, unreadCount: unreadCount, isRead: unreadCount === 0 }); } else { console.log('客服身份,跳过与其他客服的聊天:', chatUserId, userName); } }); // 按最后消息时间排序(最新的在前) messageList.sort((a, b) => { return new Date(b.lastMessageTime) - new Date(a.lastMessageTime); }); if (messageList.length > 0) { console.log('从本地存储加载了', messageList.length, '条有效聊天记录'); this.setData({ messageList: messageList }); } else { // 确保清空消息列表,避免显示任何默认用户 console.log('没有找到任何有效的聊天记录,清空消息列表'); this.setData({ messageList: [] }); // 清理可能导致默认用户显示的无效本地存储数据 this.cleanupInvalidStorageData(); } } catch (e) { console.error('从本地存储加载聊天列表失败:', e); // 出错时也确保消息列表为空 this.setData({ messageList: [] }); } }, /** * 清理无效的本地存储数据,防止显示默认用户 */ cleanupInvalidStorageData: function() { try { const storageInfo = wx.getStorageInfoSync(); const chatKeys = storageInfo.keys.filter(key => key.startsWith('chat_messages_')); chatKeys.forEach(key => { const messages = wx.getStorageSync(key); // 删除无效或空的消息列表 if (!messages || !Array.isArray(messages) || messages.length === 0) { console.log('删除无效的聊天存储键:', key); wx.removeStorageSync(key); return; } // 检查是否只有无效消息 const allInvalid = messages.every(msg => { return !msg || !msg.content || typeof msg.content !== 'string' || msg.content.trim() === ''; }); if (allInvalid) { console.log('删除全是无效消息的聊天记录:', key); wx.removeStorageSync(key); } }); console.log('清理无效存储数据完成'); } catch (e) { console.error('清理无效存储数据失败:', e); } }, /** * 根据用户ID获取用户名 - 增强版,确保不返回默认的'未知用户'名称 */ getUserNameById: function(userId) { try { // 增强的参数有效性检查 if (!userId || typeof userId === 'undefined' || userId === null || String(userId).trim() === '') { return null; } // 确保userId是字符串类型,并去除前后空格 const safeUserId = String(userId).trim(); // 避免显示"undefined"或"null" if (safeUserId === 'undefined' || safeUserId === 'null') { return null; } // 特殊处理特定用户ID,直接返回对应的手机号 if (safeUserId === 'user_1765415381781_1iy1ls177') { return '17828048259'; } // 获取当前用户类型 const app = getApp(); const currentUserType = app.globalData.userType || wx.getStorageSync('userType') || 'customer'; // 过滤掉临时用户ID(以temp_开头的ID) if (safeUserId.startsWith('temp_')) { console.log('过滤临时用户ID:', safeUserId); return null; } // 尝试从全局客服列表中获取用户名 let customerServiceList = app.globalData.customerServiceList || []; // 如果全局客服列表为空,尝试从本地存储获取 if (customerServiceList.length === 0) { customerServiceList = wx.getStorageSync('cached_customer_services') || []; // 如果本地存储也没有,尝试从服务器获取 if (customerServiceList.length === 0) { console.log('客服列表为空,尝试从服务器获取'); // 这里可以添加异步获取客服列表的逻辑,但由于getUserNameById是同步函数,暂时不实现 } } // 从客服列表中查找匹配的客服 const service = customerServiceList.find(item => { // 安全地访问对象属性,避免undefined属性错误 const itemId = item?.id ? String(item.id).trim() : ''; const itemManagerId = item?.managerId ? String(item.managerId).trim() : ''; return itemId === safeUserId || itemManagerId === safeUserId; }); if (service) { return service.alias || service.name || '客服'; } // 尝试从用户信息缓存中获取更详细的用户信息 // 客服模式下,尝试获取客户的手机号或其他标识信息 if (currentUserType === 'manager' || currentUserType === 'customer_service') { // 尝试从本地存储获取用户详细信息 try { // 尝试获取用户数据映射 const users = wx.getStorageSync('users') || {}; const userData = users[safeUserId]; // 首先检查是否是手机号格式的用户ID(中国手机号格式) if (/^1[3-9]\d{9}$/.test(safeUserId)) { // 如果是手机号,直接显示完整手机号 return safeUserId; } if (userData) { // 如果有用户信息,优先使用 if (userData.phoneNumber) { return userData.phoneNumber; // 显示完整手机号 } if (userData.phone) { return userData.phone; // 显示完整手机号 } if (userData.info && userData.info.nickName) { return userData.info.nickName; } } // 尝试获取会话相关的用户信息 const sessionInfo = wx.getStorageSync(`session_${safeUserId}`); if (sessionInfo && sessionInfo.userName) { return sessionInfo.userName; } } catch (innerError) { console.log('获取用户详细信息失败:', innerError); } } // 固定用户名映射 const userMap = { 'user_1': '张三', 'user_2': '李四', 'user_3': '王五', 'user_4': '赵六', 'user_5': '钱七' }; if (userMap[safeUserId]) { return userMap[safeUserId]; } // 对于manager_开头的ID,显示为客服 if (safeUserId.startsWith('manager_') || safeUserId.includes('manager')) { return '客服-' + (safeUserId.length >= 4 ? safeUserId.slice(-4) : safeUserId); } // 对于test_开头的测试用户ID,显示为测试用户 if (safeUserId.startsWith('test_')) { return '测试用户-' + (safeUserId.length >= 8 ? safeUserId.slice(-4) : safeUserId); } // 处理系统通知类型 if (safeUserId.startsWith('system_')) { return '系统通知'; } // 处理群组聊天 if (safeUserId.startsWith('group_')) { return '群组-' + (safeUserId.replace('group_', '').length >= 4 ? safeUserId.replace('group_', '').slice(-4) : safeUserId.replace('group_', '')); } // 从数据库记录中获取的用户ID格式处理 if (safeUserId.includes('_customer_')) { // 提取数字部分 const match = safeUserId.match(/\d+/); if (match && match[0]) { return '用户' + match[0].slice(-4); } } // 检查是否是手机号格式 if (/^1[3-9]\d{9}$/.test(safeUserId)) { // 直接显示完整手机号 return safeUserId; } // 对于未识别的有效用户ID,返回基于ID的标识而不是默认名称 // 确保不返回'未知用户',而是使用实际的用户ID信息 if (safeUserId.length > 10) { // 对于长ID,截取并添加省略号 return '用户-' + safeUserId.substring(0, 10) + '...'; } else { // 对于短ID,直接使用 return '用户-' + safeUserId; } } catch (e) { console.error('获取用户名失败:', e); // 即使出现错误,也不返回'未知用户',而是返回'用户-未知' return '用户-未知'; } }, /** * 格式化消息预览 */ formatMessagePreview: function(message) { if (message.type === 'system') { return '[系统消息] ' + message.content; } else { const senderPrefix = message.sender === 'me' ? '我: ' : ''; // 限制预览长度 let preview = senderPrefix + message.content; if (preview.length > 30) { preview = preview.substring(0, 30) + '...'; } return preview; } }, /** * 格式化消息时间 - 增强版,支持多种时间格式 - 统一使用北京时间 */ formatMessageTime: function(timeStr) { try { if (!timeStr) return ''; // 获取当前北京时间 const now = new Date(); const nowYear = now.getFullYear(); const nowMonth = now.getMonth(); const nowDate = now.getDate(); let date; // 尝试不同的时间格式解析 if (typeof timeStr === 'number') { // 处理时间戳 let adjustedTimestamp = timeStr; // 检查是否是秒级时间戳(小于1e12,毫秒级时间戳通常大于1e12) if (adjustedTimestamp < 1e12) { // 秒级时间戳转换为毫秒级 adjustedTimestamp *= 1000; } date = new Date(adjustedTimestamp); } else if (typeof timeStr === 'string') { if (/^\d+$/.test(timeStr)) { // 数字字符串,可能是时间戳 const timestamp = parseInt(timeStr); let adjustedTimestamp = timestamp; // 检查是否是秒级时间戳 if (adjustedTimestamp < 1e12) { // 秒级时间戳转换为毫秒级 adjustedTimestamp *= 1000; } date = new Date(adjustedTimestamp); } else if (timeStr.includes('T')) { // ISO 8601格式的时间字符串,如 "2025-12-18T07:03:00.000Z" // 先将字符串解析为Date对象(自动转换为本地时间) date = new Date(timeStr); } else { // 其他格式的时间字符串,直接解析 date = new Date(timeStr); } } else { // 其他类型,返回空 return ''; } // 验证日期是否有效 if (isNaN(date.getTime())) { return ''; } // 获取北京时间的各组成部分 const beijingYear = date.getFullYear(); const beijingMonth = date.getMonth(); const beijingDate = date.getDate(); const beijingHours = date.getHours(); const beijingMinutes = date.getMinutes(); // 计算天数差 const diffTime = Math.abs(now.getTime() - date.getTime()); const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24)); if (diffDays === 0) { // 今天的消息只显示时间,格式化为 HH:mm const hours = beijingHours.toString().padStart(2, '0'); const minutes = beijingMinutes.toString().padStart(2, '0'); return `${hours}:${minutes}`; } else if (diffDays === 1) { // 昨天的消息 return '昨天'; } else if (diffDays < 7) { // 一周内的消息显示星期 const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; return weekdays[date.getDay()]; } else if (diffDays < 365) { // 今年内的消息显示月日 const month = (beijingMonth + 1).toString().padStart(2, '0'); const day = beijingDate.toString().padStart(2, '0'); return `${month}-${day}`; } else { // 超过一年的消息显示完整日期 const year = beijingYear; const month = (beijingMonth + 1).toString().padStart(2, '0'); const day = beijingDate.toString().padStart(2, '0'); return `${year}-${month}-${day}`; } } catch (e) { console.error('格式化消息时间失败:', e); return ''; } }, /** * 跳转到聊天详情页 */ goToChat: function(e) { const userId = e.currentTarget.dataset.userId; // 查找对应的用户信息 const userInfo = this.data.messageList.find(item => item.userId === userId); wx.navigateTo({ url: `/pages/chat-detail/index?userId=${userId}&userName=${encodeURIComponent(userInfo?.userName || '')}` }); }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function() { console.log('用户下拉刷新,重新加载聊天列表...'); // 重新加载聊天列表 this.loadChatList(); // 添加延迟,确保用户能看到刷新效果 setTimeout(() => { wx.stopPullDownRefresh(); console.log('下拉刷新完成'); }, 1000); }, /** * 处理清除聊天记录 */ onUnload: function() { // 页面卸载时的清理工作 // 恢复原始的全局消息处理函数 try { const app = getApp(); if (this.originalMessageHandler) { app.globalData.onNewMessage = this.originalMessageHandler; } else { // 如果没有原始处理函数,则清除当前的 delete app.globalData.onNewMessage; } console.log('已清理全局新消息处理函数'); } catch (e) { console.error('清理全局新消息处理函数失败:', e); } }, handleClearChat: function(e) { const userId = e.currentTarget.dataset.userId; wx.showModal({ title: '确认清空', content: '确定要清空与该用户的所有聊天记录吗?此操作不可恢复。', success: (res) => { if (res.confirm) { this.clearChatHistory(userId); } } }); }, /** * 清空指定用户的聊天记录 */ clearChatHistory: function(userId) { try { wx.removeStorageSync(`chat_messages_${userId}`); console.log('已清空用户', userId, '的聊天记录'); // 刷新消息列表 this.loadChatList(); wx.showToast({ title: '聊天记录已清空', icon: 'success' }); } catch (e) { console.error('清空聊天记录失败:', e); wx.showToast({ title: '清空失败', icon: 'none' }); } } });