From 324bf063022bb18412e6c63fb8552320c225483b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?= <15778543+xufeiyang6017@user.noreply.gitee.com> Date: Mon, 29 Dec 2025 13:07:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=A1=86=E5=92=8C=E5=AF=BC=E8=88=AA=E6=A0=8F=E4=BA=A4=E4=BA=92?= =?UTF-8?q?=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 搜索框固定显示,移除滚动隐藏逻辑 - 优化地区选择器样式:黑色文字、透明背景、下拉箭头 - 修复滚动回顶部时内容被遮挡问题 - 移除商品区域白色背景和边距,消除分类按钮下方的空白 --- pages/index/index.js | 200 ++++++++++++++++++++++++--------- pages/index/index.wxml | 53 +++------ pages/index/index.wxss | 103 ++++++----------- pages/profile/index.js | 2 +- pages/settlement/index.wxml | 4 +- server-example/server-mysql.js | 39 +++++++ utils/api.js | 24 ++++ 7 files changed, 261 insertions(+), 164 deletions(-) diff --git a/pages/index/index.js b/pages/index/index.js index 04c5ea9..15b2d23 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -25,7 +25,6 @@ Page({ searchSectionVisible: true, lastScrollTop: 0, isScrollLocked: false, - isSearchBarFullyHidden: false, // 回到顶部按钮 showBackToTop: false, @@ -43,10 +42,15 @@ Page({ leftColumnGoods: [], rightColumnGoods: [], selectedCategory: '全部', + categories: ['全部', '粉壳', '红壳', '绿壳', '白壳'], loadingMore: false, hasMoreData: true, page: 1, pageSize: 8, + + // 防抖定时器 + searchDebounceTimer: null, + scrollDebounceTimer: null, isRefreshing: false, isLoading: true, @@ -219,9 +223,12 @@ Page({ this.setData({ sidebarBtnTop: defaultTop, - sidebarBtnHidden: savedBtnHidden || false + sidebarBtnHidden: false, + isSearchBarFullyHidden: false, + lastScrollTop: 0 }); this.checkAndRestoreLoginStatus() + this.loadCategories() this.loadGoods() // 计算搜索区域高度 @@ -279,6 +286,9 @@ Page({ }, onShow: function () { + console.log('===== onShow 执行 ====='); + console.log('onShow - 进入时的isSearchBarFullyHidden:', this.data.isSearchBarFullyHidden); + if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ selected: 0 @@ -289,10 +299,16 @@ Page({ app.globalData.showTabBar = true; const savedBtnHidden = wx.getStorageSync('sidebarBtnHidden'); + console.log('onShow - savedBtnHidden:', savedBtnHidden); + this.setData({ - sidebarBtnHidden: savedBtnHidden || false + sidebarBtnHidden: savedBtnHidden || false, + isSearchBarFullyHidden: false, + lastScrollTop: 0 }); + console.log('onShow - 设置后的isSearchBarFullyHidden:', this.data.isSearchBarFullyHidden); + this.checkAndRestoreLoginStatus() }, @@ -423,6 +439,7 @@ Page({ return { ...product, + category: product.category || '', fullRegion: product.region || '', region: product.region ? this.extractProvince(product.region) : '', grossWeight: product.grossWeight || product.weight || '', @@ -484,9 +501,16 @@ Page({ } const filteredGoods = this.applyFilters(updatedGoods, false) + console.log('===== 筛选结果 =====') + console.log('当前选中的分类:', this.data.selectedCategory) console.log('filteredGoods 数量:', filteredGoods.length) - console.log('filteredGoods[0]:', filteredGoods[0]) - console.log('filteredGoods[1]:', filteredGoods[1]) + console.log('filteredGoods[0]:', filteredGoods[0] ? JSON.stringify(filteredGoods[0], null, 2) : 'N/A') + if (filteredGoods.length > 0) { + console.log('filteredGoods[0].category:', filteredGoods[0] ? filteredGoods[0].category : 'N/A') + } + if (filteredGoods.length > 1) { + console.log('filteredGoods[1].category:', filteredGoods[1] ? filteredGoods[1].category : 'N/A') + } const { leftColumnGoods, rightColumnGoods } = this.distributeToColumns(filteredGoods) console.log('leftColumnGoods 数量:', leftColumnGoods.length) @@ -513,6 +537,7 @@ Page({ return { ...product, + category: product.category || '', fullRegion: product.region || '', region: product.region ? this.extractProvince(product.region) : '', grossWeight: product.grossWeight || product.weight || '', @@ -614,6 +639,24 @@ Page({ } }, + // 加载商品分类列表 + loadCategories: function() { + console.log('===== 开始加载分类 ====='); + API.getProductCategories().then(categories => { + console.log('加载分类成功, categories:', JSON.stringify(categories)); + if (categories && categories.length > 0) { + this.setData({ + categories: categories + }); + console.log('分类列表已设置到data, categories:', this.data.categories); + } else { + console.log('分类列表为空,使用默认分类'); + } + }).catch(err => { + console.error('加载分类失败:', err); + }); + }, + // 加载商品数据 - 淘宝风格优化 loadGoods: function(isLoadMore = false) { if (isLoadMore && !this.data.hasMoreData) { @@ -640,6 +683,14 @@ Page({ .then(res => { wx.hideLoading(); + console.log('===== API 返回的完整数据 ====='); + console.log('res:', res); + console.log('res.products:', res.products); + if (res.products && res.products.length > 0) { + console.log('第一个商品的完整字段:', JSON.stringify(res.products[0], null, 2)); + console.log('第一个商品的所有键:', Object.keys(res.products[0])); + } + if (res.success && res.products) { const totalGoods = res.total || 0; const totalPages = res.totalPages || Math.ceil(totalGoods / this.data.pageSize); @@ -715,25 +766,41 @@ Page({ // 瀑布流布局 - 淘宝风格左右交替 distributeToColumns: function(goods) { if (!goods || goods.length === 0) { + console.log('distributeToColumns: 商品列表为空') return { leftColumnGoods: [], rightColumnGoods: [] } } + console.log('distributeToColumns 开始分发,总商品数:', goods.length) + const leftColumn = [] const rightColumn = [] + // 统计广告和普通商品 + const adCount = goods.filter(item => item.isAd).length + const productCount = goods.filter(item => !item.isAd).length + console.log('广告数量:', adCount, '普通商品数量:', productCount) + for (let i = 0; i < goods.length; i += 2) { const currentRow = Math.floor(i / 2) const isEvenRow = currentRow % 2 === 0 if (i < goods.length) { - leftColumn.push({ ...goods[i], isLong: isEvenRow }) + const item = { ...goods[i], isLong: isEvenRow } + leftColumn.push(item) + console.log(`左列添加[${i}]:`, item.isAd ? '广告' : item.name, 'isLong:', item.isLong) } if (i + 1 < goods.length) { - rightColumn.push({ ...goods[i + 1], isLong: !isEvenRow }) + const item = { ...goods[i + 1], isLong: !isEvenRow } + rightColumn.push(item) + console.log(`右列添加[${i+1}]:`, item.isAd ? '广告' : item.name, 'isLong:', item.isLong) } } + console.log('分发结果 - 左列:', leftColumn.length, '右列:', rightColumn.length) + console.log('左列商品:', leftColumn.filter(i => !i.isAd).length, '广告:', leftColumn.filter(i => i.isAd).length) + console.log('右列商品:', rightColumn.filter(i => !i.isAd).length, '广告:', rightColumn.filter(i => i.isAd).length) + return { leftColumnGoods: leftColumn, rightColumnGoods: rightColumn } }, @@ -806,13 +873,26 @@ Page({ return { leftColumnGoods: leftColumn, rightColumnGoods: rightColumn } }, - // 搜索输入(实时搜索) + // 搜索输入(带防抖) onSearchInput: function(e) { + const keyword = e.detail.value + this.setData({ + searchKeyword: keyword + }) + + // 清除之前的定时器 + if (this.data.searchDebounceTimer) { + clearTimeout(this.data.searchDebounceTimer) + } + + // 设置新的定时器,300ms防抖 + const timer = setTimeout(() => { + this.searchGoods() + }, 300) + this.setData({ - searchKeyword: e.detail.value + searchDebounceTimer: timer }) - // 实时应用筛选条件 - this.searchGoods() }, // 搜索商品 @@ -889,19 +969,24 @@ Page({ } const category = e.currentTarget.dataset.category - this.setData({ - selectedCategory: category - }) + if (category === this.data.selectedCategory) { + return // 如果选择的分类和当前相同,不重复加载 + } - const filteredGoods = this.applyFilters(this.data.goods, false) - const groupedGoods = this.groupGoodsForStaggeredLayout(filteredGoods) - const { leftColumnGoods, rightColumnGoods } = this.distributeToColumns(filteredGoods) this.setData({ - filteredGoods: filteredGoods, - groupedGoods: groupedGoods, - leftColumnGoods: leftColumnGoods, - rightColumnGoods: rightColumnGoods + selectedCategory: category, + page: 1, + hasMoreData: true, + goods: [], + filteredGoods: [], + leftColumnGoods: [], + rightColumnGoods: [], + loadingMore: false, + isLoading: true }) + + // 重新从服务器加载数据 + this.loadGoods(false) }, // 查看商品详情 @@ -999,51 +1084,60 @@ Page({ }); }, - // 滚动事件处理 - 简化并修复iOS兼容性问题 + // 滚动事件处理 - 优化性能 onScroll: function(e) { const { scrollTop } = e.detail; - // 使用更平滑的阈值判断 - const threshold = 50; // 降低阈值,让隐藏更早触发 + // 清除之前的防抖定时器 + if (this.data.scrollDebounceTimer) { + clearTimeout(this.data.scrollDebounceTimer) + } - // 检查滚动方向 - const scrollingDown = scrollTop > this.data.lastScrollTop; - const scrollingUp = scrollTop < this.data.lastScrollTop; + // 设置防抖,32ms约等于30fps,限制高速滑动时的处理频率 + const timer = setTimeout(() => { + this.handleScroll(scrollTop) + }, 32) - // 只在滚动超过阈值且方向改变时才更新状态 - if (scrollingDown && scrollTop > threshold && !this.data.isSearchBarFullyHidden) { - this.setData({ - isSearchBarFullyHidden: true, - lastScrollTop: scrollTop - }); - } else if (scrollingUp && scrollTop <= threshold && this.data.isSearchBarFullyHidden) { - this.setData({ - isSearchBarFullyHidden: false, - lastScrollTop: scrollTop - }); - } else { - // 其他情况只更新滚动位置 - this.setData({ - lastScrollTop: scrollTop - }); + this.setData({ + scrollDebounceTimer: timer + }) + }, + + // 实际的滚动处理逻辑 + handleScroll: function(scrollTop) { + const threshold = 50; + const backToTopThreshold = 300; + + let needUpdate = false; + const updates = { + lastScrollTop: scrollTop + }; + + // 搜索框始终固定显示,不做隐藏处理 + + // 侧边栏按钮显示逻辑 + if (scrollTop <= threshold && this.data.sidebarBtnHidden) { + updates.sidebarBtnHidden = false; + needUpdate = true; + wx.setStorageSync('sidebarBtnHidden', false); } // 回到顶部按钮显示逻辑 - if (scrollTop > 300 && !this.data.showBackToTop) { - this.setData({ showBackToTop: true }); - } else if (scrollTop <= 300 && this.data.showBackToTop) { - this.setData({ showBackToTop: false }); + const shouldShowBackToTop = scrollTop > backToTopThreshold; + if (shouldShowBackToTop !== this.data.showBackToTop) { + updates.showBackToTop = shouldShowBackToTop; + needUpdate = true; } - const { scrollHeight, clientHeight } = e.detail; - const distanceToBottom = scrollHeight - scrollTop - clientHeight; + if (needUpdate) { + this.setData(updates); + } + // TabBar显示 const app = getApp(); - if (!app || !app.globalData) { - return; + if (app && app.globalData) { + app.globalData.showTabBar = true; } - - app.globalData.showTabBar = true; }, // 更新商品的收藏状态 diff --git a/pages/index/index.wxml b/pages/index/index.wxml index 62683c6..b7219fd 100644 --- a/pages/index/index.wxml +++ b/pages/index/index.wxml @@ -1,8 +1,6 @@ - - + + 专业的鸡蛋交易平台 @@ -13,7 +11,7 @@ {{selectedRegion || '全国'}} - + 🔍 @@ -25,7 +23,6 @@ bindinput="onSearchInput" /> - @@ -52,39 +49,13 @@ - 全部 - - - 粉壳 - - - 红壳 - - - 绿壳 - - - 白壳 + {{item}} @@ -163,7 +134,7 @@ - + + + + @@ -244,6 +218,9 @@ + + + diff --git a/pages/index/index.wxss b/pages/index/index.wxss index 9731679..aeea7fa 100644 --- a/pages/index/index.wxss +++ b/pages/index/index.wxss @@ -37,12 +37,8 @@ page { right: 0; z-index: 1000; background: linear-gradient(180deg, #f8f8f8 0%, #f0f0f0 50%, #e8e8e8 100%); - transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); - transform: translateY(0); - will-change: transform; - -webkit-transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); - padding: 10rpx 0; /* 减少内边距 */ - min-height: 120rpx; /* 降低最小高度 */ + padding: 10rpx 0; + min-height: 120rpx; } /* 确保所有主要区域背景一致 */ @@ -60,19 +56,13 @@ page { flex-direction: column; overflow: hidden; position: relative; - padding-top: 0; /* 移除顶部内边距,让瀑布流自然显示 */ + padding-top: 0; margin: 0; border-radius: 0; box-shadow: none; background: transparent; } -/* 隐藏时的状态 */ -.top-section-container.top-hidden { - transform: translateY(-100%); - opacity: 0; -} - /* 标题样式调整 */ .top-section-container .title { padding: 10rpx 0; @@ -80,25 +70,12 @@ page { font-weight: bold; text-align: center; color: #333; - transition: all 0.3s ease; margin: 0; } -.top-section-container.top-hidden .title { - padding: 0; - font-size: 0; - opacity: 0; -} - /* 搜索区域样式调整 */ .top-section-container .search-section { padding: 0 30rpx 15rpx; - transition: all 0.3s ease; -} - -.top-section-container.top-hidden .search-section { - padding: 0 30rpx; - opacity: 0; } /* 搜索框样式 */ @@ -109,19 +86,13 @@ page { border-radius: 50rpx; padding: 5rpx 15rpx; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); - transition: all 0.3s ease; min-height: 60rpx; } -.top-section-container.top-hidden .search-bar { - transform: scale(0.9); - opacity: 0; -} - /* 修复商品列表区域 */ .goods-list { flex: 1; - padding-top: 240rpx; /* 根据新的分类区域位置调整,确保不被覆盖 */ + padding-top: 280rpx; height: 100%; min-height: 100vh; box-sizing: border-box; @@ -130,20 +101,14 @@ page { background: transparent; } -/* 当搜索框隐藏时调整商品列表位置 */ -.top-section-container.top-hidden ~ .goods-section .goods-list { - padding-top: 80rpx; /* 搜索框隐藏时减少顶部间距 */ -} - /* 品种筛选区域调整 */ .category-section { position: fixed; - top: 160rpx; /* 进一步增大top值,确保完全不被搜索框覆盖 */ + top: 160rpx; left: 0; right: 0; z-index: 999; background: linear-gradient(180deg, #f8f8f8 0%, #f0f0f0 50%, #e8e8e8 100%); - transition: top 0.3s ease; padding: 10rpx 0; height: 70rpx; box-sizing: border-box; @@ -152,11 +117,6 @@ page { margin: 0; } -/* 搜索框隐藏时,分类区域上移 */ -.top-section-container.top-hidden ~ .category-section { - top: 0; -} - /* iOS专用修复 */ @media screen and (-webkit-min-device-pixel-ratio:0) { .top-section-container { @@ -164,11 +124,6 @@ page { transform: translateZ(0); } - .top-section-container.top-hidden { - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - /* 防止iOS弹性滚动导致的视觉问题 */ .goods-list { -webkit-overflow-scrolling: touch; @@ -258,24 +213,23 @@ page { gap: 5rpx; font-size: 24rpx; font-weight: 500; - color: white; + color: #333; padding: 10rpx 15rpx; - background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%); - border-radius: 40rpx; - box-shadow: 0 2rpx 8rpx rgba(22, 119, 255, 0.3); + background: transparent; + border: none; transition: all 0.3s ease; margin-right: 10rpx; } .region-selector:hover { transform: translateY(-2rpx); - box-shadow: 0 4rpx 12rpx rgba(22, 119, 255, 0.4); + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); } .region-arrow { font-size: 22rpx; font-weight: bold; - color: white; + color: #333; } .search-button { @@ -620,16 +574,16 @@ wx-button:not([size=mini]) { font-weight: bold; } -/* 商品区域样式 - 调整为占据70%空间 */ +/* 商品区域样式 */ .goods-section { - background-color: white; - padding: 20rpx; - border-radius: 10rpx; - margin: 0 20rpx 20rpx 20rpx; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); - flex: 7; + background-color: transparent; + padding: 0; + margin: 0; + border-radius: 0; + box-shadow: none; + flex: 1; overflow-y: auto; - width: calc(100% - 40rpx); + width: 100%; box-sizing: border-box; } @@ -1470,30 +1424,39 @@ wx-button:not([size=mini]) { overflow: hidden; background: #fff; box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08); - margin-bottom: 16rpx; /* 确保有下边距 */ - z-index: 1; /* 设置z-index确保在最上层 */ + margin-bottom: 16rpx; + z-index: 1; + /* 修复真机遮挡问题:确保广告不被fixed元素遮挡 */ + transform: translateZ(0); + -webkit-transform: translateZ(0); } /* 完整卡片广告 */ .ad-full-card { width: 100%; - height: 350rpx; /* 稍微降低高度,避免被遮挡 */ + height: 350rpx; + /* 修复遮挡:增加层级 */ + position: relative; + z-index: 1001; } .ad-image { width: 100%; - height: 350rpx; /* 相应调整 */ + height: 350rpx; } /* 半高图片广告 */ .ad-half-image { width: 100%; - height: 180rpx; /* 稍微降低高度 */ + height: 180rpx; + /* 修复遮挡:增加层级 */ + position: relative; + z-index: 1001; } .ad-image-half { width: 100%; - height: 180rpx; /* 相应调整 */ + height: 180rpx; } /* 广告标签 */ diff --git a/pages/profile/index.js b/pages/profile/index.js index 1eea16b..75d944d 100644 --- a/pages/profile/index.js +++ b/pages/profile/index.js @@ -520,7 +520,7 @@ Page({ const that = this; wx.showModal({ title: '登录成功', - content: '🥚 想快速找到离你最近的新鲜鸡蛋供应商、支持自提的门店,或享受精准配送服务?允许获取位置后,我们会为你优先展示周边优质货源、计算最快配送时效,省去手动输入地址的麻烦~隐私安全有保障,位置信息仅用于优化你的购物体验,放心点击【允许】吧!', + content: '🥚 允许获取位置,为你优先展示附近新鲜鸡蛋供应商、自提门店及精准配送时效,无需手动填地址,位置信息仅用于优化购物体验,隐私有保障,放心开启~', showCancel: true, cancelText: '取消', confirmText: '允许', diff --git a/pages/settlement/index.wxml b/pages/settlement/index.wxml index ad06f76..cffebca 100644 --- a/pages/settlement/index.wxml +++ b/pages/settlement/index.wxml @@ -276,7 +276,7 @@ 你可以撤回备案 - + @@ -364,7 +364,7 @@ - + {{selectedCooperationDetail.title}} diff --git a/server-example/server-mysql.js b/server-example/server-mysql.js index 26d4589..ee23be9 100644 --- a/server-example/server-mysql.js +++ b/server-example/server-mysql.js @@ -1779,6 +1779,45 @@ app.post('/api/user/update', async (req, res) => { } }); +// 获取商品分类列表 - 返回不重复的分类 +app.get('/api/product/categories', async (req, res) => { + try { + const { openid } = req.query; + + console.log('获取商品分类列表, openid:', openid || '未提供'); + + // 使用 Sequelize 的 distinct 查询获取不重复的分类 + const products = await Product.findAll({ + attributes: [ + [Sequelize.col('category'), 'category'] + ], + where: { + category: { + [Sequelize.Op.ne]: null, + [Sequelize.Op.ne]: '' + } + }, + group: ['category'] + }); + + // 提取分类数组 + const categories = products.map(p => p.category).filter(c => c); + + console.log('获取到的分类列表:', categories); + + res.json({ + success: true, + categories: ['全部', ...categories] // 添加"全部"选项 + }); + } catch (error) { + console.error('获取分类列表失败:', error); + res.status(500).json({ + success: false, + message: '获取分类列表失败: ' + error.message + }); + } +}); + // 获取商品列表 - 优化版本确保状态筛选正确应用 app.post('/api/product/list', async (req, res) => { try { diff --git a/utils/api.js b/utils/api.js index c2c7779..6037937 100644 --- a/utils/api.js +++ b/utils/api.js @@ -3909,6 +3909,30 @@ module.exports = { resolve({}); }); }); + }, + + // 获取商品分类列表 - 从product表的category字段去重获取 + getProductCategories: function () { + return new Promise((resolve, reject) => { + const openid = wx.getStorageSync('openid') || ''; + + request('/api/product/categories', 'GET', { + openid: openid + }).then(res => { + console.log('获取商品分类列表成功:', res); + if (res && res.success && res.categories) { + resolve(res.categories); + } else { + // 如果接口不存在,返回默认分类 + console.warn('获取分类接口未实现,返回默认分类'); + resolve(['全部', '粉壳', '红壳', '绿壳', '白壳']); + } + }).catch(err => { + console.error('获取商品分类列表失败:', err); + // 失败时返回默认分类 + resolve(['全部', '粉壳', '红壳', '绿壳', '白壳']); + }); + }); } }; \ No newline at end of file