diff --git a/src/pages/shop/index.tsx b/src/pages/shop/index.tsx index adbd8cd..e5a82ef 100644 --- a/src/pages/shop/index.tsx +++ b/src/pages/shop/index.tsx @@ -1,54 +1,83 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useCallback, useRef } from 'react' import { View, Text, ScrollView, Image } from '@tarojs/components' import Taro from '@tarojs/taro' import { listShopGoodsCategory } from '@/api/shop/shopGoodsCategory' import { pageShopGoods } from '@/api/shop/shopGoods' -import type { ShopGoodsCategory, ShopGoods } from '@/api/shop/shopGoodsCategory/model' -import type { ShopGoodsParam } from '@/api/shop/shopGoods/model' -import ProductCard from '@/components/common/ProductCard' +import { addToCart } from '@/api/shop/shopCart' +import type { ShopGoodsCategory } from '@/api/shop/shopGoodsCategory/model' +import type { ShopGoods, ShopGoodsParam } from '@/api/shop/shopGoods/model' +import { isGuest } from '@/utils/auth' +import { isVipMember } from '@/utils/vip' +import { requireLogin } from '@/utils/login-guard' import EmptyState from '@/components/common/EmptyState' import LoadMore from '@/components/common/LoadMore' -const categories = [ +definePageConfig({ + navigationBarTitleText: '商品分类', +}) + +// 预置分类 +const PRESET_CATEGORIES = [ { id: 0, title: '全部' }, { id: -1, title: '推荐' }, ] +// ─── 排序选项 ────────────────────────────────────────────────── +type SortKey = 'default' | 'sales' | 'newest' | 'price' + +const SORT_TABS: { key: SortKey; label: string }[] = [ + { key: 'default', label: '默认' }, + { key: 'sales', label: '销量' }, + { key: 'newest', label: '最新' }, + { key: 'price', label: '价格' }, +] + const ShopPage: React.FC = () => { - const [categoryList, setCategoryList] = useState(categories) + const [categoryList, setCategoryList] = useState(PRESET_CATEGORIES) const [activeCategory, setActiveCategory] = useState(0) + + // 商品列表 const [goodsList, setGoodsList] = useState([]) const [loading, setLoading] = useState(false) const [page, setPage] = useState(1) const [finished, setFinished] = useState(false) + const loadingRef = useRef(false) + + // 排序 + const [sortKey, setSortKey] = useState('default') + const [priceAsc, setPriceAsc] = useState(true) useEffect(() => { loadCategories() }, []) - useEffect(() => { - setPage(1) - setFinished(false) - setGoodsList([]) - loadGoods(1, activeCategory) - }, [activeCategory]) - const loadCategories = async () => { try { const list = await listShopGoodsCategory() if (list && list.length > 0) { - setCategoryList([...categories, ...list]) + const filtered = list.filter((c: any) => c.status === 1) + setCategoryList([...PRESET_CATEGORIES, ...filtered]) } } catch { /* ignore */ } } - const loadGoods = async (p: number, categoryId?: number) => { - if (loading) return + /** 构建排序参数 */ + const buildSortParams = useCallback((): Partial => { + if (sortKey === 'sales') return { sort: 'sales', order: 'desc' } + if (sortKey === 'newest') return { sort: 'create_time', order: 'desc' } + if (sortKey === 'price') return { sort: 'price', order: priceAsc ? 'asc' : 'desc' } + return {} + }, [sortKey, priceAsc]) + + /** 加载商品列表 */ + const loadGoods = useCallback(async (p: number) => { + if (loadingRef.current) return + loadingRef.current = true setLoading(true) try { - const params: ShopGoodsParam = { page: p, limit: 10, status: 0 } - if (categoryId && categoryId > 0) params.categoryId = categoryId - if (categoryId === -1) params.recommend = 1 + const params: ShopGoodsParam = { page: p, limit: 10, status: 0, ...buildSortParams() } + if (activeCategory > 0) params.categoryId = activeCategory + if (activeCategory === -1) params.recommend = 1 const res = await pageShopGoods(params) const newList = res?.list || [] if (p === 1) { @@ -59,19 +88,67 @@ const ShopPage: React.FC = () => { setFinished(newList.length < 10) setPage(p) } catch { /* ignore */ } + loadingRef.current = false setLoading(false) - } + }, [activeCategory, buildSortParams]) + + // 分类或排序变化时重新加载 + useEffect(() => { + setGoodsList([]) + setFinished(false) + setPage(1) + loadGoods(1) + }, [activeCategory, sortKey, priceAsc]) const handleLoadMore = () => { if (!finished && !loading) { - loadGoods(page + 1, activeCategory) + loadGoods(page + 1) } } + /** 排序切换 */ + const handleSortChange = (key: SortKey) => { + if (key === 'price') { + if (sortKey === 'price') { + setPriceAsc(!priceAsc) + } else { + setSortKey('price') + setPriceAsc(true) + } + } else { + setSortKey(key) + } + } + + /** 获取显示价格 */ + const getDisplayPrice = (product: ShopGoods) => { + if (isVipMember() && product.dealerPrice) return product.dealerPrice + return product.price || '0' + } + + /** 加入购物车 */ + const handleAddToCart = (e: any, product: ShopGoods) => { + e.stopPropagation() + if (!requireLogin({ action: 'addToCart' })) return + addToCart({ + goodsId: product.goodsId!, + num: product.step || 1, + }).then(() => { + Taro.showToast({ title: '已加入购物车', icon: 'success' }) + }).catch(err => { + Taro.showToast({ title: err.message || '添加失败', icon: 'none' }) + }) + } + + /** 跳转商品详情 */ + const goDetail = (product: ShopGoods) => { + Taro.navigateTo({ url: `/pages/shop/product-detail?id=${product.goodsId}` }) + } + return ( {/* 左侧分类栏 */} - + {categoryList.map(cat => ( { ))} - {/* 右侧商品列表 */} - - - - {goodsList.map(item => ( - - ))} + {/* 右侧:排序栏 + 商品列表 */} + + {/* 排序栏 */} + + {SORT_TABS.map(tab => ( + handleSortChange(tab.key)} + > + + {tab.label} + + {tab.key === 'price' && sortKey === 'price' && ( + + {priceAsc ? '↑' : '↓'} + + )} + + ))} + + 筛选 - {goodsList.length === 0 && !loading && ( - - )} - - + + {/* 商品列表 */} + + + {goodsList.length > 0 ? ( + + {goodsList.map(item => ( + goDetail(item)} + > + {/* 商品图片 */} + + + + + {/* 商品信息 */} + + {/* 标题 + 积分标签 */} + + + {item.name || item.goodsName} + + {item.gainIntegral && item.gainIntegral > 0 ? ( + + + +{item.gainIntegral}积分 + + + ) : null} + + + {/* 价格 + 销量 + 加购 */} + + + + ¥{getDisplayPrice(item)} + + {item.unitName ? ( + /{item.unitName} + ) : null} + {/* VIP 划掉原价 */} + {isVipMember() && item.dealerPrice ? ( + + ¥{item.price} + + ) : item.salePrice && item.salePrice !== item.price ? ( + isGuest() ? null : ( + + ¥{item.salePrice} + + ) + ) : null} + {/* 销量 */} + {item.sales !== undefined && item.sales > 0 && ( + + 已售{item.sales} + + )} + + {/* 加购按钮 */} + handleAddToCart(e, item)} + > + + + + + + + ))} + + ) : ( + !loading && + )} + + + + ) }