import React, { useState, useEffect, useCallback, useRef } from 'react' import { View, Text, ScrollView, Image, Input } from '@tarojs/components' import Taro from '@tarojs/taro' import { listShopGoodsCategory } from '@/api/shop/shopGoodsCategory' import { pageShopGoods } from '@/api/shop/shopGoods' import { useCartContext } from '@/contexts/CartContext' import type { ShopGoodsCategory } from '@/api/shop/shopGoodsCategory/model' import type { ShopGoods, ShopGoodsParam } from '@/api/shop/shopGoods/model' import { isGuest } from '@/utils/auth' import { useVipStatus } from '@/hooks/useVipStatus' import { getCompressedImageUrl } from '@/utils/image' import { requireLogin } from '@/utils/login-guard' import { useShare } from '@/hooks/useShare' import EmptyState from '@/components/common/EmptyState' import LoadMore from '@/components/common/LoadMore' import Price from '@/components/common/Price' import { CART_ICON_WHITE } from '@/assets/icons' 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 { addItem, totalCount } = useCartContext() // VIP 状态:异步校验并更新缓存,isVip 变化时触发重渲染 const { isVip } = useVipStatus() 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) // 搜索 const [keyword, setKeyword] = useState('') const searchTimerRef = useRef(null) // 分享(tabBar 页支持好友分享 + 朋友圈 + 复制链接) useShare({ title: '购物商城 - 精选好物,实惠到家,等你来逛~', path: '/pages/shop/index', enableTimeline: true, enableCopyUrl: true, }) useEffect(() => { loadCategories() }, []) const loadCategories = async () => { try { const list = await listShopGoodsCategory() if (list && list.length > 0) { const filtered = list.filter((c: any) => c.status === 0) setCategoryList([...PRESET_CATEGORIES, ...filtered]) } } catch { /* ignore */ } } /** 构建排序参数 */ 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, ...buildSortParams() } if (activeCategory > 0) params.categoryId = activeCategory if (activeCategory === -1) params.recommend = 1 if (keyword.trim()) params.keywords = keyword.trim() const res = await pageShopGoods(params) const newList = res?.list || [] if (p === 1) { setGoodsList(newList) } else { setGoodsList(prev => [...prev, ...newList]) } setFinished(newList.length < 10) setPage(p) } catch { /* ignore */ } loadingRef.current = false setLoading(false) }, [activeCategory, buildSortParams, keyword]) // 分类或排序变化时重新加载 useEffect(() => { setGoodsList([]) setFinished(false) setPage(1) loadGoods(1) }, [activeCategory, sortKey, priceAsc]) const handleLoadMore = () => { if (!finished && !loading) { 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 (isVip && product.dealerPrice) return product.dealerPrice return product.price || '0' } /** 加入购物车 */ const handleAddToCart = (e: any, product: ShopGoods) => { e.stopPropagation() if (!requireLogin({ action: 'addToCart' })) return addItem(product, undefined, product.step || 1).catch(() => {}) } /** 搜索输入(防抖 500ms) */ const handleSearchInput = (e: any) => { const val = e.detail.value setKeyword(val) if (searchTimerRef.current) clearTimeout(searchTimerRef.current) searchTimerRef.current = setTimeout(() => { setGoodsList([]) setFinished(false) setPage(1) loadGoods(1) }, 500) } /** 跳转商品详情 */ const goDetail = (product: ShopGoods) => { Taro.navigateTo({ url: `/pages/shop/product-detail?id=${product.goodsId}` }) } return ( {/* 顶部搜索栏 */} 🔍 { setGoodsList([]) setFinished(false) setPage(1) loadGoods(1) }} /> {keyword ? ( { setKeyword('') setGoodsList([]) setFinished(false) setPage(1) loadGoods(1) }} > ✕ ) : null} {/* 左右分栏 */} {/* 左侧分类栏 */} {categoryList.map(cat => ( setActiveCategory(cat.categoryId || cat.id)} > {cat.title} ))} {/* 右侧:排序栏 + 商品列表 */} {/* 排序栏 */} {SORT_TABS.map(tab => ( handleSortChange(tab.key)} > {tab.label} {tab.key === 'price' && sortKey === 'price' && ( {priceAsc ? '↑' : '↓'} )} ))} 筛选 {/* 商品列表 */} {goodsList.length > 0 ? ( {goodsList.map(item => ( goDetail(item)} > {/* 商品图片 */} {/* 商品信息 */} {/* 标题 + 积分标签 */} {item.name || item.goodsName} {item.gainIntegral && item.gainIntegral > 0 ? ( +{item.gainIntegral}积分 ) : null} {/* 价格 + 销量 + 加购 */} {item.unitName && !isGuest() ? ( /{item.unitName} ) : null} {/* 销量 */} {item.sales !== undefined && item.sales > 0 && ( 已售{item.sales} )} {/* 加购按钮 */} handleAddToCart(e, item)} > + ))} ) : ( !loading && )} {/* 浮动购物车按钮 */} Taro.switchTab({ url: '/pages/shop/cart' })} > {totalCount > 0 && ( {totalCount > 99 ? '99+' : totalCount} )} ) } export default ShopPage