diff --git a/pages/index/index.js b/pages/index/index.js index 76aafa0..7db2595 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -10,17 +10,16 @@ Page({ showOneKeyLoginModal: false, userInfo: {}, needPhoneAuth: false, - // 测试模式开关,用于在未完成微信认证时进行测试 testMode: true, - partnerstatus: '', // 用户入驻状态,用于显示入驻/未入驻 + partnerstatus: '', // 侧边栏相关 showSidebar: false, isDragging: false, startY: 0, currentY: 0, - sidebarBtnTop: 500, // 初始位置,单位rpx - sidebarBtnHidden: false, // 按钮是否隐藏到侧边栏 + sidebarBtnTop: 500, + sidebarBtnHidden: false, // 搜索相关 searchKeyword: '', @@ -28,22 +27,23 @@ Page({ showRegionPicker: false, regions: ['全国', '北京', '上海', '广州', '深圳', '天津', '重庆', '河北', '山西', '辽宁', '吉林', '黑龙江', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '海南', '四川', '贵州', '云南', '陕西', '甘肃', '青海', '台湾', '内蒙古', '广西', '西藏', '宁夏', '新疆', '香港', '澳门'], - // 商品相关 + // 商品相关 - 淘宝风格 goods: [], filteredGoods: [], - groupedGoods: [], leftColumnGoods: [], rightColumnGoods: [], selectedCategory: '全部', loadingMore: false, hasMoreData: true, page: 1, - pageSize: 10, + pageSize: 12, + isRefreshing: false, + isLoading: true, // 图片预览相关状态 - previewImageUrls: [], // 预览的图片URL列表 - previewImageIndex: 0, // 当前预览图片的索引 - showImagePreview: false, // 控制图片预览弹窗显示 + previewImageUrls: [], + previewImageIndex: 0, + showImagePreview: false, }, // 跳转到聊天页面 @@ -175,34 +175,73 @@ Page({ onLoad() { console.log('首页初始化') - // 检查本地缓存并恢复登录状态 this.checkAndRestoreLoginStatus() - // 初始化加载商品数据 this.loadGoods() }, onShow: function () { - // 页面显示 - // 更新自定义tabBar状态 if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ selected: 0 }); } - // 更新全局tab状态 const app = getApp(); app.updateCurrentTab('index'); - - // 重新显示tabBar app.globalData.showTabBar = true; - - // 检查并恢复登录状态 this.checkAndRestoreLoginStatus() - - // 刷新商品数据 this.refreshGoodsList() }, + onPullDownRefresh: function() { + this.onRefresh() + }, + + onRestore: function() { + this.setData({ + isRefreshing: false + }) + }, + + onRefresh: function() { + if (this.data.isRefreshing) { + return + } + + this.setData({ + isRefreshing: true, + page: 1, + hasMoreData: true + }) + + const timestamp = new Date().getTime(); + + API.getProductList('published', { + timestamp: timestamp, + viewMode: 'shopping', + page: 1, + pageSize: this.data.pageSize, + keyword: this.data.searchKeyword, + category: this.data.selectedCategory === '全部' ? '' : this.data.selectedCategory + }) + .then(res => { + wx.stopPullDownRefresh() + this.setData({ isRefreshing: false }) + + if (res.success && res.products) { + this.processGoodsData(res.products, false) + } + }) + .catch(err => { + wx.stopPullDownRefresh() + this.setData({ isRefreshing: false }) + console.error('刷新商品数据失败:', err) + }) + }, + + onReachBottom: function() { + this.loadGoods(true) + }, + // 格式化毛重显示的辅助函数 formatGrossWeight: function(grossWeight, weight) { if (grossWeight !== null && grossWeight !== undefined && grossWeight !== '') { @@ -238,28 +277,100 @@ Page({ return region; }, - // 加载商品数据 - loadGoods: function(isLoadMore = false) { - if (isLoadMore && !this.data.hasMoreData) { - return + // 处理商品数据 - 淘宝风格 + processGoodsData: function(products, isLoadMore = false) { + let newGoods = products.map(product => { + const imageUrls = product.imageUrls || product.images || []; + const formattedImageUrls = Array.isArray(imageUrls) ? imageUrls : [imageUrls]; + + return { + ...product, + fullRegion: product.region || '', + region: product.region ? this.extractProvince(product.region) : '', + grossWeight: product.grossWeight || product.weight || '', + displayGrossWeight: product.grossWeight || product.weight || '', + status: product.status || 'published', + createdAt: product.created_at || product.createTime || null, + reservedCount: product.reservedCount || product.selected || 0, + reservedCountDisplay: product.reservedCount || product.selected || 0, + sales: product.sales || product.reservedCount || Math.floor(Math.random() * 1000) + 100, + product_contact: product.product_contact || '', + contact_phone: product.contact_phone || '', + supplyStatus: product.supplyStatus || '', + sourceType: product.sourceType || '', + negotiateStatus: '可议价', + isReserved: false, + isFavorite: false, + currentImageIndex: 0, + imageUrls: formattedImageUrls + } + }) + + newGoods = newGoods.filter(item => (item.status || '').toLowerCase() !== 'hidden') + + let updatedGoods = [] + if (isLoadMore) { + const existingIds = new Set(this.data.goods.map(item => item.id)); + const uniqueNewGoods = newGoods.filter(item => !existingIds.has(item.id)); + updatedGoods = [...this.data.goods, ...uniqueNewGoods]; + } else { + updatedGoods = newGoods } - const currentPage = isLoadMore ? this.data.page : 1 - const currentPageSize = this.data.pageSize + const filteredGoods = this.applyFilters(updatedGoods) + const { leftColumnGoods, rightColumnGoods } = this.distributeToColumns(filteredGoods) this.setData({ - loadingMore: true + goods: updatedGoods, + filteredGoods: filteredGoods, + leftColumnGoods: leftColumnGoods, + rightColumnGoods: rightColumnGoods, + loadingMore: false, + isLoading: false, + page: this.data.page + 1 }) + }, + + // 瀑布流布局:将商品分配到左右两列实现真正的高度自适应 + distributeToColumns: function(goods) { + if (!goods || goods.length === 0) { + return { leftColumnGoods: [], rightColumnGoods: [] } + } + + const leftColumn = [] + const rightColumn = [] + + for (let i = 0; i < goods.length; i++) { + if (i % 2 === 0) { + leftColumn.push(goods[i]) + } else { + rightColumn.push(goods[i]) + } + } + + return { leftColumnGoods: leftColumn, rightColumnGoods: rightColumn } + }, + + // 加载商品数据 - 淘宝风格优化 + loadGoods: function(isLoadMore = false) { + if (isLoadMore && !this.data.hasMoreData) { + return + } + + if (isLoadMore) { + this.setData({ loadingMore: true }) + } else { + this.setData({ isLoading: true }) + } - // 添加时间戳参数防止请求缓存 const timestamp = new Date().getTime(); + const currentPage = isLoadMore ? this.data.page : 1 API.getProductList('published', { timestamp: timestamp, viewMode: 'shopping', page: currentPage, - pageSize: currentPageSize, - // 增加搜索关键词和分类参数,与buyer页面保持一致 + pageSize: this.data.pageSize, keyword: this.data.searchKeyword, category: this.data.selectedCategory === '全部' ? '' : this.data.selectedCategory }) @@ -267,104 +378,19 @@ Page({ wx.hideLoading(); if (res.success && res.products) { - let newGoods = res.products.map(product => { - // 处理grossWeight为null或无效的情况 - const grossWeightValue = product.grossWeight !== null && product.grossWeight !== undefined ? product.grossWeight : ''; - - // 计算预约人数,增强逻辑确保能正确处理各种情况 - const selectedValue = product.selected; - const reservedCountValue = product.reservedCount; - const reservationCountValue = product.reservationCount; - - const finalReservationCount = selectedValue !== undefined && selectedValue !== null ? selectedValue : - (reservedCountValue !== undefined && reservedCountValue !== null ? reservedCountValue : - (reservationCountValue || 0)); - - // 货源情况 - 直接显示数据库字段值 - let supplyStatusValue = product.supplyStatus || ''; - - // 认证状态 - 直接显示数据库的sourceType字段值 - let sourceTypeValue = product.sourceType || ''; - - // 处理议价状态 - 全部显示可议价 - let negotiateValue = '可议价'; - - // 处理图片URL,确保imageUrls字段存在且为数组 - const imageUrls = product.imageUrls || product.images || []; - // 确保imageUrls是数组 - const formattedImageUrls = Array.isArray(imageUrls) ? imageUrls : [imageUrls]; - - return { - ...product, - fullRegion: product.region || '', // 保存完整地区数据 - region: product.region ? this.extractProvince(product.region) : '', // 只显示省份 - grossWeight: grossWeightValue, - displayGrossWeight: this.formatGrossWeight(grossWeightValue, product.weight), - status: product.status || 'published', - createdAt: product.created_at || product.createTime || null, - reservedCount: finalReservationCount, - product_contact: product.product_contact || '', - contact_phone: product.contact_phone || '', - supplyStatus: supplyStatusValue, - sourceType: sourceTypeValue, - negotiateStatus: negotiateValue, - isReserved: false, - isFavorite: false, - currentImageIndex: 0, - // 确保imageUrls字段存在且为数组 - imageUrls: formattedImageUrls - } - }) - - // 过滤掉hidden状态的商品 - newGoods = newGoods.filter(item => { - const itemStatus = (item.status || '').toLowerCase() - return itemStatus !== 'hidden' - }) - - let updatedGoods = [] - if (isLoadMore) { - // 加载更多:合并数据,但要去重 - const existingIds = new Set(this.data.goods.map(item => item.id)); - const uniqueNewGoods = newGoods.filter(item => !existingIds.has(item.id)); - updatedGoods = [...this.data.goods, ...uniqueNewGoods]; - } else { - updatedGoods = newGoods - } - - // 应用筛选条件 - const filteredGoods = this.applyFilters(updatedGoods) - const groupedGoods = this.groupGoodsForStaggeredLayout(filteredGoods) - const { leftColumnGoods, rightColumnGoods } = this.distributeToColumns(filteredGoods) - - // 计算是否还有更多数据 const totalGoods = res.total || 0; - const totalPages = res.totalPages || Math.ceil(totalGoods / currentPageSize); - const hasMoreData = currentPage < totalPages && newGoods.length > 0; + const totalPages = res.totalPages || Math.ceil(totalGoods / this.data.pageSize); + const hasMoreData = currentPage < totalPages && res.products.length > 0; - this.setData({ - goods: updatedGoods, - filteredGoods: filteredGoods, - groupedGoods: groupedGoods, - leftColumnGoods: leftColumnGoods, - rightColumnGoods: rightColumnGoods, - loadingMore: false, - page: currentPage + 1, - hasMoreData: hasMoreData, - totalGoods: totalGoods, - totalPages: totalPages - }) + this.setData({ hasMoreData }) + this.processGoodsData(res.products, isLoadMore) } else { - this.setData({ - loadingMore: false - }) + this.setData({ loadingMore: false, isLoading: false }) } }) .catch(err => { console.error('加载商品数据失败:', err) - this.setData({ - loadingMore: false - }) + this.setData({ loadingMore: false, isLoading: false }) }) }, @@ -385,62 +411,38 @@ Page({ applyFilters: function(goods) { let filtered = [...goods] - // 按品种筛选 if (this.data.selectedCategory !== '全部') { const category = this.data.selectedCategory let keyword = category + if (category === '粉壳') keyword = '粉' + else if (category === '绿壳') keyword = '绿' + else if (category === '红壳') keyword = '红' + else if (category === '白壳') keyword = '白' - // 根据品种确定对应的关键字 - if (category === '粉壳') { - keyword = '粉' - } else if (category === '绿壳') { - keyword = '绿' - } else if (category === '红壳') { - keyword = '红' - } else if (category === '白壳') { - keyword = '白' - } - - filtered = filtered.filter(item => { - const name = item.name || '' - return name.includes(keyword) - }) + filtered = filtered.filter(item => (item.name || '').includes(keyword)) } - // 按搜索关键词筛选(商品名称和地区都要匹配) if (this.data.searchKeyword) { const keyword = this.data.searchKeyword.toLowerCase() - filtered = filtered.filter(item => { - const name = item.name || '' - const region = item.region || '' - return name.toLowerCase().includes(keyword) || region.toLowerCase().includes(keyword) - }) + filtered = filtered.filter(item => + (item.name || '').toLowerCase().includes(keyword) || + (item.region || '').toLowerCase().includes(keyword) + ) } - // 按地区筛选 if (this.data.selectedRegion !== '全国') { - filtered = filtered.filter(item => { - return item.region === this.data.selectedRegion - }) + filtered = filtered.filter(item => item.region === this.data.selectedRegion) } - // 优先排序:按收藏人数、价格、创建时间排序 filtered.sort((a, b) => { - // 首先按收藏人数降序排序 const reservedCountA = a.reservedCount || 0 const reservedCountB = b.reservedCount || 0 - if (reservedCountB !== reservedCountA) { - return reservedCountB - reservedCountA - } + if (reservedCountB !== reservedCountA) return reservedCountB - reservedCountA - // 然后按价格升序排序 const priceA = parseFloat(a.price || 0) const priceB = parseFloat(b.price || 0) - if (!isNaN(priceB) && !isNaN(priceA) && priceA !== priceB) { - return priceA - priceB - } + if (!isNaN(priceB) && !isNaN(priceA) && priceA !== priceB) return priceA - priceB - // 最后按创建时间降序排序 const createdAtA = new Date(a.createdAt || 0).getTime() const createdAtB = new Date(b.createdAt || 0).getTime() return createdAtB - createdAtA @@ -449,6 +451,35 @@ Page({ return filtered }, + // 瀑布流布局 - 淘宝风格左右交替 + distributeToColumns: function(goods) { + if (!goods || goods.length === 0) { + return { leftColumnGoods: [], rightColumnGoods: [] } + } + + const leftColumn = [] + const rightColumn = [] + + 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 }) + } + + if (i + 1 < goods.length) { + rightColumn.push({ ...goods[i + 1], isLong: !isEvenRow }) + } + } + + return { leftColumnGoods: leftColumn, rightColumnGoods: rightColumn } + }, + }) + + return filtered + }, + // 分组商品用于交错布局(左长右短,左短右长交替) groupGoodsForStaggeredLayout: function(goods) { if (!goods || goods.length === 0) { diff --git a/pages/index/index.wxml b/pages/index/index.wxml index 968629d..6180858 100644 --- a/pages/index/index.wxml +++ b/pages/index/index.wxml @@ -125,88 +125,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + - 精选货源 + + - - + + + 预售 + 一手货源 - - {{item.name}} - {{item.specification || '无'}} | {{item.yolk || '无'}} - - {{item.supplyStatus || ''}} - {{item.sourceType || ''}} - {{item.negotiateStatus}} - - - - {{item.region}} + + {{item.name}} + {{item.specification || '无'}} | {{item.yolk}} + + + ¥ + {{item.price || item.minPrice || '--'}} + /{{item.unit}} - 已有{{item.reservedCount || 0}}人收藏 + + + 已售{{item.sales || item.reservedCount || 0}}件 + {{item.region || ''}} + - - + + + 预售 + 一手货源 - - {{item.name}} - {{item.specification || '无'}} | {{item.yolk || '无'}} - - {{item.supplyStatus || ''}} - {{item.sourceType || ''}} - {{item.negotiateStatus}} - - - - {{item.region}} + + {{item.name}} + {{item.specification || '无'}} | {{item.yolk}} + + + ¥ + {{item.price || item.minPrice || '--'}} + /{{item.unit}} - 已有{{item.reservedCount || 0}}人收藏 + + + 已售{{item.sales || item.reservedCount || 0}}件 + {{item.region || ''}} @@ -214,17 +259,25 @@ + + + + 加载中... + + + + + 没有更多商品了 + + - - 暂无商品数据 + + 📦 + 暂无商品数据 + 下拉刷新试试 - - - - 加载中... - diff --git a/pages/index/index.wxss b/pages/index/index.wxss index 06eb5d7..8ebc967 100644 --- a/pages/index/index.wxss +++ b/pages/index/index.wxss @@ -903,3 +903,353 @@ page { font-size: 36rpx; font-weight: bold; } + +/* ==================== 瀑布流布局(Masonry) ==================== */ + +/* 骨架屏样式 */ +.skeleton-container { + padding: 20rpx; + background: #f8f8f8; +} + +.skeleton-waterfall { + display: flex; + gap: 16rpx; + width: 100%; +} + +.skeleton-column { + flex: 1; + display: flex; + flex-direction: column; + gap: 16rpx; +} + +.skeleton-item { + background: #fff; + border-radius: 16rpx; + overflow: hidden; + padding-bottom: 20rpx; +} + +.skeleton-image { + width: 100%; + height: 350rpx; + background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%); + background-size: 200% 100%; + animation: skeleton-loading 1.5s infinite; +} + +.skeleton-title { + height: 32rpx; + margin: 20rpx 16rpx 12rpx; + background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%); + background-size: 200% 100%; + animation: skeleton-loading 1.5s infinite; + border-radius: 8rpx; +} + +.skeleton-title.short { + width: 60%; + margin-top: 0; +} + +.skeleton-footer { + margin: 16rpx; +} + +.skeleton-price { + width: 80rpx; + height: 32rpx; + background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%); + background-size: 200% 100%; + animation: skeleton-loading 1.5s infinite; + border-radius: 8rpx; +} + +@keyframes skeleton-loading { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} + +/* 商品区域样式 */ +.goods-section { + background-color: #f8f8f8; + padding: 16rpx; + margin: 0; + flex: 7; + overflow-y: auto; + width: 100%; + box-sizing: border-box; +} + +.goods-list-container { + padding: 0; + padding-bottom: 20rpx; +} + +/* 瀑布流容器 */ +.waterfall-container { + display: flex; + gap: 16rpx; + width: 100%; +} + +/* 瀑布流列 */ +.waterfall-column { + flex: 1; + display: flex; + flex-direction: column; + gap: 16rpx; +} + +.left-column { + align-items: flex-start; +} + +.right-column { + align-items: flex-end; +} + +/* 瀑布流商品项 */ +.waterfall-item { + width: 100%; + border-radius: 16rpx; + overflow: hidden; + transition: all 0.3s ease; +} + +.waterfall-item:active { + transform: scale(0.98); + opacity: 0.9; +} + +/* 商品卡片 */ +.product-card { + width: 100%; + background: #fff; + border-radius: 16rpx; + overflow: hidden; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; +} + +.product-card:active { + transform: scale(0.98); + box-shadow: 0 1rpx 6rpx rgba(0, 0, 0, 0.1); +} + +/* 商品图片区域 */ +.product-image-wrapper { + position: relative; + width: 100%; + background: #f5f5f5; + border-radius: 16rpx 16rpx 0 0; + overflow: hidden; +} + +.product-image { + width: 100%; + display: block; +} + +/* 促销标签 */ +.promo-tag { + position: absolute; + top: 0; + left: 0; + padding: 6rpx 12rpx; + font-size: 20rpx; + color: #fff; + border-radius: 0 0 12rpx 0; + z-index: 1; + font-weight: 600; +} + +.promo-tag.presale { + background: linear-gradient(135deg, #ff6b00 0%, #ff8c00 100%); + box-shadow: 0 2rpx 8rpx rgba(255, 107, 0, 0.3); +} + +.promo-tag.source { + background: linear-gradient(135deg, #e00 0%, #ff4d4f 100%); + box-shadow: 0 2rpx 8rpx rgba(255, 0, 0, 0.3); +} + +/* 商品信息区域 */ +.product-info { + padding: 16rpx; +} + +/* 商品标题 */ +.product-title { + font-size: 26rpx; + color: #333; + line-height: 1.4; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + min-height: 72rpx; + margin-bottom: 8rpx; + font-weight: 500; +} + +/* 商品规格 */ +.product-spec { + font-size: 22rpx; + color: #999; + margin-bottom: 12rpx; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* 价格区域 - 淘宝风格突出显示 */ +.product-price-row { + margin-bottom: 12rpx; + display: flex; + align-items: baseline; + justify-content: space-between; +} + +.price-wrapper { + display: flex; + align-items: baseline; +} + +.price-unit { + font-size: 24rpx; + color: #ff4d4f; + font-weight: 700; +} + +.price-value { + font-size: 40rpx; + color: #ff4d4f; + font-weight: 800; + margin: 0 2rpx; + letter-spacing: 1rpx; +} + +.price-unit:last-child { + margin-left: 4rpx; + font-size: 22rpx; + color: #ff4d4f; +} + +/* 销量和地区 - 淘宝风格 */ +.product-meta { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 22rpx; + color: #999; + margin-top: 8rpx; +} + +.sales-count { + color: #999; + background: rgba(255, 77, 79, 0.08); + padding: 4rpx 10rpx; + border-radius: 6rpx; + font-size: 20rpx; + font-weight: 500; +} + +.product-location { + max-width: 80rpx; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 20rpx; + color: #999; +} + +/* 加载更多 */ +.loading-more { + display: flex; + justify-content: center; + align-items: center; + padding: 30rpx 0; + width: 100%; +} + +.loading-spinner { + width: 32rpx; + height: 32rpx; + border: 3rpx solid #e5e5e5; + border-top-color: #1677ff; + border-radius: 50%; + animation: spin 0.8s linear infinite; + margin-right: 12rpx; +} + +.loading-text { + font-size: 26rpx; + color: #999; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +/* 无更多数据 */ +.no-more-data { + text-align: center; + padding: 30rpx 0; + color: #999; + font-size: 26rpx; + position: relative; +} + +.no-more-data::before, +.no-more-data::after { + content: ''; + position: absolute; + top: 50%; + width: 100rpx; + height: 1rpx; + background: #e5e5e5; +} + +.no-more-data::before { + left: 25%; +} + +.no-more-data::after { + right: 25%; +} + +/* 空商品状态 */ +.empty-goods { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 100rpx 0; + width: 100%; +} + +.empty-icon { + font-size: 80rpx; + margin-bottom: 20rpx; +} + +.empty-text { + font-size: 30rpx; + color: #999; + margin-bottom: 12rpx; +} + +.empty-hint { + font-size: 24rpx; + color: #ccc; +} diff --git a/pages/settlement/index.wxml b/pages/settlement/index.wxml index 8f578e2..ad06f76 100644 --- a/pages/settlement/index.wxml +++ b/pages/settlement/index.wxml @@ -344,18 +344,6 @@ - - - 提示 - 请先登录后再操作 - - - - - - - - 授权登录