import { Button, Card, Empty, Input, Select, Space, Spin, Tag } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; import type { PointsMallProduct } from '../../../api'; import type { PointsMallPageLogicOutput } from '../PointsMallPageLogic'; import ExchangeModal from '../components/ExchangeModal'; import ConfirmExchangeModal from '../components/ConfirmExchangeModal'; interface Props { logic: PointsMallPageLogicOutput; } export default function PointsMallPageH5({ logic }: Props) { const { overview, overviewLoading, categories, categoryId, q, sort, page, pageSize, productsLoading, products, total, userPoints, totalSpentUSD, banner, promoEntries, exchangeModalVisible, confirmModalVisible, selectedProduct, exchangeQuantity, pendingExpiresAt, exchangeLoading, setCategoryId, setQ, setSort, setPage, setPageSize, handleExchangeClick, setExchangeModalVisible, setConfirmModalVisible, } = logic; return (

积分商城

使用积分兑换权益、工具和活动礼包。
积分通过 API 调用消费自动累积,1 美元 = 1000 积分。

{overviewLoading ? ( ) : (
我的积分
{userPoints.toLocaleString()}
累计消费 ${typeof totalSpentUSD === 'number' ? totalSpentUSD.toFixed(2) : '--'}
{String(overview?.me?.level || 'Lv.0')}
)}
商品分类 {categories.map((c) => ( ))}
{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 className="points-mall-search-input" style={{ height: 36 }} />
{ setPage(1); setPageSize(v); }} options={[ { value: 12, label: '每页 12' }, { value: 24, label: '每页 24' }, ]} />
共 {total.toLocaleString()} 件商品
{productsLoading ? ( ) : products.length === 0 ? ( ) : (
{products.map((p: PointsMallProduct) => (
{p.name}
{p.subtitle}
{p.tags?.length ? ( {p.tags[0]} ) : null}
{Number(p.pointsPrice).toLocaleString()} 积分
库存 {p.stock} 已兑 {p.sold}
))}
)} {!!total && (
第 {page} 页
)} { setExchangeModalVisible(false); logic.setPendingOrderId(null); logic.setPendingExpiresAt(null); logic.setSelectedProduct(null); logic.setExchangeQuantity(1); }} /> logic.setExchangeQuantity(Math.max(1, Math.floor(v || 1)))} onConfirm={logic.handleConfirmExchange} onCancel={() => { if (exchangeLoading) return; setConfirmModalVisible(false); logic.setSelectedProduct(null); logic.setExchangeQuantity(1); }} />
); }