feat: persist system settings and refine admin layouts

This commit is contained in:
rayd1o
2026-03-25 02:57:58 +08:00
parent 81a0ca5e7a
commit ef0fefdfc7
19 changed files with 2091 additions and 1231 deletions

View File

@@ -1,20 +1,16 @@
import { useEffect, useState } from 'react'
import { Layout, Menu, Card, Row, Col, Statistic, Typography, Button, Tag, Spin } from 'antd'
import { Card, Row, Col, Statistic, Typography, Button, Tag, Spin, Space } from 'antd'
import {
DashboardOutlined,
DatabaseOutlined,
UserOutlined,
SettingOutlined,
BarChartOutlined,
AlertOutlined,
WifiOutlined,
DisconnectOutlined,
ReloadOutlined,
} from '@ant-design/icons'
import { Link } from 'react-router-dom'
import { useAuthStore } from '../../stores/auth'
import AppLayout from '../../components/AppLayout/AppLayout'
const { Header, Sider, Content } = Layout
const { Title, Text } = Typography
interface Stats {
@@ -31,7 +27,7 @@ interface Stats {
}
function Dashboard() {
const { user, logout, token, clearAuth } = useAuthStore()
const { token, clearAuth } = useAuthStore()
const [stats, setStats] = useState<Stats | null>(null)
const [loading, setLoading] = useState(true)
const [wsConnected, setWsConnected] = useState(false)
@@ -63,7 +59,7 @@ function Dashboard() {
}
fetchStats()
}, [token])
}, [token, clearAuth])
useEffect(() => {
if (!token) return
@@ -112,28 +108,10 @@ function Dashboard() {
}
}, [token])
const handleLogout = () => {
logout()
window.location.href = '/'
}
const handleClearAuth = () => {
clearAuth()
window.location.href = '/'
}
const handleRetry = () => {
window.location.reload()
}
const menuItems = [
{ key: '/', icon: <DashboardOutlined />, label: <Link to="/"></Link> },
{ key: '/datasources', icon: <DatabaseOutlined />, label: <Link to="/datasources"></Link> },
{ key: '/data', icon: <BarChartOutlined />, label: <Link to="/data"></Link> },
{ key: '/users', icon: <UserOutlined />, label: <Link to="/users"></Link> },
{ key: '/settings', icon: <SettingOutlined />, label: '系统配置' },
]
if (loading && !stats) {
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
@@ -143,81 +121,78 @@ function Dashboard() {
}
return (
<Layout className="dashboard-layout">
<Sider width={240} className="dashboard-sider">
<div style={{ height: 64, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Title level={4} style={{ color: 'white', margin: 0 }}></Title>
</div>
<Menu theme="dark" mode="inline" defaultSelectedKeys={['/']} items={menuItems} />
</Sider>
<Layout>
<Header className="dashboard-header" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<Text strong>, {user?.username}</Text>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<AppLayout>
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12, flexWrap: 'wrap' }}>
<div>
<Title level={4} style={{ margin: 0 }}></Title>
<Text type="secondary"></Text>
</div>
<Space wrap>
{wsConnected ? (
<Tag icon={<WifiOutlined />} color="success"></Tag>
) : (
<Tag icon={<DisconnectOutlined />} color="default">线</Tag>
)}
<Button type="link" danger onClick={handleLogout}>退</Button>
<Button type="link" onClick={handleClearAuth}></Button>
<Button type="link" icon={<ReloadOutlined />} onClick={handleRetry}></Button>
</div>
</Header>
<Content className="dashboard-content">
{error && (
<Card style={{ marginBottom: 16, borderColor: '#ff4d4f' }}>
<Text style={{ color: '#ff4d4f' }}>{error}</Text>
<Button type="default" icon={<ReloadOutlined />} onClick={handleRetry}></Button>
</Space>
</div>
{error && (
<Card style={{ borderColor: '#ff4d4f' }}>
<Text style={{ color: '#ff4d4f' }}>{error}</Text>
</Card>
)}
<Row gutter={[16, 16]}>
<Col xs={24} sm={12} xl={6}>
<Card>
<Statistic title="数据源总数" value={stats?.total_datasources || 0} prefix={<DatabaseOutlined />} />
</Card>
)}
<Row gutter={[16, 16]}>
<Col span={6}>
<Card>
<Statistic title="数据源总数" value={stats?.total_datasources || 0} prefix={<DatabaseOutlined />} />
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic title="活跃数据源" value={stats?.active_datasources || 0} valueStyle={{ color: '#52c41a' }} />
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic title="今日任务" value={stats?.tasks_today || 0} prefix={<BarChartOutlined />} />
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic title="成功率" value={stats?.success_rate || 0} suffix="%" valueStyle={{ color: '#1890ff' }} />
</Card>
</Col>
</Row>
<Row gutter={[16, 16]} style={{ marginTop: 16 }}>
<Col span={8}>
<Card>
<Statistic title="严重告警" value={stats?.alerts?.critical || 0} valueStyle={{ color: '#ff4d4f' }} prefix={<AlertOutlined />} />
</Card>
</Col>
<Col span={8}>
<Card>
<Statistic title="警告" value={stats?.alerts?.warning || 0} valueStyle={{ color: '#faad14' }} prefix={<AlertOutlined />} />
</Card>
</Col>
<Col span={8}>
<Card>
<Statistic title="提示" value={stats?.alerts?.info || 0} valueStyle={{ color: '#1890ff' }} prefix={<AlertOutlined />} />
</Card>
</Col>
</Row>
{stats?.last_updated && (
<div style={{ marginTop: 16, textAlign: 'center', color: '#8c8c8c' }}>
: {new Date(stats.last_updated).toLocaleString('zh-CN')}
{wsConnected && <Tag color="green" style={{ marginLeft: 8 }}></Tag>}
</div>
)}
</Content>
</Layout>
</Layout>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card>
<Statistic title="活跃数据源" value={stats?.active_datasources || 0} valueStyle={{ color: '#52c41a' }} />
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card>
<Statistic title="今日任务" value={stats?.tasks_today || 0} prefix={<BarChartOutlined />} />
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card>
<Statistic title="成功率" value={stats?.success_rate || 0} suffix="%" valueStyle={{ color: '#1890ff' }} />
</Card>
</Col>
</Row>
<Row gutter={[16, 16]}>
<Col xs={24} md={8}>
<Card>
<Statistic title="严重告警" value={stats?.alerts?.critical || 0} valueStyle={{ color: '#ff4d4f' }} prefix={<AlertOutlined />} />
</Card>
</Col>
<Col xs={24} md={8}>
<Card>
<Statistic title="警" value={stats?.alerts?.warning || 0} valueStyle={{ color: '#faad14' }} prefix={<AlertOutlined />} />
</Card>
</Col>
<Col xs={24} md={8}>
<Card>
<Statistic title="提示" value={stats?.alerts?.info || 0} valueStyle={{ color: '#1890ff' }} prefix={<AlertOutlined />} />
</Card>
</Col>
</Row>
{stats?.last_updated && (
<div style={{ textAlign: 'center', color: '#8c8c8c' }}>
: {new Date(stats.last_updated).toLocaleString('zh-CN')}
{wsConnected && <Tag color="green" style={{ marginLeft: 8 }}></Tag>}
</div>
)}
</div>
</AppLayout>
)
}