|
|
@ -1,18 +1,287 @@ |
|
|
// pages/compare_price/index.js
|
|
|
// pages/compare_price/index.js
|
|
|
const API = require('../../utils/api.js'); |
|
|
const API = require('../../utils/api.js'); |
|
|
|
|
|
|
|
|
|
|
|
// 媒体类型判断函数
|
|
|
|
|
|
function isVideoUrl(url) { |
|
|
|
|
|
if (!url || typeof url !== 'string') { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
// 转换为小写,确保大小写不敏感
|
|
|
|
|
|
const lowerUrl = url.toLowerCase(); |
|
|
|
|
|
// 支持的视频格式
|
|
|
|
|
|
const videoExtensions = ['.mp4', '.mov', '.avi', '.wmv', '.flv', '.webm', '.m4v', '.3gp']; |
|
|
|
|
|
// 检查URL是否以视频扩展名结尾
|
|
|
|
|
|
for (const ext of videoExtensions) { |
|
|
|
|
|
if (lowerUrl.endsWith(ext)) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 预处理媒体URL,返回包含type字段的媒体对象数组
|
|
|
|
|
|
function processMediaUrls(urls) { |
|
|
|
|
|
if (!urls || !Array.isArray(urls)) { |
|
|
|
|
|
return []; |
|
|
|
|
|
} |
|
|
|
|
|
return urls.map(url => { |
|
|
|
|
|
return { |
|
|
|
|
|
url: url, |
|
|
|
|
|
type: isVideoUrl(url) ? 'video' : 'image' |
|
|
|
|
|
}; |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
Page({ |
|
|
Page({ |
|
|
data: { |
|
|
data: { |
|
|
// 页面数据
|
|
|
// 页面数据
|
|
|
showTips: true, |
|
|
showTips: true, |
|
|
goods: [], |
|
|
goods: [], |
|
|
loading: false, |
|
|
loading: false, |
|
|
selectedOption: '' |
|
|
selectedOption: '', |
|
|
|
|
|
selectedCategory: '', |
|
|
|
|
|
selectedSpec: '' |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
onLoad: function (options) { |
|
|
onLoad: function (options) { |
|
|
// 页面加载
|
|
|
// 页面加载
|
|
|
console.log('对比价格页面加载'); |
|
|
console.log('对比价格页面加载,接收参数:', options); |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有传递过来的商品数据
|
|
|
|
|
|
if (options.goodsData) { |
|
|
|
|
|
try { |
|
|
|
|
|
// 解析传递过来的商品数据
|
|
|
|
|
|
const goodsData = JSON.parse(decodeURIComponent(options.goodsData)); |
|
|
|
|
|
console.log('解析得到的商品数据:', goodsData); |
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
this.setData({ |
|
|
|
|
|
loading: true |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 提取选择的种类和规格
|
|
|
|
|
|
const selectedCategory = goodsData.category || ''; |
|
|
|
|
|
const selectedSpec = goodsData.selectedSpec || null; |
|
|
|
|
|
const specWeight = selectedSpec ? selectedSpec.weightSpec.trim() : ''; |
|
|
|
|
|
|
|
|
|
|
|
console.log('选择的种类:', selectedCategory); |
|
|
|
|
|
console.log('选择的规格:', selectedSpec); |
|
|
|
|
|
|
|
|
|
|
|
// 保存选择的种类和规格到页面数据
|
|
|
|
|
|
this.setData({ |
|
|
|
|
|
selectedCategory: selectedCategory, |
|
|
|
|
|
selectedSpec: specWeight |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 调用 API 获取符合条件的商品
|
|
|
|
|
|
API.getProducts(1, 20, 'all', '') |
|
|
|
|
|
.then(res => { |
|
|
|
|
|
console.log('获取商品列表成功:', res); |
|
|
|
|
|
console.log('选择的种类:', selectedCategory); |
|
|
|
|
|
console.log('选择的规格:', specWeight); |
|
|
|
|
|
|
|
|
|
|
|
let filteredGoods = []; |
|
|
|
|
|
if (res && res.products) { |
|
|
|
|
|
console.log('原始商品数量:', res.products.length); |
|
|
|
|
|
// 过滤商品
|
|
|
|
|
|
filteredGoods = res.products.filter(item => { |
|
|
|
|
|
// 1. 检查商品状态和价格
|
|
|
|
|
|
if (item.status !== 'published' || item.price === null || item.price === undefined) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 2. 过滤种类
|
|
|
|
|
|
if (selectedCategory && selectedCategory !== '全部' && item.category !== selectedCategory) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 3. 过滤规格
|
|
|
|
|
|
if (specWeight) { |
|
|
|
|
|
// 检查多个可能存储重量信息的字段
|
|
|
|
|
|
const fieldsToCheck = [ |
|
|
|
|
|
item.specification, |
|
|
|
|
|
item.grossWeight, |
|
|
|
|
|
item.weightQuantityData, |
|
|
|
|
|
item.spec // 检查spec字段
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
let hasMatchingSpec = false; |
|
|
|
|
|
for (const field of fieldsToCheck) { |
|
|
|
|
|
if (!field) continue; |
|
|
|
|
|
|
|
|
|
|
|
if (typeof field === 'string') { |
|
|
|
|
|
// 处理字符串格式的规格数据
|
|
|
|
|
|
console.log('检查字符串规格:', field, '是否包含', specWeight); |
|
|
|
|
|
// 处理逗号分隔的规格字符串
|
|
|
|
|
|
const specs = field.split(/[,,、]/).map(s => s.trim()); |
|
|
|
|
|
if (specs.some(spec => spec.includes(specWeight))) { |
|
|
|
|
|
hasMatchingSpec = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (Array.isArray(field)) { |
|
|
|
|
|
// 处理数组格式的规格数据
|
|
|
|
|
|
console.log('检查数组规格:', field); |
|
|
|
|
|
if (field.some(spec => { |
|
|
|
|
|
if (typeof spec === 'string') { |
|
|
|
|
|
console.log('检查数组元素(字符串):', spec, '是否包含', specWeight); |
|
|
|
|
|
return spec.includes(specWeight); |
|
|
|
|
|
} else if (typeof spec === 'object') { |
|
|
|
|
|
// 检查对象格式的规格数据
|
|
|
|
|
|
const specStr = spec.weightSpec || spec.display || spec.spec || ''; |
|
|
|
|
|
console.log('检查数组元素(对象):', specStr, '是否包含', specWeight); |
|
|
|
|
|
return specStr.includes(specWeight); |
|
|
|
|
|
} |
|
|
|
|
|
return false; |
|
|
|
|
|
})) { |
|
|
|
|
|
hasMatchingSpec = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (typeof field === 'object') { |
|
|
|
|
|
// 处理对象格式的规格数据
|
|
|
|
|
|
console.log('检查对象规格:', field); |
|
|
|
|
|
const specStr = field.weightSpec || field.display || field.spec || ''; |
|
|
|
|
|
console.log('检查对象规格值:', specStr, '是否包含', specWeight); |
|
|
|
|
|
if (specStr.includes(specWeight)) { |
|
|
|
|
|
hasMatchingSpec = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果没有找到匹配的规格,尝试进行更宽松的匹配
|
|
|
|
|
|
if (!hasMatchingSpec) { |
|
|
|
|
|
console.log('尝试更宽松的匹配...'); |
|
|
|
|
|
// 提取规格中的数字部分进行匹配
|
|
|
|
|
|
const weightNum = specWeight.replace(/[^0-9-]/g, ''); |
|
|
|
|
|
console.log('提取的重量数字:', weightNum); |
|
|
|
|
|
|
|
|
|
|
|
for (const field of fieldsToCheck) { |
|
|
|
|
|
if (!field) continue; |
|
|
|
|
|
|
|
|
|
|
|
if (typeof field === 'string') { |
|
|
|
|
|
if (field.includes(weightNum)) { |
|
|
|
|
|
hasMatchingSpec = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (Array.isArray(field)) { |
|
|
|
|
|
if (field.some(spec => { |
|
|
|
|
|
const specStr = typeof spec === 'string' ? spec : (spec.weightSpec || spec.display || ''); |
|
|
|
|
|
return specStr.includes(weightNum); |
|
|
|
|
|
})) { |
|
|
|
|
|
hasMatchingSpec = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!hasMatchingSpec) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
}); |
|
|
|
|
|
console.log('过滤后的商品数量:', filteredGoods.length); |
|
|
|
|
|
console.log('过滤后的商品:', filteredGoods); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理商品数据
|
|
|
|
|
|
const processedGoods = filteredGoods.map(item => { |
|
|
|
|
|
// 首先清理 imageUrls 字段(如果存在)
|
|
|
|
|
|
if (item.imageUrls && Array.isArray(item.imageUrls)) { |
|
|
|
|
|
item.imageUrls = item.imageUrls.map(url => { |
|
|
|
|
|
return url.trim().replace(/[`]/g, ''); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 使用processMediaUrls函数处理媒体数据
|
|
|
|
|
|
item.mediaItems = processMediaUrls(item.imageUrls); |
|
|
|
|
|
|
|
|
|
|
|
// 确保图片优先显示:将图片类型的媒体项移到数组前面
|
|
|
|
|
|
if (item.mediaItems && item.mediaItems.length > 1) { |
|
|
|
|
|
const imageItems = item.mediaItems.filter(media => media.type === 'image'); |
|
|
|
|
|
const videoItems = item.mediaItems.filter(media => media.type === 'video'); |
|
|
|
|
|
item.mediaItems = [...imageItems, ...videoItems]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 清理 mediaItems 中的 URL
|
|
|
|
|
|
if (item.mediaItems && Array.isArray(item.mediaItems)) { |
|
|
|
|
|
item.mediaItems = item.mediaItems.map(media => { |
|
|
|
|
|
if (media.url) { |
|
|
|
|
|
// 去除 URL 中的反引号和空格
|
|
|
|
|
|
media.url = media.url.trim().replace(/[`]/g, ''); |
|
|
|
|
|
// 确保媒体类型正确
|
|
|
|
|
|
if (!media.type) { |
|
|
|
|
|
media.type = isVideoUrl(media.url) ? 'video' : 'image'; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return media; |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理库存显示逻辑
|
|
|
|
|
|
const quantity = item.quantity || item.minOrder || item.stock || item.inventory || item.availableStock || item.totalAvailable; |
|
|
|
|
|
const totalStock = quantity; |
|
|
|
|
|
|
|
|
|
|
|
let displayStock; |
|
|
|
|
|
if (totalStock >= 10000) { |
|
|
|
|
|
// 库存>=10000时显示"库存充足"
|
|
|
|
|
|
displayStock = '充足'; |
|
|
|
|
|
} else if (totalStock === 0) { |
|
|
|
|
|
// 库存=0时显示"暂无"
|
|
|
|
|
|
displayStock = '暂无'; |
|
|
|
|
|
} else { |
|
|
|
|
|
// 其他情况显示具体数字
|
|
|
|
|
|
displayStock = totalStock; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 更新商品的库存显示
|
|
|
|
|
|
item.totalStock = displayStock; |
|
|
|
|
|
item.originalTotalStock = totalStock; |
|
|
|
|
|
|
|
|
|
|
|
return item; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 显示提示信息
|
|
|
|
|
|
wx.showToast({ |
|
|
|
|
|
title: `找到${processedGoods.length}个符合条件的商品`, |
|
|
|
|
|
icon: 'success', |
|
|
|
|
|
duration: 2000 |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 设置商品数据
|
|
|
|
|
|
this.setData({ |
|
|
|
|
|
goods: processedGoods, |
|
|
|
|
|
loading: false, |
|
|
|
|
|
selectedOption: selectedCategory || '对比价格', |
|
|
|
|
|
showTips: false |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
console.log('对比价格数据加载完成:', processedGoods); |
|
|
|
|
|
}) |
|
|
|
|
|
.catch(err => { |
|
|
|
|
|
console.error('获取商品列表失败:', err); |
|
|
|
|
|
this.setData({ |
|
|
|
|
|
loading: false |
|
|
|
|
|
}); |
|
|
|
|
|
wx.showToast({ |
|
|
|
|
|
title: '获取商品失败,请稍后重试', |
|
|
|
|
|
icon: 'none' |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('解析商品数据失败:', error); |
|
|
|
|
|
this.setData({ |
|
|
|
|
|
loading: false |
|
|
|
|
|
}); |
|
|
|
|
|
wx.showToast({ |
|
|
|
|
|
title: '数据解析失败,请重试', |
|
|
|
|
|
icon: 'none', |
|
|
|
|
|
duration: 2000 |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
onShow: function () { |
|
|
onShow: function () { |
|
|
@ -120,12 +389,14 @@ Page({ |
|
|
return url.trim().replace(/[`]/g, ''); |
|
|
return url.trim().replace(/[`]/g, ''); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 如果没有 mediaItems 字段,将 imageUrls 转换为 mediaItems 格式
|
|
|
// 使用processMediaUrls函数处理媒体数据
|
|
|
if (!item.mediaItems || !Array.isArray(item.mediaItems) || item.mediaItems.length === 0) { |
|
|
item.mediaItems = processMediaUrls(item.imageUrls); |
|
|
item.mediaItems = item.imageUrls.map(url => ({ |
|
|
|
|
|
type: 'image', |
|
|
// 确保图片优先显示:将图片类型的媒体项移到数组前面
|
|
|
url: url |
|
|
if (item.mediaItems && item.mediaItems.length > 1) { |
|
|
})); |
|
|
const imageItems = item.mediaItems.filter(media => media.type === 'image'); |
|
|
|
|
|
const videoItems = item.mediaItems.filter(media => media.type === 'video'); |
|
|
|
|
|
item.mediaItems = [...imageItems, ...videoItems]; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -135,6 +406,10 @@ Page({ |
|
|
if (media.url) { |
|
|
if (media.url) { |
|
|
// 去除 URL 中的反引号和空格
|
|
|
// 去除 URL 中的反引号和空格
|
|
|
media.url = media.url.trim().replace(/[`]/g, ''); |
|
|
media.url = media.url.trim().replace(/[`]/g, ''); |
|
|
|
|
|
// 确保媒体类型正确
|
|
|
|
|
|
if (!media.type) { |
|
|
|
|
|
media.type = isVideoUrl(media.url) ? 'video' : 'image'; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
return media; |
|
|
return media; |
|
|
}); |
|
|
}); |
|
|
|