import { useEffect, useMemo, useState } from 'react'; import { Alert, Button, Card, Empty, Input, Select, Space, Spin, Tag } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; import { PointsMallAPI, PointsMallCategory, PointsMallOverview, PointsMallProduct, PointsMallProductsResponse } from '../api'; type SortKey = 'popular' | 'price_asc' | 'price_desc' | 'newest'; const MOCK_OVERVIEW: PointsMallOverview = { me: { points: 1280, level: 'Lv.2' }, categories: [ { id: 'all', name: '全部', sort: 0 }, { id: 'digital', name: '虚拟权益', sort: 1 }, { id: 'tool', name: '工具周边', sort: 2 }, { id: 'gift', name: '礼品卡券', sort: 3 }, { id: 'limited', name: '限时活动', sort: 4 } ], announcements: [ { id: 'a1', title: '公告:积分规则升级中', content: '本期暂不开放兑换,页面仅用于 UI 预览。', linkUrl: '' } ], banners: [ { id: 'b1', title: '限时上新', subtitle: 'Up to 25% Off', imageUrl: '', linkUrl: '' } ], promoEntries: [ { id: 'p1', title: '促销活动', subtitle: '本周精选', linkUrl: '' }, { id: 'p2', title: '积分任务', subtitle: '快速涨积分', linkUrl: '' } ] }; const MOCK_PRODUCTS: PointsMallProduct[] = Array.from({ length: 12 }).map((_, i) => ({ id: String(i + 1), categoryId: i % 2 === 0 ? 'digital' : 'tool', name: `商品 ${i + 1}`, subtitle: '这里是商品简短描述', coverUrl: '', pointsPrice: 199 + i * 10, stock: 99, sold: 12 + i, tags: i % 3 === 0 ? ['限时'] : i % 3 === 1 ? ['热卖'] : [] })); export default function PointsMallPage() { const [overviewLoading, setOverviewLoading] = useState(false); const [productsLoading, setProductsLoading] = useState(false); const [overview, setOverview] = useState(null); const [categories, setCategories] = useState([]); const [categoryId, setCategoryId] = useState('all'); const [q, setQ] = useState(''); const [sort, setSort] = useState('popular'); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(24); const [productsRes, setProductsRes] = useState(null); const loadOverview = async () => { setOverviewLoading(true); try { const data = await PointsMallAPI.overview(); setOverview(data); setCategories(data.categories || []); if (!data.categories?.some((c) => c.id === categoryId) && data.categories?.[0]?.id) { setCategoryId(data.categories[0].id); } } catch { setOverview(MOCK_OVERVIEW); setCategories(MOCK_OVERVIEW.categories); } finally { setOverviewLoading(false); } }; const loadProducts = async () => { setProductsLoading(true); try { const res = await PointsMallAPI.products({ categoryId: categoryId === 'all' ? undefined : categoryId, q, sort, page, pageSize }); setProductsRes(res); } catch { const filtered = MOCK_PRODUCTS.filter((p) => (categoryId === 'all' ? true : p.categoryId === categoryId)) .filter((p) => (q ? (p.name + p.subtitle).toLowerCase().includes(q.toLowerCase()) : true)); setProductsRes({ page, pageSize, total: filtered.length, items: filtered.slice((page - 1) * pageSize, page * pageSize) }); } finally { setProductsLoading(false); } }; useEffect(() => { loadOverview(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { loadProducts(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [categoryId, q, sort, page, pageSize]); const announcement = overview?.announcements?.[0]; const banner = overview?.banners?.[0]; const promoEntries = overview?.promoEntries || []; const products = productsRes?.items || []; const total = productsRes?.total || 0; const sortOptions = useMemo( () => [ { value: 'popular', label: '热度优先' }, { value: 'newest', label: '最新上架' }, { value: 'price_asc', label: '积分从低到高' }, { value: 'price_desc', label: '积分从高到低' } ], [] ); return (

积分商城

使用积分兑换权益、工具和活动礼包。后续会接入库存、订单与积分流水。
{overviewLoading ? ( ) : (
我的积分
{Number(overview?.me?.points || 0).toLocaleString()}
{String(overview?.me?.level || 'Lv.0')}
)}
商品分类 {categories.map((c) => ( ))}
{!!announcement && ( {announcement.title} } description={announcement.content} style={{ borderRadius: 18, marginBottom: 14 }} /> )}
{banner?.title || '本期活动'}
{banner?.subtitle || 'Up to 25% Off'}
banner 图片与跳转链接由后端配置
{promoEntries.slice(0, 2).map((p) => (
{p.title}
{p.subtitle}
))} {promoEntries.length < 2 && (
促销入口由后端配置
)}
{ setPage(1); setQ(e.target.value); }} prefix={} placeholder="搜索商品" allowClear style={{ width: 260, borderRadius: 12 }} /> { setPage(1); setPageSize(v); }} options={[ { value: 12, label: '每页 12' }, { value: 24, label: '每页 24' }, { value: 48, label: '每页 48' } ]} />
共 {total.toLocaleString()} 件商品
{productsLoading ? ( ) : products.length === 0 ? ( ) : (
{products.map((p) => (
{p.name}
{p.subtitle}
{p.tags?.length ? ( {p.tags[0]} ) : null}
{Number(p.pointsPrice).toLocaleString()} 积分
库存 {p.stock} 已兑 {p.sold}
))}
)} {!!productsRes && (
第 {page} 页
)}
); }