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.

839 lines
28 KiB

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');
}
}
// 增加用户估价点击次数(进入页面时自动增加)
const API = require('../../utils/api');
API.incrementAppraisalNum().then(res => {
console.log('增加估价次数成功:', res);
}).catch(err => {
console.error('增加估价次数失败:', err);
// 即使失败也不影响主流程
});
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 => {
let category = String(product.category).trim();
// 将"白壳"替换为"土鸡蛋"
if (category === '白壳') {
category = '土鸡蛋';
}
return category;
}))];
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 });
// 尝试从本地存储中获取分类数据
let categories = wx.getStorageSync('evaluate2Categories') || [];
// 处理分类数据,将"白壳"替换为"土鸡蛋"
categories = categories.map(category => {
if (category === '白壳') {
return '土鸡蛋';
}
return category;
});
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);
// 增加用户估价点击次数
const API = require('../../utils/api');
API.incrementAppraisalNum().then(res => {
console.log('增加估价次数成功:', res);
}).catch(err => {
console.error('增加估价次数失败:', err);
// 即使失败也不影响主流程
});
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;
}
// 记录用户点击分类的踪迹
const API = require('../../utils/api');
const traceData = {
action: 'click_category',
category: category,
timestamp: new Date().toISOString(),
page: 'evaluate2/one'
};
// 调用用户踪迹记录API
API.addUserTrace(traceData).then(res => {
console.log('用户分类点击记录成功:', res);
}).catch(err => {
console.error('用户分类点击记录失败:', err);
// 即使记录失败,也不影响主流程
});
1 month ago
// 跳过合作状态检查,直接跳转到商品列表页面
// 跳转到商品列表页面,并传递分类参数
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://my-supplier-photos.oss-cn-chengdu.aliyuncs.com/products/%E6%B5%B7%E8%93%9D%E7%81%B0/image/7a2a8a17a83ba4d3d4270828531e2041.jpeg',
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);
1 month ago
// 跳过合作状态检查,不再显示入驻提示
}
} 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);
}
});
},
// 分享配置
onShareAppMessage() {
return {
title: '专业的估价平台,专为估蛋而生',
imageUrl: 'https://my-supplier-photos.oss-cn-chengdu.aliyuncs.com/products/%E7%BD%97%E6%9B%BC%E7%81%B0/image/c00cbcbfd12d747b44621701aed2ae02.jpeg',
path: '/pages/evaluate2/one'
};
},
// 朋友圈分享配置
onShareTimeline() {
return {
title: '专业的估价平台,专为估蛋而生',
imageUrl: 'https://my-supplier-photos.oss-cn-chengdu.aliyuncs.com/products/%E7%BD%97%E6%9B%BC%E7%81%B0/image/c00cbcbfd12d747b44621701aed2ae02.jpeg',
query: ''
};
}
});