feat: add xpd purchase records view
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Button, Card, Input, InputNumber, Modal, QRCode, Select, Space, Table, Tag, Tooltip, Typography, theme,
|
||||
Alert, Button, Card, Input, InputNumber, Modal, QRCode, Select, Space, Table, Tag, Tooltip, Typography, theme,
|
||||
} from 'antd';
|
||||
import type { TableProps } from 'antd';
|
||||
import {
|
||||
@@ -90,6 +90,7 @@ const PEACE_QUICK_ACTIONS = [
|
||||
{ key: 'query_xpd_role', icon: <SearchOutlined /> },
|
||||
{ key: 'query_xpd_balance', icon: <SearchOutlined /> },
|
||||
{ key: 'query_xpd_fragments', icon: <SearchOutlined /> },
|
||||
{ key: 'query_xpd_purchase_records', icon: <FieldTimeOutlined /> },
|
||||
{ key: 'refresh_xpd_goods', icon: <ReloadOutlined /> },
|
||||
{ key: 'exchange_xpd_goods', icon: <ShoppingOutlined /> },
|
||||
];
|
||||
@@ -134,6 +135,7 @@ const PEACE_TASK_TYPES = new Set([
|
||||
'refresh_xpd_goods',
|
||||
'query_xpd_balance',
|
||||
'query_xpd_fragments',
|
||||
'query_xpd_purchase_records',
|
||||
'exchange_xpd_goods',
|
||||
]);
|
||||
const DOUYU_GOLD_AMOUNT_STORAGE_KEY = 'douyu_task_gold_amount';
|
||||
@@ -418,6 +420,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
const [confirmFailTip, setConfirmFailTip] = useState<{ taskId: number; message: string } | null>(null);
|
||||
const [confirmFailCountdown, setConfirmFailCountdown] = useState(0);
|
||||
const [exchangePreview, setExchangePreview] = useState<{ task: DouyuTaskItem; url: string } | null>(null);
|
||||
const [xpdPurchaseRecordsAccountId, setXpdPurchaseRecordsAccountId] = useState<number | null>(null);
|
||||
const autoOpenQrReady = useRef(false);
|
||||
const autoOpenEsportsBindReady = useRef(false);
|
||||
const autoOpenPayReady = useRef(false);
|
||||
@@ -566,6 +569,16 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
return map;
|
||||
}, [visibleTasks]);
|
||||
|
||||
const latestXpdPurchaseRecordsTaskByAccount = useMemo(() => {
|
||||
const map = new Map<number, DouyuTaskItem>();
|
||||
for (const task of tasks) {
|
||||
if (task.task_type !== 'query_xpd_purchase_records') continue;
|
||||
const previous = map.get(task.account_id);
|
||||
if (!previous || task.id > previous.id) map.set(task.account_id, task);
|
||||
}
|
||||
return map;
|
||||
}, [tasks]);
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
@@ -1540,6 +1553,26 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
);
|
||||
},
|
||||
},
|
||||
...(isPeaceHandbook ? [{
|
||||
title: '兑换记录', width: 100, align: 'center' as const,
|
||||
render: (_: unknown, record: DouyuTaskAccountItem) => {
|
||||
const task = latestXpdPurchaseRecordsTaskByAccount.get(record.id);
|
||||
const running = task && ['planned', 'pending', 'running'].includes(task.status);
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
icon={<FieldTimeOutlined />}
|
||||
loading={running}
|
||||
onClick={() => {
|
||||
setXpdPurchaseRecordsAccountId(record.id);
|
||||
void startTask('query_xpd_purchase_records', [record.id]);
|
||||
}}
|
||||
>
|
||||
查询
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
}] : []),
|
||||
];
|
||||
|
||||
const [configFormValues, setConfigFormValues] = useState<DouyuConfig | null>(null);
|
||||
@@ -1866,7 +1899,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
},
|
||||
}}
|
||||
tableLayout="fixed"
|
||||
scroll={{ x: 1180, y: Math.max(120, accountTableAreaHeight - 80) }}
|
||||
scroll={{ x: 1280, y: Math.max(120, accountTableAreaHeight - 80) }}
|
||||
onRow={(record) => ({
|
||||
onContextMenu: (e) => handleRowContextMenu(record, e),
|
||||
style: { cursor: 'context-menu' },
|
||||
@@ -1934,6 +1967,16 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
}
|
||||
`;
|
||||
|
||||
const xpdPurchaseTask = xpdPurchaseRecordsAccountId == null
|
||||
? null
|
||||
: latestXpdPurchaseRecordsTaskByAccount.get(xpdPurchaseRecordsAccountId) || null;
|
||||
const xpdPurchaseRecords = Array.isArray(xpdPurchaseTask?.result?.records)
|
||||
? xpdPurchaseTask.result.records.filter(
|
||||
(item): item is Record<string, unknown> => Boolean(item && typeof item === 'object'),
|
||||
)
|
||||
: [];
|
||||
const xpdPurchaseAccount = accounts.find((account) => account.id === xpdPurchaseRecordsAccountId);
|
||||
|
||||
return (
|
||||
<div style={{ height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
|
||||
<style>{taskRecordTableStyle}</style>
|
||||
@@ -2390,6 +2433,93 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* 和平小店兑换记录 Modal */}
|
||||
<Modal
|
||||
title={
|
||||
<Space>
|
||||
<FieldTimeOutlined />
|
||||
<span>和平小店兑换记录</span>
|
||||
</Space>
|
||||
}
|
||||
open={xpdPurchaseRecordsAccountId != null}
|
||||
onCancel={() => setXpdPurchaseRecordsAccountId(null)}
|
||||
footer={null}
|
||||
width={980}
|
||||
centered
|
||||
>
|
||||
<Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
|
||||
{xpdPurchaseAccount?.nickname || xpdPurchaseAccount?.username || `#${xpdPurchaseRecordsAccountId}`}
|
||||
{xpdPurchaseTask?.result?.total != null ? `,共 ${String(xpdPurchaseTask.result.total)} 条` : ''}
|
||||
</Text>
|
||||
{xpdPurchaseTask && ['failed', 'error'].includes(xpdPurchaseTask.status) ? (
|
||||
<Alert
|
||||
type="error"
|
||||
showIcon
|
||||
message={xpdPurchaseTask.message || '查询兑换记录失败'}
|
||||
/>
|
||||
) : (
|
||||
<Table
|
||||
rowKey={(record, index) => String(record.serial || `${record.buy_time || ''}-${index}`)}
|
||||
size="small"
|
||||
loading={!xpdPurchaseTask || ['planned', 'pending', 'running'].includes(xpdPurchaseTask.status)}
|
||||
dataSource={xpdPurchaseRecords}
|
||||
pagination={{ pageSize: 10, showLessItems: true }}
|
||||
scroll={{ x: 850 }}
|
||||
columns={[
|
||||
{
|
||||
title: '商品',
|
||||
dataIndex: 'goods_name',
|
||||
width: 240,
|
||||
render: (value: unknown) => String(value || '-'),
|
||||
},
|
||||
{
|
||||
title: '兑换时间',
|
||||
dataIndex: 'buy_time',
|
||||
width: 170,
|
||||
render: (value: unknown) => String(value || '-'),
|
||||
},
|
||||
{
|
||||
title: '支付时间',
|
||||
dataIndex: 'pay_time',
|
||||
width: 170,
|
||||
render: (value: unknown) => String(value || '-'),
|
||||
},
|
||||
{
|
||||
title: '价格',
|
||||
width: 90,
|
||||
render: (_: unknown, record: Record<string, unknown>) =>
|
||||
record.pay_amount ?? record.price ?? '-',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 90,
|
||||
render: (value: unknown) => (
|
||||
<Tag color={String(value) === '3' ? 'success' : 'default'}>
|
||||
{String(value) === '3' ? '已完成' : String(value || '未知')}
|
||||
</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '角色',
|
||||
dataIndex: 'role_name',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
render: (value: unknown) => String(value || '-'),
|
||||
},
|
||||
{
|
||||
title: '订单号',
|
||||
dataIndex: 'serial',
|
||||
width: 250,
|
||||
ellipsis: true,
|
||||
render: (value: unknown) => String(value || '-'),
|
||||
},
|
||||
]}
|
||||
locale={{ emptyText: xpdPurchaseTask ? '暂无兑换记录' : '正在查询兑换记录...' }}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* 兑换结果图片预览 Modal */}
|
||||
<Modal
|
||||
title={
|
||||
|
||||
Reference in New Issue
Block a user