实现系统运维页面:服务状态看板、系统负载、API请求监控、操作日志、平台公告

This commit is contained in:
yml2213
2026-07-14 11:17:02 +08:00
parent 6d187d5960
commit 81c32cfdea
+139 -3
View File
@@ -1,6 +1,142 @@
const Ops = () => (
<div className="h-full flex items-center justify-center text-neutral-400 text-center">
<div><div className="text-lg mb-1"></div><div className="text-sm">...</div></div>
import { Card, Table, Tag, Button, Badge, Progress, Space, message } from 'antd'
import { PlusOutlined, EditOutlined, DeleteOutlined, ReloadOutlined } from '@ant-design/icons'
import { Line } from '@ant-design/charts'
const services = [
{ name: 'API 服务', status: 'normal' as const },
{ name: 'WebSocket 服务', status: 'normal' as const },
{ name: '数据库', status: 'warning' as const },
{ name: '消息队列', status: 'normal' as const },
{ name: 'CDN', status: 'normal' as const },
]
const statusDisplay = { normal: { color: 'green', text: '正常' }, warning: { color: 'orange', text: '告警' }, error: { color: 'red', text: '故障' } }
const loadData = [
{ type: 'CPU 使用率', percent: 45 },
{ type: '内存使用率', percent: 62 },
{ type: '磁盘使用率', percent: 38 },
]
const apiData = [
{ time: '10:00', requests: 1250, errors: 2 }, { time: '10:10', requests: 1380, errors: 3 },
{ time: '10:20', requests: 1420, errors: 1 }, { time: '10:30', requests: 1560, errors: 5 },
{ time: '10:40', requests: 1320, errors: 2 }, { time: '10:50', requests: 1480, errors: 0 },
{ time: '11:00', requests: 1620, errors: 3 },
]
const logs = [
{ time: '2026-07-14 10:30', operator: '管理员A', action: '开通新租户', detail: '赵六科技', ip: '192.168.1.100' },
{ time: '2026-07-14 09:15', operator: '管理员B', action: '套餐修改', detail: '专业版 → 企业版', ip: '192.168.1.101' },
{ time: '2026-07-13 16:20', operator: '管理员A', action: '公告发布', detail: '系统维护通知', ip: '192.168.1.100' },
{ time: '2026-07-13 14:00', operator: '管理员B', action: '租户暂停', detail: '孙八信息', ip: '192.168.1.101' },
{ time: '2026-07-13 10:45', operator: '管理员A', action: '套餐上架', detail: '专业版', ip: '192.168.1.100' },
]
const announcements = [
{ id: '1', title: '系统维护通知', content: '平台将于7月20日 02:00-04:00 进行例行维护', time: '2026-07-13', status: 'published' },
{ id: '2', title: '新功能上线', content: '知识库批量导入功能已上线', time: '2026-07-10', status: 'published' },
{ id: '3', title: '版本更新预告', content: 'V3.0 版本即将发布,新增 AI 助手功能', time: '2026-07-15', status: 'draft' },
]
const Ops = () => {
return (
<div>
<h2 className="text-lg font-semibold text-neutral-800 mb-5"></h2>
{/* 服务状态 + 系统负载 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-6">
<Card title="服务状态看板" className="!rounded-lg" bordered={false} extra={<ReloadOutlined className="cursor-pointer text-neutral-400 hover:text-blue-500" />}>
<div className="space-y-3">
{services.map(s => (
<div key={s.name} className="flex items-center justify-between py-2 px-3 bg-neutral-50 rounded-lg">
<span className="text-sm text-neutral-700">{s.name}</span>
<Space>
<Badge status={s.status === 'normal' ? 'success' : s.status === 'warning' ? 'warning' : 'error'} />
<Tag color={statusDisplay[s.status].color}>{statusDisplay[s.status].text}</Tag>
</Space>
</div>
))}
</div>
</Card>
<Card title="系统负载" className="!rounded-lg" bordered={false}>
<div className="space-y-5">
{loadData.map(l => (
<div key={l.type}>
<div className="flex justify-between text-sm mb-1.5">
<span className="text-neutral-600">{l.type}</span>
<span className={`font-medium ${l.percent > 80 ? 'text-red-500' : l.percent > 60 ? 'text-orange-500' : 'text-green-600'}`}>{l.percent}%</span>
</div>
<Progress percent={l.percent} showInfo={false} strokeColor={l.percent > 80 ? '#dc2626' : l.percent > 60 ? '#d97706' : '#16a34a'} />
</div>
))}
<div className="text-xs text-neutral-400 mt-3">30 · 80% </div>
</div>
</Card>
</div>
{/* API 请求图表 */}
<Card title="API 请求监控" className="!rounded-lg mb-6" bordered={false}>
<div style={{ height: 260 }}>
<Line
data={apiData}
xField="time"
yField="requests"
height={260}
color="#2563eb"
smooth
point={{ size: 2 }}
axis={{ y: { grid: true, gridStroke: '#f1f5f9' } }}
/>
</div>
</Card>
{/* 操作日志 + 公告 */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<Card title="操作日志" className="!rounded-lg" bordered={false}>
<Table
dataSource={logs}
rowKey="time"
pagination={{ pageSize: 5 }}
size="small"
columns={[
{ title: '时间', dataIndex: 'time', key: 'time', render: (t: string) => <span className="text-xs text-neutral-500">{t}</span> },
{ title: '操作人', dataIndex: 'operator', key: 'operator' },
{ title: '操作', dataIndex: 'action', key: 'action' },
{ title: '详情', dataIndex: 'detail', key: 'detail', render: (d: string) => <span className="text-neutral-500">{d}</span> },
]}
/>
</Card>
<Card
title="平台公告"
className="!rounded-lg"
bordered={false}
extra={<Button type="primary" size="small" icon={<PlusOutlined />} onClick={() => message.info('公告编辑')}></Button>}
>
<div className="space-y-3">
{announcements.map(a => (
<div key={a.id} className="p-3 border border-neutral-100 rounded-lg">
<div className="flex items-center justify-between mb-1">
<span className="text-sm font-medium text-neutral-700">{a.title}</span>
<Tag color={a.status === 'published' ? 'green' : 'default'} className="text-xs">{a.status === 'published' ? '已发布' : '草稿'}</Tag>
</div>
<p className="text-xs text-neutral-400 mb-2">{a.content}</p>
<div className="flex items-center justify-between">
<span className="text-xs text-neutral-300">{a.time}</span>
<Space size={0}>
<Button type="link" size="small" icon={<EditOutlined />}></Button>
<Button type="link" size="small" danger icon={<DeleteOutlined />}></Button>
</Space>
</div>
</div>
))}
</div>
</Card>
</div>
</div>
)
}
export default Ops