Browse Source

优化goods页面:添加分页加载,先加载已上架商品再加载售空商品,加入缓存机制

pull/12/head
Default User 2 months ago
parent
commit
d194442971
  1. 481
      pages/goods/index.js
  2. 2
      pages/goods/index.wxml

481
pages/goods/index.js

@ -42,9 +42,6 @@ Page({
goodsList: [], goodsList: [],
isLoading: false, isLoading: false,
isRefreshing: false, // 下拉刷新状态 isRefreshing: false, // 下拉刷新状态
currentPage: 1,
pageSize: 20,
hasMore: true,
searchKeyword: '', searchKeyword: '',
activeFilter: 'all', // 当前筛选条件:all, small, large activeFilter: 'all', // 当前筛选条件:all, small, large
filterConfig: { filterConfig: {
@ -52,7 +49,25 @@ Page({
large: ['吴海燕', '陈骏', '刘琴', '汤敏'] // 大贸易创建者 large: ['吴海燕', '陈骏', '刘琴', '汤敏'] // 大贸易创建者
}, },
total: 0, // 总数据条数 total: 0, // 总数据条数
searchTimer: null // 搜索防抖定时器 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 // 售空货源是否加载完成
}, },
/** /**
@ -105,9 +120,7 @@ Page({
this.setData({ this.setData({
isRefreshing: true, isRefreshing: true,
currentPage: 1,
goodsList: [], goodsList: [],
hasMore: true,
isLoading: false isLoading: false
}) })
this.loadGoodsList() this.loadGoodsList()
@ -117,11 +130,10 @@ Page({
* 页面上拉触底事件的处理函数 * 页面上拉触底事件的处理函数
*/ */
onReachBottom() { onReachBottom() {
if (this.data.hasMore && !this.data.isLoading) { // 检查是否还有更多数据需要加载
this.setData({ const hasMore = this.data.publishedHasMore || this.data.soldOutHasMore
currentPage: this.data.currentPage + 1 if (hasMore && !this.data.isLoading) {
}) this.loadGoodsList(true) // 传入true表示加载更多
this.loadGoodsList()
} }
}, },
@ -156,9 +168,11 @@ Page({
if (this.data.isLoading) return if (this.data.isLoading) return
this.setData({ this.setData({
currentPage: 1,
goodsList: [], goodsList: [],
hasMore: true // 清除缓存
'cache.publishedGoods': [],
'cache.soldOutGoods': [],
'cache.timestamp': 0
}) })
this.loadGoodsList() this.loadGoodsList()
}, },
@ -169,9 +183,11 @@ Page({
clearSearch() { clearSearch() {
this.setData({ this.setData({
searchKeyword: '', searchKeyword: '',
currentPage: 1,
goodsList: [], goodsList: [],
hasMore: true // 清除缓存
'cache.publishedGoods': [],
'cache.soldOutGoods': [],
'cache.timestamp': 0
}) })
this.loadGoodsList() this.loadGoodsList()
}, },
@ -185,9 +201,11 @@ Page({
const filter = e.currentTarget.dataset.filter const filter = e.currentTarget.dataset.filter
this.setData({ this.setData({
activeFilter: filter, activeFilter: filter,
currentPage: 1,
goodsList: [], goodsList: [],
hasMore: true // 清除缓存
'cache.publishedGoods': [],
'cache.soldOutGoods': [],
'cache.timestamp': 0
}) })
this.loadGoodsList() this.loadGoodsList()
}, },
@ -297,68 +315,39 @@ Page({
}, },
/** /**
* 加载货源列表 - 优化搜索功能支持搜索创建人信息 * 加载已上架(published)状态的货源 - 支持分页
*/ */
async loadGoodsList() { async loadPublishedGoods(page = 1, pageSize = this.data.pageSize) {
if (this.data.isLoading) return if (this.data.isLoadingPublished) return { goods: [], hasMore: true }
this.setData({ this.setData({
isLoading: true isLoadingPublished: true,
currentLoadingType: 'published'
}) })
console.log('开始加载货源列表,参数:', { console.log('开始加载已上架货源,分页参数:', {
page: this.data.currentPage, page,
pageSize: this.data.pageSize, pageSize,
keyword: this.data.searchKeyword, keyword: this.data.searchKeyword
activeFilter: this.data.activeFilter
}) })
// 调用API获取货源列表
try { try {
const res = await API.getGoodsList({ const res = await API.getGoodsList({
page: this.data.currentPage, page: page,
pageSize: this.data.pageSize, pageSize: pageSize,
keyword: this.data.searchKeyword keyword: this.data.searchKeyword
}) })
console.log('API返回结果:', res)
// 检查API返回的状态
if (res.success) { if (res.success) {
console.log('API调用成功,products:', res.products) let publishedGoods = res.products || []
console.log('products长度:', res.products.length)
console.log('API返回total:', res.total) // 数据格式化处理
publishedGoods = publishedGoods.map(item => {
// 更新总数据条数 // 确定creatorName
const total = res.total || 0
if (res.products && res.products.length > 0) {
// 显示第一个产品的详细信息
console.log('第一个产品:', res.products[0])
console.log('第一个产品的seller:', res.products[0].seller)
console.log('第一个产品的seller.nickName:', res.products[0].seller?.nickName)
console.log('第一个产品的seller.name:', res.products[0].seller?.name)
console.log('第一个产品的seller完整结构:', JSON.stringify(res.products[0].seller))
let newGoodsList = res.products || []
// 格式化创建时间并处理创建者信息
newGoodsList = newGoodsList.map((item, index) => {
// 详细日志,查看每个产品的seller信息
console.log(`产品${index}的seller信息:`)
console.log(`- seller对象:`, item.seller)
console.log(`- seller.nickName:`, item.seller?.nickName)
console.log(`- seller.sellerNickName:`, item.seller?.sellerNickName)
console.log(`- seller.name:`, item.seller?.name)
console.log(`- seller完整结构:`, JSON.stringify(item.seller))
// 确定creatorName - 支持多种字段,确保能获取到创建人信息
// 从seller对象中获取创建人信息,优先使用nickName,其次使用sellerNickName,最后使用name
const sellerNickName = item.seller?.nickName || item.seller?.sellerNickName || item.seller?.name || '未知'; const sellerNickName = item.seller?.nickName || item.seller?.sellerNickName || item.seller?.name || '未知';
const creatorName = sellerNickName; const creatorName = sellerNickName;
console.log('creatorName获取结果:', creatorName)
// 处理媒体URL,添加类型信息 // 处理媒体URL
const imageUrls = item.imageUrls || item.images || [] const imageUrls = item.imageUrls || item.images || []
const formattedImageUrls = Array.isArray(imageUrls) ? imageUrls : [imageUrls] const formattedImageUrls = Array.isArray(imageUrls) ? imageUrls : [imageUrls]
const mediaItems = formattedImageUrls.map(url => ({ const mediaItems = formattedImageUrls.map(url => ({
@ -366,140 +355,372 @@ Page({
type: isVideoUrl(url) ? 'video' : 'image' type: isVideoUrl(url) ? 'video' : 'image'
})) }))
// 处理商品状态,将已下架的商品标记为售空 // 处理商品状态
let status = item.status let status = item.status
// 检查是否为售空状态
const isSoldOut = status === 'sold_out' || const isSoldOut = status === 'sold_out' ||
status === 'sold' || status === 'sold' ||
status === 'out_of_stock' || status === 'out_of_stock' ||
(item.supplyStatus && item.supplyStatus.includes('售空')); (item.supplyStatus && item.supplyStatus.includes('售空'));
// 如果商品是售空状态,则标记为sold_out
if (isSoldOut) { if (isSoldOut) {
status = 'sold_out' status = 'sold_out'
} else if (status !== 'published') { } else if (status !== 'published') {
// 如果不是已上架状态且不是售空状态,仍然标记为已上架,确保预售和现货商品能正常显示
status = 'published' status = 'published'
} }
// 处理价格,只显示第一个规格的价格 // 只保留published状态的商品
if (status !== 'published') {
return null
}
// 处理价格
let processedPrice = item.price; let processedPrice = item.price;
if (processedPrice && typeof processedPrice === 'string') { if (processedPrice && typeof processedPrice === 'string') {
// 支持多种逗号分隔符:英文逗号、中文逗号、全角逗号
const priceArray = processedPrice.split(/[,,、]/).map(p => p.trim()).filter(p => p); const priceArray = processedPrice.split(/[,,、]/).map(p => p.trim()).filter(p => p);
if (priceArray.length > 0) { if (priceArray.length > 0) {
processedPrice = priceArray[0]; processedPrice = priceArray[0];
} }
} }
// 确保productName字段存在,优先使用productName,其次使用name
const productName = item.productName || item.name || '未命名商品'; const productName = item.productName || item.name || '未命名商品';
// 确定显示时间:优先使用更新时间,其次使用创建时间
const displayTime = item.updated_at || item.updatedAt || item.created_at || item.createTime; const displayTime = item.updated_at || item.updatedAt || item.created_at || item.createTime;
return { return {
...item, ...item,
productName: productName, // 确保productName字段存在 productName: productName,
name: productName, // 确保name字段存在 name: productName,
status: status, // 更新商品状态 status: status,
price: processedPrice, // 更新为第一个规格的价格 price: processedPrice,
formattedCreatedAt: this.formatDateTime(displayTime), formattedCreatedAt: this.formatDateTime(displayTime),
creatorName: creatorName, // 已处理的创建人名称 creatorName: creatorName,
imageUrls: formattedImageUrls, imageUrls: formattedImageUrls,
mediaItems: mediaItems mediaItems: mediaItems
} }
}).filter(Boolean) // 过滤掉null值
// 应用筛选和搜索
let filteredGoods = publishedGoods
if (this.data.searchKeyword && this.data.searchKeyword.trim() !== '') {
filteredGoods = this.searchGoodsList(filteredGoods, this.data.searchKeyword)
} else {
filteredGoods = this.filterGoodsList(filteredGoods)
}
// 按时间倒序排序
filteredGoods.sort((a, b) => {
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 originalList = [...newGoodsList] const hasMore = publishedGoods.length >= pageSize
// 搜索逻辑:如果有搜索关键词,只应用搜索过滤,不应用筛选条件 console.log('已上架货源加载完成,数量:', filteredGoods.length, ',是否有更多:', hasMore)
// 这样搜索时能找到所有匹配的商品,不受筛选条件限制
let filteredList; return { goods: filteredGoods, hasMore: hasMore }
if (this.data.searchKeyword && this.data.searchKeyword.trim() !== '') {
// 有搜索关键词时,只应用搜索过滤
filteredList = this.searchGoodsList(newGoodsList, this.data.searchKeyword)
} else { } else {
// 没有搜索关键词时,应用筛选条件 console.error('加载已上架货源失败:', res.message)
filteredList = this.filterGoodsList(newGoodsList) return { goods: [], hasMore: false }
}
} 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 {
filteredList.sort((a, b) => { const res = await API.getGoodsList({
if (a.status === 'published' && b.status === 'sold_out') { page: page,
return -1 // 已上架排在前面 pageSize: pageSize,
} else if (a.status === 'sold_out' && b.status === 'published') { keyword: this.data.searchKeyword
return 1 // 售空排在后面 })
if (res.success) {
let soldOutGoods = res.products || []
// 数据格式化处理
soldOutGoods = soldOutGoods.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'
}
// 只保留sold_out状态的商品
if (status !== 'sold_out') {
return null
}
// 处理价格
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
}
}).filter(Boolean) // 过滤掉null值
// 应用筛选和搜索
let filteredGoods = soldOutGoods
if (this.data.searchKeyword && this.data.searchKeyword.trim() !== '') {
filteredGoods = this.searchGoodsList(filteredGoods, this.data.searchKeyword)
} else { } else {
// 相同状态下,按显示时间(优先更新时间)倒序排序 filteredGoods = this.filterGoodsList(filteredGoods)
}
// 按时间倒序排序
filteredGoods.sort((a, b) => {
const timeA = new Date(a.updated_at || a.updatedAt || a.created_at || a.createTime).getTime() 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() const timeB = new Date(b.updated_at || b.updatedAt || b.created_at || b.createTime).getTime()
return timeB - timeA return timeB - timeA
})
// 判断是否有更多数据
const hasMore = soldOutGoods.length >= pageSize
console.log('售空货源加载完成,数量:', filteredGoods.length, ',是否有更多:', hasMore)
return { goods: filteredGoods, hasMore: hasMore }
} else {
console.error('加载售空货源失败:', res.message)
return { goods: [], hasMore: false }
} }
} catch (err) {
console.error('加载售空货源失败:', err)
return { goods: [], hasMore: false }
} finally {
this.setData({
isLoadingSoldOut: false,
currentLoadingType: ''
}) })
}
},
console.log('处理并筛选后的产品列表:', filteredList) /**
console.log('筛选前后数量对比:', originalList.length, '->', filteredList.length) * 检查缓存是否有效
*/
isCacheValid() {
const now = Date.now()
const cache = this.data.cache
return cache.timestamp > 0 && now - cache.timestamp < cache.expiry
},
// 处理分页逻辑 /**
let updatedGoodsList = this.data.currentPage === 1 ? filteredList : [...this.data.goodsList, ...filteredList] * 加载货源列表 - 先加载已上架再加载售空支持分页和缓存
*/
async loadGoodsList(isLoadMore = false) {
if (this.data.isLoading) return
// 对整个列表进行排序,确保已上架商品始终在前面,售空商品在后面 // 如果是初始加载,重置分页状态
updatedGoodsList.sort((a, b) => { if (!isLoadMore) {
if (a.status === 'published' && b.status === 'sold_out') { this.setData({
return -1 // 已上架排在前面 isLoading: true,
} else if (a.status === 'sold_out' && b.status === 'published') { publishedLoaded: false,
return 1 // 售空排在后面 soldOutLoaded: false,
goodsList: [],
publishedCurrentPage: 1,
publishedHasMore: true,
soldOutCurrentPage: 1,
soldOutHasMore: true
})
} else { } else {
// 相同状态下,按创建时间倒序排序 this.setData({
const timeA = new Date(a.created_at || a.createTime).getTime() isLoading: true
const timeB = new Date(b.created_at || b.createTime).getTime() })
return timeB - timeA
} }
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 {
// 正确逻辑:如果API返回的原始数据数量小于pageSize,说明没有更多数据 // 如果是初始加载,检查缓存是否有效
// 即使筛选后的数据量小于pageSize,只要API返回的原始数据数量等于pageSize,就应该继续尝试加载更多数据 if (!isLoadMore && this.isCacheValid()) {
const hasMore = res.products.length >= this.data.pageSize console.log('使用缓存数据')
const cache = this.data.cache
console.log('分页判断:', { this.setData({
updatedGoodsListLength: updatedGoodsList.length, goodsList: [...cache.publishedGoods, ...cache.soldOutGoods],
originalDataLength: res.products.length, publishedLoaded: true,
pageSize: this.data.pageSize, soldOutLoaded: true,
hasMore: hasMore 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({ this.setData({
goodsList: updatedGoodsList, goodsList: isLoadMore ? [...this.data.goodsList, ...newGoods] : newGoods,
hasMore: hasMore, publishedHasMore: updatedPublishedHasMore
total: total
}) })
// 移除递归调用逻辑,避免无限递归风险 // 如果已上架商品还有更多,更新页码,返回等待下一次加载
// 用户可以通过正常的上拉加载获取更多数据 if (updatedPublishedHasMore) {
this.setData({
publishedCurrentPage: this.data.publishedCurrentPage + 1
})
return
} else { } else {
console.log('没有产品数据返回') // 已上架商品加载完成
this.setData({ this.setData({
goodsList: [], publishedLoaded: true
hasMore: false,
total: 0
}) })
} }
// 添加缓冲,避免请求太快
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 { } else {
console.error('API调用失败:', res.message) // 售空商品加载完成
wx.showToast({ this.setData({
title: res.message || '获取货源列表失败', soldOutLoaded: true
icon: 'none'
}) })
} }
}
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) { } catch (err) {
console.error('获取货源列表失败:', err) console.error('获取货源列表失败:', err)
wx.showToast({ wx.showToast({
title: '获取货源列表失败: ' + err.message, title: '获取货源列表失败: ' + err.message,
icon: 'none' 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 { } finally {
// 结束下拉刷新和加载状态 // 结束下拉刷新和加载状态
this.setData({ this.setData({

2
pages/goods/index.wxml

@ -135,7 +135,7 @@
</view> </view>
<!-- 无更多数据 --> <!-- 无更多数据 -->
<view wx:if="{{!hasMore && goodsList.length > 0}}" class="no-more-data"> <view wx:if="{{!publishedHasMore && !soldOutHasMore && goodsList.length > 0}}" class="no-more-data">
<text>货源正在快马加鞭的赶来</text> <text>货源正在快马加鞭的赶来</text>
</view> </view>

Loading…
Cancel
Save