Use usable recent DEB training rankings

This commit is contained in:
2569718930@qq.com
2026-06-08 13:37:20 +08:00
parent 721173aea3
commit 956cb8a8e3
6 changed files with 236 additions and 21 deletions
@@ -68,7 +68,7 @@ export function TrainingAccuracyCharts({
{debChartData.length > 0 ? (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card>
<CardHeader><CardTitle>DEB by </CardTitle></CardHeader>
<CardHeader><CardTitle>DEB by </CardTitle></CardHeader>
<CardContent>
<div className="h-[400px]">
<ResponsiveContainer>
@@ -78,7 +78,7 @@ export function TrainingAccuracyCharts({
<YAxis domain={[0, 100]} tick={{ fill: "#94a3b8", fontSize: 11 }} unit="%" />
<Tooltip
contentStyle={CHART_TOOLTIP_STYLE}
formatter={(value: unknown) => [`${Number(value).toFixed(1)}%`, "命中率"]}
formatter={(value: unknown) => [`${Number(value).toFixed(1)}%`, "可用近期命中率"]}
/>
<Bar dataKey="hitRate" radius={[4, 4, 0, 0]} maxBarSize={36}>
{debChartData.map((entry, i) => (
@@ -93,7 +93,7 @@ export function TrainingAccuracyCharts({
</Card>
<Card>
<CardHeader><CardTitle>DEB MAE by </CardTitle></CardHeader>
<CardHeader><CardTitle>DEB MAE by </CardTitle></CardHeader>
<CardContent>
<div className="h-[400px]">
<ResponsiveContainer>
@@ -103,7 +103,7 @@ export function TrainingAccuracyCharts({
<YAxis tick={{ fill: "#94a3b8", fontSize: 11 }} unit="°" />
<Tooltip
contentStyle={CHART_TOOLTIP_STYLE}
formatter={(value: unknown) => [`${Number(value).toFixed(1)}°`, "MAE"]}
formatter={(value: unknown) => [`${Number(value).toFixed(1)}°`, "可用近期 MAE"]}
/>
<Bar dataKey="mae" radius={[4, 4, 0, 0]} maxBarSize={36}>
{debChartData.map((entry, i) => (
@@ -6,6 +6,7 @@ import { RefreshCcw, TrendingUp, TrendingDown, Target, Activity } from "lucide-r
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { buildDebRecentRankingRows } from "@/lib/deb-training-ranking";
import { opsApi } from "@/lib/ops-api";
import type { SystemStatusPayload } from "@/types/ops";
import Link from "next/link";
@@ -183,19 +184,23 @@ export function TrainingPageClient() {
const usableWindowLabel = (window?: string) =>
window === "recent_14d" ? "DEB 可用近 14 天命中" : "DEB 可用近 7 天命中";
const debRecentRanked = useMemo(() => buildDebRecentRankingRows(accuracy || []), [accuracy]);
const debRecentRankIndex = useMemo(
() => new Map(debRecentRanked.map((row, index) => [row.cityId, index])),
[debRecentRanked],
);
const debChartData = useMemo(() => {
if (!accuracy?.length) return [];
return accuracy
.filter((c) => c.deb && c.deb.total_days >= 5)
.sort((a, b) => (b.deb?.hit_rate ?? 0) - (a.deb?.hit_rate ?? 0))
return debRecentRanked
.slice(0, 24)
.map((c) => ({
name: c.name,
cityId: c.city_id,
hitRate: Number((c.deb?.hit_rate ?? 0).toFixed(1)),
mae: Number((c.deb?.mae ?? 0).toFixed(1)),
days: c.deb?.total_days ?? 0,
cityId: c.cityId,
hitRate: c.hitRate,
mae: c.mae,
days: c.samples,
}));
}, [accuracy]);
}, [debRecentRanked]);
const muChartData = useMemo(() => {
if (!accuracy?.length) return [];
@@ -212,6 +217,18 @@ export function TrainingPageClient() {
}));
}, [accuracy]);
const sortedAccuracy = useMemo(() => {
if (!accuracy?.length) return [];
return [...accuracy].sort((a, b) => {
const aDebRank = debRecentRankIndex.get(a.city_id) ?? 9999;
const bDebRank = debRecentRankIndex.get(b.city_id) ?? 9999;
if (aDebRank !== bDebRank) return aDebRank - bDebRank;
const aMax = Math.max(a.deb?.hit_rate ?? 0, a.mu?.hit_rate ?? 0);
const bMax = Math.max(b.deb?.hit_rate ?? 0, b.mu?.hit_rate ?? 0);
return bMax - aMax;
});
}, [accuracy, debRecentRankIndex]);
if (loading) return <div className="text-slate-400 animate-pulse">...</div>;
if (!status) return <div className="text-red-400"></div>;
@@ -350,8 +367,8 @@ export function TrainingPageClient() {
</tr>
</thead>
<tbody className="divide-y divide-white/5">
{accuracy && accuracy.length > 0 ? (
accuracy.map((row) => (
{sortedAccuracy.length > 0 ? (
sortedAccuracy.map((row) => (
<tr key={row.city_id} className="hover:bg-white/5 transition-colors">
<td className="px-4 py-3 font-medium text-white capitalize">
{row.name}