实现虎牙商品兑换并优化列表展示
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Button, Card, Col, Form, Input, InputNumber, message, Modal, QRCode, Row, Select, Space, Table, Tabs, Tag, Tooltip, Typography, theme,
|
||||
Button, Card, Col, DatePicker, Form, Input, InputNumber, message, Modal, QRCode, Row, Select, Space, Table, Tabs, Tag, Tooltip, Typography, theme,
|
||||
} from 'antd';
|
||||
import type { TableProps } from 'antd';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import {
|
||||
AppstoreOutlined, CheckCircleOutlined, CreditCardOutlined, FieldTimeOutlined,
|
||||
LinkOutlined, PlayCircleOutlined, QrcodeOutlined, ReloadOutlined, SearchOutlined, SettingOutlined, ShoppingOutlined,
|
||||
@@ -31,6 +32,7 @@ const FALLBACK_TASK_TYPES: Record<string, string> = {
|
||||
query_exchange_records: '一键查询兑换记录',
|
||||
refresh_goods: '刷新商品列表',
|
||||
refresh_recharge_goods: '刷新充值商品列表',
|
||||
exchange_goods: '兑换商品',
|
||||
create_recharge_order: '生成支付二维码',
|
||||
};
|
||||
|
||||
@@ -42,6 +44,7 @@ const QUICK_ACTIONS = [
|
||||
{ key: 'query_exchange_records', icon: <FieldTimeOutlined /> },
|
||||
{ key: 'refresh_goods', icon: <ReloadOutlined /> },
|
||||
{ key: 'refresh_recharge_goods', icon: <ShoppingOutlined /> },
|
||||
{ key: 'exchange_goods', icon: <ShoppingOutlined /> },
|
||||
{ key: 'create_recharge_order', icon: <CreditCardOutlined /> },
|
||||
];
|
||||
|
||||
@@ -140,6 +143,8 @@ export default function HuyaTasksPage() {
|
||||
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
||||
const [selectedTaskType, setSelectedTaskType] = useState('query_points');
|
||||
const [selectedGoodsCategory, setSelectedGoodsCategory] = useState('');
|
||||
const [selectedExchangeGoodsId, setSelectedExchangeGoodsId] = useState('');
|
||||
const [exchangeAt, setExchangeAt] = useState<Dayjs | null>(null);
|
||||
const [selectedRechargeGoodsId, setSelectedRechargeGoodsId] = useState<string>('');
|
||||
const [rechargeCount, setRechargeCount] = useState(1);
|
||||
const [rechargePayChannel, setRechargePayChannel] = useState('Weixin');
|
||||
@@ -340,7 +345,35 @@ export default function HuyaTasksPage() {
|
||||
return sortedGoods.filter((item) => goodsCategoryKey(item) === selectedGoodsCategory);
|
||||
}, [sortedGoods, selectedGoodsCategory]);
|
||||
|
||||
const goodsOptions = useMemo(() => {
|
||||
return sortedGoods.map((item) => ({
|
||||
value: item.product_id,
|
||||
label: `${item.name || item.product_id}${item.price ? ` / ${item.price}积分` : ''}`,
|
||||
}));
|
||||
}, [sortedGoods]);
|
||||
|
||||
const selectedExchangeGoods = useMemo(() => {
|
||||
return sortedGoods.find((item) => item.product_id === selectedExchangeGoodsId) || null;
|
||||
}, [selectedExchangeGoodsId, sortedGoods]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sortedGoods.length === 0) {
|
||||
if (selectedExchangeGoodsId) setSelectedExchangeGoodsId('');
|
||||
return;
|
||||
}
|
||||
if (!sortedGoods.some((item) => item.product_id === selectedExchangeGoodsId)) {
|
||||
setSelectedExchangeGoodsId(sortedGoods[0].product_id);
|
||||
}
|
||||
}, [selectedExchangeGoodsId, sortedGoods]);
|
||||
|
||||
const createPayload = (taskType: string) => {
|
||||
if (taskType === 'exchange_goods') {
|
||||
return {
|
||||
product_id: selectedExchangeGoods?.product_id || selectedExchangeGoodsId,
|
||||
product_name: selectedExchangeGoods?.name || '',
|
||||
scheduled_at: exchangeAt ? exchangeAt.toISOString() : '',
|
||||
};
|
||||
}
|
||||
if (taskType !== 'create_recharge_order') return {};
|
||||
return {
|
||||
spu_id: selectedRechargeGoods?.spu_id || selectedRechargeGoodsId,
|
||||
@@ -360,6 +393,10 @@ export default function HuyaTasksPage() {
|
||||
message.warning('请先选择充值商品');
|
||||
return;
|
||||
}
|
||||
if (taskType === 'exchange_goods' && !selectedExchangeGoodsId) {
|
||||
message.warning('请先选择兑换商品');
|
||||
return;
|
||||
}
|
||||
|
||||
setStarting(true);
|
||||
try {
|
||||
@@ -489,6 +526,20 @@ export default function HuyaTasksPage() {
|
||||
if (typeof goodsCount === 'number') return <Tag color="green">商品 {goodsCount} 个</Tag>;
|
||||
return <Text type="secondary">-</Text>;
|
||||
}
|
||||
if (record.task_type === 'exchange_goods') {
|
||||
const productName = resultText(value, 'product_name');
|
||||
const orderId = resultText(value, 'order_id');
|
||||
if (record.status !== 'success') {
|
||||
return productName ? <Text>{productName}</Text> : <Text type="secondary">-</Text>;
|
||||
}
|
||||
return (
|
||||
<Space size={6}>
|
||||
<Tag color="green">已兑换</Tag>
|
||||
{productName ? <Text>{productName}</Text> : null}
|
||||
{orderId ? <Text type="secondary">{orderId}</Text> : null}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
if (record.task_type === 'refresh_recharge_goods') {
|
||||
const goodsCount = value?.goods_count;
|
||||
const failedCount = value?.failed_count;
|
||||
@@ -560,11 +611,28 @@ export default function HuyaTasksPage() {
|
||||
];
|
||||
|
||||
const goodsColumns: TableProps<HuyaGoodsItem>['columns'] = [
|
||||
{ title: '商品ID', dataIndex: 'product_id', width: 120, ellipsis: true },
|
||||
{ title: '名称', dataIndex: 'name', ellipsis: true },
|
||||
{ title: '商品ID', dataIndex: 'product_id', width: 88, ellipsis: true },
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
width: 230,
|
||||
render: (value: string) => (
|
||||
<Text
|
||||
title={value}
|
||||
style={{
|
||||
display: 'block',
|
||||
lineHeight: '20px',
|
||||
whiteSpace: 'normal',
|
||||
wordBreak: 'break-all',
|
||||
}}
|
||||
>
|
||||
{value || '-'}
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '分类',
|
||||
width: 110,
|
||||
width: 96,
|
||||
render: (_: unknown, record) => {
|
||||
const label = goodsCategoryLabel(record);
|
||||
return label ? <Tag>{label}</Tag> : <Text type="secondary">-</Text>;
|
||||
@@ -573,20 +641,20 @@ export default function HuyaTasksPage() {
|
||||
{
|
||||
title: '价格',
|
||||
dataIndex: 'price',
|
||||
width: 90,
|
||||
width: 78,
|
||||
align: 'center',
|
||||
render: (value: number | null) => value ?? <Text type="secondary">-</Text>,
|
||||
},
|
||||
{
|
||||
title: '库存',
|
||||
dataIndex: 'remain_text',
|
||||
width: 100,
|
||||
width: 72,
|
||||
render: (value: string) => formatRemainText(value) || <Text type="secondary">-</Text>,
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updated_at',
|
||||
width: 160,
|
||||
width: 154,
|
||||
render: (value: string | null) => value ? formatTime(value) : <Text type="secondary">-</Text>,
|
||||
},
|
||||
];
|
||||
@@ -728,7 +796,52 @@ export default function HuyaTasksPage() {
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card size="small" title={<Space><ShoppingOutlined />兑换商品列表</Space>} style={{ marginBottom: 12 }}>
|
||||
<Card
|
||||
size="small"
|
||||
title={<Space><ShoppingOutlined />兑换商品列表</Space>}
|
||||
extra={(
|
||||
<Space size={6}>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<ReloadOutlined />}
|
||||
onClick={() => startTask('refresh_goods')}
|
||||
disabled={!canTask || selectedIds.length === 0 || wsConnected}
|
||||
>
|
||||
刷新
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
icon={<CheckCircleOutlined />}
|
||||
onClick={() => startTask('exchange_goods')}
|
||||
disabled={!canTask || selectedIds.length === 0 || wsConnected}
|
||||
>
|
||||
兑换
|
||||
</Button>
|
||||
</Space>
|
||||
)}
|
||||
style={{ marginBottom: 12 }}
|
||||
>
|
||||
<Space style={{ marginBottom: 8 }} wrap>
|
||||
<Select
|
||||
showSearch
|
||||
allowClear
|
||||
placeholder="选择兑换商品"
|
||||
value={selectedExchangeGoodsId || undefined}
|
||||
onChange={(value) => setSelectedExchangeGoodsId(value || '')}
|
||||
options={goodsOptions}
|
||||
style={{ minWidth: 220 }}
|
||||
filterOption={(input, option) => String(option?.label || '').toLowerCase().includes(input.toLowerCase())}
|
||||
/>
|
||||
<DatePicker
|
||||
showTime
|
||||
allowClear
|
||||
value={exchangeAt}
|
||||
onChange={setExchangeAt}
|
||||
placeholder="立即兑换"
|
||||
style={{ width: 190 }}
|
||||
/>
|
||||
</Space>
|
||||
{goodsCategories.length > 0 && (
|
||||
<Tabs
|
||||
size="small"
|
||||
@@ -750,6 +863,10 @@ export default function HuyaTasksPage() {
|
||||
pagination={false}
|
||||
scroll={{ y: 220 }}
|
||||
locale={{ emptyText: '暂无兑换商品,请先刷新商品列表' }}
|
||||
onRow={(record) => ({
|
||||
onClick: () => setSelectedExchangeGoodsId(record.product_id),
|
||||
})}
|
||||
rowClassName={(record) => record.product_id === selectedExchangeGoodsId ? 'ant-table-row-selected' : ''}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -885,9 +1002,11 @@ export default function HuyaTasksPage() {
|
||||
? '使用一个选中的 CK 刷新当前 SID 兑换商品'
|
||||
: item.key === 'refresh_recharge_goods'
|
||||
? '使用一个选中的 CK 刷新充值商品列表'
|
||||
: item.key === 'create_recharge_order'
|
||||
? '按左侧选择生成扫码支付二维码'
|
||||
: undefined
|
||||
: item.key === 'exchange_goods'
|
||||
? '按左侧选择商品,支持立即或定时兑换'
|
||||
: item.key === 'create_recharge_order'
|
||||
? '按左侧选择生成扫码支付二维码'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Button
|
||||
@@ -902,7 +1021,7 @@ export default function HuyaTasksPage() {
|
||||
))}
|
||||
</div>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
当前已接入查询积分、绑定、兑换记录、兑换商品、充值商品列表和扫码支付。
|
||||
当前已接入查询积分、绑定、兑换记录、兑换商品列表、商品兑换、充值商品列表和扫码支付。
|
||||
</Text>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user