feat: 新增日志中心、功能优化与代码重构
- 新增 log_datasource.go / log_proxy.go / user_api_token.go 后端控制器 - 新增 log_datasource.go model - 新增 monitor/log-center.ts API 模块 - 新增 LogCenter 前端组件及页面 - 重构 deployment 相关组件 (HPDA/UpdateImageModal/bundle-yaml 等) - 新增 ResetPasswordDialog / code-snippet-block / copy-button 等 UI 组件 - 重构多个 k8s 相关组件 (TopologyView/ResourceVisualEditor/PodFileBrowser 等) - 更新多个 API 和工具函数 (auth.ts/monitor/index.ts/request.ts 等) - 更新静态资源 (index.html + 新 JS/CSS bundle) - 删除废弃静态资源文件
This commit is contained in:
1 parent
5ca0e6d83a
commit
8d46e8f352
197 files changed
+5014
-815
No files matched your search
@@ -3,7 +3,7 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/com
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Cloud, XCircle } from 'lucide-react';
|
||||
import { Cloud, XCircle, RefreshCw } from 'lucide-react';
|
||||
import { kubernetesApi } from '@/api';
|
||||
import {
|
||||
AreaChart,
|
||||
@@ -15,8 +15,9 @@ import {
|
||||
ResponsiveContainer,
|
||||
} from 'recharts';
|
||||
|
||||
// 资源使用趋势数据 — 从节点 metrics 实时计算(不再用硬编码 mock) // Logan.Li
|
||||
// 由于当前无 time-series 存储,用当前快照展示一个合理的汇总值
|
||||
// 资源使用趋势数据
|
||||
// 由于当前无持久化时序存储,这里基于当前节点 metrics 构造一个简短的模拟趋势(最近几分钟变化)
|
||||
// 真正历史数据需要后端记录指标快照后才能实现 // Logan.Li
|
||||
|
||||
export function KubernetesClusterDetail({ cluster, onClose }: { cluster: any; onClose: () => void }) {
|
||||
const [nodes, setNodes] = useState<any[]>([]);
|
||||
@@ -50,6 +51,21 @@ export function KubernetesClusterDetail({ cluster, onClose }: { cluster: any; on
|
||||
};
|
||||
}, [nodes]);
|
||||
|
||||
// 构造趋势数据(多点),避免单点导致“光点”效果 // Logan.Li
|
||||
const trendData = useMemo(() => {
|
||||
const cpu = Math.max(0, Math.min(100, Number(clusterMetrics.cpuPct.toFixed(1))));
|
||||
const mem = Math.max(0, Math.min(100, Number(clusterMetrics.memPct.toFixed(1))));
|
||||
|
||||
// 模拟最近 5 个时间点的趋势(基于当前值轻微回溯)
|
||||
return [
|
||||
{ time: '10m前', cpu: Math.max(0, cpu * 0.72), memory: Math.max(0, mem * 0.78) },
|
||||
{ time: '7m前', cpu: Math.max(0, cpu * 0.82), memory: Math.max(0, mem * 0.85) },
|
||||
{ time: '4m前', cpu: Math.max(0, cpu * 0.90), memory: Math.max(0, mem * 0.93) },
|
||||
{ time: '2m前', cpu: Math.max(0, cpu * 0.96), memory: Math.max(0, mem * 0.97) },
|
||||
{ time: '现在', cpu, memory: mem },
|
||||
];
|
||||
}, [clusterMetrics]);
|
||||
|
||||
const loadClusterDetail = async (clusterId: string) => {
|
||||
try {
|
||||
// 后端 ListNodes/ListPods/etc 返回 data 直接为数组(非 {list,total})
|
||||
@@ -132,49 +148,63 @@ export function KubernetesClusterDetail({ cluster, onClose }: { cluster: any; on
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<Card className="bg-slate-800/50 border-slate-700">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm text-slate-400">资源使用趋势</CardTitle>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<CardTitle className="text-sm text-slate-400">资源使用趋势(模拟最近变化)</CardTitle>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 w-6 p-0 text-slate-400 hover:text-slate-200"
|
||||
onClick={() => cluster?.id && loadClusterDetail(cluster.id)}
|
||||
title="刷新节点指标"
|
||||
>
|
||||
<RefreshCw className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-[200px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart data={[
|
||||
{ time: 'CPU', cpu: Number(clusterMetrics.cpuPct.toFixed(1)), memory: Number(clusterMetrics.memPct.toFixed(1)) },
|
||||
]}>
|
||||
<AreaChart data={trendData} margin={{ top: 5, right: 10, left: 0, bottom: 5 }}>
|
||||
<defs>
|
||||
<linearGradient id="colorCpu" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#3b82f6" stopOpacity={0.3} />
|
||||
<stop offset="95%" stopColor="#3b82f6" stopOpacity={0} />
|
||||
<stop offset="5%" stopColor="#3b82f6" stopOpacity={0.35} />
|
||||
<stop offset="95%" stopColor="#3b82f6" stopOpacity={0.05} />
|
||||
</linearGradient>
|
||||
<linearGradient id="colorMemory" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#10b981" stopOpacity={0.3} />
|
||||
<stop offset="95%" stopColor="#10b981" stopOpacity={0} />
|
||||
<stop offset="5%" stopColor="#10b981" stopOpacity={0.35} />
|
||||
<stop offset="95%" stopColor="#10b981" stopOpacity={0.05} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
|
||||
<XAxis dataKey="time" stroke="#475569" fontSize={12} />
|
||||
<YAxis stroke="#475569" fontSize={12} domain={[0, 100]} />
|
||||
<CartesianGrid strokeDasharray="2 2" stroke="#1e293b" />
|
||||
<XAxis dataKey="time" stroke="#475569" fontSize={11} tickLine={false} />
|
||||
<YAxis stroke="#475569" fontSize={11} domain={[0, 100]} unit="%" tickLine={false} />
|
||||
<Tooltip
|
||||
contentStyle={{
|
||||
backgroundColor: '#0f172a',
|
||||
border: '1px solid #1e293b',
|
||||
borderRadius: '6px',
|
||||
color: '#f8fafc',
|
||||
fontSize: '12px',
|
||||
}}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="cpu"
|
||||
stroke="#3b82f6"
|
||||
fillOpacity={1}
|
||||
strokeWidth={2}
|
||||
fill="url(#colorCpu)"
|
||||
dot={false}
|
||||
activeDot={{ r: 3, fill: '#3b82f6' }}
|
||||
name="CPU(%)"
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="memory"
|
||||
stroke="#10b981"
|
||||
fillOpacity={1}
|
||||
strokeWidth={2}
|
||||
fill="url(#colorMemory)"
|
||||
dot={false}
|
||||
activeDot={{ r: 3, fill: '#10b981' }}
|
||||
name="内存(%)"
|
||||
/>
|
||||
</AreaChart>
|
||||
|
||||
Reference in new issue
Block a user