// pages/customer-service/index.js const api = require('../../utils/api'); Page({ // 客服数据,将从后端动态获取 data: { customerServices: [], filteredServices: [], searchKeyword: '', selectedArea: '全部', totalCount: 0, onlineCount: 0, userType: 'seller' // 初始化用户类型,默认为销售员 }, // 获取客服列表的方法 async fetchCustomerServices() { try { console.log('开始请求客服列表...'); // 导入API工具并使用正确的请求方法 const api = require('../../utils/api'); // 获取当前用户类型参数 const userType = this.data.userType || 'seller'; const res = await new Promise((resolve, reject) => { wx.request({ url: `http://localhost:3003/api/managers?type=${userType}`, method: 'GET', timeout: 15000, header: { 'content-type': 'application/json' }, success: resolve, fail: (error) => { console.error('网络请求失败:', error); reject(error); } }); }); console.log('API响应状态码:', res?.statusCode); console.log('API响应数据:', res?.data ? JSON.stringify(res.data) : 'undefined'); // 更宽松的响应检查,确保能处理各种有效的响应格式 if (res && res.statusCode === 200 && res.data) { // 无论success字段是否存在,只要有data字段就尝试处理 const dataSource = res.data.data || res.data; if (Array.isArray(dataSource)) { const processedData = dataSource.map(item => { // 解析information字段中的信息 let experience = ''; let serviceCount = ''; let purchaseCount = ''; let profitFarmCount = ''; let profitIncreaseRate = ''; if (item.information) { // 处理不同类型的换行符(\r\n和\n) const lines = item.information.split(/\r?\n/).filter(line => line.trim()); // 解析第一行:服务平台X年 服务X+鸡场 if (lines[0]) { const firstLine = lines[0].trim(); const experienceMatch = firstLine.match(/服务平台(.*?)年/); if (experienceMatch) { experience = experienceMatch[1].trim() + '年'; } const serviceCountMatch = firstLine.match(/服务(.*?)鸡场/); if (serviceCountMatch) { serviceCount = serviceCountMatch[1].trim(); } } // 解析第二行:数字 数字 数字% if (lines[1]) { const secondLine = lines[1].trim(); const numbers = secondLine.split(/\s+/).filter(num => num.trim()); if (numbers.length >= 3) { purchaseCount = numbers[0].trim(); profitFarmCount = numbers[1].trim(); profitIncreaseRate = numbers[2].replace('%', '').trim(); } } } // 提取egg_section中的数字部分,去掉"鸡蛋分"后缀 let score = Math.floor(Math.random() * 20) + 980; if (item.egg_section) { const scoreMatch = item.egg_section.match(/(\d+)/); if (scoreMatch) { score = scoreMatch[1]; } } return { id: item.id || `id_${Date.now()}_${Math.random()}`, // 确保有id managerId: item.managerId || '', managercompany: item.managercompany || '', managerdepartment: item.managerdepartment || '', organization: item.organization || '', projectName: item.projectName || '', name: item.name || '未知', alias: item.alias || item.name || '未知', phoneNumber: item.phoneNumber || '', avatarUrl: item.avatar || item.avatarUrl || '', // 兼容avatar和avatarUrl score: score, // 使用数据库中的鸡蛋分,提取数字部分 isOnline: !!item.online, // 转换为布尔值 responsibleArea: item.responsible_area || '', // 使用数据库中的负责区域 experience: experience, serviceCount: serviceCount, purchaseCount: purchaseCount, profitIncreaseRate: profitIncreaseRate, profitFarmCount: profitFarmCount, skills: [], // 技能信息 information: item.information || '', // 保存原始个人信息 label: item.label || '' // 保存标签信息 }; }); console.log('处理后的数据数量:', processedData.length); return processedData; } else { console.error('响应数据格式错误,不是预期的数组格式:', dataSource); return []; } } else { console.error('获取客服列表失败,状态码:', res?.statusCode, '响应数据:', res?.data); return []; } } catch (error) { console.error('请求客服列表出错:', error); // 网络错误时显示提示 wx.showToast({ title: '网络请求失败,请检查网络连接', icon: 'none' }); return []; } }, // 辅助函数:生成随机区域 getRandomArea() { const areas = ['华北区', '华东区', '华南区', '全国', '西南区', '西北区', '东北区']; return areas[Math.floor(Math.random() * areas.length)]; }, // 辅助函数:生成随机工作经验 getRandomExperience() { const experiences = ['1-2年', '1-3年', '2-3年', '3-5年', '5年以上']; return experiences[Math.floor(Math.random() * experiences.length)]; }, // 辅助函数:生成随机数字 getRandomNumber(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, // 辅助函数:生成随机技能 getRandomSkills() { const allSkills = ['渠道拓展', '供应商维护', '质量把控', '精准把控市场价格', '谈判技巧', '库存管理']; const skillCount = Math.floor(Math.random() * 3) + 2; // 2-4个技能 const selectedSkills = []; while (selectedSkills.length < skillCount) { const skill = allSkills[Math.floor(Math.random() * allSkills.length)]; if (!selectedSkills.includes(skill)) { selectedSkills.push(skill); } } return selectedSkills; }, // 定期刷新客服列表(每30秒) startPeriodicRefresh() { this.refreshTimer = setInterval(() => { console.log('定期刷新客服列表...'); this.loadCustomerServices(); }, 30000); }, // 停止定期刷新 stopPeriodicRefresh() { if (this.refreshTimer) { clearInterval(this.refreshTimer); this.refreshTimer = null; } }, // 加载客服列表 async loadCustomerServices() { console.log('开始加载客服列表...'); // 确保在开始时调用hideLoading,防止重复调用showLoading try { wx.hideLoading(); } catch (e) { console.log('没有正在显示的loading'); } wx.showLoading({ title: '加载中...' }); try { const services = await this.fetchCustomerServices(); console.log('获取到的客服数量:', services.length); // 计算在线数量 const onlineCount = services.filter(item => item.isOnline).length; console.log('在线客服数量:', onlineCount); // 更新数据 this.setData({ customerServices: services, totalCount: services.length, onlineCount: onlineCount }); console.log('数据更新成功'); // 应用当前的筛选条件 this.filterServices(); console.log('筛选条件应用完成'); // 如果没有数据,显示提示(确保在hideLoading后显示) if (services.length === 0) { setTimeout(() => { wx.showToast({ title: '暂无客服数据', icon: 'none', duration: 2000 }); }, 100); } } catch (error) { console.error('加载客服列表失败:', error); // 确保在hideLoading后显示错误提示 setTimeout(() => { wx.showToast({ title: '加载失败,请重试', icon: 'none', duration: 2000 }); }, 100); } finally { wx.hideLoading(); } }, onLoad: function (options) { // 获取页面参数(seller=销售员,buyer=采购员) this.setData({ userType: options.type || 'seller' // 默认销售员 }); console.log('客服列表页面加载,类型:', this.data.userType); // 加载客服列表 this.loadCustomerServices(); // 检查当前用户身份 this.checkUserType(); }, /** * 检查当前用户身份 */ checkUserType: function() { const app = getApp(); const userInfo = app.globalData.userInfo || {}; const isManager = userInfo.userType === 'manager' || userInfo.type === 'manager'; console.log('当前用户身份检查:', { isManager, userType: userInfo.userType }); this.setData({ isCurrentUserManager: isManager }); }, onShow() { // 更新自定义tabBar状态 if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ selected: -1 // 不选中任何tab }); } // 当页面显示时重新加载数据,确保数据最新 this.loadCustomerServices(); }, onUnload: function() { // 停止定期刷新 this.stopPeriodicRefresh(); }, onSearch: function (e) { const keyword = e.detail.value; this.setData({ searchKeyword: keyword }); this.filterServices(); }, onAreaFilter: function () { // 区域筛选弹窗 - 鸡蛋采购区域 wx.showActionSheet({ itemList: ['全部', '华北区', '华东区', '华南区', '全国', '西南区', '西北区', '东北区'], success: res => { const areas = ['全部', '华北区', '华东区', '华南区', '全国', '西南区', '西北区', '东北区']; const selectedArea = areas[res.tapIndex]; this.setData({ selectedArea: selectedArea }); this.filterServices(); } }); }, filterServices: function () { const { customerServices, searchKeyword, selectedArea } = this.data; let filtered = customerServices; // 关键词搜索 if (searchKeyword) { const keyword = searchKeyword.toLowerCase(); filtered = filtered.filter(item => { return item.alias?.toLowerCase().includes(keyword) || item.name.toLowerCase().includes(keyword) || item.phoneNumber?.includes(keyword) || item.managercompany?.toLowerCase().includes(keyword); }); } // 区域筛选 if (selectedArea && selectedArea !== '全部') { filtered = filtered.filter(item => { return item.responsibleArea?.includes(selectedArea); }); } this.setData({ filteredServices: filtered }); }, // 封装测试聊天列表功能的函数 async testChatListFunctionality(userPhone, managerPhone) { try { console.log('=== 开始测试聊天列表功能 ==='); console.log('测试用户手机号:', userPhone); console.log('测试客服手机号:', managerPhone); // 1. 测试添加聊天记录(双向) console.log('\n1. 测试添加聊天记录(双向)...'); const addChatResponse = await api.addChatRecord(userPhone, managerPhone); console.log('添加聊天记录响应:', addChatResponse); // 2. 测试用户获取聊天列表 console.log('\n2. 测试用户获取聊天列表...'); const userChatListResponse = await api.getChatList(userPhone); console.log('用户聊天列表响应:', userChatListResponse); console.log('用户聊天列表数量:', Array.isArray(userChatListResponse) ? userChatListResponse.length : 0); // 3. 测试客服获取聊天列表 console.log('\n3. 测试客服获取聊天列表...'); const managerChatListResponse = await api.getChatList(managerPhone); console.log('客服聊天列表响应:', managerChatListResponse); console.log('客服聊天列表数量:', Array.isArray(managerChatListResponse) ? managerChatListResponse.length : 0); // 4. 验证双向聊天记录是否都能正确获取 console.log('\n4. 验证双向聊天记录...'); // 检查用户是否能看到与客服的聊天记录 const userHasManagerChat = Array.isArray(userChatListResponse) && userChatListResponse.some(chat => (chat.user_phone === userPhone && chat.manager_phone === managerPhone) || (chat.user_phone === managerPhone && chat.manager_phone === userPhone) ); // 检查客服是否能看到与用户的聊天记录 const managerHasUserChat = Array.isArray(managerChatListResponse) && managerChatListResponse.some(chat => (chat.user_phone === userPhone && chat.manager_phone === managerPhone) || (chat.user_phone === managerPhone && chat.manager_phone === userPhone) ); if (userHasManagerChat) { console.log('✓ 用户可以看到与客服的聊天记录'); } else { console.log('❌ 用户无法看到与客服的聊天记录'); } if (managerHasUserChat) { console.log('✓ 客服可以看到与用户的聊天记录'); } else { console.log('❌ 客服无法看到与用户的聊天记录'); } // 5. 测试重复添加聊天记录(应该不会重复创建) console.log('\n5. 测试重复添加聊天记录...'); const duplicateAddResponse = await api.addChatRecord(userPhone, managerPhone); console.log('重复添加聊天记录响应:', duplicateAddResponse); // 6. 再次测试获取聊天列表,确保数量没有变化 console.log('\n6. 再次测试获取聊天列表,确保数量没有变化...'); const finalUserChatListResponse = await api.getChatList(userPhone); console.log('最终用户聊天列表数量:', Array.isArray(finalUserChatListResponse) ? finalUserChatListResponse.length : 0); const initialLength = Array.isArray(userChatListResponse) ? userChatListResponse.length : 0; const finalLength = Array.isArray(finalUserChatListResponse) ? finalUserChatListResponse.length : 0; if (finalLength === initialLength) { console.log('✓ 重复添加聊天记录没有导致重复数据'); } else { console.log('❌ 重复添加聊天记录导致了重复数据'); } console.log('\n=== 聊天列表功能测试完成 ==='); // 总结测试结果 if (userHasManagerChat && managerHasUserChat) { console.log('\n🎉 所有测试通过!聊天列表功能正常工作。'); return true; } else { console.log('\n❌ 测试失败!聊天列表功能存在问题。'); return false; } } catch (error) { console.error('测试过程中出现错误:', error.message); if (error.response) { console.error('错误响应数据:', error.response.data); } return false; } }, onChat: function (e) { const id = e.currentTarget.dataset.id; const service = this.data.customerServices.find(item => item.id === id); if (!service) return; // 获取当前用户的手机号 let userPhone = ''; try { // 尝试从不同的存储位置获取手机号 const userInfo = wx.getStorageSync('userInfo'); if (userInfo && userInfo.phoneNumber) { userPhone = userInfo.phoneNumber; } else { // 尝试从其他可能的存储位置获取 const users = wx.getStorageSync('users') || {}; const userId = wx.getStorageSync('userId'); if (userId && users[userId] && users[userId].phoneNumber) { userPhone = users[userId].phoneNumber; } else { userPhone = wx.getStorageSync('phoneNumber'); } } // 如果都获取不到,使用用户提供的默认登录手机号 if (!userPhone) { userPhone = '18482694520'; } } catch (e) { console.error('获取用户手机号失败:', e); // 如果获取失败,使用用户提供的默认登录手机号 userPhone = '18482694520'; } console.log('当前用户手机号:', userPhone); console.log('客服信息:', service); // 验证手机号 if (!userPhone) { wx.showToast({ title: '请先登录获取手机号', icon: 'none' }); return; } // 验证客服手机号 if (!service.phoneNumber) { console.error('客服手机号不存在:', service.name); wx.showToast({ title: '客服信息不完整,请稍后重试', icon: 'none' }); return; } console.log('客服手机号:', service.phoneNumber); // 显示加载提示 wx.showLoading({ title: '正在建立聊天...', }); // 调用修复函数,确保用户和客服之间的聊天记录是双向的(成双成对) api.fixChatRecordsPair(userPhone, service.phoneNumber).then(res => { console.log('聊天建立成功:', JSON.stringify(res, null, 2)); // 隐藏加载提示 wx.hideLoading(); // 使用客服手机号作为聊天会话ID const chatSessionId = service.phoneNumber; // 跳转到聊天页面,确保正确传递客服手机号和用户名 wx.navigateTo({ url: `/pages/chat-detail/index?userId=${chatSessionId}&userName=${encodeURIComponent(service?.alias || '')}&phone=${service?.phoneNumber || ''}&isManager=true` }); console.log('跳转到聊天页面:', { chatUserId: chatSessionId, userName: service?.alias, customerServicePhone: service?.phoneNumber, userPhone: userPhone }); }).catch(err => { console.error('建立聊天失败:', err); // 隐藏加载提示 wx.hideLoading(); wx.showToast({ title: '建立聊天失败,请重试', icon: 'none' }); }); }, onCall: function (e) { const phone = e.currentTarget.dataset.phone; wx.makePhoneCall({ phoneNumber: phone, success: function () { console.log('拨打电话成功'); }, fail: function () { console.log('拨打电话失败'); } }); }, // 查看客服详情 onViewDetail: function (e) { const id = e.currentTarget.dataset.id; const service = this.data.customerServices.find(item => item.id === id); if (service) { // 将完整的客服数据通过URL参数传递给详情页面 wx.navigateTo({ url: `/pages/customer-service/detail/index?id=${id}&serviceData=${encodeURIComponent(JSON.stringify(service))}` }); } }, onBack: function () { wx.navigateBack(); } });