// pages/goods/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']; for (const ext of videoExtensions) { if (lowerUrl.endsWith(ext)) { return true; } } return false; } Page({ // 分享给朋友/群聊 onShareAppMessage() { return { title: '内部货源管理 - 鸡蛋贸易平台', path: '/pages/goods/index', imageUrl: '/images/你有好蛋.png' } }, // 分享到朋友圈 onShareTimeline() { return { title: '内部货源管理 - 鸡蛋贸易平台', query: '', imageUrl: '/images/你有好蛋.png' } }, /** * 页面的初始数据 */ data: { goodsList: [], isLoading: false, isRefreshing: false, // 下拉刷新状态 searchKeyword: '', activeFilter: 'all', // 当前筛选条件:all, small, large filterConfig: { small: ['何佳芹', '李真音'], // 小品种创建者 large: ['吴海燕', '陈骏', '刘琴', '汤敏'] // 大贸易创建者 }, total: 0, // 总数据条数 searchTimer: null, // 搜索防抖定时器 // 分页相关字段 pageSize: 20, // 每页数量 publishedCurrentPage: 1, // 已上架商品当前页码 publishedHasMore: true, // 已上架商品是否有更多 soldOutCurrentPage: 1, // 售空商品当前页码 soldOutHasMore: true, // 售空商品是否有更多 currentLoadingType: '', // 当前加载类型:published, soldOut // 缓存相关字段 cache: { publishedGoods: [], // 已上架货源缓存 soldOutGoods: [], // 售空货源缓存 timestamp: 0, // 缓存时间戳 expiry: 5 * 60 * 1000 // 缓存有效期:5分钟 }, isLoadingPublished: false, // 正在加载已上架货源 isLoadingSoldOut: false, // 正在加载售空货源 publishedLoaded: false, // 已上架货源是否加载完成 soldOutLoaded: false // 售空货源是否加载完成 }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { this.loadGoodsList() }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady() { }, /** * 生命周期函数--监听页面显示 */ onShow() { }, /** * 生命周期函数--监听页面隐藏 */ onHide() { }, /** * 生命周期函数--监听页面卸载 */ onUnload() { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh() { // 这里的onPullDownRefresh是页面级的,但我们使用的是scroll-view内置的下拉刷新,所以不需要实现这个方法 }, /** * scroll-view下拉刷新事件处理 */ onRefresherRefresh() { if (this.data.isLoading) return // 清除缓存,确保获取最新数据 this.setData({ isRefreshing: true, goodsList: [], isLoading: false, 'cache.publishedGoods': [], 'cache.soldOutGoods': [], 'cache.timestamp': 0 }) this.loadGoodsList() }, /** * 页面上拉触底事件的处理函数 */ onReachBottom() { // 检查是否还有更多数据需要加载 const hasMore = this.data.publishedHasMore || this.data.soldOutHasMore if (hasMore && !this.data.isLoading) { this.loadGoodsList(true) // 传入true表示加载更多 } }, /** * 处理搜索输入 - 添加防抖功能 */ onSearchInput(e) { const keyword = e.detail.value; this.setData({ searchKeyword: keyword }); // 清除之前的定时器 if (this.data.searchTimer) { clearTimeout(this.data.searchTimer); } // 设置新的定时器,300ms后执行搜索 const searchTimer = setTimeout(() => { this.searchGoods(); }, 300); this.setData({ searchTimer: searchTimer }); }, /** * 执行搜索 */ searchGoods() { if (this.data.isLoading) return this.setData({ goodsList: [], // 清除缓存 'cache.publishedGoods': [], 'cache.soldOutGoods': [], 'cache.timestamp': 0 }) this.loadGoodsList() }, /** * 清除搜索 */ clearSearch() { this.setData({ searchKeyword: '', goodsList: [], // 清除缓存 'cache.publishedGoods': [], 'cache.soldOutGoods': [], 'cache.timestamp': 0 }) this.loadGoodsList() }, /** * 筛选条件改变 */ onFilterChange(e) { if (this.data.isLoading) return const filter = e.currentTarget.dataset.filter this.setData({ activeFilter: filter, goodsList: [], // 清除缓存 'cache.publishedGoods': [], 'cache.soldOutGoods': [], 'cache.timestamp': 0 }) this.loadGoodsList() }, /** * 根据搜索关键词过滤数据 - 确保能搜索到creatorName字段 */ searchGoodsList(goodsList, keyword) { if (!keyword || keyword.trim() === '') { return goodsList } const searchTerm = keyword.toLowerCase().trim() return goodsList.filter(item => { // 确保creatorName字段存在 const creatorName = item.creatorName || ''; // 检查多个字段是否包含搜索关键词,包括creatorName const fieldsToCheck = [ // 产品基本信息 item.productName || item.name || '', // 产品名称 item.specification || item.spec || '', // 规格 item.description || item.remark || '', // 描述 item.region || item.area || '', // 地区 item.yolk || item.variety || '', // 蛋黄 item.price || '', // 价格 item.costprice || '', // 采购价格 item.grossWeight || item.weight || '', // 重量 item.category || '', // 种类 item.minOrder || item.quantity || '', // 最小起订量 // 创建人信息 creatorName, // 已处理的创建人名称,确保能搜索到 // 创建/更新时间 item.formattedCreatedAt || item.updated_at || item.updatedAt || item.created_at || item.createdAt || '' // 创建/更新时间 ] // 检查是否有任何字段包含搜索关键词 return fieldsToCheck.some(field => { return field.toLowerCase().includes(searchTerm) }) }) }, /** * 根据筛选条件过滤数据 */ filterGoodsList(goodsList) { const { activeFilter, filterConfig } = this.data if (activeFilter === 'all') { return goodsList } const allowedCreators = filterConfig[activeFilter] || [] return goodsList.filter(item => { return allowedCreators.includes(item.creatorName) }) }, /** * 格式化时间 */ formatDateTime(dateString) { if (!dateString) return '未知时间' // 检查是否已经是格式化好的北京时间字符串(如:2026-01-05 17:30) if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?$/.test(dateString)) { // 直接返回格式化好的字符串,只保留到分钟 return dateString.slice(0, 16) } // 检查是否是ISO格式的字符串(如:2026-01-05T12:00:00.000Z) if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/.test(dateString)) { // 转换ISO格式为本地时间 const date = new Date(dateString) if (isNaN(date.getTime())) { return '未知时间' } const year = date.getFullYear() const month = (date.getMonth() + 1).toString().padStart(2, '0') const day = date.getDate().toString().padStart(2, '0') const hours = date.getHours().toString().padStart(2, '0') const minutes = date.getMinutes().toString().padStart(2, '0') return `${year}-${month}-${day} ${hours}:${minutes}` } // 对于其他格式的字符串,直接返回,不进行转换 // 这是为了避免对后端返回的北京时间字符串进行错误的时区转换 return dateString }, /** * 点击货源项跳转 */ onGoodsItemClick(e) { const goodsItem = e.currentTarget.dataset.item; console.log('点击了货源项:', goodsItem); // 跳转到货源详情页面(goods-update) wx.navigateTo({ url: `/pages/goods-update/goods-update?productId=${goodsItem.id || goodsItem.productId}&goodsData=${encodeURIComponent(JSON.stringify(goodsItem))}` }); }, /** * 加载所有商品数据 - 辅助方法 */ async loadAllGoodsData() { try { // 使用getProducts方法获取所有商品数据 const allGoods = await API.getProducts() // 对所有商品进行格式化处理 const formattedGoods = allGoods.map(item => { // 确定creatorName const sellerNickName = item.seller?.nickName || item.seller?.sellerNickName || item.seller?.name || '未知'; const creatorName = sellerNickName; // 处理媒体URL const imageUrls = item.imageUrls || item.images || [] const formattedImageUrls = Array.isArray(imageUrls) ? imageUrls : [imageUrls] const mediaItems = formattedImageUrls.map(url => ({ url: url, type: isVideoUrl(url) ? 'video' : 'image' })) // 处理商品状态 let status = item.status const isSoldOut = status === 'sold_out' || status === 'sold' || status === 'out_of_stock' || (item.supplyStatus && item.supplyStatus.includes('售空')); if (isSoldOut) { status = 'sold_out' } else if (status !== 'published') { status = 'published' } // 处理价格 let processedPrice = item.price; if (processedPrice && typeof processedPrice === 'string') { const priceArray = processedPrice.split(/[,,、]/).map(p => p.trim()).filter(p => p); if (priceArray.length > 0) { processedPrice = priceArray[0]; } } const productName = item.productName || item.name || '未命名商品'; const displayTime = item.updated_at || item.updatedAt || item.created_at || item.createTime; return { ...item, productName: productName, name: productName, status: status, price: processedPrice, formattedCreatedAt: this.formatDateTime(displayTime), creatorName: creatorName, imageUrls: formattedImageUrls, mediaItems: mediaItems } }) return formattedGoods } catch (err) { console.error('加载所有商品数据失败:', err) return [] } }, /** * 加载已上架(published)状态的货源 - 支持分页 */ async loadPublishedGoods(page = 1, pageSize = this.data.pageSize) { if (this.data.isLoadingPublished) return { goods: [], hasMore: true } this.setData({ isLoadingPublished: true, currentLoadingType: 'published' }) console.log('开始加载已上架货源,分页参数:', { page, pageSize, keyword: this.data.searchKeyword }) try { // 先获取所有商品数据 const allGoods = await this.loadAllGoodsData() // 过滤出已上架状态的商品 let publishedGoods = allGoods.filter(item => item.status === 'published') // 应用筛选和搜索 if (this.data.searchKeyword && this.data.searchKeyword.trim() !== '') { publishedGoods = this.searchGoodsList(publishedGoods, this.data.searchKeyword) } else { publishedGoods = this.filterGoodsList(publishedGoods) } // 排序逻辑:没有销售价格的商品排在最前面,然后按时间倒序排序 publishedGoods.sort((a, b) => { // 检查是否有销售价格 const hasPriceA = !!(a.price && a.price.trim() !== ''); const hasPriceB = !!(b.price && b.price.trim() !== ''); // 没有销售价格的排在前面 if (hasPriceA !== hasPriceB) { return hasPriceA ? 1 : -1; } // 都有或都没有销售价格时,按时间倒序排序 const timeA = new Date(a.updated_at || a.updatedAt || a.created_at || a.createTime).getTime(); const timeB = new Date(b.updated_at || b.updatedAt || b.created_at || b.createTime).getTime(); return timeB - timeA; }) // 进行分页处理 const startIndex = (page - 1) * pageSize const endIndex = startIndex + pageSize const paginatedGoods = publishedGoods.slice(startIndex, endIndex) const hasMore = endIndex < publishedGoods.length console.log('已上架货源加载完成,数量:', paginatedGoods.length, ',是否有更多:', hasMore) return { goods: paginatedGoods, hasMore: hasMore } } catch (err) { console.error('加载已上架货源失败:', err) return { goods: [], hasMore: false } } finally { this.setData({ isLoadingPublished: false, currentLoadingType: '' }) } }, /** * 加载售空(sold_out)状态的货源 - 支持分页 */ async loadSoldOutGoods(page = 1, pageSize = this.data.pageSize) { if (this.data.isLoadingSoldOut) return { goods: [], hasMore: true } this.setData({ isLoadingSoldOut: true, currentLoadingType: 'soldOut' }) console.log('开始加载售空货源,分页参数:', { page, pageSize, keyword: this.data.searchKeyword }) try { // 先获取所有商品数据 const allGoods = await this.loadAllGoodsData() // 过滤出售空状态的商品 let soldOutGoods = allGoods.filter(item => item.status === 'sold_out') // 应用筛选和搜索 if (this.data.searchKeyword && this.data.searchKeyword.trim() !== '') { soldOutGoods = this.searchGoodsList(soldOutGoods, this.data.searchKeyword) } else { soldOutGoods = this.filterGoodsList(soldOutGoods) } // 排序逻辑:没有销售价格的商品排在最前面,然后按时间倒序排序 soldOutGoods.sort((a, b) => { // 检查是否有销售价格 const hasPriceA = !!(a.price && a.price.trim() !== ''); const hasPriceB = !!(b.price && b.price.trim() !== ''); // 没有销售价格的排在前面 if (hasPriceA !== hasPriceB) { return hasPriceA ? 1 : -1; } // 都有或都没有销售价格时,按时间倒序排序 const timeA = new Date(a.updated_at || a.updatedAt || a.created_at || a.createTime).getTime(); const timeB = new Date(b.updated_at || b.updatedAt || b.created_at || b.createTime).getTime(); return timeB - timeA; }) // 进行分页处理 const startIndex = (page - 1) * pageSize const endIndex = startIndex + pageSize const paginatedGoods = soldOutGoods.slice(startIndex, endIndex) const hasMore = endIndex < soldOutGoods.length console.log('售空货源加载完成,数量:', paginatedGoods.length, ',是否有更多:', hasMore) return { goods: paginatedGoods, hasMore: hasMore } } catch (err) { console.error('加载售空货源失败:', err) return { goods: [], hasMore: false } } finally { this.setData({ isLoadingSoldOut: false, currentLoadingType: '' }) } }, /** * 检查缓存是否有效 */ isCacheValid() { const now = Date.now() const cache = this.data.cache return cache.timestamp > 0 && now - cache.timestamp < cache.expiry }, /** * 加载货源列表 - 先加载已上架,再加载售空,支持分页和缓存 */ async loadGoodsList(isLoadMore = false) { if (this.data.isLoading) return // 如果是初始加载,重置分页状态 if (!isLoadMore) { this.setData({ isLoading: true, publishedLoaded: false, soldOutLoaded: false, goodsList: [], publishedCurrentPage: 1, publishedHasMore: true, soldOutCurrentPage: 1, soldOutHasMore: true }) } else { this.setData({ isLoading: true }) } console.log('开始加载货源列表,参数:', { keyword: this.data.searchKeyword, activeFilter: this.data.activeFilter, useCache: this.isCacheValid(), isLoadMore: isLoadMore, publishedCurrentPage: this.data.publishedCurrentPage, publishedHasMore: this.data.publishedHasMore, soldOutCurrentPage: this.data.soldOutCurrentPage, soldOutHasMore: this.data.soldOutHasMore }) try { // 为了确保获取最新数据,暂时禁用缓存,直接从服务器获取 // 后续可以根据需要恢复缓存逻辑 // if (!isLoadMore && this.isCacheValid()) { // console.log('使用缓存数据') // const cache = this.data.cache // // this.setData({ // goodsList: [...cache.publishedGoods, ...cache.soldOutGoods], // publishedLoaded: true, // soldOutLoaded: true, // publishedHasMore: false, // soldOutHasMore: false, // total: cache.publishedGoods.length + cache.soldOutGoods.length // }) // // return // } console.log('缓存无效或加载更多,从服务器获取数据') let newGoods = [] let updatedPublishedHasMore = this.data.publishedHasMore let updatedSoldOutHasMore = this.data.soldOutHasMore // 1. 如果已上架商品还有更多,继续加载已上架商品 if (this.data.publishedHasMore) { console.log('加载已上架商品第', this.data.publishedCurrentPage, '页') const publishedResult = await this.loadPublishedGoods( this.data.publishedCurrentPage, this.data.pageSize ) newGoods = publishedResult.goods updatedPublishedHasMore = publishedResult.hasMore // 如果是加载更多,追加数据;否则替换数据 this.setData({ goodsList: isLoadMore ? [...this.data.goodsList, ...newGoods] : newGoods, publishedHasMore: updatedPublishedHasMore }) // 如果已上架商品还有更多,更新页码,返回等待下一次加载 if (updatedPublishedHasMore) { this.setData({ publishedCurrentPage: this.data.publishedCurrentPage + 1 }) return } else { // 已上架商品加载完成 this.setData({ publishedLoaded: true }) } // 添加缓冲,避免请求太快 await new Promise(resolve => setTimeout(resolve, 500)) } // 2. 如果已上架商品加载完,开始加载售空商品 if (!this.data.publishedHasMore && this.data.soldOutHasMore) { console.log('加载售空商品第', this.data.soldOutCurrentPage, '页') const soldOutResult = await this.loadSoldOutGoods( this.data.soldOutCurrentPage, this.data.pageSize ) newGoods = soldOutResult.goods updatedSoldOutHasMore = soldOutResult.hasMore // 追加售空商品数据 this.setData({ goodsList: [...this.data.goodsList, ...newGoods], soldOutHasMore: updatedSoldOutHasMore }) // 如果售空商品还有更多,更新页码 if (updatedSoldOutHasMore) { this.setData({ soldOutCurrentPage: this.data.soldOutCurrentPage + 1 }) } else { // 售空商品加载完成 this.setData({ soldOutLoaded: true }) } } console.log('货源列表加载完成,当前总数:', this.data.goodsList.length) // 如果是初始加载且所有数据加载完成,更新缓存 if (!isLoadMore && !this.data.publishedHasMore && !this.data.soldOutHasMore) { // 分离已上架和售空商品 const publishedGoods = this.data.goodsList.filter(item => item.status === 'published') const soldOutGoods = this.data.goodsList.filter(item => item.status === 'sold_out') this.setData({ 'cache.publishedGoods': publishedGoods, 'cache.soldOutGoods': soldOutGoods, 'cache.timestamp': Date.now() }) } } catch (err) { console.error('获取货源列表失败:', err) wx.showToast({ title: '获取货源列表失败: ' + err.message, icon: 'none' }) // 加载失败时,如果是初始加载,尝试使用缓存数据 if (!isLoadMore && (this.data.cache.publishedGoods.length > 0 || this.data.cache.soldOutGoods.length > 0)) { console.log('使用缓存数据作为 fallback') const cache = this.data.cache this.setData({ goodsList: [...cache.publishedGoods, ...cache.soldOutGoods], publishedLoaded: true, soldOutLoaded: true, publishedHasMore: false, soldOutHasMore: false, total: cache.publishedGoods.length + cache.soldOutGoods.length }) } } finally { // 结束下拉刷新和加载状态 this.setData({ isLoading: false, isRefreshing: false }) } } })