177 lines
5.9 KiB
TypeScript
177 lines
5.9 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import { Table, Tag, Empty, Spin, Typography, Pagination } from 'antd';
|
|
import { FileTextOutlined, AlipayCircleOutlined, WechatOutlined } from '@ant-design/icons';
|
|
import { getPaymentOrders } from '../api';
|
|
|
|
const OrderRecordsPage: React.FC = () => {
|
|
const [loading, setLoading] = useState(true);
|
|
const [orders, setOrders] = useState<any[]>([]);
|
|
const [total, setTotal] = useState(0);
|
|
const [page, setPage] = useState(1);
|
|
const [pageSize] = useState(10);
|
|
|
|
useEffect(() => {
|
|
loadData();
|
|
}, [page]);
|
|
|
|
const loadData = async () => {
|
|
setLoading(true);
|
|
try {
|
|
const data = await getPaymentOrders(page, pageSize);
|
|
setOrders(data.items || []);
|
|
setTotal(data.total || 0);
|
|
} catch {
|
|
setOrders([]);
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
const handlePageChange = (newPage: number) => {
|
|
setPage(newPage);
|
|
};
|
|
|
|
const columns = [
|
|
{
|
|
title: '订单号',
|
|
key: 'orderNo',
|
|
width: 200,
|
|
render: (_, record: any) => {
|
|
const orderNo = record.order_no || record.orderNo || record.id;
|
|
return (
|
|
<span style={{ fontFamily: 'monospace', fontSize: 13, color: '#64748b' }}>
|
|
{orderNo}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '支付方式',
|
|
key: 'paymentMethod',
|
|
width: 100,
|
|
render: (_, record: any) => {
|
|
const method = record.payment_method || record.paymentMethod || 'wechat';
|
|
const methodConfig: Record<string, { icon: React.ReactNode; label: string; color: string }> = {
|
|
alipay: { icon: <AlipayCircleOutlined style={{ fontSize: 16 }} />, label: '支付宝', color: '#1677ff' },
|
|
wechat: { icon: <WechatOutlined style={{ fontSize: 16 }} />, label: '微信支付', color: '#07c160' },
|
|
};
|
|
const config = methodConfig[method] || methodConfig.wechat;
|
|
return (
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
|
<span style={{ color: config.color }}>{config.icon}</span>
|
|
<span style={{ fontSize: 13, color: '#374151' }}>{config.label}</span>
|
|
</div>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '金额',
|
|
key: 'amount',
|
|
width: 100,
|
|
align: 'right' as const,
|
|
render: (_, record: any) => {
|
|
const amount = record.amount || record.total_amount || 0;
|
|
return (
|
|
<Typography.Text strong style={{ fontWeight: 700, fontSize: 14, color: '#1e293b' }}>
|
|
¥{amount}
|
|
</Typography.Text>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '获得积分',
|
|
key: 'credits',
|
|
width: 100,
|
|
align: 'center' as const,
|
|
render: (_, record: any) => {
|
|
const credits = record.credits || record.credit_amount || 0;
|
|
return (
|
|
<Typography.Text strong style={{ fontWeight: 600, fontSize: 14, color: '#f59e0b' }}>
|
|
{credits}
|
|
</Typography.Text>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '状态',
|
|
key: 'status',
|
|
width: 100,
|
|
render: (_, record: any) => {
|
|
const status = record.status || 'pending';
|
|
const statusConfig: Record<string, { color: string; label: string; bg: string }> = {
|
|
pending: { color: '#f59e0b', label: '待支付', bg: 'rgba(245,158,11,0.1)' },
|
|
paid: { color: '#10b981', label: '已支付', bg: 'rgba(16,185,129,0.1)' },
|
|
refunded: { color: '#94a3b8', label: '已退款', bg: 'rgba(148,163,184,0.1)' },
|
|
failed: { color: '#ef4444', label: '支付失败', bg: 'rgba(239,68,68,0.1)' },
|
|
cancelled: { color: '#64748b', label: '已取消', bg: 'rgba(100,116,139,0.1)' },
|
|
processing: { color: '#0ea5e9', label: '处理中', bg: 'rgba(14,165,233,0.1)' },
|
|
};
|
|
const config = statusConfig[status] || { color: '#64748b', label: status, bg: 'rgba(100,116,139,0.1)' };
|
|
return (
|
|
<Tag color={config.color} style={{ background: config.bg, fontWeight: 500, padding: '4px 12px' }}>
|
|
{config.label}
|
|
</Tag>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '创建时间',
|
|
key: 'createdAt',
|
|
width: 180,
|
|
render: (_, record: any) => {
|
|
const createdAt = record.created_at || record.createdAt;
|
|
return createdAt ? new Date(createdAt).toLocaleString('zh-CN') : '-';
|
|
},
|
|
},
|
|
{
|
|
title: '支付时间',
|
|
key: 'paidAt',
|
|
width: 180,
|
|
render: (_, record: any) => {
|
|
const paidAt = record.paid_at || record.paidAt;
|
|
return paidAt ? new Date(paidAt).toLocaleString('zh-CN') : '-';
|
|
},
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div>
|
|
<div>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
|
|
<FileTextOutlined style={{ color: '#0ea5e9', fontSize: 16 }} />
|
|
<Typography.Text strong style={{ fontSize: 16 }}>订单记录</Typography.Text>
|
|
<span style={{ color: '#94a3b8', fontSize: 13 }}>共 {orders.length} 条记录</span>
|
|
</div>
|
|
<div style={{ borderRadius: 16, background: '#fff', border: '1px solid #f0f0f5', overflow: 'hidden' }}>
|
|
<Spin spinning={loading}>
|
|
{orders.length === 0 ? (
|
|
<Empty
|
|
description={<span style={{ color: '#94a3b8' }}>暂无订单记录</span>}
|
|
/>
|
|
) : (
|
|
<>
|
|
<Table
|
|
dataSource={orders}
|
|
columns={columns}
|
|
rowKey="order_no"
|
|
pagination={false}
|
|
bordered={false}
|
|
/>
|
|
<div style={{ padding: '16px', textAlign: 'right' }}>
|
|
<Pagination
|
|
current={page}
|
|
pageSize={pageSize}
|
|
total={total}
|
|
onChange={handlePageChange}
|
|
size="small"
|
|
/>
|
|
</div>
|
|
</>
|
|
)}
|
|
</Spin>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default OrderRecordsPage; |