import { useQuery } from '@tanstack/react-query' import { createFileRoute, Link } from '@tanstack/react-router' import { Area, CartesianGrid, ComposedChart, Line, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts' import type { NameType, ValueType } from 'recharts/types/component/DefaultTooltipContent' import { orpc } from '@/client/orpc' import type { DashboardSnapshot, DeviceStatus } from '@/domain/battery' export const Route = createFileRoute('/')({ component: Dashboard, errorComponent: ({ error }) => (

数据加载失败

{error.message}

), }) function buildChartData(soh: DashboardSnapshot['soh']) { const chartData: { month: string; history?: number; forecast?: number }[] = soh.history.map((h) => ({ month: h.month, history: h.value, forecast: undefined, })) if (chartData.length > 0 && soh.forecast.length > 0) { // Overlap: last history point is also first forecast point const last = chartData[chartData.length - 1] if (last) { last.forecast = soh.forecast[0]?.value } } for (let i = 1; i < soh.forecast.length; i++) { const f = soh.forecast[i] if (f) { chartData.push({ month: f.month, history: undefined, forecast: f.value, }) } } return chartData } const statusColorMap: Record = { 健康: 'text-emerald-400', 关注: 'text-amber-400', 预警: 'text-red-400', } const severityColorMap: Record = { 高: 'text-red-400', 中: 'text-amber-400', 低: 'text-zinc-400', } function formatChartTooltip(value: ValueType | undefined, name: NameType | undefined) { const numericValue = typeof value === 'number' ? value : Number(value) return [ `${Number.isFinite(numericValue) ? numericValue.toFixed(1) : (value ?? '-')}%`, name === 'history' ? '历史观测' : '模型预测', ] } function Dashboard() { const { data, error, isPending } = useQuery(orpc.battery.dashboard.queryOptions()) if (error) { return (

数据加载失败

{error.message}

) } if (isPending || !data) { return (

加载中…

) } const { devices, soh, events, strategies, summary } = data const { totalDevices, avgSoh, avgSoh30d, avgSoh90d, warningCount, watchCount, healthyCount, batchPerformance, riskFactorCounts, firmwareHealth, updatedAt, executiveSummary, } = summary const chartData = buildChartData(soh) return (
{/* Background gradient */}
{/* Header */}
智能戒指电池健康预测模型 (v2.4)

SoH 预测与风险洞察

模型回测准确率 (MAE) 1.2%
预测命中率 94.5%

数据更新时间: {updatedAt}

设备电池实时状态 →
{/* Executive Summary */}

执行摘要

{executiveSummary}

{/* Primary KPI Row */}
{/* Hero KPI */}

当前平均 SoH

{avgSoh.toFixed(1)}

%
基线健康 | 共 {totalDevices} 台设备
{/* Regular KPIs */}

30 天预测均值

{avgSoh30d.toFixed(1)}

%
{(avgSoh - avgSoh30d).toFixed(1)}% 衰减

90 天预测均值

{avgSoh90d.toFixed(1)}

%
{(avgSoh - avgSoh90d).toFixed(1)}% 衰减

高风险设备

{warningCount}

占比 {totalDevices > 0 ? ((warningCount / totalDevices) * 100).toFixed(1) : 0}%
{/* Divider */}
{/* SoH Trend Chart */}

SoH 衰减趋势与 90 天预测

基于历史 12 个月真实数据与未来 3 个月模型预测区间

历史观测值 模型预测值
Math.floor(min) - 2, (max: number) => Math.ceil(max) + 2]} tick={{ fill: '#71717A', fontSize: 11 }} axisLine={false} tickLine={false} tickFormatter={(v: number) => `${v}%`} width={48} />
{/* Two-column grid */}
{/* Left Column */}
{/* Risk Distribution */}

风险分层与结构

健康 (SoH > 90%) {healthyCount} 台{' '} / {totalDevices > 0 ? ((healthyCount / totalDevices) * 100).toFixed(1) : 0}%
0 ? (healthyCount / totalDevices) * 100 : 0}%` }} />
关注 (85% < SoH ≤ 90%) {watchCount} 台{' '} / {totalDevices > 0 ? ((watchCount / totalDevices) * 100).toFixed(1) : 0}%
0 ? (watchCount / totalDevices) * 100 : 0}%` }} />
预警 (SoH ≤ 85%) {warningCount} 台{' '} / {totalDevices > 0 ? ((warningCount / totalDevices) * 100).toFixed(1) : 0}%
0 ? (warningCount / totalDevices) * 100 : 0}%` }} />
{/* Regional Performance */}

批次健康度概览

{batchPerformance.length > 0 ? ( batchPerformance.map((item) => (
{item.batch}
{item.avgSoh.toFixed(1)}%
)) ) : (
暂无数据
)}
{/* Right Column */}
{/* Event Timeline */}

异常特征时间轴

{events.length > 0 ? ( events.map((event) => (
{event.time} {event.severity}风险

{event.title}

{event.detail}

)) ) : (
暂无数据
)}
{/* Risk Factor Frequency */}

主要风险因子分布

{riskFactorCounts.length > 0 ? ( riskFactorCounts.map((item) => (
{item.factor} {item.count}
)) ) : (
暂无数据
)}
{/* Divider */}
{/* Device Table */}

高风险设备清单与预测明细

按综合风险评分排序,展示未来 30/60/90 天衰减预测

{devices.length > 0 ? ( devices .slice() .sort((a, b) => b.riskScore - a.riskScore) .map((unit) => ( )) ) : ( )}
设备标识 生产批次 当前 SoH 30天预测 90天预测 风险评分 状态 主要风险因子
{unit.id} {unit.batch} {unit.soh.toFixed(1)}% {unit.soh30d.toFixed(1)}% {unit.soh90d.toFixed(1)}%
= 75 ? 'bg-red-400' : unit.riskScore >= 45 ? 'bg-amber-400' : 'bg-emerald-400' }`} style={{ width: `${unit.riskScore}%` }} />
{unit.riskScore}
{unit.status}
{unit.riskFactors.length > 0 ? ( unit.riskFactors.map((factor) => ( {factor} {factor !== unit.riskFactors[unit.riskFactors.length - 1] && '、'} )) ) : ( - )}
暂无设备数据
{/* Bottom Row */}
{/* Strategy Cards */}

模型驱动的维护策略建议

{strategies.length > 0 ? ( strategies.map((item, index) => (

{item.name}

{item.impact}

范围: {item.scope} 时效: {item.eta}
)) ) : (
暂无策略建议
)}
{/* Firmware Comparison */}

固件版本健康度对比

{firmwareHealth.length > 0 ? ( firmwareHealth.map((item) => (
{item.firmware}
{item.count} 台设备
{item.avgSoh.toFixed(1)}%
平均 SoH
)) ) : (
暂无数据
)}
) }