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.
 
 

620 lines
23 KiB

// 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';
// 直接使用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();
}
});