feat: add area diagnostics

This commit is contained in:
2026-06-24 16:06:18 +08:00
parent b002c44218
commit e6f26152d1
6 changed files with 314 additions and 12 deletions

View File

@@ -1031,6 +1031,7 @@ function AreaDetailPanel({
<div className="h-72 rounded-md border border-[var(--border)] p-3">
<AreaMetricTrendChart metrics={detail.monthly_metrics} />
</div>
<AreaDiagnosticsPanel diagnostics={detail.diagnostics} />
<div className="grid gap-4 lg:grid-cols-2">
<AreaMetricHistoryTable metrics={detail.monthly_metrics} />
<AreaNeighborhoodTable
@@ -1051,6 +1052,57 @@ function AreaDetailPanel({
);
}
function AreaDiagnosticsPanel({ diagnostics }: { diagnostics: AreaDetail["diagnostics"] }) {
if (!diagnostics) {
return (
<div className="rounded-md border border-[var(--border)] px-4 py-8 text-sm text-[var(--muted-foreground)]">
</div>
);
}
return (
<div className="rounded-md border border-[var(--border)] p-3">
<div className="mb-3 flex items-center justify-between gap-3">
<p className="text-sm font-semibold text-slate-950"></p>
<Badge variant={diagnostics.anomaly_count > 0 ? "warning" : "success"}>
{diagnostics.anomaly_count}
</Badge>
</div>
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
{diagnostics.metrics.map((metric) => (
<div key={metric.key} className="rounded-md border border-[var(--border)] bg-white p-3">
<div className="flex items-center justify-between gap-2">
<span className="text-sm font-medium text-slate-950">{metric.label}</span>
<Badge variant={metric.anomaly ? "warning" : "muted"}>{metric.severity}</Badge>
</div>
<p className="mt-2 text-lg font-semibold text-slate-950">
{formatMetricValue(metric.current_value, metric.unit)}
</p>
<div className="mt-3 h-2 rounded-full bg-[var(--muted)]">
<div
className={
metric.anomaly
? "h-2 rounded-full bg-[var(--warning)]"
: "h-2 rounded-full bg-[var(--primary)]"
}
style={{ width: `${Math.max(0, Math.min(100, metric.percentile))}%` }}
/>
</div>
<div className="mt-2 flex items-center justify-between text-xs text-[var(--muted-foreground)]">
<span>P{formatNumber(metric.percentile, 1)}</span>
<span>
{formatMetricValue(metric.historical_min, metric.unit)}-
{formatMetricValue(metric.historical_max, metric.unit)}
</span>
</div>
</div>
))}
</div>
</div>
);
}
function AreaMetricTrendChart({ metrics }: { metrics: AreaDetail["monthly_metrics"] }) {
const data = [...metrics].reverse();
if (data.length === 0) {