fix: 仪表盘死按钮修复+K8s进度条可视化+标题简化

- Dashboard: 移除无功能的"实时监控"按钮,"刷新"按钮接上数据重载(useCallback+spin动画)
- DashboardRecent: 4个"查看全部"按钮接上路由导航(告警→/alerts, 发布→/releases, 服务器→/servers, 集群→/clusters)
- K8sNodes: CPU/Mem使用率从纯文本改为迷你进度条(颜色阈值:绿<60%/黄60-85%/红>85%)
- K8sWorkloads: Deployment副本比用进度条可视化(满=绿/未满=黄)
- K8sClusters: 页面标题"K8s集群管理"→"集群列表"
This commit is contained in:
attacker committed 2026-06-15 03:35:30 +08:00
1 parent bf3d642b59
commit 18aa445b32
5 files changed
+104 -71

No files matched your search

+56 -59
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Clock, Activity, Server, Cloud, Bell, DollarSign } from 'lucide-react';
import { Clock, Server, Cloud, Bell, DollarSign } from 'lucide-react';
import { dashboardStatsApi, serverApi, k8sApi } from '@/services/api';
import { StatCard } from './DashboardStats';
import { CostOverviewCard, TopResourceUsageCard, ResourceUsageCard, computeMonthChange } from './DashboardCharts';
@@ -13,7 +13,8 @@ import {
} from './DashboardRecent';
export function Dashboard() {
const [loading, setLoading] = useState(true);
const [initialLoading, setInitialLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const [stats, setStats] = useState<any>(null);
const [servers, setServers] = useState<any[]>([]);
const [clusters, setClusters] = useState<any[]>([]);
@@ -22,55 +23,57 @@ export function Dashboard() {
const [expCerts, setExpCerts] = useState<any[]>([]);
const [metrics, setMetrics] = useState<any[]>([]); // 真实 Agent 指标时间序列 // Logan.Li
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const [statsRes, serversRes, clustersRes, alertsRes, releasesRes, metricsRes] = await Promise.all([
dashboardStatsApi.getStats().catch((e) => {
console.error('Failed to fetch dashboard stats:', e);
return null;
}),
serverApi.getServers({ page: 1, page_size: 100 }).catch((e) => {
console.error('Failed to fetch servers:', e);
return null;
}),
k8sApi.getClusters().catch((e) => {
console.error('Failed to fetch k8s clusters:', e);
return null;
}),
dashboardStatsApi.getAlerts(10).catch((e) => {
console.error('Failed to fetch dashboard alerts:', e);
return null;
}),
dashboardStatsApi.getReleases(5).catch((e) => {
console.error('Failed to fetch dashboard releases:', e);
return null;
}),
// 获取真实 Agent 指标时间序列(过去24小时按小时聚合) // Logan.Li
dashboardStatsApi.getMetrics(24).catch((e) => {
console.error('Failed to fetch metrics:', e);
return [];
}),
]);
const refreshData = useCallback(async () => {
setRefreshing(true);
try {
const [statsRes, serversRes, clustersRes, alertsRes, releasesRes, metricsRes] = await Promise.all([
dashboardStatsApi.getStats().catch((e) => {
console.error('Failed to fetch dashboard stats:', e);
return null;
}),
serverApi.getServers({ page: 1, page_size: 100 }).catch((e) => {
console.error('Failed to fetch servers:', e);
return null;
}),
k8sApi.getClusters().catch((e) => {
console.error('Failed to fetch k8s clusters:', e);
return null;
}),
dashboardStatsApi.getAlerts(10).catch((e) => {
console.error('Failed to fetch dashboard alerts:', e);
return null;
}),
dashboardStatsApi.getReleases(5).catch((e) => {
console.error('Failed to fetch dashboard releases:', e);
return null;
}),
// 获取真实 Agent 指标时间序列(过去24小时按小时聚合) // Logan.Li
dashboardStatsApi.getMetrics(24).catch((e) => {
console.error('Failed to fetch metrics:', e);
return [];
}),
]);
setStats(statsRes);
setServers(serversRes?.list ?? []);
setClusters(clustersRes?.list ?? []);
setAlerts(Array.isArray(alertsRes) ? alertsRes : []);
setReleases(Array.isArray(releasesRes) ? releasesRes : []);
setExpCerts(statsRes?.expiring_certs ?? []);
setMetrics(Array.isArray(metricsRes) ? metricsRes : []);
} catch (error) {
console.error('Failed to load dashboard data:', error);
} finally {
setLoading(false);
}
};
fetchData();
setStats(statsRes);
setServers(serversRes?.list ?? []);
setClusters(clustersRes?.list ?? []);
setAlerts(Array.isArray(alertsRes) ? alertsRes : []);
setReleases(Array.isArray(releasesRes) ? releasesRes : []);
setExpCerts(statsRes?.expiring_certs ?? []);
setMetrics(Array.isArray(metricsRes) ? metricsRes : []);
} catch (error) {
console.error('Failed to load dashboard data:', error);
} finally {
setRefreshing(false);
setInitialLoading(false);
}
}, []);
if (loading) {
useEffect(() => {
refreshData();
}, [refreshData]);
if (initialLoading) {
return (
<div className="flex items-center justify-center h-96">
<div className="h-8 w-8 border-2 border-slate-700 border-t-blue-500 rounded-full animate-spin" />
@@ -92,16 +95,10 @@ export function Dashboard() {
<h1 className="text-2xl font-bold text-slate-100">仪表盘</h1>
<p className="text-sm text-slate-500 mt-1">实时监控和运维概览</p>
</div>
<div className="flex items-center gap-2">
<Button variant="outline" className="border-slate-700 text-slate-300 hover:text-slate-100 hover:bg-slate-800">
<Clock className="h-4 w-4 mr-2" />
刷新
</Button>
<Button className="bg-blue-600 hover:bg-blue-700 text-white">
<Activity className="h-4 w-4 mr-2" />
实时监控
</Button>
</div>
<Button variant="outline" className="border-slate-700 text-slate-300 hover:text-slate-100 hover:bg-slate-800" onClick={refreshData}>
<Clock className={`h-4 w-4 mr-2 ${refreshing ? 'animate-spin' : ''}`} />
刷新
</Button>
</div>
{/* Stats Grid */}