This commit is contained in:
2026-06-11 14:14:58 +08:00
parent e975ccc6d2
commit 28232e62a7
+124 -151
View File
@@ -1,7 +1,8 @@
import React, { useEffect, useState } from 'react';
import {
Card, Col, Row, Space, Table, Tag, Typography, Statistic, message, Select, DatePicker, Button
Card, Col, Row, Space, Table, Tag, Typography, Statistic, message, Select, DatePicker, Button, ConfigProvider
} from 'antd';
import zhCN from 'antd/locale/zh_CN';
import {
DollarOutlined, CheckCircleOutlined, ClockCircleOutlined, CloseCircleOutlined, ReloadOutlined
} from '@ant-design/icons';
@@ -110,162 +111,134 @@ const AdminPaymentStats: React.FC = () => {
const monthInfo = stats.month || { count: 0, amount: 0 };
return (
<div>
{/* Filters */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', marginBottom: 24 }}>
<Row gutter={[16, 16]} align="middle">
<Col xs={24} sm={12} md={6}>
<span style={{ marginRight: 8 }}></span>
<Select
placeholder="全部"
allowClear
style={{ width: 150 }}
value={filters.paymentMethod}
onChange={(value) => setFilters(prev => ({ ...prev, paymentMethod: value }))}
>
<Option value="alipay"></Option>
<Option value="wechat"></Option>
</Select>
<ConfigProvider locale={zhCN}>
<div>
{/* Summary cards */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col xs={24} sm={12} lg={12}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<Statistic
title="今日收入"
value={stats.today.paidAmount}
precision={2}
prefix={<DollarOutlined style={{ color: '#10b981' }} />}
suffix="元"
valueStyle={{ color: '#10b981', fontWeight: 700 }}
/>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{stats.today.paidCount}
</Typography.Text>
</Card>
</Col>
<Col xs={24} sm={12} md={6}>
<span style={{ marginRight: 8 }}></span>
<Select
placeholder="全部"
allowClear
style={{ width: 150 }}
value={filters.status}
onChange={(value) => setFilters(prev => ({ ...prev, status: value }))}
>
<Option value="paid"></Option>
<Option value="pending"></Option>
<Option value="cancelled"></Option>
</Select>
</Col>
<Col xs={24} sm={12} md={8}>
<span style={{ marginRight: 8 }}></span>
<RangePicker
value={[
dayjs(filters.startDate),
dayjs(filters.endDate),
]}
onChange={handleDateChange}
/>
</Col>
<Col xs={24} sm={12} md={4}>
<Button icon={<ReloadOutlined />} onClick={handleReset}>
</Button>
<Col xs={24} sm={12} lg={12}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<Statistic
title="本月累计"
value={monthInfo.paidAmount}
precision={2}
prefix={<DollarOutlined style={{ color: '#6366f1' }} />}
suffix="元"
valueStyle={{ color: '#6366f1', fontWeight: 700 }}
/>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{monthInfo.paidCount}
</Typography.Text>
</Card>
</Col>
</Row>
</Card>
{/* Summary cards */}
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
<Col xs={24} sm={12} lg={6}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<Statistic
title="今日收入"
value={stats.today.paidAmount}
precision={2}
prefix={<DollarOutlined style={{ color: '#10b981' }} />}
suffix="元"
valueStyle={{ color: '#10b981', fontWeight: 700 }}
/>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{stats.today.paidCount}
</Typography.Text>
</Card>
</Col>
<Col xs={24} sm={12} lg={6}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<Statistic
title="本月累计"
value={monthInfo.paidAmount}
precision={2}
prefix={<DollarOutlined style={{ color: '#6366f1' }} />}
suffix="元"
valueStyle={{ color: '#6366f1', fontWeight: 700 }}
/>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{monthInfo.paidCount}
</Typography.Text>
</Card>
</Col>
<Col xs={12} sm={12} lg={6}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<Statistic
title="待支付"
value={pendingInfo.count}
prefix={<ClockCircleOutlined style={{ color: '#f59e0b' }} />}
suffix="笔"
valueStyle={{ color: '#f59e0b', fontWeight: 700 }}
/>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
¥{pendingInfo.amount.toFixed(2)}
</Typography.Text>
</Card>
</Col>
<Col xs={12} sm={12} lg={6}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<Statistic
title="已取消"
value={cancelledInfo.count}
prefix={<CloseCircleOutlined style={{ color: '#94a3b8' }} />}
suffix="笔"
valueStyle={{ color: '#94a3b8', fontWeight: 700 }}
/>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
¥{cancelledInfo.amount.toFixed(2)}
</Typography.Text>
</Card>
</Col>
</Row>
{/* Status breakdown */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', marginBottom: 16 }}
title={<Space><DollarOutlined /></Space>}>
<Row gutter={16}>
{['paid', 'pending', 'cancelled'].map(s => {
const info = stats.byStatus?.[s] || { count: 0, amount: 0 };
const c = statusConfig[s];
const pct = totalOrders > 0 ? ((info.count / totalOrders) * 100).toFixed(1) : '0.0';
return (
<Col span={8} key={s}>
<div style={{
padding: 16, borderRadius: 10,
background: '#fafbff', border: '1px solid #f0f0f5',
}}>
<Space>
<Tag color={c.color} icon={c.icon}>{c.label}</Tag>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>{pct}%</Typography.Text>
</Space>
<div style={{ marginTop: 8, fontSize: 20, fontWeight: 700 }}>
{info.count} <span style={{ fontSize: 13, color: '#94a3b8', fontWeight: 400 }}></span>
{/* Status breakdown */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', marginBottom: 16 }}
title={<Space><DollarOutlined /></Space>}>
<Row gutter={16}>
{['paid', 'pending', 'cancelled'].map(s => {
const info = stats.byStatus?.[s] || { count: 0, amount: 0 };
const c = statusConfig[s];
const pct = totalOrders > 0 ? ((info.count / totalOrders) * 100).toFixed(1) : '0.0';
return (
<Col span={8} key={s}>
<div style={{
padding: 16, borderRadius: 10,
background: '#fafbff', border: '1px solid #f0f0f5',
}}>
<Space>
<Tag color={c.color} icon={c.icon}>{c.label}</Tag>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>{pct}%</Typography.Text>
</Space>
<div style={{ marginTop: 8, fontSize: 20, fontWeight: 700 }}>
{info.count} <span style={{ fontSize: 13, color: '#94a3b8', fontWeight: 400 }}></span>
</div>
<div style={{ fontSize: 13, color: '#64748b', marginTop: 4 }}>
¥{info.amount.toFixed(2)}
</div>
</div>
<div style={{ fontSize: 13, color: '#64748b', marginTop: 4 }}>
¥{info.amount.toFixed(2)}
</div>
</div>
</Col>
);
})}
</Row>
</Card>
</Col>
);
})}
</Row>
</Card>
{/* Recent orders table */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}
title={<Space><DollarOutlined /></Space>}>
<Table
columns={columns}
dataSource={stats.recent}
rowKey="id"
loading={loading}
pagination={{ pageSize: 10, size: 'small' }}
scroll={{ x: 1000 }}
size="middle"
/>
</Card>
</div>
{/* Recent orders table */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}
title={<Space><DollarOutlined /></Space>}>
{/* Filters */}
<Row gutter={[16, 16]} align="middle" style={{ marginBottom: 24 }}>
<Col xs={24} sm={12} md={6}>
<span style={{ marginRight: 8 }}></span>
<Select
placeholder="全部"
allowClear
style={{ width: 150 }}
value={filters.paymentMethod}
onChange={(value) => setFilters(prev => ({ ...prev, paymentMethod: value }))}
>
<Option value="alipay"></Option>
<Option value="wechat"></Option>
</Select>
</Col>
<Col xs={24} sm={12} md={6}>
<span style={{ marginRight: 8 }}></span>
<Select
placeholder="全部"
allowClear
style={{ width: 150 }}
value={filters.status}
onChange={(value) => setFilters(prev => ({ ...prev, status: value }))}
>
<Option value="paid"></Option>
<Option value="pending"></Option>
<Option value="cancelled"></Option>
</Select>
</Col>
<Col xs={24} sm={12} md={8}>
<span style={{ marginRight: 8 }}></span>
<RangePicker
value={[
dayjs(filters.startDate),
dayjs(filters.endDate),
]}
onChange={handleDateChange}
/>
</Col>
<Col xs={24} sm={12} md={4}>
<Button icon={<ReloadOutlined />} onClick={handleReset}>
</Button>
</Col>
</Row>
<Table
columns={columns}
dataSource={stats.recent}
rowKey="id"
loading={loading}
pagination={{ pageSize: 10, size: 'small' }}
scroll={{ x: 1000 }}
size="middle"
/>
</Card>
</div>
</ConfigProvider>
);
};