You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

727 lines
26 KiB

// 消息列表页面
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();
let messageDate;
// 尝试不同的时间格式解析
if (typeof timeStr === 'number') {
// 处理时间戳
messageDate = new Date(timeStr);
} else if (typeof timeStr === 'string') {
// 处理字符串格式
if (/^\d+$/.test(timeStr)) {
// 数字字符串,可能是时间戳
messageDate = new Date(parseInt(timeStr));
} else {
// 其他字符串格式
messageDate = new Date(timeStr);
}
} else {
// 其他类型,返回空
return '';
}
// 验证日期是否有效
if (isNaN(messageDate.getTime())) {
return '';
}
const diffTime = Math.abs(now - messageDate);
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
if (diffDays === 0) {
// 今天的消息只显示时间,格式化为 HH:mm
const hours = messageDate.getHours().toString().padStart(2, '0');
const minutes = messageDate.getMinutes().toString().padStart(2, '0');
return `${hours}:${minutes}`;
} else if (diffDays === 1) {
// 昨天的消息
return '昨天';
} else if (diffDays < 7) {
// 一周内的消息显示星期
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
return weekdays[messageDate.getDay()];
} else if (diffDays < 365) {
// 今年内的消息显示月日
const month = (messageDate.getMonth() + 1).toString().padStart(2, '0');
const day = messageDate.getDate().toString().padStart(2, '0');
return `${month}-${day}`;
} else {
// 超过一年的消息显示完整日期
const year = messageDate.getFullYear();
const month = (messageDate.getMonth() + 1).toString().padStart(2, '0');
const day = messageDate.getDate().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'
});
}
}
});