P0(4): 假数据清除(avg_latency_ms:2400→null,无端点字段改null)、假进度条改诚实的不确定态、 公共页不再反向依赖 admin(api/public.ts)、PredictProgress 重写 P1(6): 23处 any 归零(对齐后端 Pydantic 契约新增 PredictionMatchRef/HealthProbe 等)、 a11y(aria-live 0→4,htmlFor 1→17,aria-describedby/invalid 补齐)、App.tsx 抽 SiteLayout、 路由级 lazy+代码分割(首屏 315KB→238KB)、index.html 补 SEO/favicon/OG、死代码清理(AdminIcon 抽出) P2(7): Login/index.css 裸色值令牌化、groupByDate useMemo、滚动监听统一、原生控件基元化、 useLeagues 静默失败补告警、路由级 ErrorBoundary 另修复审计未列问题: - Monitoring todos 过滤器 t!==false 放行 null 导致整页崩溃 → Boolean(t) 真值过滤 - Collection 渲染期 Date.now()(react-hooks/purity 捕获)→ 计时器 effect - bg-press-wash/60 透明度修饰符静默失效 → RGB 三元组 + 构建期令牌守卫(下个提交接入) 工程化:数据层 dal/api/types(1047行)git mv 至 src/api/,admin 留 @deprecated 兼容壳, 21 个引用方直指新路径;tsconfig 开启 noUnusedLocals/noUnusedParameters(清理9处存量)
77 lines
2.9 KiB
TypeScript
77 lines
2.9 KiB
TypeScript
/**
|
|
* Admin 后台 - 路由配置
|
|
*
|
|
* 所有 Admin 页面的路由定义,使用嵌套路由。
|
|
* 挂载路径: /admin/*
|
|
*
|
|
* 全部页面采用 `lazy` 动态导入。
|
|
*
|
|
* 此前这里是 10 个静态 import:App.tsx 引入 adminRoutes 就把
|
|
* Dashboard/Collection/Logs/Eval/Backtest/Settings/Monitoring/
|
|
* DataCompleteness/DataPipeline/PredictionHistory 连同它们的
|
|
* 数据访问层一次性拉进首屏 —— 一个只想看赛程的匿名访客,
|
|
* 要为完整的后台界面付出流量。改为 lazy 后,后台代码只在实际
|
|
* 访问 /admin/* 时才下载。
|
|
*
|
|
* AdminLayout 保持静态引入:它是所有后台页面的公共外壳,
|
|
* 若也 lazy 则会与页面 chunk 形成串行请求(先下载 layout,
|
|
* 再下载页面),反而更慢。
|
|
*/
|
|
|
|
import { lazy, Suspense } from 'react'
|
|
import type { ReactNode } from 'react'
|
|
import { Navigate } from 'react-router-dom'
|
|
import AdminLayout from './AdminLayout'
|
|
|
|
const Dashboard = lazy(() => import('./pages/Dashboard'))
|
|
const CollectionPage = lazy(() => import('./pages/Collection'))
|
|
const DataCompletenessPage = lazy(() => import('./pages/DataCompleteness'))
|
|
const DataPipelinePage = lazy(() => import('./pages/DataPipeline'))
|
|
const PredictionsPage = lazy(() => import('./pages/PredictionHistory'))
|
|
const BacktestPage = lazy(() => import('./pages/Backtest'))
|
|
const MonitoringPage = lazy(() => import('./pages/Monitoring'))
|
|
const SettingsPage = lazy(() => import('./pages/Settings'))
|
|
const LogsPage = lazy(() => import('./pages/Logs'))
|
|
const EvalPage = lazy(() => import('./pages/EvalPage'))
|
|
|
|
/**
|
|
* 页面级懒加载的兜底:后台各页共用。
|
|
* 保持极简,避免后台切换时出现大块占位跳动。
|
|
*/
|
|
function AdminPageFallback() {
|
|
return (
|
|
<div className="flex min-h-[40vh] items-center justify-center">
|
|
<span className="text-xs text-ink-400" role="status" aria-live="polite">
|
|
加载中…
|
|
</span>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
/** 用 Suspense 包住单个后台页面 */
|
|
function page(node: ReactNode): ReactNode {
|
|
return <Suspense fallback={<AdminPageFallback />}>{node}</Suspense>
|
|
}
|
|
|
|
export const adminRoutes = [
|
|
{
|
|
path: '/admin',
|
|
element: <AdminLayout />,
|
|
children: [
|
|
{ index: true, element: page(<Dashboard />) },
|
|
{ path: 'collection', element: page(<CollectionPage />) },
|
|
{ path: 'data-completeness', element: page(<DataCompletenessPage />) },
|
|
{ path: 'data-pipeline', element: page(<DataPipelinePage />) },
|
|
{ path: 'predictions', element: page(<PredictionsPage />) },
|
|
{ path: 'backtest', element: page(<BacktestPage />) },
|
|
{ path: 'monitoring', element: page(<MonitoringPage />) },
|
|
{ path: 'settings', element: page(<SettingsPage />) },
|
|
{ path: 'logs', element: page(<LogsPage />) },
|
|
{ path: 'eval', element: page(<EvalPage />) },
|
|
{ path: '*', element: <Navigate to="/admin" replace /> },
|
|
],
|
|
},
|
|
]
|
|
|
|
export { adminRoutes as default }
|