- 总览:每块板一块面板、五个刀片槽(状态灯 + 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]>
56 行
2.7 KiB
Vue
56 行
2.7 KiB
Vue
<template>
|
|
<div class="shell">
|
|
<header class="top">
|
|
<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>
|
|
<router-link to="/audit">操作记录</router-link>
|
|
<router-link to="/recovery">自动恢复</router-link>
|
|
<router-link to="/firmware">固件</router-link>
|
|
</nav>
|
|
<div class="conn" :title="connTitle">
|
|
<span :class="['led', connLevel]" />
|
|
<span class="ct">{{ connText }}</span>
|
|
<span class="user">{{ state.user }}</span>
|
|
</div>
|
|
</header>
|
|
<main><router-view /></main>
|
|
</div>
|
|
</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>
|
|
.shell { min-height: 100vh; }
|
|
.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: 8px; padding: 0 10px; height: 50px; }
|
|
.top .brand { font-size: 0; gap: 0; }
|
|
.conn .ct, .conn .user { display: none; }
|
|
main { padding: 12px 10px; }
|
|
}
|
|
</style>
|