rack:界面改版(仪器前面板风格 + 暗色模式)+ 底板温度曲线

- 总览:每块板一块面板、五个刀片槽(状态灯 + DIN 读数 + 最近两分钟电流小曲线,平线 = 疑似卡死);
  只有异常 / 故障 / 执行中上色;顶上一句话概况,有问题直接列出是哪几路
- 单板页:新增「底板温度」(两路 NTC + 风扇占空比,上下两块共用时间轴,10 分钟 ~ 7 天);
  每路电流 / 电压去掉双 Y 轴,改上下两块,电压固定 3.5~4.1 V;名称 / 位置就地编辑
- 主题:theme.css 亮 / 暗两套变量(跟随系统,Element Plus 暗色变量同挂 html.dark),图表切换时重画;
  读数用系统自带 DIN 系字体(不加载网络字体);温度两色按本页亮暗底色跑过 dataviz validate_palette.js 全通过
- 后端:board_tele_min 分钟聚合(温度带 min/max,留 90 天)+ GET /api/boards/{id}/history(Db.board_history)
- 修一个偶发失败的测试(test_ota_events_are_named_by_arg:只推一次遥测,赶上 Hub 正在同步时会漏触发);
  后端 42 例本机 + 服务器全绿,已部署;线上已取到板 B 温度 24.4 / 26.0 °C

Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
zhou yang
2026-09-27 15:03:24 +08:00
共同撰写人 Claude Opus 5.5
父节点 1cd4fd4082
当前提交 9858b6c98e
共修改 25 个文件,包含 828 行新增和 225 行删除
+132
查看文件
@@ -0,0 +1,132 @@
/* PhoneRail 机架 —— 仪器前面板风格。
一处用力:每块板是一块「面板」,五个槽是凹进去的「刀片槽」,槽里是状态灯 + 读数 + 电流小曲线。
其余一律安静:冷灰阳极铝底、细线分隔、读数用 DIN 系等宽数字。
颜色只有两类职责:
· 状态(运行 / 忙 / 异常 / 故障 / 断电 / 空槽 / 失联)—— 只用来表示状态,旁边一定有文字;
· 交互(选中、链接、主按钮)—— 阳极蓝。
图表的系列色在 chart.js 里(dataviz 参考调色板第 1/2 槽,按本页底色校验过)。 */
:root {
color-scheme: light;
--plane: #eceff2; /* 页面底 */
--panel: #fbfcfd; /* 面板 */
--bay: #f2f4f7; /* 凹槽(比面板深一档) */
--bay-edge: #dde2e8;
--ink: #16202b;
--ink-2: #566270;
--muted: #8a94a0;
--line: #d9dee4;
--line-soft: #e8ecf0;
--accent: #1d5fd1;
--accent-soft: #e3ecfb;
--bar: #fbfcfd;
--st-ok: #0c8a0c; /* 运行(比 dataviz 的 good 深一档:它要当文字用) */
--st-busy: #1d5fd1;
--st-warn: #b07a00;
--st-bad: #c62f2f;
--st-off: #5d6875;
--st-empty: #b9c1ca;
--st-lost: #98a1ab;
--led-ok: #16b416; /* 灯本身:亮一点,但只当圆点用,不当文字 */
--led-warn: #fab219;
--led-bad: #e04343;
--readout: "DIN Alternate", "DIN 2014", Bahnschrift, "Roboto Condensed", "Arial Narrow", system-ui, sans-serif;
--ui: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei",
"Noto Sans CJK SC", system-ui, sans-serif;
--r-panel: 10px;
--r-bay: 6px;
/* Element Plus:主色换成阳极蓝,其余跟着面板走 */
--el-color-primary: #1d5fd1;
--el-color-primary-light-3: #6190e0;
--el-color-primary-light-5: #8eafe8;
--el-color-primary-light-7: #bbcff1;
--el-color-primary-light-8: #d2dff6;
--el-color-primary-light-9: #e8effb;
--el-color-primary-dark-2: #184ca7;
--el-font-family: var(--ui);
--el-border-radius-base: 6px;
}
html.dark {
color-scheme: dark;
--plane: #0f1216;
--panel: #171b21;
--bay: #12161b;
--bay-edge: #262c34;
--ink: #e8ecf1;
--ink-2: #a7b0bb;
--muted: #76808b;
--line: #2a3038;
--line-soft: #20252c;
--accent: #5b95f2;
--accent-soft: #1b2a44;
--bar: #13171c;
--st-ok: #3cc43c;
--st-busy: #5b95f2;
--st-warn: #f0b23a;
--st-bad: #ef6464;
--st-off: #8a95a1;
--st-empty: #3a414a;
--st-lost: #5d6671;
--led-ok: #2fd12f;
--led-warn: #fab219;
--led-bad: #ef5353;
--el-color-primary: #5b95f2;
--el-color-primary-light-3: #3f6fb8;
--el-color-primary-light-5: #2f548b;
--el-color-primary-light-7: #203a5f;
--el-color-primary-light-8: #1a2f4c;
--el-color-primary-light-9: #142338;
--el-color-primary-dark-2: #7eabf5;
--el-bg-color: #171b21;
--el-bg-color-overlay: #1c2128;
--el-fill-color-blank: #171b21;
--el-border-color: #2f363f;
--el-border-color-light: #2a3038;
--el-border-color-lighter: #242a31;
}
* { box-sizing: border-box; }
html, body { background: var(--plane); }
body { margin: 0; font-family: var(--ui); color: var(--ink); font-size: 14px; line-height: 1.5;
-webkit-font-smoothing: antialiased; }
a { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* 面板:页面上的一级容器 */
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-panel); padding: 16px; }
.muted { color: var(--muted); font-size: 13px; }
.readout { font-family: var(--readout); font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.bad { color: var(--st-bad); }
.warn { color: var(--st-warn); }
/* 面板标题:粗一点的正文字,不加眉标、不全大写 */
.ttl { font-weight: 600; font-size: 15px; margin: 0 0 10px; color: var(--ink); }
/* 状态灯 */
.led { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex-shrink: 0;
background: var(--st-empty); box-shadow: 0 0 0 2px var(--panel); }
.led.ok { background: var(--led-ok); }
.led.busy { background: var(--st-busy); }
.led.warn { background: var(--led-warn); }
.led.bad { background: var(--led-bad); }
.led.off { background: var(--st-off); }
.led.lost { background: var(--st-lost); }
@media (prefers-reduced-motion: no-preference) {
.led.busy { animation: led-blink 1s steps(2, jump-none) infinite; }
}
@keyframes led-blink { 50% { opacity: .35; } }
/* 表格:去掉 Element Plus 的斑马感,行线用细线 */
.el-table { --el-table-border-color: var(--line-soft); --el-table-header-bg-color: transparent;
--el-table-tr-bg-color: transparent; --el-table-bg-color: transparent; --el-table-row-hover-bg-color: var(--bay);
--el-table-text-color: var(--ink); --el-table-header-text-color: var(--muted); }
.el-table th.el-table__cell { font-weight: 500; }
code { font-size: 12px; background: var(--bay); border: 1px solid var(--line-soft); padding: 0 4px; border-radius: 4px;
word-break: break-all; }