Show aftersales stats and recent orders on dashboard
- Adds a second row of cards (total / pending / closed / rejected) - New "最近售后工单" table linking to detail pages - DashboardStats type extended; dashboardApi maps backend overview Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+136
-4
@@ -1,10 +1,44 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Card, Row, Col, Statistic, Table, Spin, message, Tag } from 'antd';
|
||||
import { TeamOutlined, KeyOutlined, CheckCircleOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
TeamOutlined,
|
||||
KeyOutlined,
|
||||
CheckCircleOutlined,
|
||||
UserOutlined,
|
||||
ToolOutlined,
|
||||
ClockCircleOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { dashboardApi } from '@/services/api';
|
||||
import type { DashboardStats } from '@/types';
|
||||
import type {
|
||||
DashboardStats,
|
||||
AftersalesServiceType,
|
||||
AftersalesWorkOrderStatus,
|
||||
} from '@/types';
|
||||
|
||||
const SERVICE_TYPE_LABEL: Record<AftersalesServiceType, string> = {
|
||||
software: '软件',
|
||||
hardware: '硬件',
|
||||
other: '其他',
|
||||
};
|
||||
|
||||
const WORK_ORDER_STATUS_LABEL: Record<AftersalesWorkOrderStatus, string> = {
|
||||
created: '待处理',
|
||||
pending_confirmation: '待客户确认',
|
||||
closed: '已完成',
|
||||
rejected: '已退回',
|
||||
};
|
||||
|
||||
const WORK_ORDER_STATUS_COLOR: Record<AftersalesWorkOrderStatus, string> = {
|
||||
created: 'default',
|
||||
pending_confirmation: 'processing',
|
||||
closed: 'success',
|
||||
rejected: 'warning',
|
||||
};
|
||||
|
||||
function DashboardPage() {
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [stats, setStats] = useState<DashboardStats | null>(null);
|
||||
|
||||
@@ -26,7 +60,14 @@ function DashboardPage() {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '400px' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '400px',
|
||||
}}
|
||||
>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
@@ -77,6 +118,49 @@ function DashboardPage() {
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={[16, 16]} style={{ marginBottom: '24px' }}>
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="售后工单总数"
|
||||
value={stats?.totalAftersales || 0}
|
||||
prefix={<ToolOutlined />}
|
||||
valueStyle={{ color: '#165DFF' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="待客户确认"
|
||||
value={stats?.pendingConfirmation || 0}
|
||||
prefix={<ClockCircleOutlined />}
|
||||
valueStyle={{ color: '#faad14' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="已完成工单"
|
||||
value={stats?.closedAftersales || 0}
|
||||
prefix={<CheckCircleOutlined />}
|
||||
valueStyle={{ color: '#52c41a' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="已退回工单"
|
||||
value={stats?.rejectedAftersales || 0}
|
||||
prefix={<ExclamationCircleOutlined />}
|
||||
valueStyle={{ color: '#ff4d4f' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Card title="最近生成的序列号" style={{ marginBottom: '24px' }}>
|
||||
<Table
|
||||
columns={[
|
||||
@@ -114,8 +198,56 @@ function DashboardPage() {
|
||||
pagination={false}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Card title="最近售后工单">
|
||||
<Table
|
||||
columns={[
|
||||
{
|
||||
title: '工单号',
|
||||
dataIndex: 'serialNumber',
|
||||
key: 'serialNumber',
|
||||
render: (sn: string) => (
|
||||
<a
|
||||
style={{ fontFamily: 'monospace', color: '#165DFF' }}
|
||||
onClick={() => navigate(`/admin/aftersales/${sn}`)}
|
||||
>
|
||||
{sn}
|
||||
</a>
|
||||
),
|
||||
},
|
||||
{ title: '客户公司', dataIndex: 'companyName', key: 'companyName' },
|
||||
{
|
||||
title: '服务类型',
|
||||
dataIndex: 'serviceType',
|
||||
key: 'serviceType',
|
||||
render: (type: AftersalesServiceType) =>
|
||||
SERVICE_TYPE_LABEL[type] || type,
|
||||
},
|
||||
{ title: '处理人', dataIndex: 'technicianName', key: 'technicianName' },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'workOrderStatus',
|
||||
key: 'workOrderStatus',
|
||||
render: (status: AftersalesWorkOrderStatus) => (
|
||||
<Tag color={WORK_ORDER_STATUS_COLOR[status]}>
|
||||
{WORK_ORDER_STATUS_LABEL[status]}
|
||||
</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
key: 'createdAt',
|
||||
render: (date: string) => new Date(date).toLocaleString('zh-CN'),
|
||||
},
|
||||
]}
|
||||
dataSource={stats?.recentAftersales || []}
|
||||
rowKey="serialNumber"
|
||||
pagination={false}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DashboardPage;
|
||||
export default DashboardPage;
|
||||
|
||||
Reference in New Issue
Block a user