diff --git a/.gitignore b/.gitignore index e42107b..e3b694b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules pages/test/ -pages/test-tools/ \ No newline at end of file +pages/test-tools/ +server-example/db-query.js \ No newline at end of file diff --git a/app.js b/app.js deleted file mode 100644 index 13298e1..0000000 --- a/app.js +++ /dev/null @@ -1,165 +0,0 @@ -App({ - // 全局事件总线功能 - eventBus: { - listeners: {}, - - // 监听事件 - on: function (event, callback) { - if (!this.listeners[event]) { - this.listeners[event] = []; - } - this.listeners[event].push(callback); - }, - - // 触发事件 - emit: function (event, data) { - if (this.listeners[event]) { - this.listeners[event].forEach(callback => { - try { - callback(data); - } catch (error) { - console.error('事件处理错误:', error); - } - }); - } - }, - - // 移除事件监听 - off: function (event, callback) { - if (this.listeners[event]) { - if (callback) { - this.listeners[event] = this.listeners[event].filter(cb => cb !== callback); - } else { - delete this.listeners[event]; - } - } - } - }, - - onLaunch: function () { - // 初始化应用 - console.log('App Launch') - // 初始化本地存储的标签和用户数据 - if (!wx.getStorageSync('users')) { - wx.setStorageSync('users', {}) - } - if (!wx.getStorageSync('tags')) { - wx.setStorageSync('tags', {}) - } - if (!wx.getStorageSync('goods')) { - // 初始化空的商品列表,不预置默认数据,由服务器获取 - wx.setStorageSync('goods', []) - } - if (!wx.getStorageSync('supplies')) { - // 初始化空的供应列表,不预置默认数据,由服务器获取 - wx.setStorageSync('supplies', []) - } - - // 检查是否是首次启动 - const isFirstLaunch = !wx.getStorageSync('hasLaunched') - if (isFirstLaunch) { - // 标记应用已经启动过 - wx.setStorageSync('hasLaunched', true) - - // 只有在首次启动时才检查用户身份并可能跳转 - const userId = wx.getStorageSync('userId') - if (userId) { - const users = wx.getStorageSync('users') - const user = users[userId] - if (user && user.type) { - // 延迟跳转,确保页面加载完成 - setTimeout(() => { - try { - if (user.type === 'buyer') { - wx.switchTab({ url: '/pages/buyer/index' }) - } else if (user.type === 'seller') { - wx.switchTab({ url: '/pages/seller/index' }) - } - } catch (e) { - console.error('启动时页面跳转异常:', e) - // 即使跳转失败,也不影响应用正常启动 - } - }, 100) - } - } - } - - // 获取本地存储的用户信息和用户类型 - const storedUserInfo = wx.getStorageSync('userInfo'); - const storedUserType = wx.getStorageSync('userType'); - - if (storedUserInfo) { - this.globalData.userInfo = storedUserInfo; - } - - if (storedUserType) { - this.globalData.userType = storedUserType; - } - - console.log('App初始化 - 用户类型:', this.globalData.userType); - console.log('App初始化 - 用户信息:', this.globalData.userInfo); - - // 获取用户信息 - wx.getSetting({ - success: res => { - if (res.authSetting['scope.userInfo']) { - // 已经授权,可以直接调用 getUserInfo 获取头像昵称 - wx.getUserInfo({ - success: res => { - // 将用户信息存储到本地和全局,不自动登录 - // 登录流程将在用户点击登录按钮时触发 - console.log('获取用户信息成功,暂不自动登录'); - - // 更新全局用户信息 - this.globalData.userInfo = res.userInfo; - - // 更新本地存储的用户信息 - wx.setStorageSync('userInfo', res.userInfo); - }, - fail: error => { - console.error('获取用户信息失败:', error); - } - }); - } - }, - fail: error => { - console.error('获取用户设置失败:', error); - } - }); - }, - onShow: function () { - console.log('App Show') - }, - onHide: function () { - console.log('App Hide') - }, - - // 更新当前选中的tab - updateCurrentTab(tabKey) { - if (this.globalData) { - this.globalData.currentTab = tabKey - } - }, - - // 跳转到估价页面 - goToEvaluatePage() { - wx.navigateTo({ - url: '/pages/evaluate/index' - }) - }, - - // 上传手机号数据 - async uploadPhoneNumberData(phoneData) { - const API = require('./utils/api.js') - return await API.uploadPhoneNumberData(phoneData) - }, - - globalData: { - userInfo: null, - userType: 'customer', // 默认客户类型 - currentTab: 'index', // 当前选中的tab - showTabBar: true, // 控制底部tab-bar显示状态 - // 测试环境配置 - isTestMode: false - } -}) \ No newline at end of file diff --git a/pages/customer-service/detail/index.js b/pages/customer-service/detail/index.js new file mode 100644 index 0000000..f917aa2 --- /dev/null +++ b/pages/customer-service/detail/index.js @@ -0,0 +1,221 @@ +// pages/customer-service/detail/index.js +const api = require('../../../utils/api'); + +Page({ + data: { + customerData: null, + customerServices: [ + { + id: 1, + managerId: 'PM001', + managercompany: '鸡蛋贸易有限公司', + managerdepartment: '采购部', + organization: '鸡蛋采购组', + projectName: '高级采购经理', + name: '张三', + alias: '张经理', + phoneNumber: '13800138001', + avatarUrl: '', + score: 999, + isOnline: true, + responsibleArea: '华北区鸡蛋采购', + experience: '1-3年', + serviceCount: 200, + purchaseCount: 15000, + profitIncreaseRate: 15, + profitFarmCount: 120, + skills: ['渠道拓展', '供应商维护', '质量把控', '精准把控市场价格'] + }, + { + id: 2, + managerId: 'PM002', + managercompany: '鸡蛋贸易有限公司', + managerdepartment: '采购部', + organization: '全国采购组', + projectName: '采购经理', + name: '李四', + alias: '李经理', + phoneNumber: '13900139002', + avatarUrl: '', + score: 998, + isOnline: true, + responsibleArea: '全国鸡蛋采购', + experience: '2-3年', + serviceCount: 200, + purchaseCount: 20000, + profitIncreaseRate: 18, + profitFarmCount: 150, + skills: ['精准把控市场价格', '渠道拓展', '供应商维护'] + }, + { + id: 3, + managerId: 'PM003', + managercompany: '鸡蛋贸易有限公司', + managerdepartment: '采购部', + organization: '华东采购组', + projectName: '采购专员', + name: '王五', + alias: '王专员', + phoneNumber: '13700137003', + avatarUrl: '', + score: 997, + isOnline: false, + responsibleArea: '华东区鸡蛋采购', + experience: '1-2年', + serviceCount: 150, + purchaseCount: 12000, + profitIncreaseRate: 12, + profitFarmCount: 80, + skills: ['质量把控', '供应商维护'] + }, + { + id: 4, + managerId: 'PM004', + managercompany: '鸡蛋贸易有限公司', + managerdepartment: '采购部', + organization: '华南采购组', + projectName: '高级采购经理', + name: '赵六', + alias: '赵经理', + phoneNumber: '13600136004', + avatarUrl: '', + score: 996, + isOnline: true, + responsibleArea: '华南区鸡蛋采购', + experience: '3-5年', + serviceCount: 250, + purchaseCount: 25000, + profitIncreaseRate: 20, + profitFarmCount: 180, + skills: ['精准把控市场价格', '渠道拓展', '质量把控', '供应商维护'] + } + ] + }, + + onLoad: function (options) { + // 获取传递过来的客服ID + const { id } = options; + // 根据ID查找客服数据 + const customerData = this.data.customerServices.find(item => item.id === parseInt(id)); + + if (customerData) { + this.setData({ + customerData: customerData + }); + // 设置导航栏标题 + wx.setNavigationBarTitle({ + title: `${customerData.alias} - 客服详情`, + }); + } else { + // 如果找不到对应ID的客服,显示错误提示 + wx.showToast({ + title: '未找到客服信息', + icon: 'none' + }); + } + }, + + onShow() { + // 更新自定义tabBar状态 + if (typeof this.getTabBar === 'function' && this.getTabBar()) { + this.getTabBar().setData({ + selected: -1 // 不选中任何tab + }); + } + }, + + // 返回上一页 + onBack: function () { + wx.navigateBack(); + }, + + // 在线沟通 + onChat: function () { + const { customerData } = this.data; + if (!customerData) 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'); + } + } + } catch (e) { + console.error('获取用户手机号失败:', e); + } + + console.log('当前用户手机号:', userPhone); + console.log('客服手机号:', customerData.phoneNumber); + + // 验证手机号 + if (!userPhone) { + wx.showToast({ + title: '请先登录获取手机号', + icon: 'none' + }); + return; + } + + // 显示加载提示 + wx.showLoading({ + title: '正在建立聊天...', + }); + + // 调用API添加聊天记录 + api.addChatRecord(userPhone, customerData.phoneNumber).then(res => { + console.log('添加聊天记录成功:', res); + // 隐藏加载提示 + wx.hideLoading(); + // 导航到聊天页面 + wx.navigateTo({ + url: `/pages/chat/index?id=${customerData.id}&name=${customerData.alias}&phone=${customerData.phoneNumber}` + }); + }).catch(err => { + console.error('添加聊天记录失败:', err); + // 隐藏加载提示 + wx.hideLoading(); + // 显示错误提示 + wx.showToast({ + title: '建立聊天失败: ' + (err.message || '请稍后重试'), + icon: 'none' + }); + }); + }, + + // 拨打电话 + onCall: function () { + const { customerData } = this.data; + if (customerData && customerData.phoneNumber) { + wx.makePhoneCall({ + phoneNumber: customerData.phoneNumber, + success: function () { + console.log('拨打电话成功'); + }, + fail: function () { + console.log('拨打电话失败'); + } + }); + } + }, + + // 分享功能 + onShareAppMessage: function () { + const { customerData } = this.data; + return { + title: `${customerData?.alias || '优秀客服'} - 鸡蛋贸易平台`, + path: `/pages/customer-service/detail/index?id=${customerData?.id}`, + imageUrl: '' + }; + } +}); diff --git a/pages/customer-service/detail/index.json b/pages/customer-service/detail/index.json index b8a7eb8..0e81cc4 100644 --- a/pages/customer-service/detail/index.json +++ b/pages/customer-service/detail/index.json @@ -1,9 +1,7 @@ { "navigationBarTitleText": "客服详情", - "navigationStyle": "custom", - "usingComponents": { - "custom-header": "../../components/custom-header/custom-header", - "service-card": "../../components/service-card/service-card", - "faq-item": "../../components/faq-item/faq-item" - } -} \ No newline at end of file + "navigationBarBackgroundColor": "#ffffff", + "navigationBarTextStyle": "black", + "backgroundColor": "#f8f8f8", + "usingComponents": {} +} diff --git a/pages/customer-service/detail/index.wxml b/pages/customer-service/detail/index.wxml index fecc3e9..893c478 100644 --- a/pages/customer-service/detail/index.wxml +++ b/pages/customer-service/detail/index.wxml @@ -1,65 +1,93 @@ + - - - + + + + 返回 + + 客服详情 + + - 客服详情 - - - - - - 💁 + + + + + + + 在线 + 离线 - - 客服小王 - 在线 + + + {{customerData.alias}} + {{customerData.score}} 鸡蛋分 + + {{customerData.projectName}} + {{customerData.managercompany}} - - - - 服务类型 - 在线客服 + + + + + + + 负责区域 + {{customerData.responsibleArea}} + + + 联系电话 + {{customerData.phoneNumber}} - - 服务时间 - 24小时在线 + + 工作经验 + 服务平台{{customerData.experience}} - - 专业领域 - 产品咨询、订单处理、售后支持 + + 服务规模 + 服务{{customerData.serviceCount}}家鸡场 - - - 联系方式 - - - + + + + + 专业技能 + + + {{item}} + - - - 常见问题 - - 如何查询订单状态? - > + + + + + 业绩数据 + + + {{customerData.purchaseCount}} + 累计采购鸡蛋(件) - - 如何申请退款? - > + + {{customerData.profitFarmCount}} + 累计服务鸡场(家) - - 物流配送时间是多久? - > + + {{customerData.profitIncreaseRate}}% + 平均盈利增长 - \ No newline at end of file + + + + + 💬 在线沟通 + + + 📞 电话联系 + + + diff --git a/pages/customer-service/detail/index.wxss b/pages/customer-service/detail/index.wxss index a84d263..82c5a70 100644 --- a/pages/customer-service/detail/index.wxss +++ b/pages/customer-service/detail/index.wxss @@ -1,180 +1,317 @@ +/* pages/customer-service/detail/index.wxss */ .container { - background-color: #f5f5f5; + padding-bottom: 100rpx; + background-color: #f8f8f8; min-height: 100vh; } -.service-detail-header { - background-color: #fff; +/* 顶部导航栏 */ +.nav-bar { display: flex; - align-items: center; justify-content: space-between; - padding: 16rpx 24rpx; - border-bottom: 1rpx solid #e8e8e8; - position: sticky; + align-items: center; + padding: 44rpx 30rpx 20rpx; + background-color: #fff; + border-bottom: 1rpx solid #f0f0f0; + position: fixed; top: 0; - z-index: 100; + left: 0; + right: 0; + z-index: 1000; + width: 100%; + box-sizing: border-box; } -.header-back, .header-placeholder { - width: 60rpx; - height: 60rpx; +.nav-left { + width: 80rpx; display: flex; - align-items: center; - justify-content: center; - font-size: 32rpx; - font-weight: bold; + justify-content: flex-start; } -.header-title { +.back-icon { font-size: 32rpx; + color: #333; + font-weight: normal; +} + +.nav-title { + font-size: 36rpx; font-weight: bold; color: #333; + flex: 1; + text-align: center; } -.service-detail-content { - padding: 20rpx; +.nav-right { + display: flex; + align-items: center; + gap: 30rpx; } -.service-info-section { +.share-icon { + font-size: 32rpx; + color: #333; +} + +/* 客服基本信息 */ +.info-section { background-color: #fff; - border-radius: 16rpx; - padding: 32rpx; + padding: 120rpx 30rpx 30rpx; margin-bottom: 20rpx; - box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); +} + +.header-info { display: flex; align-items: center; } -.service-avatar { - width: 120rpx; - height: 120rpx; - background-color: #f0f0f0; +.avatar-container { + width: 160rpx; + height: 160rpx; + margin-right: 30rpx; + position: relative; +} + +.avatar { + width: 100%; + height: 100%; border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 64rpx; - margin-right: 32rpx; + background-color: #f0f0f0; + border: 4rpx solid #f0f0f0; +} + +.online-indicator-large { + position: absolute; + bottom: 0; + right: 0; + background-color: #52c41a; + color: white; + font-size: 24rpx; + padding: 8rpx 20rpx; + border-radius: 20rpx; + border: 4rpx solid white; } -.service-basic-info { +.offline-indicator-large { + position: absolute; + bottom: 0; + right: 0; + background-color: #999; + color: white; + font-size: 24rpx; + padding: 8rpx 20rpx; + border-radius: 20rpx; + border: 4rpx solid white; +} + +.header-details { flex: 1; } -.service-name { - display: block; - font-size: 36rpx; +.name-score-row { + display: flex; + align-items: center; + margin-bottom: 12rpx; +} + +.name-large { + font-size: 40rpx; font-weight: bold; color: #333; + margin-right: 16rpx; +} + +.score-large { + font-size: 28rpx; + color: #fff; + background: linear-gradient(135deg, #ffb800, #ff7700); + padding: 6rpx 16rpx; + border-radius: 20rpx; +} + +.position { + font-size: 32rpx; + color: #666; margin-bottom: 8rpx; } -.service-status { - display: block; +.company-large { font-size: 28rpx; - color: #07C160; + color: #999; } -.service-details { - background-color: #fff; - border-radius: 16rpx; - padding: 24rpx; +/* 核心信息卡片 */ +.core-info-section { + padding: 0 30rpx; margin-bottom: 20rpx; - box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); } -.detail-item { +.info-card { + background-color: #fff; + border-radius: 24rpx; + padding: 30rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05); +} + +.info-item { display: flex; justify-content: space-between; align-items: center; - padding: 16rpx 0; + padding: 20rpx 0; border-bottom: 1rpx solid #f0f0f0; } -.detail-item:last-child { +.info-item:last-child { border-bottom: none; } -.detail-label { - font-size: 28rpx; +.info-label { + font-size: 30rpx; color: #666; } -.detail-value { - font-size: 28rpx; +.info-value { + font-size: 30rpx; color: #333; text-align: right; flex: 1; - margin-left: 40rpx; + margin-left: 30rpx; +} + +.phone-number { + color: #1890ff; } -.contact-section, .faq-section { +/* 专业技能标签 */ +.skills-section { background-color: #fff; - border-radius: 16rpx; - padding: 24rpx; + padding: 30rpx; margin-bottom: 20rpx; - box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); } .section-title { - display: block; font-size: 32rpx; font-weight: bold; color: #333; - margin-bottom: 24rpx; -} - -.contact-button { - display: block; - width: 100%; - background-color: #FF6B81; - color: #fff; - font-size: 32rpx; - font-weight: bold; - padding: 24rpx; - border-radius: 12rpx; - border: none; - margin-bottom: 16rpx; - line-height: normal; - height: auto; + margin-bottom: 20rpx; } -.contact-button:last-child { - margin-bottom: 0; +.skills-container { + display: flex; + flex-wrap: wrap; + gap: 16rpx; + padding-bottom: 10rpx; } -.contact-button.phone-button { - background-color: #07C160; +.skill-tag { + background-color: #f0f9ff; + color: #1890ff; + font-size: 26rpx; + padding: 12rpx 24rpx; + border-radius: 20rpx; + border: 1rpx solid #bae7ff; + transition: all 0.2s ease; } -.contact-button.email-button { - background-color: #1989fa; +.skill-tag:active { + background-color: #bae7ff; + transform: scale(0.98); } -.contact-button:hover { - opacity: 0.9; +/* 业绩数据 */ +.performance-section { + background-color: #fff; + padding: 30rpx; + margin-bottom: 120rpx; } -.faq-item { +.performance-cards { display: flex; justify-content: space-between; - align-items: center; - padding: 24rpx 0; - border-bottom: 1rpx solid #f0f0f0; + gap: 20rpx; } -.faq-item:last-child { - border-bottom: none; +.performance-card { + flex: 1; + background-color: #f9f9f9; + padding: 24rpx; + border-radius: 16rpx; + text-align: center; + transition: all 0.2s ease; + position: relative; + overflow: hidden; } -.faq-question { - font-size: 28rpx; +.performance-card:active { + transform: translateY(2rpx); + background-color: #f0f0f0; +} + +.performance-number { + font-size: 36rpx; + font-weight: bold; color: #333; + margin-bottom: 12rpx; +} + +.performance-number.profit-rate { + color: #52c41a; +} + +.performance-label { + font-size: 24rpx; + color: #666; + line-height: 1.4; +} + +/* 底部操作按钮 */ +.bottom-actions { + position: fixed; + bottom: 0; + left: 0; + right: 0; + display: flex; + background-color: #fff; + padding: 20rpx 30rpx; + border-top: 1rpx solid #f0f0f0; + gap: 20rpx; +} + +.action-button { flex: 1; + padding: 24rpx; + border-radius: 40rpx; + text-align: center; + font-size: 32rpx; + font-weight: 500; + transition: all 0.2s ease; + position: relative; + overflow: hidden; } -.faq-arrow { - font-size: 28rpx; - color: #999; - margin-left: 20rpx; -} \ No newline at end of file +.action-button:active { + transform: scale(0.98); + opacity: 0.9; +} + +.chat-button:active { + background-color: #096dd9; +} + +.call-button:active { + background-color: #389e0d; +} + +.chat-button { + background-color: #1890ff; + color: white; +} + +.call-button { + background-color: #52c41a; + color: white; +} + +.button-text { + font-size: 30rpx; +} diff --git a/pages/customer-service/index.js b/pages/customer-service/index.js index 0a057b0..c9b128f 100644 --- a/pages/customer-service/index.js +++ b/pages/customer-service/index.js @@ -1,55 +1,377 @@ // pages/customer-service/index.js +const api = require('../../utils/api'); Page({ + // 客服数据,将从后端动态获取 data: { - serviceList: [] + customerServices: [], + filteredServices: [], + searchKeyword: '', + selectedArea: '全部', + totalCount: 0, + onlineCount: 0 + }, + + // 获取客服列表的方法 + async fetchCustomerServices() { + try { + console.log('开始请求客服列表...'); + // 导入API工具并使用正确的请求方法 + const api = require('../../utils/api'); + + const res = await new Promise((resolve, reject) => { + wx.request({ + url: 'http://localhost:3003/api/managers', + 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 => ({ + 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: Math.floor(Math.random() * 20) + 980, // 随机生成分数 + isOnline: !!item.online, // 转换为布尔值 + responsibleArea: `${this.getRandomArea()}鸡蛋采购`, + experience: this.getRandomExperience(), + serviceCount: this.getRandomNumber(100, 300), + purchaseCount: this.getRandomNumber(10000, 30000), + profitIncreaseRate: this.getRandomNumber(10, 25), + profitFarmCount: this.getRandomNumber(50, 200), + skills: this.getRandomSkills() + })); + 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 []; + } }, - onLoad: function (options) { - this.loadServiceInfo(); + // 辅助函数:生成随机区域 + getRandomArea() { + const areas = ['华北区', '华东区', '华南区', '全国', '西南区', '西北区', '东北区']; + return areas[Math.floor(Math.random() * areas.length)]; }, - loadServiceInfo: function () { - // 模拟加载客服信息 - const serviceList = [ - { - id: 1, - type: 'phone', - name: '电话客服', - desc: '周一至周日 9:00-18:00', - number: '400-123-4567' - }, - { - id: 2, - type: 'online', - name: '在线客服', - desc: '24小时在线为您服务' - }, - { - id: 3, - type: 'email', - name: '邮箱客服', - desc: 'service@example.com' + // 辅助函数:生成随机工作经验 + 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 () { + // 加载客服列表 + this.loadCustomerServices(); + + // 启动定期刷新 + this.startPeriodicRefresh(); + + // 检查当前用户身份 + 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({ - serviceList: serviceList + filteredServices: filtered }); }, - startOnlineChat: function () { - // 跳转到在线聊天页面 - wx.showToast({ - title: '在线客服功能开发中', - icon: 'none' + 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'); + } + } + } catch (e) { + console.error('获取用户手机号失败:', e); + } + + console.log('当前用户手机号:', userPhone); + console.log('客服手机号:', service.phoneNumber); + + // 验证手机号 + if (!userPhone) { + wx.showToast({ + title: '请先登录获取手机号', + icon: 'none' + }); + return; + } + + // 显示加载提示 + wx.showLoading({ + title: '正在建立聊天...', + }); + + // 调用API添加聊天记录 + api.addChatRecord(userPhone, service.phoneNumber).then(res => { + console.log('添加聊天记录成功:', res); + // 隐藏加载提示 + wx.hideLoading(); + + // 确保使用managerId作为聊天对象的唯一标识符 + const chatUserId = service?.managerId || id; + // 跳转到聊天页面 + wx.navigateTo({ + url: `/pages/chat-detail/index?userId=${chatUserId}&userName=${encodeURIComponent(service?.alias || '')}&phone=${service?.phoneNumber || ''}&isManager=true` + }); + console.log('跳转到聊天页面:', { chatUserId, userName: service?.alias }); + }).catch(err => { + console.error('添加聊天记录失败:', err); + // 隐藏加载提示 + wx.hideLoading(); + wx.showToast({ + title: '建立聊天失败,请重试', + icon: 'none' + }); }); }, - sendEmail: function () { - // 打开邮件客户端 - 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; + wx.navigateTo({ + url: `/pages/customer-service/detail?id=${id}` + }); + }, + + onBack: function () { + wx.navigateBack(); } -}); \ No newline at end of file +}); diff --git a/pages/customer-service/index.json b/pages/customer-service/index.json index 8728543..a641449 100644 --- a/pages/customer-service/index.json +++ b/pages/customer-service/index.json @@ -1,3 +1,5 @@ { - "navigationBarTitleText": "客服中心" -} \ No newline at end of file + "navigationBarBackgroundColor": "#f8f8f8", + "navigationBarTextStyle": "black", + "usingComponents": {} +} diff --git a/pages/customer-service/index.wxml b/pages/customer-service/index.wxml index 47c86a5..7a36e93 100644 --- a/pages/customer-service/index.wxml +++ b/pages/customer-service/index.wxml @@ -1,40 +1,89 @@ + - - 客服中心 + + + + 返回 + + 客服列表 + + ⚙️ + - - - - - 📞 - - - 电话客服 - 周一至周日 9:00-18:00 - - + + + + + 🔍 + - - - - 💬 + + + 区域 + - - 在线客服 - 24小时在线为您服务 - - - - - - 📧 - - - 邮箱客服 - service@example.com + + + + + + + + + + 在线 + 离线 + + + + {{item.alias}} + {{item.score}} 鸡蛋分 + (在线) + + {{item.managercompany || '暂无公司信息'}} + {{item.managerdepartment}} · {{item.projectName}} + 负责区域:{{item.responsibleArea}} + 服务平台{{item.experience}} 服务{{item.serviceCount}}家鸡场 + + + + {{item.purchaseCount}} + 累计采购(件) + + | + + {{item.profitFarmCount}} + 服务盈利鸡场(家) + + | + + {{item.profitIncreaseRate}}% + 平均盈利增长 + + + + + + {{item}} + + +{{item.skills.length - 3}} + + + + + + 💬 + + + 📞 + + - + + + 👤 + 暂无匹配的经纪人 - \ No newline at end of file + diff --git a/pages/customer-service/index.wxss b/pages/customer-service/index.wxss index 35e174d..8477c4a 100644 --- a/pages/customer-service/index.wxss +++ b/pages/customer-service/index.wxss @@ -1,80 +1,383 @@ +/* pages/customer-service/index.wxss */ .container { - background-color: #f5f5f5; + padding-bottom: 100rpx; + background-color: #f8f8f8; min-height: 100vh; } -.service-header { - background-color: #fff; - padding: 20rpx; - border-bottom: 1rpx solid #e8e8e8; +/* 顶部导航栏 */ +.nav-bar { display: flex; + justify-content: space-between; align-items: center; - justify-content: center; + padding: 44rpx 30rpx 20rpx; + background-color: #fff; + border-bottom: 1rpx solid #f0f0f0; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + width: 100%; + box-sizing: border-box; +} + +.nav-left { + width: 80rpx; + display: flex; + justify-content: flex-start; +} + +.back-icon { + font-size: 32rpx; + color: #333; + font-weight: normal; } -.service-title { +.nav-title { font-size: 36rpx; font-weight: bold; color: #333; + flex: 1; + text-align: center; +} + +.nav-right { + display: flex; + align-items: center; + gap: 30rpx; } -.service-content { - padding: 20rpx; +.search-icon, .settings-icon { + font-size: 32rpx; + color: #333; } -.service-item { +/* 搜索区域 */ +.search-container { background-color: #fff; - border-radius: 12rpx; - padding: 24rpx; + padding: 20rpx 30rpx; + border-bottom: 10rpx solid #f8f8f8; + position: fixed; + top: 110rpx; + left: 0; + right: 0; + z-index: 999; + width: 100%; + box-sizing: border-box; +} + +.search-bar { + display: flex; + align-items: center; + background-color: #f5f5f5; + border-radius: 40rpx; + padding: 16rpx 24rpx; margin-bottom: 20rpx; - box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); + transition: all 0.3s ease; +} + +.search-bar:focus-within { + background-color: #e6f7ff; + box-shadow: 0 0 0 4rpx rgba(24, 144, 255, 0.1); +} + +.search-icon-small { + font-size: 28rpx; + color: #999; + margin-right: 16rpx; +} + +.search-input { + flex: 1; + font-size: 28rpx; + color: #333; + background: none; + padding: 0; +} + +.search-input::placeholder { + color: #999; +} + +.filter-area { display: flex; align-items: center; } -.service-icon { - width: 80rpx; - height: 80rpx; - border-radius: 50%; - background-color: #f0f0f0; +.area-picker { display: flex; align-items: center; - justify-content: center; + background-color: #f5f5f5; + padding: 12rpx 24rpx; + border-radius: 24rpx; + font-size: 28rpx; + color: #333; +} + +.picker-arrow { + margin-left: 8rpx; + font-size: 20rpx; + color: #999; +} + +/* 经纪人列表 */ +.broker-list { + background-color: #f8f8f8; + padding: 0 30rpx; + margin-top: 280rpx; /* 为固定导航和搜索区域留出空间 */ +} + +.broker-item { + background-color: #fff; + border-radius: 24rpx; + margin: 20rpx 0; + padding: 28rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05); + transition: all 0.2s ease; +} + +.broker-item:active { + transform: translateY(2rpx); + box-shadow: 0 1rpx 6rpx rgba(0, 0, 0, 0.03); + background-color: #fafafa; +} + +.broker-info { + display: flex; + margin-bottom: 24rpx; +} + +.avatar-container { + width: 100rpx; + height: 100rpx; margin-right: 24rpx; - font-size: 40rpx; + position: relative; +} + +.avatar { + width: 100%; + height: 100%; + border-radius: 50%; + background-color: #f0f0f0; + border: 2rpx solid #f0f0f0; +} + +.online-indicator { + position: absolute; + bottom: 0; + right: 0; + background-color: #52c41a; + color: white; + font-size: 18rpx; + padding: 4rpx 12rpx; + border-radius: 12rpx; + border: 2rpx solid white; } -.service-info { +.offline-indicator { + position: absolute; + bottom: 0; + right: 0; + background-color: #999; + color: white; + font-size: 18rpx; + padding: 4rpx 12rpx; + border-radius: 12rpx; + border: 2rpx solid white; +} + +.broker-details { flex: 1; + display: flex; + flex-direction: column; + justify-content: center; } -.service-name { - display: block; +.name-row { + display: flex; + align-items: center; + margin-bottom: 8rpx; + flex-wrap: wrap; +} + +.name { font-size: 32rpx; font-weight: bold; color: #333; - margin-bottom: 8rpx; + margin-right: 12rpx; } -.service-desc { - display: block; - font-size: 26rpx; +.score-text { + font-size: 24rpx; + color: #fff; + background: linear-gradient(135deg, #ffb800, #ff7700); + padding: 4rpx 12rpx; + border-radius: 12rpx; + margin-right: 8rpx; +} + +.online-status { + font-size: 22rpx; + color: #52c41a; +} + +.company { + font-size: 28rpx; color: #666; + margin-bottom: 6rpx; + line-height: 1.4; } -.call-button, .chat-button, .email-button { - padding: 12rpx 32rpx; - border-radius: 24rpx; +.department { + font-size: 26rpx; + color: #999; + margin-bottom: 6rpx; + line-height: 1.4; +} + +.area { + font-size: 26rpx; + color: #333; + margin-bottom: 6rpx; + line-height: 1.4; + font-weight: 500; +} + +.experience { + font-size: 24rpx; + color: #999; + margin-top: 8rpx; +} + +/* 专业技能标签预览 */ +.skills-preview { + display: flex; + flex-wrap: wrap; + gap: 10rpx; + margin-top: 12rpx; +} + +.skill-tag-small { + background-color: #f0f9ff; + color: #1890ff; + font-size: 22rpx; + padding: 8rpx 16rpx; + border-radius: 16rpx; + border: 1rpx solid #bae7ff; +} + +.skill-more { + background-color: #f5f5f5; + color: #999; + font-size: 22rpx; + padding: 8rpx 16rpx; + border-radius: 16rpx; + border: 1rpx solid #e0e0e0; +} + +/* 业绩数据统计样式 */ +.performance-stats { + display: flex; + justify-content: space-between; + margin-top: 16rpx; + padding-top: 16rpx; + border-top: 1rpx solid #f0f0f0; +} + +.stat-item { + flex: 1; + text-align: center; +} + +.stat-value { font-size: 28rpx; font-weight: bold; - background-color: #FF6B81; - color: #fff; - border: none; - margin: 0; - line-height: normal; - height: auto; + color: #333; + display: block; } -.call-button:hover, .chat-button:hover, .email-button:hover { - background-color: #FF526D; -} \ No newline at end of file +.stat-value.profit-rate { + color: #52c41a; +} + +.stat-label { + font-size: 22rpx; + color: #999; + margin-top: 4rpx; + display: block; +} + +.stat-divider { + color: #e0e0e0; + font-size: 24rpx; + margin: 0 10rpx; + display: flex; + align-items: center; + } + +.action-buttons { + display: flex; + justify-content: flex-end; + gap: 24rpx; + padding-top: 20rpx; + border-top: 1rpx solid #f0f0f0; +} + +.button-chat, .button-call { + width: 72rpx; + height: 72rpx; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + position: relative; + overflow: hidden; +} + +.button-chat { + background-color: #e6f7f0; +} + +.button-call { + background-color: #e6f0f7; +} + +.button-chat:active { + transform: scale(0.95); + opacity: 0.9; + background-color: #c3e6cb; +} + +.button-call:active { + transform: scale(0.95); + opacity: 0.9; + background-color: #b3d8ff; +} + +.button-icon { + font-size: 36rpx; +} + +/* 空状态 */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 100rpx 0; + background-color: #fff; + margin: 20rpx 0; + border-radius: 24rpx; +} + +.empty-state text:first-child { + font-size: 100rpx; + margin-bottom: 20rpx; +} + +.empty-text { + font-size: 28rpx; + color: #999; +} diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 9bb968f..d548f94 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -6481,9 +6481,92 @@ app.get('/api/online-stats', async (req, res) => { }); } }); - - +// REST API接口 - 获取客服列表 - 修改为按照用户需求:工位名为采购员且有电话号码 +app.get('/api/managers', async (req, res) => { + try { + // 查询userlogin数据库中的personnel表,获取工位为销售员且有电话号码的用户 + // 根据表结构选择所有需要的字段 + const [personnelData] = await sequelize.query( + 'SELECT id, managerId, managercompany, managerdepartment, organization, projectName, name, alias, phoneNumber, avatarUrl FROM userlogin.personnel WHERE projectName = ? AND phoneNumber IS NOT NULL AND phoneNumber != "" ORDER BY id ASC', + { replacements: ['销售员'] } + ); + + // 查询chat_online_status表获取客服在线状态(添加错误处理) + let onlineStatusData = []; + try { + const [statusResults] = await sequelize.query( + 'SELECT userId, is_online FROM chat_online_status WHERE type = 2', // type=2表示客服 + { type: sequelize.QueryTypes.SELECT } + ); + onlineStatusData = statusResults || []; + } catch (statusError) { + console.warn('获取在线状态失败(可能是表不存在):', statusError.message); + // 表不存在或查询失败时,使用空数组 + onlineStatusData = []; + } + + // 创建在线状态映射 + const onlineStatusMap = {}; + // 检查onlineStatusData是否存在,防止undefined调用forEach + if (Array.isArray(onlineStatusData)) { + onlineStatusData.forEach(status => { + onlineStatusMap[status.userId] = status.is_online === 1; + }); + } + + // 将获取的数据映射为前端需要的格式,添加online状态(综合考虑内存中的onlineManagers和数据库中的状态) + const isManagerOnline = (id, managerId) => { + // 转换ID为字符串以便正确比较 + const stringId = String(id); + const stringManagerId = managerId ? String(managerId) : null; + + console.log(`检查客服在线状态: id=${id}(${stringId}), managerId=${managerId}(${stringManagerId})`); + // 首先从内存中的onlineManagers检查(实时性更好) + if (onlineManagers && typeof onlineManagers.has === 'function') { + // 检查id或managerId是否在onlineManagers中 + if (onlineManagers.has(stringId) || (stringManagerId && onlineManagers.has(stringManagerId))) { + console.log(`客服在线(内存检查): id=${id}`); + return true; + } + } + + // 其次从数据库查询结果检查 + const dbStatus = onlineStatusMap[stringId] || (stringManagerId && onlineStatusMap[stringManagerId]) || false; + console.log(`客服在线状态(数据库): id=${id}, status=${dbStatus}`); + return dbStatus; + }; + + const managers = personnelData.map((person, index) => ({ + id: person.id, + managerId: person.managerId || `PM${String(index + 1).padStart(3, '0')}`, + managercompany: person.managercompany || '未知公司', + managerdepartment: person.managerdepartment || '采购部', + organization: person.organization || '采购组', + projectName: person.projectName || '采购员', + name: person.name || '未知', + alias: person.alias || person.name || '未知', + phoneNumber: person.phoneNumber || '', + avatar: person.avatarUrl || '', // 使用表中的avatarUrl字段 + online: isManagerOnline(person.id, person.managerId) // 综合检查在线状态 + })); + + res.status(200).json({ + success: true, + code: 200, + data: managers + }); + } catch (error) { + console.error('获取客服列表失败:', error); + res.status(500).json({ + success: false, + code: 500, + message: '获取客服列表失败: ' + error.message + }); + } +}); + + // 认证处理函数 async function handleAuth(ws, data) { @@ -7975,6 +8058,72 @@ app.post('/api/chat/list', async (req, res) => { } }); +// 新增:添加聊天记录到chat_list表 +app.post('/api/chat/add', async (req, res) => { + try { + const { user_phone, manager_phone } = req.body; + console.log('添加聊天记录 - user_phone:', user_phone, 'manager_phone:', manager_phone); + + if (!user_phone || !manager_phone) { + return res.status(400).json({ + success: false, + code: 400, + message: '用户手机号和业务员手机号不能为空' + }); + } + + // 检查chat_list表是否存在,如果不存在则创建 + try { + await sequelize.query( + `CREATE TABLE IF NOT EXISTS chat_list ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_phone VARCHAR(20) NOT NULL, + manager_phone VARCHAR(20) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX idx_user_phone (user_phone), + INDEX idx_manager_phone (manager_phone) + ) ENGINE=InnoDB;` + ); + console.log('✅ chat_list表检查/创建成功'); + } catch (createError) { + console.warn('创建chat_list表时出错(可能已存在):', createError.message); + } + + // 插入两条记录: + // 1. 用户手机号 -> 业务员手机号 + await sequelize.query( + 'INSERT INTO chat_list (user_phone, manager_phone) VALUES (?, ?)', + { replacements: [user_phone, manager_phone] } + ); + + // 2. 业务员手机号 -> 用户手机号 + await sequelize.query( + 'INSERT INTO chat_list (user_phone, manager_phone) VALUES (?, ?)', + { replacements: [manager_phone, user_phone] } + ); + + console.log('✅ 成功插入两条聊天记录'); + + res.status(200).json({ + success: true, + code: 200, + message: '聊天记录添加成功', + data: { + user_phone, + manager_phone + } + }); + } catch (error) { + console.error('添加聊天记录失败:', error); + res.status(500).json({ + success: false, + code: 500, + message: '添加聊天记录失败: ' + error.message + }); + } +}); + // 新增:获取业务员信息接口 - 根据手机号查询 app.post('/api/personnel/get', async (req, res) => { try { diff --git a/utils/api.js b/utils/api.js index 331da39..b5c68fe 100644 --- a/utils/api.js +++ b/utils/api.js @@ -924,6 +924,33 @@ module.exports = { return this.uploadProductWithRecursiveImages(uploadData, imageUrls); }, + // 添加聊天记录 - 为用户和客服创建双向聊天记录 + addChatRecord: function (user_phone, manager_phone) { + console.log('API.addChatRecord - user_phone:', user_phone, 'manager_phone:', manager_phone); + if (!user_phone || !manager_phone) { + return Promise.reject(new Error('用户手机号和客服手机号不能为空')); + } + + return request('/api/chat/add', 'POST', { + user_phone: user_phone, + manager_phone: manager_phone + }).then(res => { + console.log('添加聊天记录服务器响应:', res); + if (res && (res.success || res.code === 200)) { + console.log('添加聊天记录成功'); + return res; + } else { + console.error('添加聊天记录失败,服务器返回:', res); + let errorMessage = res && res.message ? res.message : '添加聊天记录失败'; + return Promise.reject(new Error(errorMessage)); + } + }).catch(err => { + console.error('添加聊天记录请求失败:', err); + console.error('错误详情:', { message: err.message, statusCode: err.statusCode, responseData: err.responseData }); + return Promise.reject(new Error('添加聊天记录失败,请稍后重试')); + }); + }, + // 上传带图片的商品 - 改进版,确保所有图片都被实际上传到服务器 uploadProductWithImages: function (productData, imageUrls) { console.log('===== 开始上传带图片的商品 =====');