采集从仪表盘组件挪进模块级单例(web/telemetry.ts),流量曲线和每路 吞吐的历史跨页面留存——跟着组件走的话切一次页面就清零一次。每路吞吐 从 /connections 快照按连接逐条求差再按 inboundName 聚合:先求和再求差 会在连接关闭时算出负数。 图表换 ECharts(按需注册):手写 SVG 折线做不出平滑曲线和时间轴, 颜色在运行时从 CSS 变量取,跟随主题切换重取。 路由列表每行带走势、速率和可选的公网 IP 检测,点击跳路由页并选中 那一路(外壳传 focus 给 RouterPage 消费)。
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
/**
|
|
* 仪表盘页的数据整理。
|
|
*
|
|
* 「拿到内核数据之后怎么摆」的纯逻辑,放在这里而不是 DashboardPage.vue 的
|
|
* computed 里,才能被 bun test 直接测到。流量窗口和每路吞吐的聚合在
|
|
* shared/telemetry.ts——那些是采集层的事,跨页面共用。
|
|
*/
|
|
|
|
/** 内核运行模式在界面上怎么念。不在表里的原样显示,不猜它的意思。 */
|
|
export function modeLabel(mode: unknown): string {
|
|
switch (mode) {
|
|
case 'rule':
|
|
return '规则'
|
|
case 'global':
|
|
return '全局'
|
|
case 'direct':
|
|
return '直连'
|
|
default:
|
|
return typeof mode === 'string' && mode ? mode : '—'
|
|
}
|
|
}
|
|
|
|
/** 一个监听中的代理端口。name 用配置键原词,和路由页默认入站的命名一致。 */
|
|
export interface KernelPort {
|
|
name: string
|
|
port: number
|
|
}
|
|
|
|
const PORT_KEYS = ['port', 'socks-port', 'mixed-port', 'redir-port', 'tproxy-port'] as const
|
|
|
|
/** 从内核 /configs 的运行时设置里挑出正在监听的代理端口。0 和缺省都表示没启用。 */
|
|
export function kernelPorts(configs: Record<string, unknown>): KernelPort[] {
|
|
const result: KernelPort[] = []
|
|
for (const key of PORT_KEYS) {
|
|
const raw = configs[key]
|
|
const port = typeof raw === 'number' ? raw : Number(raw)
|
|
if (Number.isFinite(port) && port > 0) result.push({ name: key, port })
|
|
}
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* 入站声明的端口在探测公网 IP 时用哪个数。
|
|
* 新式入站的端口可以写 "200,302" 或 "401-429",探测取第一个数字;解析不出返回 null。
|
|
*/
|
|
export function firstPort(port: string): number | null {
|
|
const match = /\d+/.exec(port)
|
|
if (!match) return null
|
|
const value = Number(match[0])
|
|
return value >= 1 && value <= 65535 ? value : null
|
|
}
|