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]>
这个提交包含在:
+29
-27
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="shell">
|
||||
<header class="top">
|
||||
<router-link to="/" class="brand">PhoneRail 机架</router-link>
|
||||
<router-link to="/" class="brand"><span class="mark" aria-hidden="true" />PhoneRail 机架</router-link>
|
||||
<nav>
|
||||
<router-link to="/">总览</router-link>
|
||||
<router-link to="/events">事件</router-link>
|
||||
@@ -9,10 +9,9 @@
|
||||
<router-link to="/recovery">自动恢复</router-link>
|
||||
<router-link to="/firmware">固件</router-link>
|
||||
</nav>
|
||||
<div class="conn">
|
||||
<span :class="['dot', state.ws ? 'up' : 'down']" :title="state.ws ? '已连上服务器' : '与服务器断开,重连中'" />
|
||||
<span v-if="!state.ws" class="warn">断开</span>
|
||||
<span v-else-if="!state.mqtt" class="warn" title="后端连不上 MQTT broker:所有板子都会显示通信中断">broker 断开</span>
|
||||
<div class="conn" :title="connTitle">
|
||||
<span :class="['led', connLevel]" />
|
||||
<span class="ct">{{ connText }}</span>
|
||||
<span class="user">{{ state.user }}</span>
|
||||
</div>
|
||||
</header>
|
||||
@@ -21,33 +20,36 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { state } from './store'
|
||||
|
||||
const connLevel = computed(() => (!state.ws ? 'bad' : !state.mqtt ? 'warn' : 'ok'))
|
||||
const connText = computed(() => (!state.ws ? '与服务器断开' : !state.mqtt ? 'broker 断开' : '已连接'))
|
||||
const connTitle = computed(() => (!state.ws ? '浏览器与后端断开,正在重连'
|
||||
: !state.mqtt ? '后端连不上 MQTT broker:所有板子都会显示通信中断' : '实时数据正常'))
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root { --bg: #f1f5f9; --card: #fff; --line: #e2e8f0; --muted: #64748b; }
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; background: var(--bg); font-family: -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif; color: #0f172a; }
|
||||
.shell { min-height: 100vh; }
|
||||
.top { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: 16px;
|
||||
padding: 0 16px; height: 52px; background: #0f172a; color: #fff; }
|
||||
.top a { color: #cbd5e1; text-decoration: none; }
|
||||
.top .brand { color: #fff; font-weight: 600; white-space: nowrap; }
|
||||
.top nav { display: flex; gap: 14px; overflow-x: auto; flex: 1; min-width: 0; }
|
||||
.top nav a { white-space: nowrap; padding: 4px 0; }
|
||||
.top nav a.router-link-exact-active { color: #fff; border-bottom: 2px solid #38bdf8; }
|
||||
.conn { display: flex; align-items: center; gap: 8px; font-size: 13px; white-space: nowrap; }
|
||||
.dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
|
||||
.dot.up { background: #22c55e; } .dot.down { background: #ef4444; }
|
||||
.conn .warn { color: #fca5a5; }
|
||||
.conn .user { color: #94a3b8; }
|
||||
main { padding: 16px; max-width: 1400px; margin: 0 auto; }
|
||||
.card { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 14px; }
|
||||
.muted { color: var(--muted); font-size: 13px; }
|
||||
.top { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: 20px;
|
||||
padding: 0 20px; height: 54px; background: var(--bar); border-bottom: 1px solid var(--line); }
|
||||
.top a { color: var(--ink-2); text-decoration: none; }
|
||||
.top .brand { color: var(--ink); font-weight: 700; white-space: nowrap; display: flex; align-items: center; gap: 8px;
|
||||
letter-spacing: .01em; }
|
||||
/* 标志:一块板上五个槽 */
|
||||
.top .mark { width: 22px; height: 14px; border-radius: 3px; border: 2px solid var(--ink);
|
||||
background: repeating-linear-gradient(90deg, transparent 0 2px, var(--ink) 2px 3px, transparent 3px 3.6px); }
|
||||
.top nav { display: flex; gap: 4px; overflow-x: auto; flex: 1; min-width: 0; scrollbar-width: none; }
|
||||
.top nav a { white-space: nowrap; padding: 6px 10px; border-radius: 6px; }
|
||||
.top nav a:hover { color: var(--ink); background: var(--bay); }
|
||||
.top nav a.router-link-exact-active { color: var(--accent); background: var(--accent-soft); font-weight: 600; }
|
||||
.conn { display: flex; align-items: center; gap: 8px; font-size: 13px; white-space: nowrap; color: var(--ink-2); }
|
||||
.conn .user { color: var(--muted); padding-left: 8px; border-left: 1px solid var(--line); }
|
||||
main { padding: 20px; max-width: 1440px; margin: 0 auto; }
|
||||
@media (max-width: 640px) {
|
||||
.top { gap: 10px; padding: 0 10px; }
|
||||
.top .brand { display: none; }
|
||||
.conn .user { display: none; }
|
||||
main { padding: 10px; }
|
||||
.top { gap: 8px; padding: 0 10px; height: 50px; }
|
||||
.top .brand { font-size: 0; gap: 0; }
|
||||
.conn .ct, .conn .user { display: none; }
|
||||
main { padding: 12px 10px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
在新工单中引用
屏蔽一个用户