You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
460 lines
14 KiB
460 lines
14 KiB
// 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, // 下拉刷新状态
|
|
currentPage: 1,
|
|
pageSize: 20,
|
|
hasMore: true,
|
|
searchKeyword: '',
|
|
activeFilter: 'all', // 当前筛选条件:all, small, large
|
|
filterConfig: {
|
|
small: ['何佳芹', '李真音'], // 小品种创建者
|
|
large: ['吴海燕', '陈骏', '刘琴', '汤敏'] // 大贸易创建者
|
|
},
|
|
total: 0 // 总数据条数
|
|
},
|
|
|
|
/**
|
|
* 生命周期函数--监听页面加载
|
|
*/
|
|
onLoad(options) {
|
|
this.loadGoodsList()
|
|
},
|
|
|
|
/**
|
|
* 生命周期函数--监听页面初次渲染完成
|
|
*/
|
|
onReady() {
|
|
|
|
},
|
|
|
|
/**
|
|
* 生命周期函数--监听页面显示
|
|
*/
|
|
onShow() {
|
|
|
|
},
|
|
|
|
/**
|
|
* 生命周期函数--监听页面隐藏
|
|
*/
|
|
onHide() {
|
|
|
|
},
|
|
|
|
/**
|
|
* 生命周期函数--监听页面卸载
|
|
*/
|
|
onUnload() {
|
|
|
|
},
|
|
|
|
/**
|
|
* 页面相关事件处理函数--监听用户下拉动作
|
|
*/
|
|
onPullDownRefresh() {
|
|
// 这里的onPullDownRefresh是页面级的,但我们使用的是scroll-view内置的下拉刷新,所以不需要实现这个方法
|
|
},
|
|
|
|
/**
|
|
* scroll-view下拉刷新事件处理
|
|
*/
|
|
onRefresherRefresh() {
|
|
if (this.data.isLoading) return
|
|
|
|
this.setData({
|
|
isRefreshing: true,
|
|
currentPage: 1,
|
|
goodsList: [],
|
|
hasMore: true,
|
|
isLoading: false
|
|
})
|
|
this.loadGoodsList()
|
|
},
|
|
|
|
/**
|
|
* 页面上拉触底事件的处理函数
|
|
*/
|
|
onReachBottom() {
|
|
if (this.data.hasMore && !this.data.isLoading) {
|
|
this.setData({
|
|
currentPage: this.data.currentPage + 1
|
|
})
|
|
this.loadGoodsList()
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 处理搜索输入
|
|
*/
|
|
onSearchInput(e) {
|
|
this.setData({
|
|
searchKeyword: e.detail.value
|
|
})
|
|
},
|
|
|
|
/**
|
|
* 执行搜索
|
|
*/
|
|
searchGoods() {
|
|
if (this.data.isLoading) return
|
|
|
|
this.setData({
|
|
currentPage: 1,
|
|
goodsList: [],
|
|
hasMore: true
|
|
})
|
|
this.loadGoodsList()
|
|
},
|
|
|
|
/**
|
|
* 清除搜索
|
|
*/
|
|
clearSearch() {
|
|
this.setData({
|
|
searchKeyword: '',
|
|
currentPage: 1,
|
|
goodsList: [],
|
|
hasMore: true
|
|
})
|
|
this.loadGoodsList()
|
|
},
|
|
|
|
/**
|
|
* 筛选条件改变
|
|
*/
|
|
onFilterChange(e) {
|
|
if (this.data.isLoading) return
|
|
|
|
const filter = e.currentTarget.dataset.filter
|
|
this.setData({
|
|
activeFilter: filter,
|
|
currentPage: 1,
|
|
goodsList: [],
|
|
hasMore: true
|
|
})
|
|
this.loadGoodsList()
|
|
},
|
|
|
|
/**
|
|
* 根据搜索关键词过滤数据
|
|
*/
|
|
searchGoodsList(goodsList, keyword) {
|
|
if (!keyword || keyword.trim() === '') {
|
|
return goodsList
|
|
}
|
|
|
|
const searchTerm = keyword.toLowerCase().trim()
|
|
|
|
return goodsList.filter(item => {
|
|
// 检查多个字段是否包含搜索关键词
|
|
const fieldsToCheck = [
|
|
item.productName || item.name || '', // 产品名称
|
|
item.creatorName || '', // 创建人
|
|
item.specification || item.spec || '', // 规格
|
|
item.description || '', // 描述
|
|
item.region || '', // 地区
|
|
item.yolk || '', // 蛋黄
|
|
item.price || '', // 价格
|
|
item.grossWeight || item.weight || '', // 重量
|
|
item.category || '', // 种类
|
|
item.formattedCreatedAt || item.created_at || '' // 创建时间
|
|
]
|
|
|
|
// 检查是否有任何字段包含搜索关键词
|
|
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 loadGoodsList() {
|
|
if (this.data.isLoading) return
|
|
|
|
this.setData({
|
|
isLoading: true
|
|
})
|
|
|
|
console.log('开始加载货源列表,参数:', {
|
|
page: this.data.currentPage,
|
|
pageSize: this.data.pageSize,
|
|
keyword: this.data.searchKeyword,
|
|
activeFilter: this.data.activeFilter
|
|
})
|
|
|
|
// 调用API获取货源列表
|
|
try {
|
|
const res = await API.getGoodsList({
|
|
page: this.data.currentPage,
|
|
pageSize: this.data.pageSize,
|
|
keyword: this.data.searchKeyword
|
|
})
|
|
|
|
console.log('API返回结果:', res)
|
|
|
|
// 检查API返回的状态
|
|
if (res.success) {
|
|
console.log('API调用成功,products:', res.products)
|
|
console.log('products长度:', res.products.length)
|
|
console.log('API返回total:', res.total)
|
|
|
|
// 更新总数据条数
|
|
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.name:`, item.seller?.name)
|
|
console.log(`- seller完整结构:`, JSON.stringify(item.seller))
|
|
|
|
// 确定creatorName - 只使用nickName和sellerNickName字段,不使用name字段
|
|
// 详细日志,查看seller对象的完整结构和各个字段值
|
|
console.log('seller对象完整结构:', JSON.stringify(item.seller))
|
|
console.log('seller.nickName:', item.seller?.nickName)
|
|
console.log('seller.sellerNickName:', item.seller?.sellerNickName)
|
|
const creatorName = item.seller?.nickName || item.seller?.sellerNickName || '未知'
|
|
console.log('creatorName获取结果:', creatorName)
|
|
|
|
// 处理媒体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('售空'));
|
|
|
|
// 如果商品是售空状态,则标记为sold_out
|
|
if (isSoldOut) {
|
|
status = 'sold_out'
|
|
} else if (status !== 'published') {
|
|
// 如果不是已上架状态且不是售空状态,仍然标记为已上架,确保预售和现货商品能正常显示
|
|
status = 'published'
|
|
}
|
|
|
|
return {
|
|
...item,
|
|
status: status, // 更新商品状态
|
|
formattedCreatedAt: this.formatDateTime(item.created_at || item.createTime),
|
|
creatorName: creatorName,
|
|
imageUrls: formattedImageUrls,
|
|
mediaItems: mediaItems
|
|
}
|
|
})
|
|
|
|
// 应用筛选条件和搜索过滤
|
|
const originalList = [...newGoodsList]
|
|
// 先应用搜索过滤
|
|
let searchFilteredList = this.searchGoodsList(newGoodsList, this.data.searchKeyword)
|
|
// 再应用筛选条件
|
|
let filteredList = this.filterGoodsList(searchFilteredList)
|
|
|
|
// 排序:已上架商品排在前面,售空商品排在后面
|
|
filteredList.sort((a, b) => {
|
|
if (a.status === 'published' && b.status === 'sold_out') {
|
|
return -1 // 已上架排在前面
|
|
} else if (a.status === 'sold_out' && b.status === 'published') {
|
|
return 1 // 售空排在后面
|
|
} else {
|
|
// 相同状态下,按创建时间倒序排序
|
|
const timeA = new Date(a.created_at || a.createTime).getTime()
|
|
const timeB = new Date(b.created_at || b.createTime).getTime()
|
|
return timeB - timeA
|
|
}
|
|
})
|
|
|
|
console.log('处理并筛选后的产品列表:', filteredList)
|
|
console.log('筛选前后数量对比:', originalList.length, '->', filteredList.length)
|
|
|
|
// 处理分页逻辑
|
|
let updatedGoodsList = this.data.currentPage === 1 ? filteredList : [...this.data.goodsList, ...filteredList]
|
|
|
|
// 对整个列表进行排序,确保已上架商品始终在前面,售空商品在后面
|
|
updatedGoodsList.sort((a, b) => {
|
|
if (a.status === 'published' && b.status === 'sold_out') {
|
|
return -1 // 已上架排在前面
|
|
} else if (a.status === 'sold_out' && b.status === 'published') {
|
|
return 1 // 售空排在后面
|
|
} else {
|
|
// 相同状态下,按创建时间倒序排序
|
|
const timeA = new Date(a.created_at || a.createTime).getTime()
|
|
const timeB = new Date(b.created_at || b.createTime).getTime()
|
|
return timeB - timeA
|
|
}
|
|
})
|
|
|
|
// 判断是否还有更多数据
|
|
// 正确逻辑:如果API返回的原始数据数量小于pageSize,说明没有更多数据
|
|
// 即使筛选后的数据量小于pageSize,只要API返回的原始数据数量等于pageSize,就应该继续尝试加载更多数据
|
|
const hasMore = res.products.length >= this.data.pageSize
|
|
|
|
console.log('分页判断:', {
|
|
updatedGoodsListLength: updatedGoodsList.length,
|
|
originalDataLength: res.products.length,
|
|
pageSize: this.data.pageSize,
|
|
hasMore: hasMore
|
|
})
|
|
|
|
this.setData({
|
|
goodsList: updatedGoodsList,
|
|
hasMore: hasMore,
|
|
total: total
|
|
})
|
|
|
|
// 移除递归调用逻辑,避免无限递归风险
|
|
// 用户可以通过正常的上拉加载获取更多数据
|
|
} else {
|
|
console.log('没有产品数据返回')
|
|
this.setData({
|
|
goodsList: [],
|
|
hasMore: false,
|
|
total: 0
|
|
})
|
|
}
|
|
} else {
|
|
console.error('API调用失败:', res.message)
|
|
wx.showToast({
|
|
title: res.message || '获取货源列表失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
} catch (err) {
|
|
console.error('获取货源列表失败:', err)
|
|
wx.showToast({
|
|
title: '获取货源列表失败: ' + err.message,
|
|
icon: 'none'
|
|
})
|
|
} finally {
|
|
// 结束下拉刷新和加载状态
|
|
this.setData({
|
|
isLoading: false,
|
|
isRefreshing: false
|
|
})
|
|
}
|
|
}
|
|
})
|