机架管理前后端(rack/):FastAPI + SQLite + Vue3,经统一门户上线
- 后端 prrack:MQTT(phonerail-backend @ 127.0.0.1:1884)↔ 遥测入库 / 事件增量同步 / WebSocket 推送; 命令白名单 + 重传同 seq;审计记门户 X-Auth-User(只绑 127.0.0.1,main.py 拒绝非回环)。 - 自动恢复:只看电流(平线 / 过低,服务器够不到手机 adb),先长按电源再断电重启, 每小时限次后停手;默认逐台关闭。adb 探活接口 recovery.Prober 预留。 - 前端:总览 / 板子页(五路操作、电流电压曲线)/ 事件 / 操作记录 / 自动恢复;手机宽度可用。 - 部署 deploy/deploy.sh:服务器 Python 3.8 上先跑测试再替换;systemd phonerail-rack,每日备份。 - 门户应用 id 16、key rack(phonerail 已被需求文档站占用),授权 admin + staff。 测试 26 例(本机 3.14 / 服务器 3.8 均过)。线上板 b81f3fc9c8bc 在线,WS 经门户 101 + 1 条/s 遥测。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,54 @@
|
||||
// 显示用的小工具:单位换算、每一路的健康状态。
|
||||
|
||||
export const mA = ua => (ua == null ? '—' : (ua / 1000).toFixed(ua >= 100000 || ua <= -100000 ? 0 : 1))
|
||||
export const V = mv => (mv == null ? '—' : (mv / 1000).toFixed(3))
|
||||
export const C = mc => (mc == null ? '—' : (mc / 1000).toFixed(1))
|
||||
|
||||
export function ago(ts) {
|
||||
if (!ts) return '从未'
|
||||
const s = Math.round((Date.now() - ts) / 1000)
|
||||
if (s < 60) return `${s} 秒前`
|
||||
if (s < 3600) return `${Math.round(s / 60)} 分钟前`
|
||||
if (s < 86400) return `${Math.round(s / 3600)} 小时前`
|
||||
return `${Math.round(s / 86400)} 天前`
|
||||
}
|
||||
|
||||
export function fmtTime(ts) {
|
||||
if (!ts) return ''
|
||||
const d = new Date(ts)
|
||||
const p = n => String(n).padStart(2, '0')
|
||||
return `${d.getMonth() + 1}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
|
||||
}
|
||||
|
||||
// 执行器状态(firmware t_actuator_state_str)
|
||||
export const ACT_ZH = {
|
||||
idle: '空闲', 'hr-off': '断电中', 'hr-ramp': '上电中', 'hr-pg': '等 PG',
|
||||
'key-hold': '按键中', 'edl-short': '进 EDL', 'edl-enum': '等枚举', cleanup: '收尾',
|
||||
}
|
||||
|
||||
// 一路的健康状态 → { level, text }。level 决定颜色:
|
||||
// ok 绿 / busy 蓝 / warn 橙 / bad 红 / off 深灰 / empty 浅灰 / lost 灰(通信中断)
|
||||
export function railHealth(board, r) {
|
||||
if (!board || board.stale || !board.online) return { level: 'lost', text: '通信中断' }
|
||||
if (!r) return { level: 'lost', text: '无数据' }
|
||||
if (!r.pr) return { level: 'empty', text: '空槽' }
|
||||
if (r.st && r.st !== 'idle') return { level: 'busy', text: ACT_ZH[r.st] || r.st }
|
||||
if (!r.en) return { level: 'off', text: '已断电' }
|
||||
if (r.flt) return { level: 'bad', text: 'eFuse 故障' }
|
||||
if (r.pg === false) return { level: 'bad', text: 'PG 丢失' }
|
||||
if (r.mv == null || r.ua == null) return { level: 'warn', text: '读不到' }
|
||||
return { level: 'ok', text: '运行' }
|
||||
}
|
||||
|
||||
export const LEVEL_COLOR = {
|
||||
ok: '#16a34a', busy: '#2563eb', warn: '#d97706', bad: '#dc2626',
|
||||
off: '#475569', empty: '#cbd5e1', lost: '#94a3b8',
|
||||
}
|
||||
|
||||
export const RECOVERY_ZH = {
|
||||
idle: '正常', soft: '已长按电源', hard: '已断电重启', gave_up: '已放弃(需人工)',
|
||||
}
|
||||
export const REASON_ZH = {
|
||||
flat: '电流平直(疑似卡死)', low: '电流过低(疑似关机)', recovered: '已恢复',
|
||||
rate_limit: '一小时内动作过多', manual_reset: '人工复位',
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户