feat(analysis): Ingress 访问分析卡 — 自动加载、无 ingress 自动折叠

- 新增常驻「Ingress 访问分析」卡:自动探测 ingress-nginx/ingress 命名空间并聚合访问日志
  (PV/UV、4xx/5xx、慢请求、接口排行、异常/慢请求 Top10、请求明细),随数据源与时间范围刷新
- 从历史恢复 ingress 洞察表与聚合工具到 analysis 域(ingress-access-log 解析已在 lib)
- 折叠交互:未检测到 ingress-nginx 时自动收起并显示徽章;手动切换记入 localStorage 优先生效
This commit is contained in:
opsx committed 2026-10-28 22:43:57 +08:00
1 parent 16306a9532
commit 2da0a2bece
4 files changed
+280 -6

No files matched your search

+8 -6
View File
@@ -21,6 +21,7 @@ import { AppStreamChart } from './components/AppStreamChart'
import { DailyVolumeChart } from './components/DailyVolumeChart'
import { NamespacePie } from './components/NamespacePie'
import { TopAppsTable } from './components/TopAppsTable'
import { IngressAnalysisSection } from './components/IngressAnalysisSection'
const toLocal = (date: Date) => new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, 19)
@@ -120,14 +121,14 @@ const AnalysisPage = memo(function AnalysisPage() {
<div className="grid gap-4 lg:grid-cols-3">
<Card className="lg:col-span-2">
<CardHeader className="pb-2">
<CardHeader className="pb-3">
<CardTitle className="text-base">{t('trend.title')}</CardTitle>
<p className="text-xs text-muted-foreground">{t('trend.subtitle')}</p>
</CardHeader>
<CardContent><TrendChart trend={data.trend} /></CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardHeader className="pb-3">
<CardTitle className="text-base">{t('pie.title')}</CardTitle>
<p className="text-xs text-muted-foreground">{t('pie.subtitle')}</p>
</CardHeader>
@@ -136,7 +137,7 @@ const AnalysisPage = memo(function AnalysisPage() {
</div>
<Card>
<CardHeader className="pb-2">
<CardHeader className="pb-3">
<CardTitle className="text-base">{t('stream.title')}</CardTitle>
<p className="text-xs text-muted-foreground">{t('stream.subtitle', { count: Math.min(data.apps.length, 10) })}</p>
</CardHeader>
@@ -144,7 +145,7 @@ const AnalysisPage = memo(function AnalysisPage() {
</Card>
<Card>
<CardHeader className="pb-2">
<CardHeader className="pb-3">
<div className="flex flex-wrap items-center gap-2">
<CardTitle className="text-base">{t('daily.title')}</CardTitle>
<span className="rounded-full bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground">{t('daily.fixedBadge')}</span>
@@ -153,7 +154,7 @@ const AnalysisPage = memo(function AnalysisPage() {
</CardHeader>
<CardContent>
{daily.error ? (
<p className="py-6 text-center text-xs text-destructive">{daily.error}</p>
<ErrorState message={daily.error} onRetry={daily.refresh} />
) : daily.loading && !daily.data ? (
<LoadingSpinner className="h-40" />
) : (
@@ -163,7 +164,7 @@ const AnalysisPage = memo(function AnalysisPage() {
</Card>
<Card>
<CardHeader className="pb-2">
<CardHeader className="pb-3">
<CardTitle className="text-base">{t('table.title')}</CardTitle>
<p className="text-xs text-muted-foreground">{t('table.subtitle')}</p>
</CardHeader>
@@ -177,6 +178,7 @@ const AnalysisPage = memo(function AnalysisPage() {
</CardContent>
</Card>
<IngressAnalysisSection sourceId={sourceId} start={start} end={end} />
</>
)}
</PageContainer>