// 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']; return videoExtensions.some(ext => lowerUrl.endsWith(ext)); } 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') { if (dateString.includes(' ')) { // 直接返回格式化好的字符串,只保留到分钟 return dateString.slice(0, 16) } else if (dateString.includes('T')) { // 转换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; // 跳转到货源详情页面(goods-update) wx.navigateTo({ url: `/pages/goods-update/goods-update?productId=${goodsItem.id || goodsItem.productId}&goodsData=${encodeURIComponent(JSON.stringify(goodsItem))}` }); }, /** * 加载商品数据 - 支持分页 */ async loadGoodsData(page = 1, pageSize = this.data.pageSize, status = 'all', keyword = '') { try { // 使用getProducts方法获取商品数据,支持分页和搜索 const result = await API.getProducts(page, pageSize, status, keyword) console.log('API返回原始数据:', result) console.log('API返回商品数量:', result.products.length) console.log('当前分页参数:', { page, pageSize, status, keyword }) // 对商品进行格式化处理 const formattedGoods = result.products.map(item => { // 确定creatorName console.log('商品原始数据:', item) console.log('商品seller字段:', item.seller) 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 } }) console.log('格式化后的商品数据:', formattedGoods) return { goods: formattedGoods, total: result.total, hasMore: result.hasMore } } catch (err) { console.error('加载商品数据失败:', err) return { goods: [], total: 0, hasMore: false } } }, /** * 加载已上架(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 }) } try { // 检查缓存是否有效 if (!isLoadMore && this.isCacheValid()) { console.log('使用缓存数据') const cache = this.data.cache // 重新应用当前筛选条件到缓存数据 const allCachedGoods = [...cache.publishedGoods, ...cache.soldOutGoods] const filteredGoods = this.filterGoodsList(allCachedGoods) console.log('缓存商品数量:', allCachedGoods.length) console.log('筛选后缓存商品数量:', filteredGoods.length) this.setData({ goodsList: filteredGoods, publishedLoaded: true, soldOutLoaded: true, publishedHasMore: false, soldOutHasMore: false, total: filteredGoods.length }) return } // 1. 处理已上架商品 - 持续加载直到找到足够的符合条件的商品 if (this.data.publishedHasMore) { let accumulatedFilteredGoods = [] let currentPage = this.data.publishedCurrentPage let hasMore = true // 持续加载,直到找到至少20条符合条件的商品或者没有更多数据 while (hasMore && accumulatedFilteredGoods.length < this.data.pageSize) { // 从服务器获取已上架商品数据,支持分页和搜索 const result = await this.loadGoodsData( currentPage, this.data.pageSize, 'published', this.data.searchKeyword ) console.log('原始商品数据:', result.goods) console.log('当前筛选条件:', this.data.activeFilter) console.log('筛选配置:', this.data.filterConfig) console.log('分页参数:', { page: currentPage, pageSize: this.data.pageSize }) console.log('hasMore:', result.hasMore) // 应用筛选逻辑 const filteredGoods = this.filterGoodsList(result.goods) console.log('筛选后商品数据:', filteredGoods) console.log('筛选后商品数量:', filteredGoods.length) // 累积符合条件的商品 accumulatedFilteredGoods = [...accumulatedFilteredGoods, ...filteredGoods] // 更新状态 hasMore = result.hasMore currentPage++ // 如果已经找到足够的商品,跳出循环 if (accumulatedFilteredGoods.length >= this.data.pageSize) { break } } console.log('累积筛选后商品数量:', accumulatedFilteredGoods.length) // 如果是加载更多,追加数据;否则替换数据 if (accumulatedFilteredGoods.length > 0) { this.setData({ goodsList: isLoadMore ? [...this.data.goodsList, ...accumulatedFilteredGoods] : accumulatedFilteredGoods }) } // 更新页码和hasMore状态 this.setData({ publishedCurrentPage: currentPage, publishedHasMore: hasMore }) console.log('已上架商品加载完成,更新页码为:', currentPage, ',是否有更多:', hasMore) // 如果没有更多数据,标记为加载完成 if (!hasMore) { this.setData({ publishedLoaded: true }) console.log('已上架商品加载完成') } } // 2. 处理售空商品 - 持续加载直到找到足够的符合条件的商品 // 对于初始加载,即使已上架商品还有更多,也尝试加载售空商品 // 这样可以确保用户能看到所有类型的商品 if ((!isLoadMore || !this.data.publishedHasMore) && this.data.soldOutHasMore) { let accumulatedFilteredGoods = [] let currentPage = this.data.soldOutCurrentPage let hasMore = true // 持续加载,直到找到至少20条符合条件的商品或者没有更多数据 while (hasMore && accumulatedFilteredGoods.length < this.data.pageSize) { // 从服务器获取售空商品数据,支持分页和搜索 const result = await this.loadGoodsData( currentPage, this.data.pageSize, 'sold_out', this.data.searchKeyword ) console.log('售空商品数据:', result.goods) console.log('售空商品分页参数:', { page: currentPage, pageSize: this.data.pageSize }) console.log('售空商品hasMore:', result.hasMore) console.log('当前筛选条件:', this.data.activeFilter) // 应用筛选逻辑 const filteredGoods = this.filterGoodsList(result.goods) console.log('筛选后售空商品数据:', filteredGoods) console.log('筛选后售空商品数量:', filteredGoods.length) // 累积符合条件的商品 accumulatedFilteredGoods = [...accumulatedFilteredGoods, ...filteredGoods] // 更新状态 hasMore = result.hasMore currentPage++ // 如果已经找到足够的商品,跳出循环 if (accumulatedFilteredGoods.length >= this.data.pageSize) { break } } console.log('累积筛选后售空商品数量:', accumulatedFilteredGoods.length) // 追加售空商品数据 if (accumulatedFilteredGoods.length > 0) { this.setData({ goodsList: isLoadMore ? [...this.data.goodsList, ...accumulatedFilteredGoods] : [...this.data.goodsList, ...accumulatedFilteredGoods] }) } // 更新页码和hasMore状态 this.setData({ soldOutCurrentPage: currentPage, soldOutHasMore: hasMore }) console.log('售空商品加载完成,更新页码为:', currentPage, ',是否有更多:', hasMore) // 如果没有更多数据,标记为加载完成 if (!hasMore) { this.setData({ soldOutLoaded: true }) console.log('售空商品加载完成') } } console.log('加载完成后状态:', { publishedHasMore: this.data.publishedHasMore, soldOutHasMore: this.data.soldOutHasMore, publishedCurrentPage: this.data.publishedCurrentPage, soldOutCurrentPage: this.data.soldOutCurrentPage, goodsListLength: this.data.goodsList.length }) // 如果是初始加载且所有数据加载完成,更新缓存 if (!isLoadMore && !this.data.publishedHasMore && !this.data.soldOutHasMore) { // 由于现在采用分页加载,缓存逻辑需要调整 // 暂时禁用缓存更新,确保每次都从服务器获取最新数据 console.log('分页加载模式,跳过缓存更新') } } catch (err) { wx.showToast({ title: '获取货源列表失败: ' + err.message, icon: 'none' }) // 加载失败时,如果是初始加载,尝试使用缓存数据 if (!isLoadMore && (this.data.cache.publishedGoods.length > 0 || this.data.cache.soldOutGoods.length > 0)) { 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 }) } } })