Page({ data: { productName: '', specifications: [], loading: false, error: '', categories: [], selectedCategory: '', showOneKeyLoginModal: false // 是否显示登录弹窗 }, onLoad(options) { let productName = ''; // 首先检查URL参数 if (options.productName) { productName = options.productName; } else { // 然后检查本地存储(用于wx.switchTab导航) productName = wx.getStorageSync('selectedProductName') || ''; // 清除本地存储中的商品名称,避免影响下次进入 if (productName) { wx.removeStorageSync('selectedProductName'); } } if (productName) { this.setData({ productName: productName }); this.loadSpecifications(productName); } else { // 如果没有商品名称参数,加载所有商品数据并计算 this.loadAllData(); } }, // 下拉刷新 onPullDownRefresh() { console.log('开始下拉刷新'); this.loadAllData(); }, // 加载所有商品数据并计算 loadAllData() { this.setData({ loading: true, categories: [] // 清空分类数据,确保加载时只显示加载状态 }); const api = require('../../utils/api'); // 使用正确的参数调用getProducts方法 api.getProducts(1, 1000, 'all', '').then(result => { console.log('API返回结果:', result); // 从返回对象中提取products数组,如果不存在则使用空数组 const products = result.products || []; console.log('提取的products数组:', products); console.log('products数组长度:', products.length); // 存储原始商品数据到本地存储 wx.setStorageSync('allProducts', products); // 过滤出有有效category字段的商品(忽略空字符串和仅包含空格的分类) const productsWithCategory = products.filter(product => { if (!product.category) return false; const categoryStr = String(product.category).trim(); return categoryStr !== ''; }); console.log('有有效category的商品:', productsWithCategory); console.log('有有效category的商品数量:', productsWithCategory.length); // 提取所有分类(去除前后空格) const categories = [...new Set(productsWithCategory.map(product => { return String(product.category).trim(); }))]; console.log('提取的分类数组:', categories); console.log('分类数量:', categories.length); // 存储分类数据到本地存储 wx.setStorageSync('evaluate2Categories', categories); // 计算每个分类下的商品名称列表 const categoryProductsMap = {}; categories.forEach(category => { // 过滤出该分类下的商品 const categoryProducts = productsWithCategory.filter(product => { const productCategory = String(product.category).trim(); return productCategory === category; }); // 提取商品名称(去除前后空格,去重) const productNames = [...new Set(categoryProducts.map(product => { // 尝试从多个字段获取商品名称 const nameFields = [product.productName, product.name, product.product]; for (const field of nameFields) { if (field) { const trimmedName = String(field).trim(); if (trimmedName !== '') { return trimmedName; } } } return ''; }).filter(name => name !== ''))]; categoryProductsMap[category] = productNames; }); // 存储分类商品映射到本地存储 wx.setStorageSync('evaluate2CategoryProductsMap', categoryProductsMap); // 计算每个商品的规格和价格信息 const productSpecsMap = {}; products.forEach(product => { // 尝试从多个字段获取商品名称 const nameFields = [product.productName, product.name, product.product]; let productName = ''; for (const field of nameFields) { if (field) { const trimmedName = String(field).trim(); if (trimmedName !== '') { productName = trimmedName; break; } } } if (productName) { if (!productSpecsMap[productName]) { productSpecsMap[productName] = []; } // 提取规格和价格 const specStr = (product.specification || product.spec || '').trim(); const price = product.price || ''; if (specStr && price) { productSpecsMap[productName].push({ specification: specStr, price: price }); } } }); // 存储商品规格映射到本地存储 wx.setStorageSync('evaluate2ProductSpecsMap', productSpecsMap); // 加载分类数据到页面 this.setData({ categories: categories, loading: false }); // 结束下拉刷新 wx.stopPullDownRefresh(); }).catch(err => { console.error('获取商品数据失败:', err); this.setData({ error: '获取商品数据失败,请稍后重试', loading: false }); // 结束下拉刷新 wx.stopPullDownRefresh(); }); }, // 加载商品分类数据 loadCategories() { this.setData({ loading: true }); // 尝试从本地存储中获取分类数据 const categories = wx.getStorageSync('evaluate2Categories') || []; if (categories.length > 0) { // 如果本地存储中有分类数据,直接使用 console.log('从本地存储获取分类数据:', categories); this.setData({ categories: categories, loading: false }); } else { // 如果本地存储中没有分类数据,重新加载所有数据 this.loadAllData(); } }, loadSpecifications(productName) { if (!productName) { this.setData({ error: '请先选择商品', loading: false }); return; } this.setData({ loading: true, specifications: [] }); // 直接从本地存储获取商品数据,避免重复请求 const localGoods = wx.getStorageSync('goods') || []; console.log('从本地存储获取的商品数量:', localGoods.length); if (localGoods.length > 0) { this.processSpecifications(productName, localGoods); } else { // 如果本地没有数据,再请求服务器 const api = require('../../utils/api'); // 使用正确的参数调用getProducts方法 api.getProducts(1, 1000, 'all', '').then(result => { // 从返回对象中提取products数组 const products = result.products || []; this.processSpecifications(productName, products); }).catch(err => { console.error('获取规格失败:', err); this.setData({ error: '获取规格失败,请稍后重试', loading: false }); }); } }, // 解析规格,提取类型(净重/毛重)和数值范围 parseSpecification(spec) { const weightMatch = spec.match(/(净重|毛重)(\d+)-(\d+)/); if (weightMatch) { const type = weightMatch[1]; // 净重或毛重 const min = parseFloat(weightMatch[2]); const max = parseFloat(weightMatch[3]); const avg = (min + max) / 2; return { type: type, min: min, max: max, avg: avg }; } return null; }, processSpecifications(productName, products) { console.log('处理的商品数据数量:', products.length); console.log('当前处理的商品名称:', productName); // 检查products是否为空 if (!products || products.length === 0) { console.error('商品数据为空'); this.setData({ error: '商品数据为空', loading: false }); return; } // 过滤出当前商品名称的所有商品 const filteredProducts = products.filter(product => { const match = product.productName === productName; console.log('商品:', product.productName, '规格:', product.specification, '价格:', product.price, '匹配:', match); return match; }); console.log('过滤后的商品数量:', filteredProducts.length); console.log('过滤后的商品详情:', filteredProducts); // 检查filteredProducts是否为空 if (filteredProducts.length === 0) { console.error('未找到商品名称为"' + productName + '"的商品'); this.setData({ error: '未找到对应商品名称的商品', loading: false }); return; } // 提取规格和价格,处理可能的空值和空格 const specPriceMap = {}; filteredProducts.forEach((product, productIndex) => { const specStr = (product.specification || product.spec || '').trim(); const price = product.price || ''; console.log(`处理第${productIndex + 1}个商品: 规格字符串='${specStr}', 价格字符串='${price}'`); // 价格为空的不参与计算 if (!price || price.trim() === '') { console.log(`商品价格为空,跳过处理`); return; } if (specStr.length > 0) { // 处理逗号分隔的多个规格,确保每个规格都被正确分割 // 首先按逗号分割 let specs = specStr.split(',').map(spec => spec.trim()).filter(spec => spec.length > 0); // 进一步处理规格,确保每个规格都是独立的 const processedSpecs = []; specs.forEach(spec => { // 检查规格是否包含多个规格(例如:"净重29-30,净重31-32") if (spec.includes(',')) { // 按中文逗号分割 const subSpecs = spec.split(',').map(s => s.trim()).filter(s => s.length > 0); processedSpecs.push(...subSpecs); } else { processedSpecs.push(spec); } }); specs = processedSpecs; // 处理逗号分隔的多个价格 const prices = (price || '').split(',').map(p => p.trim()).filter(p => p && p.trim() !== ''); console.log(`规格数组:`, specs); console.log(`价格数组:`, prices); // 价格为空的不参与计算 if (prices.length === 0) { console.log(`价格数组为空,跳过处理`); return; } // 将规格和价格配对 specs.forEach((spec, index) => { if (spec.length > 0) { // 确保价格索引不超出范围 const priceIndex = index % prices.length; const matchedPrice = prices[priceIndex] || ''; console.log(`规格'${spec}' 配对价格: '${matchedPrice}'`); // 只有当价格不为空时才添加该规格 if (matchedPrice && matchedPrice.trim() !== '') { // 收集相同规格的所有价格,以便计算平均值 if (!specPriceMap[spec]) { specPriceMap[spec] = []; } specPriceMap[spec].push(matchedPrice); } else { console.log(`规格'${spec}' 价格为空,不添加`); } } }); } }); // 转换为规格对象数组 const specifications = Object.keys(specPriceMap).map(spec => { const prices = specPriceMap[spec]; console.log(`规格'${spec}' 的所有原始价格:`, prices); // 解析规格 const specInfo = this.parseSpecification(spec); // 处理每个价格 const processedPrices = prices.map(price => { if (!price || price.trim() === '' || isNaN(parseFloat(price))) { return 0; } const priceValue = parseFloat(price); console.log(`处理价格: ${priceValue}`); // 价格<10的需要按照公式计算 if (priceValue < 10 && specInfo) { console.log(`价格 ${priceValue} < 10,按照公式计算`); if (specInfo.type === '净重') { // 净重:规格平均值 × 价格 return specInfo.avg * priceValue; } else if (specInfo.type === '毛重') { // 毛重:(规格平均值 - 5) × 价格 return (specInfo.avg - 5) * priceValue; } } // 价格>=10的直接使用 return priceValue; }).filter(price => price > 0); // 过滤掉0值 console.log(`规格'${spec}' 处理后的价格:`, processedPrices); // 计算处理后价格的平均值 let finalPrice = 0; let finalPriceText = ''; if (processedPrices.length > 0) { const sum = processedPrices.reduce((acc, price) => acc + price, 0); finalPrice = sum / processedPrices.length; finalPriceText = finalPrice.toFixed(2); console.log(`规格'${spec}' 处理后价格的平均值: ${finalPriceText} (基于 ${processedPrices.length} 个价格)`); } else { console.log(`规格'${spec}' 没有有效价格`); } const specObj = { name: spec, price: finalPriceText, priceText: finalPriceText, finalPrice: finalPrice, finalPriceText: finalPriceText }; console.log('创建的规格对象:', specObj); return specObj; }); console.log('提取的规格和价格:', specifications); // 对规格进行排序 specifications.sort((a, b) => { // 解析两个规格 const specA = this.parseSpecification(a.name); const specB = this.parseSpecification(b.name); // 如果有一个规格解析失败,保持原顺序 if (!specA || !specB) { return 0; } // 1. 按类型排序:净重在前,毛重在后 if (specA.type !== specB.type) { return specA.type === '净重' ? -1 : 1; } // 2. 按规格最小值排序:从小到大 return specA.min - specB.min; }); console.log('排序后的规格:', specifications); this.setData({ specifications: specifications, error: '', // 清除之前的错误 loading: false }); }, // 跳转到规格详情页面 goToSpecDetail(e) { const specItem = e.currentTarget.dataset.spec; console.log('点击的规格项:', specItem); console.log('传递的价格:', specItem.finalPriceText); wx.navigateTo({ url: `/pages/evaluate1/spec-detail?productName=${encodeURIComponent(this.data.productName)}&specification=${encodeURIComponent(specItem.name)}&price=${encodeURIComponent(specItem.finalPriceText)}` }); }, // 返回上一页 goBack() { wx.navigateBack(); }, // 返回商品列表页面 goBackToProductList() { wx.redirectTo({ url: '/pages/evaluate1/product-list' }); }, // 选择分类,跳转到商品列表页面 selectCategory(e) { const category = e.currentTarget.dataset.category; console.log('选择分类:', category); // 检查用户登录状态 const openid = wx.getStorageSync('openid'); const userId = wx.getStorageSync('userId'); if (!openid || !userId) { // 用户未登录,显示登录弹窗 console.log('用户未登录,显示登录弹窗'); this.setData({ showOneKeyLoginModal: true }); return; } // 跳过合作状态检查,直接跳转到商品列表页面 // 跳转到商品列表页面,并传递分类参数 wx.redirectTo({ url: `/pages/evaluate2/product-list?category=${encodeURIComponent(category)}` }); }, // 关闭登录弹窗 closeOneKeyLoginModal() { this.setData({ showOneKeyLoginModal: false }); }, // 处理登录授权 async onGetPhoneNumber(e) { console.log('收到手机号授权事件:', e.detail); // 关闭手机号授权弹窗 this.setData({ showOneKeyLoginModal: false }); // 用户点击拒绝授权 if (e.detail.errMsg === 'getPhoneNumber:fail user deny') { wx.showToast({ title: '需要授权手机号才能使用', icon: 'none', duration: 2000 }); return; } // 处理没有权限的情况 if (e.detail.errMsg === 'getPhoneNumber:fail no permission') { wx.showToast({ title: '当前环境无法获取手机号权限', icon: 'none', duration: 3000 }); return; } // 检查是否已经登录,避免重复授权 const existingOpenid = wx.getStorageSync('openid'); const existingUserId = wx.getStorageSync('userId'); const existingUserInfo = wx.getStorageSync('userInfo'); if (existingOpenid && existingUserId && existingUserInfo && existingUserInfo.phoneNumber) { console.log('用户已登录且手机号有效,登录流程已完成'); wx.showToast({ title: '您已登录', icon: 'success', duration: 1500 }); return; } wx.showLoading({ title: '登录中...', mask: true }); try { if (e.detail.errMsg === 'getPhoneNumber:ok') { // 用户同意授权,实际处理授权流程 console.log('用户同意授权获取手机号'); // 1. 先执行微信登录获取code const loginRes = await new Promise((resolve, reject) => { wx.login({ success: resolve, fail: reject }); }); if (!loginRes.code) { throw new Error('获取登录code失败'); } console.log('获取登录code成功:', loginRes.code); // 2. 使用code换取openid const API = require('../../utils/api'); const openidRes = await API.getOpenid(loginRes.code); // 改进错误处理逻辑,更宽容地处理服务器返回格式 let openid = null; let userId = null; console.log('openidRes完整响应:', JSON.stringify(openidRes)); if (openidRes && typeof openidRes === 'object') { // 适配服务器返回格式:{success: true, code: 200, message: '获取openid成功', data: {openid, userId}} if (openidRes.data && typeof openidRes.data === 'object') { console.log('识别到标准服务器返回格式,从data字段提取信息'); openid = openidRes.data.openid || openidRes.data.OpenID || null; userId = openidRes.data.userId || null; } else { // 尝试从响应对象中直接提取openid console.log('尝试从根对象直接提取openid'); openid = openidRes.openid || openidRes.OpenID || null; userId = openidRes.userId || null; } } if (!openid) { console.error('无法从服务器响应中提取openid,完整响应:', JSON.stringify(openidRes)); throw new Error(`获取openid失败: 服务器返回数据格式可能不符合预期`); } console.log('获取openid成功:', openid); // 3. 存储openid和session_key wx.setStorageSync('openid', openid); // 从服务器返回中获取session_key if (openidRes && openidRes.session_key) { wx.setStorageSync('sessionKey', openidRes.session_key); } else if (openidRes && openidRes.data && openidRes.data.session_key) { wx.setStorageSync('sessionKey', openidRes.data.session_key); } // 优先使用从服务器响应data字段中提取的userId if (userId) { wx.setStorageSync('userId', userId); console.log('使用从服务器data字段提取的userId:', userId); } else if (openidRes && openidRes.userId) { wx.setStorageSync('userId', openidRes.userId); console.log('使用服务器根对象中的userId:', openidRes.userId); } else { // 生成临时userId const tempUserId = 'user_' + Date.now(); wx.setStorageSync('userId', tempUserId); console.log('生成临时userId:', tempUserId); } // 4. 上传手机号加密数据到服务器解密 const phoneData = { ...e.detail, openid: openid }; console.log('准备上传手机号加密数据到服务器'); const phoneRes = await API.uploadPhoneNumberData(phoneData); // 改进手机号解密结果的处理逻辑 if (!phoneRes || (!phoneRes.success && !phoneRes.phoneNumber)) { // 如果服务器返回格式不标准但包含手机号,也接受 if (phoneRes && phoneRes.phoneNumber) { console.warn('服务器返回格式可能不符合预期,但成功获取手机号'); } else { throw new Error('获取手机号失败: ' + (phoneRes && phoneRes.message ? phoneRes.message : '未知错误')); } } // 检查是否有手机号冲突 const hasPhoneConflict = phoneRes.phoneNumberConflict || false; const isNewPhone = phoneRes.isNewPhone || true; const phoneNumber = phoneRes.phoneNumber || null; // 如果有手机号冲突且没有返回手机号,使用实际返回的手机号 const finalPhoneNumber = phoneNumber; console.log('手机号解密结果:', { phoneNumber: finalPhoneNumber, hasPhoneConflict: hasPhoneConflict, isNewPhone: isNewPhone }); // 5. 获取用户微信名称和头像 let userProfile = null; try { userProfile = await new Promise((resolve, reject) => { wx.getUserProfile({ desc: '用于完善会员资料', success: resolve, fail: reject }); }); console.log('获取用户信息成功:', userProfile); } catch (err) { console.warn('获取用户信息失败:', err); // 如果获取失败,使用默认值 } // 6. 创建用户信息 const tempUserInfo = { name: userProfile ? (userProfile.userInfo.name || userProfile.userInfo.nickName) : '微信用户', // 获取微信头像失败时使用微信默认头像 avatarUrl: userProfile ? userProfile.userInfo.avatarUrl : 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0', gender: userProfile ? userProfile.userInfo.gender : 0, country: userProfile ? userProfile.userInfo.country : '', province: userProfile ? userProfile.userInfo.province : '', city: userProfile ? userProfile.userInfo.city : '', language: userProfile ? userProfile.userInfo.language : 'zh_CN', phoneNumber: finalPhoneNumber }; // 7. 保存用户信息 const storedUserId = wx.getStorageSync('userId'); const users = wx.getStorageSync('users') || {}; const currentUserType = users[storedUserId] && users[storedUserId].type ? users[storedUserId].type : 'buyer'; console.log('用户身份类型:', currentUserType); // 8. 保存用户信息到本地和服务器 console.log('开始保存用户信息...'); await this.saveUserInfo(tempUserInfo, currentUserType); console.log('用户信息保存完成'); wx.hideLoading(); // 根据服务器返回的结果显示不同的提示 if (phoneRes && phoneRes.phoneNumberConflict) { wx.showModal({ title: '登录成功', content: '您的手机号已被其他账号绑定', showCancel: false, confirmText: '我知道了', success(res) { if (res.confirm) { console.log('用户点击了我知道了'); } } }); } // 1. 登录成功提示 wx.showToast({ title: '登录成功', icon: 'success', duration: 1500 }); // 2. 从服务器获取最新用户信息 const userInfoRes = await API.getUserInfo(openid); // 3. 获取服务器返回的partnerstatus const serverUserInfo = userInfoRes.data; const partnerStatus = serverUserInfo.partnerstatus || 'pending'; // 4. 更新本地缓存 const localUserInfo = wx.getStorageSync('userInfo') || {}; const updatedUserInfo = { ...localUserInfo, partnerstatus: partnerStatus }; wx.setStorageSync('userInfo', updatedUserInfo); // 跳过合作状态检查,不再显示入驻提示 } } catch (error) { wx.hideLoading(); console.error('登录失败:', error); wx.showToast({ title: '登录失败,请重试', icon: 'none', duration: 2000 }); } }, // 保存用户信息 async saveUserInfo(userInfo, userType = 'buyer') { return new Promise(async (resolve, reject) => { try { const storedUserId = wx.getStorageSync('userId'); const users = wx.getStorageSync('users') || {}; // 更新用户信息 users[storedUserId] = { ...users[storedUserId], ...userInfo, type: userType, lastLogin: new Date().toISOString() }; // 保存到本地存储 wx.setStorageSync('users', users); wx.setStorageSync('userInfo', userInfo); // 上传用户信息到服务器 const API = require('../../utils/api'); const submitData = { openid: wx.getStorageSync('openid'), userId: storedUserId, ...userInfo, type: userType }; await API.request('/api/user/update', 'POST', submitData).then(res => { console.log('用户信息上传成功:', res); resolve({ success: true, message: '用户信息保存成功' }); }).catch(err => { console.error('用户信息上传失败:', err); // 即使服务器上传失败,也继续流程,只在本地保存 resolve({ success: false, message: '本地保存成功,服务器同步失败' }); }); } catch (error) { console.error('保存用户信息失败:', error); reject(error); } }); } });