// pages/customer-service/index.js const api = require('../../utils/api'); Page({ // 分享给朋友/群聊 onShareAppMessage() { return { title: '鸡蛋贸易平台 - 专业客服,服务贴心', path: '/pages/customer-service/index', imageUrl: '/images/你有好蛋.png' } }, // 分享到朋友圈 onShareTimeline() { return { title: '鸡蛋贸易平台 - 专业客服,服务贴心', query: '', imageUrl: '/images/你有好蛋.png' } }, // 客服数据,将从后端动态获取 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'; // 直接使用api.request函数,该函数已经配置了正确的BASE_URL const res = await api.request(`/api/managers?type=${userType}`, 'GET', {}); console.log('API响应数据:', res ? JSON.stringify(res) : 'undefined'); // 更宽松的响应检查,确保能处理各种有效的响应格式 // 注意:api.request函数直接返回res.data,所以res已经是响应数据,不再有statusCode字段 if (res) { // 无论success字段是否存在,只要有数据就尝试处理 const dataSource = Array.isArray(res) ? res : (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家(或X+鸡场) if (lines[0]) { const firstLine = lines[0].trim(); // 提取完整的经验信息,包括"服务平台" const fullExperienceMatch = firstLine.match(/(服务平台.*?年|服务平台.*?月)/); if (fullExperienceMatch) { // 直接使用完整的经验信息,如"服务平台1年"或"服务平台2个月" experience = fullExperienceMatch[1].trim(); } else { // 如果没有匹配到,使用默认格式 experience = '服务平台1年'; } // 匹配服务数量,支持多种格式:服务66家、服务100+鸡场等 // 确保只匹配最后一个"服务"后面的数量 const serviceMatches = firstLine.match(/服务(.*?)(家|鸡场)/g); if (serviceMatches && serviceMatches.length > 0) { // 使用最后一个匹配项 const lastServiceMatch = serviceMatches[serviceMatches.length - 1]; const serviceCountMatch = lastServiceMatch.match(/服务(.*?)(家|鸡场)/); if (serviceCountMatch) { serviceCount = serviceCountMatch[1].trim(); } } } // 解析数字行:数字 数字% 或 数字 数字 数字% for (let i = 1; i < lines.length; i++) { const line = lines[i].trim(); // 匹配数字序列 const numbers = line.split(/\s+/).filter(num => num.trim() && /\d/.test(num)); if (numbers.length >= 2) { // 销售相关数据:累计销售和客户满意度 purchaseCount = numbers[0].trim(); profitFarmCount = numbers[1].replace('%', '').trim(); // 如果有第三个数字,可能是其他数据 if (numbers.length >= 3) { profitIncreaseRate = numbers[2].replace('%', '').trim(); } break; // 只处理第一行数字 } } } // 处理鸡蛋分显示 let score = '新人暂无'; if (item.egg_section) { if (item.egg_section.trim() === '新人暂无') { // 新人暂无,直接显示 score = '新人暂无'; } else { // 提取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 || '', // 解析头像URL,处理JSON数组格式和多余字符 avatarUrl: function() { let url = ''; const avatarData = item.avatar || item.avatarUrl || ''; if (avatarData) { try { // 尝试解析JSON数组 const avatarArray = JSON.parse(avatarData); if (Array.isArray(avatarArray) && avatarArray.length > 0) { // 提取数组中的第一个URL,并清理多余字符 url = avatarArray[0].trim() .replace(/^`/, '') // 移除开头的反引号 .replace(/`$/, '') // 移除结尾的反引号 .replace(/^"/, '') // 移除开头的引号 .replace(/"$/, ''); // 移除结尾的引号 } } catch (e) { // 如果不是JSON数组,直接使用,并清理多余字符 url = avatarData.trim() .replace(/^`/, '') // 移除开头的反引号 .replace(/`$/, '') // 移除结尾的反引号 .replace(/^"/, '') // 移除开头的引号 .replace(/"$/, ''); // 移除结尾的引号 } } return url; }(), 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); // 按鸡蛋分从高到低排序 processedData.sort((a, b) => { const scoreA = parseInt(a.score) || 0; const scoreB = parseInt(b.score) || 0; return scoreB - scoreA; }); console.log('排序后的数据:', processedData.map(item => ({ id: item.id, name: item.name, score: item.score }))); return processedData; } else { console.error('响应数据格式错误,不是预期的数组格式:', dataSource); return []; } } else { console.error('获取客服列表失败,响应数据无效:', res); 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) || item.responsibleArea?.includes('全国'); }); // 按所选地区优先排序 filtered.sort((a, b) => { // 优先显示所选地区的客服 const aHasSelectedArea = a.responsibleArea?.includes(selectedArea); const bHasSelectedArea = b.responsibleArea?.includes(selectedArea); if (aHasSelectedArea && !bHasSelectedArea) return -1; if (!aHasSelectedArea && bHasSelectedArea) return 1; // 同一地区的客服按鸡蛋分排序 const scoreA = parseInt(a.score) || 0; const scoreB = parseInt(b.score) || 0; return scoreB - scoreA; }); } else { // 全部区域时,按鸡蛋分排序 filtered.sort((a, b) => { const scoreA = parseInt(a.score) || 0; const scoreB = parseInt(b.score) || 0; return scoreB - scoreA; }); } 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(); } });