From 950edef6868e84f9a1854fc4b505dbb00b0f4810 Mon Sep 17 00:00:00 2001 From: User Date: Sat, 28 Feb 2026 15:13:57 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=94=B9=E5=8F=98=E5=AF=B9=E6=AF=94?= =?UTF-8?q?=E4=BB=B7=E6=A0=BC=E7=9A=84=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/compare_price/index.js | 291 ++++++++++++++++++++++++++++- pages/compare_price/index.wxml | 128 +++++++------ pages/goods-detail/goods-detail.js | 135 ++++++++++--- 3 files changed, 455 insertions(+), 99 deletions(-) diff --git a/pages/compare_price/index.js b/pages/compare_price/index.js index d975db7..73b061b 100644 --- a/pages/compare_price/index.js +++ b/pages/compare_price/index.js @@ -1,18 +1,287 @@ // pages/compare_price/index.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({ data: { // 页面数据 showTips: true, goods: [], loading: false, - selectedOption: '' + selectedOption: '', + selectedCategory: '', + selectedSpec: '' }, 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 () { @@ -120,12 +389,14 @@ Page({ return url.trim().replace(/[`]/g, ''); }); - // 如果没有 mediaItems 字段,将 imageUrls 转换为 mediaItems 格式 - if (!item.mediaItems || !Array.isArray(item.mediaItems) || item.mediaItems.length === 0) { - item.mediaItems = item.imageUrls.map(url => ({ - type: 'image', - url: url - })); + // 使用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]; } } @@ -135,6 +406,10 @@ Page({ if (media.url) { // 去除 URL 中的反引号和空格 media.url = media.url.trim().replace(/[`]/g, ''); + // 确保媒体类型正确 + if (!media.type) { + media.type = isVideoUrl(media.url) ? 'video' : 'image'; + } } return media; }); diff --git a/pages/compare_price/index.wxml b/pages/compare_price/index.wxml index 4b43172..9657f76 100644 --- a/pages/compare_price/index.wxml +++ b/pages/compare_price/index.wxml @@ -7,34 +7,15 @@ - 请选择想要了解的商品 + 请从商品详情页点击对比价格 - - - - - 绿壳 - - - - - - 粉壳 - - - - - - 褐壳 - - + + 此页面仅用于展示对比价格数据 + 请返回商品详情页 + 点击对比价格按钮 - - - - @@ -42,9 +23,10 @@ - + - {{selectedOption}}在售商品 + 选择的种类: {{selectedCategory}} + 选择的规格: {{selectedSpec}} @@ -62,26 +44,39 @@ - - - + + + + + + + + - - - + + + + + + + + { + const selectedCategoryIndex = categoryRes.tapIndex; + const selectedCategory = categoryOptions[selectedCategoryIndex]; + + // 构建规格选择列表 + const specList = currentSpecifications.map((spec, index) => { + return spec.display || spec.weightSpec || `规格${index + 1}`; + }); + + // 显示规格选择对话框 + wx.showActionSheet({ + itemList: specList, + success: (specRes) => { + const selectedSpecIndex = specRes.tapIndex; + const selectedSpec = currentSpecifications[selectedSpecIndex]; + + // 显示提示信息 + wx.showToast({ + title: `已选择${selectedCategory} ${selectedSpec.display}`, + icon: 'info', + duration: 1500, + success: () => { + setTimeout(() => { + // 构建要传递的数据 + const goodsData = { + id: currentGoods.id || currentGoods.productId, + name: currentGoods.name || '', + price: currentGoods.price || '', + imageUrls: currentGoods.imageUrls || [], + region: currentGoods.region || '', + weightQuantityData: currentGoods.weightQuantityData || [], + category: selectedCategory, + yolk: currentGoods.yolk || '', + sourceType: currentGoods.sourceType || '', + supplyStatus: currentGoods.supplyStatus || '', + mediaItems: currentGoods.mediaItems || [], + frequency: currentGoods.frequency || 0, + status: currentGoods.status || 'published', + totalStock: currentGoods.totalStock || '充足', + selectedSpec: selectedSpec + }; + + console.log('准备跳转到对比价格页面,传递的数据:', goodsData); + + // 跳转到对比价格页面 + wx.navigateTo({ + url: `/pages/compare_price/index?goodsData=${encodeURIComponent(JSON.stringify(goodsData))}`, + success: function () { + console.log('成功跳转到对比价格页面'); + }, + fail: function (error) { + console.error('跳转到对比价格页面失败:', error); + wx.showToast({ + title: '跳转失败,请稍后重试', + icon: 'none' + }); + } + }); + }, 1500); + } + }); + }, + fail: (res) => { + console.log('选择规格失败:', res); + } + }); + }, + fail: (res) => { + console.log('选择种类失败:', res); + } + }); }, // 关闭对比价格弹窗 @@ -3802,18 +3872,21 @@ Page({ }, // 加载首页商品数据 - loadHomeGoods: function () { + loadHomeGoods: function (selectedCategory, selectedSpec) { this.setData({ loadingHome: true }); // 获取当前商品的规格信息 const currentGoods = this.data.goodsDetail; const currentSpecifications = currentGoods.weightQuantityData || []; - // 提取当前商品的净重规格(如"净重41-42") - const currentWeightSpecs = currentSpecifications.map(item => item.weightSpec.trim()) - .filter(spec => spec && (spec.includes('净重') || spec.includes('毛重'))); - // 提取当前商品的种类(category) - const currentCategory = currentGoods.category || ''; - console.log('当前商品的种类:', currentCategory); + + // 使用传入的参数或默认值 + const categoryToUse = selectedCategory || currentGoods.category || ''; + const specToUse = selectedSpec || (currentSpecifications.length > 0 ? currentSpecifications[0] : null); + + // 提取规格信息 + const currentWeightSpecs = specToUse ? [specToUse.weightSpec.trim()] : []; + console.log('当前选择的种类:', categoryToUse); + console.log('当前选择的规格:', specToUse); // 调用API获取首页商品列表 API.getProducts() @@ -3883,12 +3956,12 @@ Page({ isSoldOutLabel: isSoldOutLabel // 添加是否显示已售空标签的标记 }; }).filter(goods => { - // 1. 先过滤相同种类(category)的商品 - if (currentCategory && goods.category !== currentCategory) { + // 1. 先过滤种类(category)的商品 + if (categoryToUse && categoryToUse !== '全部' && goods.category !== categoryToUse) { return false; } - // 2. 只有当当前商品有明确的规格时才进行筛选 + // 2. 只有当有明确的规格时才进行筛选 if (currentWeightSpecs.length === 0) { return true; } From 6f882874b292ebf25df6becf4e39a754131f9043 Mon Sep 17 00:00:00 2001 From: User Date: Sat, 28 Feb 2026 17:12:48 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9=E6=AF=94?= =?UTF-8?q?=E4=BB=B7=E6=A0=BCui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../@socket.io/component-emitter/index.js | 189 ++++++++++++++++++ .../@socket.io/component-emitter/index.js.map | 1 + .../accepts/miniprogram_npm/mime-db/index.js | 8 +- pages/compare_price/index.js | 107 +++++++++- pages/compare_price/index.wxml | 98 ++++++--- pages/compare_price/index.wxss | 21 +- 6 files changed, 378 insertions(+), 46 deletions(-) create mode 100644 miniprogram_npm/@socket.io/component-emitter/index.js create mode 100644 miniprogram_npm/@socket.io/component-emitter/index.js.map diff --git a/miniprogram_npm/@socket.io/component-emitter/index.js b/miniprogram_npm/@socket.io/component-emitter/index.js new file mode 100644 index 0000000..19242b8 --- /dev/null +++ b/miniprogram_npm/@socket.io/component-emitter/index.js @@ -0,0 +1,189 @@ +module.exports = (function() { +var __MODS__ = {}; +var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; }; +var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; }; +var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } }; +var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; }; +__DEFINE__(1772256867255, function(require, module, exports) { + +/** + * Expose `Emitter`. + */ + +exports.Emitter = Emitter; + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +} + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = +Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks['$' + event] = this._callbacks['$' + event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + function on() { + this.off(event, on); + fn.apply(this, arguments); + } + + on.fn = fn; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = +Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks['$' + event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks['$' + event]; + return this; + } + + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; + } + } + + // Remove event specific arrays for event types that no + // one is subscribed for to avoid memory leak. + if (callbacks.length === 0) { + delete this._callbacks['$' + event]; + } + + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + + var args = new Array(arguments.length - 1) + , callbacks = this._callbacks['$' + event]; + + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +// alias used for reserved events (protected method) +Emitter.prototype.emitReserved = Emitter.prototype.emit; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks['$' + event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; + +}, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); }) +return __REQUIRE__(1772256867255); +})() +//miniprogram-npm-outsideDeps=[] +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/miniprogram_npm/@socket.io/component-emitter/index.js.map b/miniprogram_npm/@socket.io/component-emitter/index.js.map new file mode 100644 index 0000000..b3e5acb --- /dev/null +++ b/miniprogram_npm/@socket.io/component-emitter/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["index.js"],"names":[],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"index.js","sourcesContent":["\n/**\n * Expose `Emitter`.\n */\n\nexports.Emitter = Emitter;\n\n/**\n * Initialize a new `Emitter`.\n *\n * @api public\n */\n\nfunction Emitter(obj) {\n if (obj) return mixin(obj);\n}\n\n/**\n * Mixin the emitter properties.\n *\n * @param {Object} obj\n * @return {Object}\n * @api private\n */\n\nfunction mixin(obj) {\n for (var key in Emitter.prototype) {\n obj[key] = Emitter.prototype[key];\n }\n return obj;\n}\n\n/**\n * Listen on the given `event` with `fn`.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.on =\nEmitter.prototype.addEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n (this._callbacks['$' + event] = this._callbacks['$' + event] || [])\n .push(fn);\n return this;\n};\n\n/**\n * Adds an `event` listener that will be invoked a single\n * time then automatically removed.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.once = function(event, fn){\n function on() {\n this.off(event, on);\n fn.apply(this, arguments);\n }\n\n on.fn = fn;\n this.on(event, on);\n return this;\n};\n\n/**\n * Remove the given callback for `event` or all\n * registered callbacks.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.off =\nEmitter.prototype.removeListener =\nEmitter.prototype.removeAllListeners =\nEmitter.prototype.removeEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n\n // all\n if (0 == arguments.length) {\n this._callbacks = {};\n return this;\n }\n\n // specific event\n var callbacks = this._callbacks['$' + event];\n if (!callbacks) return this;\n\n // remove all handlers\n if (1 == arguments.length) {\n delete this._callbacks['$' + event];\n return this;\n }\n\n // remove specific handler\n var cb;\n for (var i = 0; i < callbacks.length; i++) {\n cb = callbacks[i];\n if (cb === fn || cb.fn === fn) {\n callbacks.splice(i, 1);\n break;\n }\n }\n\n // Remove event specific arrays for event types that no\n // one is subscribed for to avoid memory leak.\n if (callbacks.length === 0) {\n delete this._callbacks['$' + event];\n }\n\n return this;\n};\n\n/**\n * Emit `event` with the given args.\n *\n * @param {String} event\n * @param {Mixed} ...\n * @return {Emitter}\n */\n\nEmitter.prototype.emit = function(event){\n this._callbacks = this._callbacks || {};\n\n var args = new Array(arguments.length - 1)\n , callbacks = this._callbacks['$' + event];\n\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n\n if (callbacks) {\n callbacks = callbacks.slice(0);\n for (var i = 0, len = callbacks.length; i < len; ++i) {\n callbacks[i].apply(this, args);\n }\n }\n\n return this;\n};\n\n// alias used for reserved events (protected method)\nEmitter.prototype.emitReserved = Emitter.prototype.emit;\n\n/**\n * Return array of callbacks for `event`.\n *\n * @param {String} event\n * @return {Array}\n * @api public\n */\n\nEmitter.prototype.listeners = function(event){\n this._callbacks = this._callbacks || {};\n return this._callbacks['$' + event] || [];\n};\n\n/**\n * Check if this emitter has `event` handlers.\n *\n * @param {String} event\n * @return {Boolean}\n * @api public\n */\n\nEmitter.prototype.hasListeners = function(event){\n return !! this.listeners(event).length;\n};\n"]} \ No newline at end of file diff --git a/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js b/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js index bcd7c6a..e11ead6 100644 --- a/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js +++ b/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js @@ -4,7 +4,7 @@ var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexport var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; }; var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } }; var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; }; -__DEFINE__(1761637667903, function(require, module, exports) { +__DEFINE__(1772256867256, function(require, module, exports) { /*! * mime-db * Copyright(c) 2014 Jonathan Ong @@ -18,8 +18,8 @@ __DEFINE__(1761637667903, function(require, module, exports) { module.exports = require('./db.json') -}, function(modId) {var map = {"./db.json":1761637667904}; return __REQUIRE__(map[modId], modId); }) -__DEFINE__(1761637667904, function(require, module, exports) { +}, function(modId) {var map = {"./db.json":1772256867257}; return __REQUIRE__(map[modId], modId); }) +__DEFINE__(1772256867257, function(require, module, exports) { module.exports = { "application/1d-interleaved-parityfec": { "source": "iana" @@ -9364,7 +9364,7 @@ module.exports = { } }, function(modId) { var map = {}; return __REQUIRE__(map[modId], modId); }) -return __REQUIRE__(1761637667903); +return __REQUIRE__(1772256867256); })() //miniprogram-npm-outsideDeps=[] //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pages/compare_price/index.js b/pages/compare_price/index.js index 73b061b..a384548 100644 --- a/pages/compare_price/index.js +++ b/pages/compare_price/index.js @@ -40,7 +40,9 @@ Page({ loading: false, selectedOption: '', selectedCategory: '', - selectedSpec: '' + selectedSpec: '', + currentGoods: null, + currentSwiperIndex: 0 }, onLoad: function (options) { @@ -67,10 +69,44 @@ Page({ console.log('选择的种类:', selectedCategory); console.log('选择的规格:', selectedSpec); - // 保存选择的种类和规格到页面数据 + // 处理当前商品的价格,使用选中规格的价格 + let currentPrice = goodsData.price; + if (selectedSpec && selectedSpec.price) { + // 如果selectedSpec包含价格信息,使用它 + currentPrice = selectedSpec.price; + } else if (goodsData.weightQuantityData && Array.isArray(goodsData.weightQuantityData)) { + // 如果weightQuantityData存在,尝试从中找到对应规格的价格 + const matchingSpec = goodsData.weightQuantityData.find(spec => { + if (spec.weightSpec) { + return spec.weightSpec.trim() === specWeight; + } + return false; + }); + if (matchingSpec && matchingSpec.price) { + currentPrice = matchingSpec.price; + } + } + + // 更新currentGoods的价格 + goodsData.price = currentPrice; + + // 清理价格字段,确保只显示单一价格 + if (goodsData.price) { + // 如果价格是字符串且包含逗号,只取第一个价格 + if (typeof goodsData.price === 'string' && goodsData.price.includes(',')) { + goodsData.price = goodsData.price.split(',')[0].trim(); + } + // 如果价格是数组,只取第一个价格 + if (Array.isArray(goodsData.price)) { + goodsData.price = goodsData.price[0]; + } + } + + // 保存选择的种类、规格和当前商品数据到页面数据 this.setData({ selectedCategory: selectedCategory, - selectedSpec: specWeight + selectedSpec: specWeight, + currentGoods: goodsData }); // 调用 API 获取符合条件的商品 @@ -83,19 +119,30 @@ Page({ let filteredGoods = []; if (res && res.products) { console.log('原始商品数量:', res.products.length); + // 获取当前商品的唯一标识符 + const currentGoodsId = goodsData.productId || goodsData.id || goodsData._id; + console.log('当前商品ID:', currentGoodsId); + // 过滤商品 filteredGoods = res.products.filter(item => { - // 1. 检查商品状态和价格 + // 1. 排除当前商品 + const itemId = item.productId || item.id || item._id; + if (currentGoodsId && itemId && currentGoodsId === itemId) { + console.log('排除当前商品:', itemId); + return false; + } + + // 2. 检查商品状态和价格 if (item.status !== 'published' || item.price === null || item.price === undefined) { return false; } - // 2. 过滤种类 + // 3. 过滤种类 if (selectedCategory && selectedCategory !== '全部' && item.category !== selectedCategory) { return false; } - // 3. 过滤规格 + // 4. 过滤规格 if (specWeight) { // 检查多个可能存储重量信息的字段 const fieldsToCheck = [ @@ -220,6 +267,35 @@ Page({ }); } + // 处理商品价格,使用选中规格的价格 + if (specWeight) { + if (item.weightQuantityData && Array.isArray(item.weightQuantityData)) { + // 尝试从weightQuantityData中找到对应规格的价格 + const matchingSpec = item.weightQuantityData.find(spec => { + if (spec.weightSpec) { + return spec.weightSpec.trim() === specWeight; + } + return false; + }); + if (matchingSpec && matchingSpec.price) { + // 确保价格是一个单一的值,而不是多个价格的组合 + item.price = matchingSpec.price; + } + } + } + + // 清理价格字段,确保只显示单一价格 + if (item.price) { + // 如果价格是字符串且包含逗号,只取第一个价格 + if (typeof item.price === 'string' && item.price.includes(',')) { + item.price = item.price.split(',')[0].trim(); + } + // 如果价格是数组,只取第一个价格 + if (Array.isArray(item.price)) { + item.price = item.price[0]; + } + } + // 处理库存显示逻辑 const quantity = item.quantity || item.minOrder || item.stock || item.inventory || item.availableStock || item.totalAvailable; const totalStock = quantity; @@ -458,5 +534,24 @@ Page({ icon: 'none' }); }); + }, + + // 轮播图切换事件 + onSwiperChange: function (e) { + this.setData({ + currentSwiperIndex: e.detail.current + }); + }, + + // 视频播放结束事件 + onVideoEnded: function () { + const { currentGoods, currentSwiperIndex } = this.data; + if (currentGoods && currentGoods.mediaItems) { + const totalItems = currentGoods.mediaItems.length; + const nextIndex = (currentSwiperIndex + 1) % totalItems; + this.setData({ + currentSwiperIndex: nextIndex + }); + } } }); \ No newline at end of file diff --git a/pages/compare_price/index.wxml b/pages/compare_price/index.wxml index 9657f76..33e5f51 100644 --- a/pages/compare_price/index.wxml +++ b/pages/compare_price/index.wxml @@ -3,7 +3,7 @@ - + @@ -23,14 +23,53 @@ - - - 选择的种类: {{selectedCategory}} - 选择的规格: {{selectedSpec}} + + + + 当前商品 + + + + + + + + + + + + + + + + {{currentGoods.name}} + + {{selectedSpec}} + {{currentGoods.yolk || '无'}} + 库存:{{currentGoods.totalStock || '充足'}} + + + + ¥{{currentGoods.price}} + ¥{{currentGoods.originalPrice}} + + + + + + + + + + + + 选择的种类: {{selectedCategory}} + 规格: {{selectedSpec}} + - + {{item.name}} - {{item.description || ''}} + + {{item.category || selectedCategory || '无'}} + {{item.specification || item.weightSpec || item.grossWeight || selectedSpec || '无'}} + {{item.yolk}} + 库存:{{item.totalStock && item.totalStock !== '充足' ? item.totalStock + '件' : (item.totalStock || '充足')}} @@ -100,7 +143,10 @@ 已有{{item.frequency || 0}}人浏览 - ¥{{item.price}} + + ¥{{item.price}} + ¥{{item.originalPrice}} + @@ -141,7 +187,7 @@ show-center-play-btn="{{true}}" show-play-btn="{{false}}" controls="{{true}}" - autoplay="{{false}}" + autoplay="{{true}}" loop="{{true}}" muted="{{true}}" poster="" @@ -167,7 +213,11 @@ {{item.sourceType || ''}} {{item.name}} - {{item.description || ''}} + + {{item.category || selectedCategory || '无'}} + {{item.specification || item.weightSpec || item.grossWeight || selectedSpec || '无'}} + {{item.yolk}} + 库存:{{item.totalStock && item.totalStock !== '充足' ? item.totalStock + '件' : (item.totalStock || '充足')}} @@ -175,13 +225,21 @@ 已有{{item.frequency || 0}}人浏览 - ¥{{item.price}} + + ¥{{item.price}} + ¥{{item.originalPrice}} + + + + + 已经加载全部符合的商品 + @@ -190,19 +248,5 @@ - - - - 欢迎使用对比价格功能 - 此页面用于对比不同商品的价格信息。 - 对比同种商品,不同规格 - 的商品价格信息。 - 想要看到相同规格的同种类型 - 相同规格的同种类型 - 点击商品内的对比价格按钮即可展示 - - - - - + \ No newline at end of file diff --git a/pages/compare_price/index.wxss b/pages/compare_price/index.wxss index 9085200..8f0327c 100644 --- a/pages/compare_price/index.wxss +++ b/pages/compare_price/index.wxss @@ -4,9 +4,9 @@ /* 瀑布流容器 */ .waterfall-container { display: flex; - gap: 16rpx; + gap: 8rpx; width: 100%; - padding: 0 10rpx; + padding: 0; box-sizing: border-box; } @@ -34,7 +34,7 @@ .product-card { width: 100%; height: auto; - min-height: 450rpx; + min-height: 550rpx; background: #fff; border-radius: 16rpx; overflow: hidden; @@ -54,7 +54,7 @@ .product-image-wrapper { position: relative; width: 100%; - height: 320rpx; + height: 380rpx; background: #f5f5f5; border-radius: 16rpx 16rpx 0 0; overflow: hidden; @@ -153,12 +153,14 @@ .status-tag { display: inline; margin-right: 8rpx; - font-size: 20rpx; - padding: 4rpx 8rpx; - border-radius: 4rpx; + font-size: 24rpx; + padding: 4rpx 12rpx; + border-radius: 16rpx; font-weight: 600; white-space: nowrap; flex-shrink: 0; + background-color: #f0f0f0; + color: #666; } .status-tag.source-third { @@ -211,7 +213,8 @@ } .product-price { - font-size: 26rpx; + font-size: 40rpx; font-weight: bold; - color: #ff6b81; + color: #ff4d4f; + flex-shrink: 0; }