/** * 继电器开发板按钮点击次数报告 —— 统计每块板、每个通道(=设备按键)的累计点击, * 对照继电器约 20 万次寿命,显示占比/剩余/告警。多块板按串口序列号自动分别统计。 * npx ts-node scripts/relay-press-report.ts * 数据来源:test-plan/relay-press-counts.json(由 SerialController 每次通道吸合时累加)。 */ import * as fs from 'fs'; import * as path from 'path'; import { RELAY_MAP } from '../config/relay.config'; const FILE = path.resolve(__dirname, '../test-plan/relay-press-counts.json'); const LIFE = 200000; // 反查:通道号 → "设备.按键"(取 android 通道;两端不同时也显示 ios) const chLabel: Record = {}; for (const [dev, cfg] of Object.entries(RELAY_MAP)) { for (const [btn, spec] of Object.entries(cfg.buttons)) { const chs = typeof spec === 'number' ? [spec] : [spec.android, spec.ios].filter((x): x is number => x != null); for (const ch of chs) chLabel[ch] = `${dev}.${btn}`; } } const data: Record> = fs.existsSync(FILE) ? JSON.parse(fs.readFileSync(FILE, 'utf-8')) : {}; if (!Object.keys(data).length) { console.log('(暂无点击计数;跑过添加/继电器操作后才会有。文件:' + FILE + ')'); process.exit(0); } for (const [board, chs] of Object.entries(data)) { console.log(`\n=== 开发板 ${board} ===`); console.log('通道'.padEnd(6) + '设备.按键'.padEnd(22) + '点击次数'.padEnd(12) + '寿命占比'.padEnd(10) + '剩余'); const entries = Object.entries(chs).map(([ch, c]) => [Number(ch), c] as [number, number]).sort((a, b) => b[1] - a[1]); let total = 0; for (const [ch, cnt] of entries) { total += cnt; const pct = (cnt / LIFE * 100).toFixed(2) + '%'; const warn = cnt >= LIFE * 0.9 ? ' ⚠️已超90%寿命' : cnt >= LIFE * 0.8 ? ' ⚠接近寿命' : ''; console.log( `ch${ch}`.padEnd(6) + (chLabel[ch] || '-').padEnd(22) + String(cnt).padEnd(12) + pct.padEnd(10) + String(LIFE - cnt) + warn ); } console.log(`板内累计点击: ${total}`); }