Browse Source

修复聊天列表红点点击后不消失的问题

pull/1/head
徐飞洋 3 months ago
parent
commit
8d1784d1f8
  1. 105
      pages/chat-detail/index.js
  2. 152
      pages/chat/index.js
  3. 55
      utils/api.js

105
pages/chat-detail/index.js

@ -2,6 +2,9 @@
const API = require('../../utils/api.js'); const API = require('../../utils/api.js');
Page({ Page({
// 页面状态标志,用于检测页面是否已卸载
isUnloaded: false,
data: { data: {
chatId: null, chatId: null,
messages: [], messages: [],
@ -57,10 +60,16 @@ Page({
const managerPhone = this.data.managerPhone; const managerPhone = this.data.managerPhone;
if (managerPhone) { if (managerPhone) {
API.getSalesPersonnelInfo(managerPhone).then(personnelInfo => { API.getSalesPersonnelInfo(managerPhone).then(personnelInfo => {
// 检查页面是否已卸载
if (this.isUnloaded) return;
if (personnelInfo && personnelInfo.alias) { if (personnelInfo && personnelInfo.alias) {
this.setData({ chatTitle: personnelInfo.alias }); this.setData({ chatTitle: personnelInfo.alias });
} }
}).catch(error => { }).catch(error => {
// 检查页面是否已卸载
if (this.isUnloaded) return;
console.error('获取业务员信息失败:', error); console.error('获取业务员信息失败:', error);
}); });
} }
@ -132,6 +141,12 @@ Page({
console.log('加载聊天消息 - 聊天ID:', this.data.chatId, '用户手机号:', userPhone); console.log('加载聊天消息 - 聊天ID:', this.data.chatId, '用户手机号:', userPhone);
// 获取聊天消息 // 获取聊天消息
API.getChatMessages(this.data.chatId, userPhone).then(res => { API.getChatMessages(this.data.chatId, userPhone).then(res => {
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略聊天消息加载结果');
return;
}
console.log('加载聊天消息 - API返回:', JSON.stringify(res, null, 2)); console.log('加载聊天消息 - API返回:', JSON.stringify(res, null, 2));
if (Array.isArray(res)) { if (Array.isArray(res)) {
console.log('加载聊天消息 - API返回消息数量:', res.length); console.log('加载聊天消息 - API返回消息数量:', res.length);
@ -163,6 +178,12 @@ Page({
messages: processedMessages, messages: processedMessages,
loading: false loading: false
}, () => { }, () => {
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略滚动和新消息检测');
return;
}
// 在数据更新完成的回调中执行逻辑,确保DOM已更新 // 在数据更新完成的回调中执行逻辑,确保DOM已更新
// 首次加载消息或明确需要滚动时,直接滚动到底部 // 首次加载消息或明确需要滚动时,直接滚动到底部
@ -176,10 +197,12 @@ Page({
// 有新消息的条件: // 有新消息的条件:
// 1. 消息列表不为空 // 1. 消息列表不为空
// 2. 新消息列表的最后一条消息与当前显示的最后一条消息ID不同 // 2. 新消息列表的最后一条消息与当前显示的最后一条消息ID不同
// 3. 最新消息是对方发送的(不是自己发送的)
const hasNewMessages = newLastMessage && currentLastMessage && const hasNewMessages = newLastMessage && currentLastMessage &&
newLastMessage.id !== currentLastMessage.id; newLastMessage.id !== currentLastMessage.id &&
newLastMessage.sender === 'other'; // 只有对方发送的消息才视为新消息
console.log('新消息检测:', { hasNewMessages, isAtBottom: this.data.isAtBottom }); console.log('新消息检测:', { hasNewMessages, isAtBottom: this.data.isAtBottom, sender: newLastMessage ? newLastMessage.sender : 'none' });
if (hasNewMessages) { if (hasNewMessages) {
if (this.data.isAtBottom) { if (this.data.isAtBottom) {
@ -205,8 +228,16 @@ Page({
}); });
} }
}).catch(error => { }).catch(error => {
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略聊天消息加载错误');
return;
}
console.error('加载聊天记录失败:', error); console.error('加载聊天记录失败:', error);
this.setData({ loading: false }); this.setData({
loading: false
});
wx.showToast({ wx.showToast({
title: '加载聊天记录失败', title: '加载聊天记录失败',
icon: 'none' icon: 'none'
@ -218,19 +249,44 @@ Page({
scrollToBottom: function (withAnimation = true) { scrollToBottom: function (withAnimation = true) {
console.log('执行滚动到底部操作,是否使用动画:', withAnimation); console.log('执行滚动到底部操作,是否使用动画:', withAnimation);
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略滚动操作');
return;
}
// 使用wx.nextTick确保在DOM更新后执行 // 使用wx.nextTick确保在DOM更新后执行
wx.nextTick(() => { wx.nextTick(() => {
// 再次检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略滚动设置');
return;
}
this.setData({ this.setData({
scrollWithAnimation: withAnimation, scrollWithAnimation: withAnimation,
scrollTop: 999999 scrollTop: 999999
}, () => { }, () => {
// 滚动完成后清除新消息提示 // 再次检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略滚动完成后的操作');
return;
}
// 滚动完成后清除新消息提示并显式设置isAtBottom为true
setTimeout(() => { setTimeout(() => {
// 再次检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略滚动完成后的状态更新');
return;
}
this.setData({ this.setData({
hasNewMessages: false, hasNewMessages: false,
newMessageCount: 0 newMessageCount: 0,
isAtBottom: true // 显式设置为在底部
}); });
console.log('滚动完成,清除新消息提示'); console.log('滚动完成,清除新消息提示并设置为在底部');
}, 100); }, 100);
}); });
}); });
@ -246,6 +302,15 @@ Page({
console.log('滚动检测:', { scrollTop, scrollHeight, clientHeight, distanceToBottom, isAtBottom }); console.log('滚动检测:', { scrollTop, scrollHeight, clientHeight, distanceToBottom, isAtBottom });
// 如果滚动到底部,并且有新消息提示,自动隐藏提示
if (isAtBottom && this.data.hasNewMessages) {
this.setData({
hasNewMessages: false,
newMessageCount: 0
});
console.log('用户滑动到底部,自动隐藏新消息提示');
}
// 直接更新状态,确保滚动位置实时反映 // 直接更新状态,确保滚动位置实时反映
this.setData({ this.setData({
isAtBottom: isAtBottom isAtBottom: isAtBottom
@ -313,11 +378,23 @@ Page({
messages: newMessages, messages: newMessages,
inputValue: '' inputValue: ''
}, () => { }, () => {
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略发送消息后的操作');
return;
}
// 发送消息时无论用户在哪个位置,都自动滚动到底部 // 发送消息时无论用户在哪个位置,都自动滚动到底部
this.scrollToBottom(true); this.scrollToBottom(true);
// 短暂延迟后移除isNew标记,确保动画完成 // 短暂延迟后移除isNew标记,确保动画完成
setTimeout(() => { setTimeout(() => {
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略消息状态更新');
return;
}
const updatedMessages = this.data.messages.map(msg => ({ const updatedMessages = this.data.messages.map(msg => ({
...msg, ...msg,
isNew: false isNew: false
@ -328,8 +405,20 @@ Page({
// 发送到服务器 // 发送到服务器
API.sendMessage(userPhone, managerPhone, content).then(res => { API.sendMessage(userPhone, managerPhone, content).then(res => {
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略消息发送结果');
return;
}
console.log('消息发送成功:', res); console.log('消息发送成功:', res);
}).catch(error => { }).catch(error => {
// 检查页面是否已卸载
if (this.isUnloaded) {
console.log('页面已卸载,忽略消息发送错误');
return;
}
console.error('消息发送失败:', error); console.error('消息发送失败:', error);
wx.showToast({ wx.showToast({
title: '消息发送失败', title: '消息发送失败',
@ -361,6 +450,10 @@ Page({
}, },
onUnload: function () { onUnload: function () {
console.log('聊天详情页面卸载 - 清除定时器并设置卸载标志');
// 设置页面卸载标志
this.isUnloaded = true;
if (this.data.timer) { if (this.data.timer) {
clearInterval(this.data.timer); clearInterval(this.data.timer);
this.setData({ timer: null }); this.setData({ timer: null });

152
pages/chat/index.js

@ -9,7 +9,8 @@ Page({
timer: null, timer: null,
debugCount: 0, // 调试信息输出计数器 debugCount: 0, // 调试信息输出计数器
loginToastShown: false, // 登录提示是否已显示 loginToastShown: false, // 登录提示是否已显示
lastLoadTime: 0 // 用于节流的时间戳 lastLoadTime: 0, // 用于节流的时间戳
chatContentCache: {} // 缓存聊天项的内容,避免重复获取
}, },
onLoad: function (options) { onLoad: function (options) {
@ -216,11 +217,18 @@ Page({
// 调用API获取聊天列表 // 调用API获取聊天列表
API.getChatList(userPhone).then(res => { API.getChatList(userPhone).then(res => {
if (res && Array.isArray(res)) { if (res && Array.isArray(res)) {
console.log('===== 获取聊天列表原始数据 =====');
console.log(JSON.stringify(res, null, 2));
// 创建业务员信息缓存,避免重复调用API // 创建业务员信息缓存,避免重复调用API
const personnelCache = {}; const personnelCache = {};
// 处理每个聊天项,获取业务员信息 // 处理每个聊天项,获取业务员信息
const chatListPromises = res.map(async (chatItem) => { 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) { if (chatItem.manager_phone) {
try { try {
// 先检查缓存中是否已有该业务员信息 // 先检查缓存中是否已有该业务员信息
@ -253,35 +261,92 @@ Page({
chatItem.avatar = chatItem.avatar || 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'; chatItem.avatar = chatItem.avatar || 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0';
} }
// 修复:对所有没有消息内容的聊天项获取最新消息内容 // 获取用户已查看过的聊天列表
if (!chatItem.content) { const viewedChats = wx.getStorageSync('viewedChats') || {};
const chatId = chatItem.manager_phone;
// 获取最新消息内容和时间
let lastMessage = null;
try { try {
const messages = await API.getChatMessages(chatItem.manager_phone, userPhone, { limit: 1 }); 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) { if (messages.length > 0) {
chatItem.content = messages[0].content || '暂无消息内容'; lastMessage = messages[0];
chatItem.content = lastMessage.content || '暂无消息内容';
// 同时更新时间为最新消息的时间 // 同时更新时间为最新消息的时间
chatItem.time = messages[0].created_at || null; chatItem.time = lastMessage.created_at || null;
} else {
// 更新缓存
const newCache = {
...this.data.chatContentCache,
[cacheKey]: {
content: chatItem.content,
time: chatItem.time,
timestamp: now,
messageId: lastMessage.id || lastMessage.message_id || null
}
};
this.setData({ chatContentCache: newCache });
console.log('更新聊天内容缓存:', cacheKey);
} else if (!chatItem.content) {
chatItem.content = '暂无消息内容'; chatItem.content = '暂无消息内容';
} }
} catch (error) { } catch (error) {
console.error('获取聊天消息失败:', 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.content = '暂无消息内容';
} }
} }
// 格式化时间 // 格式化时间
chatItem.time = this.formatDateTime(chatItem.time || null); chatItem.time = this.formatDateTime(chatItem.time || null);
// 确保unread字段存在
chatItem.unread = chatItem.unread || false;
// 未读状态判断:基于用户是否查看过该聊天
// 只在用户未查看过时显示未读红点
console.log('当前已查看的聊天:', viewedChats);
console.log('当前聊天ID:', chatId);
// 检查该聊天是否已被查看过
const isViewed = viewedChats[chatId] === true;
console.log('是否已查看:', isViewed);
// 设置未读状态:未查看过则显示未读
chatItem.unread = !isViewed;
console.log('设置unread的值:', chatItem.unread);
// 保存最后一条消息的ID或内容作为标识(可选)
if (lastMessage) {
chatItem.lastMessageId = lastMessage.id || lastMessage.message_id;
chatItem.lastMessageContent = lastMessage.content;
}
console.log('处理完成的聊天项:', JSON.stringify(chatItem, null, 2));
return chatItem; return chatItem;
}); });
// 等待所有聊天项处理完成 // 等待所有聊天项处理完成
Promise.all(chatListPromises).then(processedChatList => { Promise.all(chatListPromises).then(processedChatList => {
console.log('\n===== 所有聊天项处理完成 =====');
console.log('处理后的列表:', JSON.stringify(processedChatList, null, 2));
this.setData({ this.setData({
chatList: processedChatList, chatList: processedChatList,
filteredChatList: 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(); wx.hideLoading();
}).catch(error => { }).catch(error => {
@ -344,6 +409,73 @@ Page({
// 使用对方的电话号码作为聊天ID,而不是会话ID // 使用对方的电话号码作为聊天ID,而不是会话ID
const chatId = chatItem.manager_phone; 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,标记为已查看
const viewedChats = wx.getStorageSync('viewedChats') || {};
viewedChats[chatId] = true;
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参数 // 跳转到聊天详情页,传递chatId和name参数
wx.navigateTo({ wx.navigateTo({
url: '/pages/chat-detail/index?id=' + chatId + '&name=' + encodeURIComponent(chatItem.name), url: '/pages/chat-detail/index?id=' + chatId + '&name=' + encodeURIComponent(chatItem.name),

55
utils/api.js

@ -3748,6 +3748,61 @@ module.exports = {
reject(new Error(error.message || '获取业务员信息失败,请稍后重试')); reject(new Error(error.message || '获取业务员信息失败,请稍后重试'));
}); });
}); });
},
// 标记消息为已读
markMessagesAsRead: function (chatId, userPhone) {
console.log('API.markMessagesAsRead - chatId:', chatId, 'userPhone:', userPhone);
return new Promise((resolve, reject) => {
// 如果没有传入手机号,尝试从本地存储获取
if (!userPhone) {
// 获取用户信息,包含手机号
const users = wx.getStorageSync('users') || {};
const userId = wx.getStorageSync('userId');
// 尝试从users中获取手机号
if (userId && users[userId] && users[userId].phoneNumber) {
userPhone = users[userId].phoneNumber;
} else {
// 尝试从全局用户信息获取
const userInfo = wx.getStorageSync('userInfo');
if (userInfo && userInfo.phoneNumber) {
userPhone = userInfo.phoneNumber;
} else {
// 尝试从直接存储的phoneNumber获取
userPhone = wx.getStorageSync('phoneNumber');
}
}
}
// 如果没有手机号,直接返回错误
if (!userPhone) {
reject(new Error('请先登录并绑定手机号'));
return;
}
// 如果没有chatId,直接返回错误
if (!chatId) {
reject(new Error('聊天ID不能为空'));
return;
}
const requestData = {
chat_id: chatId,
user_phone: userPhone
};
console.log('API.markMessagesAsRead - 请求数据:', requestData);
request('/api/chat/read', 'POST', requestData).then(res => {
console.log('API.markMessagesAsRead - 响应数据:', res);
resolve(res);
}).catch(error => {
console.error('API.markMessagesAsRead - 请求失败:', error);
// 标记为已读的API可能尚未实现,所以不抛出错误,让前端继续执行
resolve({});
});
});
} }
}; };
Loading…
Cancel
Save