// pages/chat/index.js const API = require('../../utils/api.js'); Page({ data: { chatList: [], searchKeyword: '', filteredChatList: [], timer: null, debugCount: 0, // 调试信息输出计数器 loginToastShown: false, // 登录提示是否已显示 lastLoadTime: 0, // 用于节流的时间戳 chatContentCache: {} // 缓存聊天项的内容,避免重复获取 }, onLoad: function (options) { this.loadChatList(); }, // 检查用户是否已登录(与loadChatList中的手机号检查逻辑保持一致) isUserLoggedIn: function () { const users = wx.getStorageSync('users') || {}; const userId = wx.getStorageSync('userId'); let userPhone = null; // 与loadChatList中的手机号检查逻辑完全一致 if (userId && users[userId]) { if (users[userId].phoneNumber) { userPhone = users[userId].phoneNumber; } else if (users[userId].phone) { userPhone = users[userId].phone; } } if (!userPhone) { const userInfo = wx.getStorageSync('userInfo'); if (userInfo) { if (userInfo.phoneNumber) { userPhone = userInfo.phoneNumber; } else if (userInfo.phone) { userPhone = userInfo.phone; } } } if (!userPhone) { userPhone = wx.getStorageSync('phoneNumber') || wx.getStorageSync('phone'); } if (!userPhone) { const loginInfo = wx.getStorageSync('loginInfo'); if (loginInfo) { if (loginInfo.phoneNumber) { userPhone = loginInfo.phoneNumber; } else if (loginInfo.phone) { userPhone = loginInfo.phone; } } } // 只有获取到手机号才视为已登录 return !!userPhone; }, onShow: function () { // 只有已登录用户才执行操作 if (this.isUserLoggedIn()) { // 从聊天详情页返回时,强制刷新列表,绕过节流限制 // 保存当前时间戳,用于强制刷新 const forcedLoadTime = Date.now(); this.setData({ lastLoadTime: forcedLoadTime - 3000, // 设置为3秒前,确保能绕过2秒的节流限制 }, () => { // 重新加载聊天列表,实现从聊天详情页返回时立即更新 this.loadChatList(); }); // 启动定时器 if (!this.data.timer) { this.startTimer(); } } }, startTimer: function () { // 确保只有一个定时器在运行 if (this.data.timer) { clearInterval(this.data.timer); this.setData({ timer: null }); } // 设置30秒刷新定时器 this.setData({ timer: setInterval(() => { this.loadChatList(); }, 30000) }); }, loadChatList: function () { // 节流逻辑:避免短时间内多次调用 const currentTime = Date.now(); if (currentTime - this.data.lastLoadTime < 2000) { // 2秒内不重复调用 console.log('API调用节流中,距离上次调用仅' + (currentTime - this.data.lastLoadTime) + 'ms'); return; } // 更新上次加载时间 this.setData({ lastLoadTime: currentTime }); // 增加调试信息计数器 const newDebugCount = this.data.debugCount + 1; this.setData({ debugCount: newDebugCount }); // 获取用户手机号 - 增强版,增加更多获取途径和调试信息 const users = wx.getStorageSync('users') || {}; const userId = wx.getStorageSync('userId'); let userPhone = null; // 添加调试信息,显示当前存储的用户信息 console.log('调试信息 - 登录用户 (第' + newDebugCount + '次):', { userId: userId, users: users, userInfo: wx.getStorageSync('userInfo'), phoneNumber: wx.getStorageSync('phoneNumber'), phone: wx.getStorageSync('phone'), debugCount: newDebugCount }); // 尝试从users中获取手机号(支持不同的键名) if (userId && users[userId]) { if (users[userId].phoneNumber) { userPhone = users[userId].phoneNumber; console.log('从users[userId].phoneNumber获取到手机号:', userPhone); } else if (users[userId].phone) { userPhone = users[userId].phone; console.log('从users[userId].phone获取到手机号:', userPhone); } } // 如果还没有获取到,尝试从全局用户信息获取 if (!userPhone) { const userInfo = wx.getStorageSync('userInfo'); if (userInfo) { if (userInfo.phoneNumber) { userPhone = userInfo.phoneNumber; console.log('从userInfo.phoneNumber获取到手机号:', userPhone); } else if (userInfo.phone) { userPhone = userInfo.phone; console.log('从userInfo.phone获取到手机号:', userPhone); } } } // 如果还没有获取到,尝试从直接存储获取(支持不同的键名) if (!userPhone) { if (wx.getStorageSync('phoneNumber')) { userPhone = wx.getStorageSync('phoneNumber'); console.log('从storage.phoneNumber获取到手机号:', userPhone); } else if (wx.getStorageSync('phone')) { userPhone = wx.getStorageSync('phone'); console.log('从storage.phone获取到手机号:', userPhone); } } // 如果还没有获取到,尝试从更多可能的存储位置获取 if (!userPhone) { const loginInfo = wx.getStorageSync('loginInfo'); if (loginInfo) { if (loginInfo.phoneNumber) { userPhone = loginInfo.phoneNumber; console.log('从loginInfo.phoneNumber获取到手机号:', userPhone); } else if (loginInfo.phone) { userPhone = loginInfo.phone; console.log('从loginInfo.phone获取到手机号:', userPhone); } } } // 如果没有手机号,显示错误提示 if (!userPhone) { wx.hideLoading(); // 登录提示只显示一次 if (!this.data.loginToastShown) { wx.showToast({ title: '请先登录并绑定手机号', icon: 'none' }); this.setData({ loginToastShown: true }); } // 调试信息输出3次后返回首页并关闭定时器 if (newDebugCount >= 3) { console.log('调试信息已输出3次,准备返回首页并关闭定时器'); // 关闭定时器 if (this.data.timer) { clearInterval(this.data.timer); this.setData({ timer: null }); } // 返回首页 wx.navigateBack({ delta: 1, success: function() { console.log('已成功返回首页'); } }); } return; } // 调用API获取聊天列表 API.getChatList(userPhone).then(res => { if (res && Array.isArray(res)) { console.log('===== 获取聊天列表原始数据 ====='); console.log(JSON.stringify(res, null, 2)); // 创建业务员信息缓存,避免重复调用API const personnelCache = {}; // 处理每个聊天项,获取业务员信息 const chatListPromises = res.map(async (chatItem, index) => { console.log(`\n===== 处理聊天项 ${index} =====`); console.log('原始聊天项数据:', JSON.stringify(chatItem, null, 2)); console.log('原始unread值:', chatItem.unread, '类型:', typeof chatItem.unread); if (chatItem.manager_phone) { try { // 先检查缓存中是否已有该业务员信息 if (personnelCache[chatItem.manager_phone]) { const cachedInfo = personnelCache[chatItem.manager_phone]; chatItem.name = cachedInfo.alias || chatItem.manager_phone; chatItem.avatar = chatItem.avatar || 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'; console.log('使用缓存的业务员信息:', chatItem.manager_phone); } else { // 获取业务员信息 const personnelInfo = await API.getSalesPersonnelInfo(chatItem.manager_phone); if (personnelInfo) { // 缓存业务员信息 personnelCache[chatItem.manager_phone] = personnelInfo; // 使用业务员的alias作为显示名称 chatItem.name = personnelInfo.alias || chatItem.manager_phone; chatItem.avatar = chatItem.avatar || 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'; console.log('获取并缓存业务员信息:', chatItem.manager_phone); } } } catch (error) { console.error('获取业务员信息失败:', error); // 如果获取失败,使用默认名称 chatItem.name = chatItem.manager_phone; chatItem.avatar = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'; } } else { // 系统消息或其他没有manager_phone的消息 chatItem.name = chatItem.name || '系统消息'; chatItem.avatar = chatItem.avatar || 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'; } // 获取用户已查看过的聊天列表 const viewedChats = wx.getStorageSync('viewedChats') || {}; const chatId = chatItem.manager_phone; // 获取最新消息内容和时间 let lastMessage = null; try { const cacheKey = chatId; const cache = this.data.chatContentCache[cacheKey]; const now = Date.now(); // 每次刷新列表时都尝试获取最新消息,确保消息实时性 const messages = await API.getChatMessages(chatId, userPhone, { limit: 1 }); if (messages.length > 0) { lastMessage = messages[0]; chatItem.content = lastMessage.content || '暂无消息内容'; // 同时更新时间为最新消息的时间 chatItem.time = lastMessage.created_at || null; // 更新缓存 const newCache = { ...this.data.chatContentCache, [cacheKey]: { content: chatItem.content, time: chatItem.time, timestamp: now, messageId: lastMessage.id || lastMessage.message_id || null, senderPhone: lastMessage.sender_phone || null // 保存发送者手机号 } }; this.setData({ chatContentCache: newCache }); console.log('更新聊天内容缓存:', cacheKey); } else if (!chatItem.content) { chatItem.content = '暂无消息内容'; } } catch (error) { console.error('获取聊天消息失败:', error); // 如果获取失败,尝试使用缓存内容 const cacheKey = chatId; const cache = this.data.chatContentCache[cacheKey]; if (cache && !chatItem.content) { chatItem.content = cache.content; chatItem.time = cache.time; console.log('获取最新消息失败,使用缓存内容:', cacheKey); } else if (!chatItem.content) { chatItem.content = '暂无消息内容'; } } // 格式化时间 chatItem.time = this.formatDateTime(chatItem.time || null); // 未读状态判断:基于用户查看时的最新消息ID console.log('当前已查看的聊天:', viewedChats); console.log('当前聊天ID:', chatId); // 获取当前聊天的最后一条消息ID和发送者 const currentMessageId = lastMessage ? (lastMessage.id || lastMessage.message_id) : null; const currentMessageSender = lastMessage ? (lastMessage.sender_phone) : null; console.log('当前最新消息ID:', currentMessageId); console.log('当前最新消息发送者:', currentMessageSender); console.log('当前用户手机号:', userPhone); // 检查该聊天的查看记录 const chatViewRecord = viewedChats[chatId] || {}; const lastViewedMessageId = chatViewRecord.lastViewedMessageId; console.log('上次查看时的消息ID:', lastViewedMessageId); // 检查是否是用户自己发送的消息 const isMyMessage = currentMessageSender === userPhone; console.log('是否是自己发送的消息:', isMyMessage); // 如果最后一条消息是用户自己发送的,自动标记为已查看 if (isMyMessage && !chatViewRecord.hasViewed) { console.log('最后一条消息是自己发送的,自动标记为已查看:', chatId); viewedChats[chatId] = { hasViewed: true, lastViewedMessageId: currentMessageId, viewedTime: Date.now() }; // 立即更新本地存储 wx.setStorageSync('viewedChats', viewedChats); // 重新获取更新后的查看记录 chatViewRecord.hasViewed = true; chatViewRecord.lastViewedMessageId = currentMessageId; } // 设置未读状态: // 1. 如果是自己发送的消息,不显示未读 // 2. 如果从未查看过且不是自己发送的,显示未读 // 3. 如果有新消息(当前消息ID不同且不是自己发送的),显示未读 // 4. 否则不显示未读 let unread = false; if (!isMyMessage) { if (!chatViewRecord.hasViewed) { // 从未查看过,显示未读 unread = true; } else if (currentMessageId && lastViewedMessageId && currentMessageId !== lastViewedMessageId) { // 有新消息,显示未读 unread = true; } else if (currentMessageId && !lastViewedMessageId) { // 之前没有消息,现在有新消息,显示未读 unread = true; } } chatItem.unread = unread; console.log('设置unread的值:', chatItem.unread); chatItem.lastMessageId = currentMessageId; // 保存当前消息ID供点击事件使用 // 保存最后一条消息的ID或内容作为标识(可选) if (lastMessage) { chatItem.lastMessageId = lastMessage.id || lastMessage.message_id; chatItem.lastMessageContent = lastMessage.content; } console.log('处理完成的聊天项:', JSON.stringify(chatItem, null, 2)); return chatItem; }); // 等待所有聊天项处理完成 Promise.all(chatListPromises).then(processedChatList => { console.log('\n===== 所有聊天项处理完成 ====='); console.log('处理后的列表:', JSON.stringify(processedChatList, null, 2)); this.setData({ chatList: processedChatList, filteredChatList: processedChatList }, () => { console.log('===== 页面数据已更新 ====='); console.log('chatList:', JSON.stringify(this.data.chatList, null, 2)); console.log('filteredChatList:', JSON.stringify(this.data.filteredChatList, null, 2)); }); wx.hideLoading(); }).catch(error => { console.error('处理聊天列表失败:', error); wx.hideLoading(); wx.showToast({ title: '加载聊天列表失败', icon: 'none' }); }); } else { wx.hideLoading(); wx.showToast({ title: '加载聊天列表失败', icon: 'none' }); } }).catch(error => { console.error('获取聊天列表失败:', error); wx.hideLoading(); wx.showToast({ title: error.message || '加载聊天列表失败', icon: 'none' }); }); }, // 搜索功能 onSearchInput: function (e) { const keyword = e.detail.value; this.setData({ searchKeyword: keyword }); this.filterChatList(keyword); }, // 过滤聊天列表 filterChatList: function (keyword) { if (!keyword) { this.setData({ filteredChatList: this.data.chatList }); return; } const filteredList = this.data.chatList.filter(item => { return item.name.includes(keyword) || item.content.includes(keyword); }); this.setData({ filteredChatList: filteredList }); }, // 聊天项点击事件 onChatItemTap: function (e) { const index = e.currentTarget.dataset.index; const chatItem = this.data.filteredChatList[index]; // 使用对方的电话号码作为聊天ID,而不是会话ID const chatId = chatItem.manager_phone; // 获取用户手机号 const users = wx.getStorageSync('users') || {}; const userId = wx.getStorageSync('userId'); let userPhone = null; // 尝试从users中获取手机号(支持不同的键名) if (userId && users[userId]) { if (users[userId].phoneNumber) { userPhone = users[userId].phoneNumber; } else if (users[userId].phone) { userPhone = users[userId].phone; } } // 如果还没有获取到,尝试从全局用户信息获取 if (!userPhone) { const userInfo = wx.getStorageSync('userInfo'); if (userInfo) { if (userInfo.phoneNumber) { userPhone = userInfo.phoneNumber; } else if (userInfo.phone) { userPhone = userInfo.phone; } } } // 如果还没有获取到,尝试从直接存储获取(支持不同的键名) if (!userPhone) { if (wx.getStorageSync('phoneNumber')) { userPhone = wx.getStorageSync('phoneNumber'); } else if (wx.getStorageSync('phone')) { userPhone = wx.getStorageSync('phone'); } } // 1. 更新localStorage中的viewedChats,标记为已查看并记录当前最新消息ID const viewedChats = wx.getStorageSync('viewedChats') || {}; // 获取当前聊天项的最新消息ID const currentMessageId = chatItem.lastMessageId; // 更新查看记录:包含是否已查看和查看时的最新消息ID viewedChats[chatId] = { hasViewed: true, lastViewedMessageId: currentMessageId, viewedTime: Date.now() }; wx.setStorageSync('viewedChats', viewedChats); console.log('更新localStorage中的viewedChats:', chatId, viewedChats[chatId]); // 2. 更新filteredChatList中的unread状态 const updatedFilteredChatList = [...this.data.filteredChatList]; updatedFilteredChatList[index].unread = false; // 3. 更新chatList中的unread状态 const updatedChatList = [...this.data.chatList]; const originalIndex = updatedChatList.findIndex(item => item.manager_phone === chatItem.manager_phone); if (originalIndex !== -1) { updatedChatList[originalIndex].unread = false; } // 4. 更新页面数据 this.setData({ filteredChatList: updatedFilteredChatList, chatList: updatedChatList }); console.log('标记聊天为已读:', chatId); // 5. 调用API将服务器端的消息标记为已读 API.markMessagesAsRead(chatId, userPhone).then(() => { console.log('服务器端消息标记为已读成功'); }).catch(error => { console.error('服务器端消息标记为已读失败:', error); }); // 跳转到聊天详情页,传递chatId和name参数 wx.navigateTo({ url: '/pages/chat-detail/index?id=' + chatId + '&name=' + encodeURIComponent(chatItem.name), success: function () { console.log('成功跳转到聊天详情页'); }, fail: function (error) { console.error('跳转到聊天详情页失败:', error); wx.showToast({ title: '聊天功能开发中', icon: 'none' }); } }); }, onPullDownRefresh: function () { this.loadChatList(); wx.stopPullDownRefresh(); }, onHide: function () { if (this.data.timer) { clearInterval(this.data.timer); this.setData({ timer: null }); } }, onUnload: function () { if (this.data.timer) { clearInterval(this.data.timer); this.setData({ timer: null }); } }, // 格式化时间显示 formatDateTime: function (dateString) { if (!dateString) return '刚刚'; const now = new Date(); const msgDate = new Date(dateString); const diffMs = now - msgDate; const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) { return '刚刚'; } else if (diffMins < 60) { return `${diffMins}分钟前`; } else if (diffHours < 24) { return `${diffHours}小时前`; } else if (diffDays < 7) { return `${diffDays}天前`; } else { // 超过一周显示具体日期 const year = msgDate.getFullYear(); const month = (msgDate.getMonth() + 1).toString().padStart(2, '0'); const day = msgDate.getDate().toString().padStart(2, '0'); const hours = msgDate.getHours().toString().padStart(2, '0'); const minutes = msgDate.getMinutes().toString().padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}`; } } });