feat: 初始化 ChatOne 管理后台前端
基于 React + Vite + Ant Design Pro 搭建登录、动态菜单、布局主题与数据总览,并补充按菜单整理的 UI 设计稿。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
217
src/pages/dashboard/index.tsx
Normal file
217
src/pages/dashboard/index.tsx
Normal file
@@ -0,0 +1,217 @@
|
||||
import { ApiOutlined, MessageOutlined, RiseOutlined, TeamOutlined, ThunderboltOutlined } from '@ant-design/icons';
|
||||
import { Line, Pie } from '@ant-design/charts';
|
||||
import { ProCard } from '@ant-design/pro-components';
|
||||
import { Col, Progress, Row, Select, Space, Statistic, Table, Tag, Typography, theme } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
import { themeConfig } from '@/styles/theme';
|
||||
|
||||
import {
|
||||
alertList,
|
||||
conversationTrend,
|
||||
modelShare,
|
||||
overviewStats,
|
||||
topModels,
|
||||
type AlertItem,
|
||||
type OverviewStat,
|
||||
} from './mock';
|
||||
|
||||
const iconMap: Record<OverviewStat['icon'], ReactNode> = {
|
||||
message: <MessageOutlined />,
|
||||
token: <ThunderboltOutlined />,
|
||||
user: <TeamOutlined />,
|
||||
api: <ApiOutlined />,
|
||||
};
|
||||
|
||||
const alertColumns: ColumnsType<AlertItem> = [
|
||||
{ title: '类型', dataIndex: 'type', width: 100 },
|
||||
{ title: '内容', dataIndex: 'content', ellipsis: true },
|
||||
{
|
||||
title: '级别',
|
||||
dataIndex: 'level',
|
||||
width: 80,
|
||||
render: (level: AlertItem['level']) => {
|
||||
const color = level === '高' ? 'error' : level === '中' ? 'warning' : 'default';
|
||||
return <Tag color={color}>{level}</Tag>;
|
||||
},
|
||||
},
|
||||
{ title: '时间', dataIndex: 'time', width: 170 },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 90,
|
||||
render: (status: AlertItem['status']) => <Tag color={status === '已恢复' ? 'success' : 'error'}>{status}</Tag>,
|
||||
},
|
||||
];
|
||||
|
||||
const primary = themeConfig.token.colorPrimary;
|
||||
|
||||
export default function Dashboard() {
|
||||
const { token } = theme.useToken();
|
||||
|
||||
const lineConfig = {
|
||||
data: conversationTrend,
|
||||
xField: 'date',
|
||||
yField: 'value',
|
||||
height: 280,
|
||||
autoFit: true,
|
||||
// 给曲线/圆点留边,避免贴边裁切
|
||||
padding: [12, 16, 8, 8], // 上 右 下 左,可按观感微调
|
||||
// 或用 inset: 12 / insetRight: 16
|
||||
shapeField: 'smooth',
|
||||
style: {
|
||||
stroke: primary,
|
||||
lineWidth: 2,
|
||||
},
|
||||
area: {
|
||||
style: {
|
||||
fill: `linear-gradient(-90deg, ${primary}00 0%, ${primary}40 100%)`,
|
||||
},
|
||||
},
|
||||
point: {
|
||||
sizeField: 4,
|
||||
shapeField: 'circle',
|
||||
style: {
|
||||
fill: primary,
|
||||
stroke: '#fff',
|
||||
lineWidth: 1,
|
||||
},
|
||||
},
|
||||
axis: {
|
||||
y: {
|
||||
labelFormatter: (v: number) => `${Math.round(v / 1000)}k`,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
items: [{ channel: 'y', name: '对话量' }],
|
||||
},
|
||||
};
|
||||
|
||||
const pieConfig = {
|
||||
data: modelShare,
|
||||
angleField: 'value',
|
||||
colorField: 'type',
|
||||
height: 280,
|
||||
innerRadius: 0.6,
|
||||
legend: {
|
||||
color: {
|
||||
position: 'right' as const,
|
||||
itemLabelFontSize: 12,
|
||||
},
|
||||
},
|
||||
label: false,
|
||||
annotations: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
style: {
|
||||
text: '总计\n100%',
|
||||
x: '50%',
|
||||
y: '50%',
|
||||
textAlign: 'center',
|
||||
fontSize: 14,
|
||||
fill: token.colorTextSecondary,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<Space vertical size={16} style={{ width: '100%' }}>
|
||||
<Row gutter={[16, 16]}>
|
||||
{overviewStats.map(item => (
|
||||
<Col key={item.key} xs={24} sm={12} md={6}>
|
||||
<ProCard key={item.key} colSpan={{ xs: 24, sm: 12, md: 6 }} variant="outlined">
|
||||
<Statistic
|
||||
title={
|
||||
<Space>
|
||||
<span style={{ color: token.colorPrimary }}>{iconMap[item.icon]}</span>
|
||||
{item.title}
|
||||
</Space>
|
||||
}
|
||||
value={item.value}
|
||||
suffix={
|
||||
<Typography.Text type="success" style={{ fontSize: 13 }}>
|
||||
<RiseOutlined /> 较昨日 ↑ {item.trend}%
|
||||
</Typography.Text>
|
||||
}
|
||||
/>
|
||||
</ProCard>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col xs={24} lg={16} style={{ minWidth: 0 }}>
|
||||
<ProCard
|
||||
title="近7日对话趋势"
|
||||
variant="outlined"
|
||||
styles={{ body: { overflow: 'hidden' } }}
|
||||
extra={
|
||||
<Select
|
||||
defaultValue="7d"
|
||||
style={{ width: 100 }}
|
||||
options={[
|
||||
{ label: '近7日', value: '7d' },
|
||||
{ label: '近30日', value: '30d' },
|
||||
]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Line {...lineConfig} autoFit containerStyle={{ width: '100%', height: 280 }} />
|
||||
</ProCard>
|
||||
</Col>
|
||||
<Col xs={24} lg={8}>
|
||||
<ProCard title="模型调用占比" variant="outlined">
|
||||
<Pie {...pieConfig} />
|
||||
</ProCard>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col xs={24} lg={16}>
|
||||
<ProCard title="异常告警" variant="outlined">
|
||||
<Table<AlertItem>
|
||||
rowKey="id"
|
||||
size="middle"
|
||||
columns={alertColumns}
|
||||
dataSource={alertList}
|
||||
pagination={{ pageSize: 5, showTotal: total => `共 ${total} 条` }}
|
||||
/>
|
||||
</ProCard>
|
||||
</Col>
|
||||
<Col xs={24} lg={8}>
|
||||
<ProCard
|
||||
title="热门模型 TOP5"
|
||||
variant="outlined"
|
||||
extra={
|
||||
<Typography.Link type="secondary" style={{ fontSize: 13 }}>
|
||||
查看更多 >
|
||||
</Typography.Link>
|
||||
}
|
||||
>
|
||||
<Space vertical size={16} style={{ width: '100%' }}>
|
||||
{topModels.map((item, index) => (
|
||||
<div key={item.name}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 6,
|
||||
}}
|
||||
>
|
||||
<Typography.Text>
|
||||
{index + 1}. {item.name}
|
||||
</Typography.Text>
|
||||
<Typography.Text type="secondary">{item.percent}%</Typography.Text>
|
||||
</div>
|
||||
<Progress percent={item.percent} showInfo={false} strokeColor={token.colorPrimary} size="small" />
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
</ProCard>
|
||||
</Col>
|
||||
</Row>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user