diff --git a/src/pages/PointsMallPage/components/PointsMallH5Products.tsx b/src/pages/PointsMallPage/components/PointsMallH5Products.tsx
new file mode 100644
index 0000000..fee7b32
--- /dev/null
+++ b/src/pages/PointsMallPage/components/PointsMallH5Products.tsx
@@ -0,0 +1,137 @@
+import { SearchOutlined } from '@ant-design/icons';
+import { Button, Card, Empty, Input, Select, Space, Spin, Tag } from 'antd';
+import type { PointsMallProduct } from '../../../api';
+import type { PointsMallPageLogicOutput } from '../PointsMallPageLogic';
+
+interface Props {
+ logic: PointsMallPageLogicOutput;
+}
+
+export default function PointsMallH5Products({ logic }: Props) {
+ const {
+ q,
+ sort,
+ page,
+ pageSize,
+ productsLoading,
+ products,
+ total,
+ userPoints,
+ exchangeLoading,
+ setQ,
+ setSort,
+ setPage,
+ setPageSize,
+ handleExchangeClick
+ } = logic;
+
+ return (
+
+
+
+ {
+ setPage(1);
+ setQ(e.target.value);
+ }}
+ prefix={}
+ placeholder="搜索商品"
+ allowClear
+ className="points-mall-search-input"
+ />
+
+
+
+
共 {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} 页
+
+
+
+
+ )}
+
+ );
+}
diff --git a/src/pages/PointsMallPage/components/PointsMallH5Top.tsx b/src/pages/PointsMallPage/components/PointsMallH5Top.tsx
new file mode 100644
index 0000000..efaebcc
--- /dev/null
+++ b/src/pages/PointsMallPage/components/PointsMallH5Top.tsx
@@ -0,0 +1,106 @@
+import { Button, Card, Spin, Tag } from 'antd';
+import type { PointsMallPageLogicOutput } from '../PointsMallPageLogic';
+
+interface Props {
+ logic: PointsMallPageLogicOutput;
+}
+
+export default function PointsMallH5Top({ logic }: Props) {
+ const {
+ overview,
+ overviewLoading,
+ categories,
+ categoryId,
+ userPoints,
+ totalSpentUSD,
+ banner,
+ promoEntries,
+ setCategoryId,
+ setPage
+ } = 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 &&
促销入口由后端配置
}
+
+
+ >
+ );
+}
diff --git a/src/pages/PointsMallPage/components/PointsMallPageH5.tsx b/src/pages/PointsMallPage/components/PointsMallPageH5.tsx
index e4b601d..bb319b5 100644
--- a/src/pages/PointsMallPage/components/PointsMallPageH5.tsx
+++ b/src/pages/PointsMallPage/components/PointsMallPageH5.tsx
@@ -1,10 +1,11 @@
-import { Button, Card, Empty, Form, Input, Select, Space, Spin, Tag } from 'antd';
-import { SearchOutlined } from '@ant-design/icons';
-import type { PointsMallProduct } from '../../../api';
+import { Form } from 'antd';
import type { PointsMallPageLogicOutput } from '../PointsMallPageLogic';
-import ExchangeModal from '../components/ExchangeModal';
-import ConfirmExchangeModal from '../components/ConfirmExchangeModal';
+import ConfirmExchangeModal from './ConfirmExchangeModal';
+import ExchangeModal from './ExchangeModal';
+import PointsMallH5Products from './PointsMallH5Products';
+import PointsMallH5Top from './PointsMallH5Top';
import type { ExchangeFormValues } from '../types';
+import '../styles/points-mall-h5.css';
interface Props {
logic: PointsMallPageLogicOutput;
@@ -13,234 +14,21 @@ interface Props {
export default function PointsMallPageH5({ logic }: Props) {
const [exchangeForm] = Form.useForm
();
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,
+ userPoints,
setExchangeModalVisible,
- setConfirmModalVisible,
+ 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);
- setSort(v);
- }}
- options={[
- { value: 'popular', label: '热度优先' },
- { value: 'newest', label: '最新上架' },
- { value: 'price_asc', label: '积分从低到高' },
- { value: 'price_desc', label: '积分从高到低' },
- ]}
- />
- {
- 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} 页
-
-
-
-
- )}
-
+
+
+
void }) {
const { onSelect } = props;
+ const isMobile = useIsMobile();
const { message } = AntApp.useApp();
const [scope, setScope] = useState<'all' | 'mine' | 'public'>('all');
const [q, setQ] = useState('');
@@ -90,7 +96,7 @@ export default function PromptLibraryPage(props: { onSelect?: (tpl: PromptTempla
});
return (
-
+
-
-
-
-
+
+
+
+
-
+
Prompt 模板库
-
+
把高质量提示词沉淀成可复用模板,像挑选灵感卡片一样快速使用,而不是面对一页页生硬的配置项。
- } onClick={onCreate} style={{ borderRadius: 14, height: 46, padding: '0 18px', fontWeight: 600 }}>
+ } onClick={onCreate} className="prompt-library-create-btn">
新建模板
-
+
onChangeQ(e.target.value)}
onPressEnter={onSearch}
- prefix={
}
+ prefix={
}
suffix={
q ? (
-