Files

386 lines
15 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { state as appState } from "/assets/js/state.js";
import { tr } from "/assets/js/i18n.js";
import { esc } from "/assets/js/shared.js";
export const sectionMeta = {
plugins: ["硬件插件", "独立安装,按实际能力提供风扇、屏幕或灯光控制"],
hardware: ["硬件插件", "可选 Yahboom 散热板;未安装时保持关闭"],
device: ["设备标识", "自定义本机显示名称和稳定标识"],
hosts: ["机器列表", "登记需要聚合监控的其他节点"],
led: ["灯光设置", "正常灯效与告警颜色"],
alerts: ["告警阈值", "处理器、内存、温度、磁盘和 Wi-Fi"],
fan: ["风扇温控", "温度档位与降档回差"],
timing: ["刷新周期", "传感器、屏幕、网络和健康检查"],
display: ["屏幕布局", "OLED 四行文字位置"],
dark_mode: ["板载指示灯", "树莓派电源灯与活动灯"],
services: ["服务监控", "监控 systemd 服务"],
processes: ["进程监控", "监控普通进程关键字"],
api: ["API 设置", "API 开关、监听地址、端口和日志数量"],
bulk_sync: ["批量同步", "从当前配置机器复制所选配置项到目标机器"],
};
export const labels = {
"api.enabled": "启用远程管理 API",
"hardware.cooling_hat_enabled": "启用散热板(OLED、风扇、RGB)",
"led.alert_mode": "告警灯效模式",
"led.custom_min_hold_ms": "自定义闪烁最小保持时间",
"led.normal_mode": "正常状态灯效",
"led.normal_r": "红色通道",
"led.normal_g": "绿色通道",
"led.normal_b": "蓝色通道",
"led.normal_flash_on_ms": "亮灯时间",
"led.normal_flash_off_ms": "灭灯时间",
"led.normal_effect_speed": "内置效果速度",
"led.normal_effect_color": "内置效果颜色",
"led.warning_flash_on_ms": "普通告警亮灯",
"led.warning_flash_off_ms": "普通告警灭灯",
"led.critical_flash_on_ms": "严重告警亮灯",
"led.critical_flash_off_ms": "严重告警灭灯",
"led.emergency_flash_on_ms": "紧急告警亮灯",
"led.emergency_flash_off_ms": "紧急告警灭灯",
"led.write_delay_ms": "RGB 寄存器写入间隔",
"alerts.cpu_high": "处理器高负载阈值",
"alerts.cpu_recover": "处理器恢复阈值",
"alerts.cpu_high_seconds": "处理器持续时间",
"alerts.memory_high": "内存高占用阈值",
"alerts.memory_recover": "内存恢复阈值",
"alerts.memory_high_seconds": "内存持续时间",
"alerts.temp_high": "高温告警阈值",
"alerts.temp_critical": "严重高温阈值",
"alerts.disk_high": "磁盘高占用阈值",
"alerts.disk_critical": "磁盘严重阈值",
"alerts.wifi_weak": "Wi-Fi 弱信号阈值",
"alerts.wifi_recover": "Wi-Fi 恢复阈值",
"alerts.wifi_weak_seconds": "弱信号持续时间",
"alerts.ethernet_min_speed_mbps": "有线最低协商速率",
"alerts.ethernet_speed_seconds": "有线降速持续时间",
"fan.start": "风扇启动温度",
"fan.level2": "二档起始温度",
"fan.level3": "三档起始温度",
"fan.level4": "四档起始温度",
"fan.max": "全速起始温度",
"fan.hysteresis": "降档温度回差",
"timing.sensor_interval": "传感器采样周期",
"timing.oled_refresh_interval": "OLED 刷新周期",
"timing.page_interval": "OLED 页面轮播周期",
"timing.network_interval": "网络检查周期",
"timing.service_interval": "服务检查周期",
"timing.health_interval": "健康检查周期",
"display.row1_y": "第一行纵坐标",
"display.row2_y": "第二行纵坐标",
"display.row3_y": "第三行纵坐标",
"display.row4_y": "第四行纵坐标",
"dark_mode.pi_pwr_led": "树莓派电源灯",
"dark_mode.pi_act_led": "树莓派活动灯",
"api.bind": "监听地址",
"api.port": "监听端口",
"api.log_limit": "默认日志条数",
"device.identifier": "机器标识",
"device.name": "显示名称",
};
["cpu", "power", "memory", "storage", "network", "service"].forEach((g) =>
["r", "g", "b"].forEach(
(c) =>
(labels[`led.${g}_${c}`] = `${{ r: "红", g: "绿", b: "蓝" }[c]}色通道`),
),
);
export const hints = {
"hardware.cooling_hat_enabled":
"默认关闭;启用前运行安装器 --enable-cooling-hat 安装依赖。",
"led.alert_mode": "推荐内置呼吸;自定义闪烁仍可能异色或延迟。",
"led.custom_min_hold_ms": "范围 1500–60000 毫秒。实际亮灭时间不会低于此值。",
"led.normal_mode": "仅在没有当前告警时生效;告警会立即抢占。",
"led.normal_r": "范围 0–255。",
"led.normal_g": "范围 0–255。",
"led.normal_b": "范围 0–255。",
"led.normal_flash_on_ms": "范围 50–60000 毫秒。",
"led.normal_flash_off_ms": "范围 50–60000 毫秒。",
"led.normal_effect_speed": "MCU 内置速度档位。",
"led.normal_effect_color": "仅流水灯和呼吸灯使用。",
"led.write_delay_ms": "MCU 内置灯效参数写入间隔,通常保持 10 毫秒。",
"alerts.wifi_weak": "单位 dBm,数值越接近 0 信号越强。",
"alerts.wifi_recover": "单位 dBm,应高于弱信号阈值。",
"alerts.ethernet_min_speed_mbps":
"低于此协商速率并持续设定时间后告警;设为 0 关闭。",
"alerts.ethernet_speed_seconds": "过滤网线插拔或协商过程中的瞬时降速。",
"fan.hysteresis": "避免临界温度附近频繁切换档位。",
"api.bind": "0.0.0.0 允许局域网访问;127.0.0.1 仅本机。",
"api.port": "范围 1–65535;保存后 API 自动重启。",
"dark_mode.pi_pwr_led": "选择“关闭”时由程序熄灭板载灯。",
"dark_mode.pi_act_led": "选择“关闭”时由程序熄灭板载灯。",
};
["normal", "cpu", "power", "memory", "storage", "network", "service"].forEach(
(g) =>
["r", "g", "b"].forEach((c) => (hints[`led.${g}_${c}`] = "范围 0–255。")),
);
export const options = {
"api.enabled": [
["false", "关闭"],
["true", "开启"],
],
"hardware.cooling_hat_enabled": [
["false", "关闭"],
["true", "启用"],
],
"led.alert_mode": [
["breathe", "内置呼吸(推荐)"],
["flash", "自定义颜色闪烁(实验性)"],
],
"led.normal_mode": [
["off", "全灭"],
["solid", "自定义颜色常亮"],
["flash", "自定义颜色闪烁"],
["flow", "流水灯"],
["breathe", "呼吸灯"],
["marquee", "跑马灯"],
["rainbow", "彩虹灯"],
["colorful", "炫彩灯"],
],
"led.normal_effect_speed": [
["1", "慢速"],
["2", "中速"],
["3", "快速"],
],
"led.normal_effect_color": [
["red", "红色"],
["green", "绿色"],
["blue", "蓝色"],
["yellow", "黄色"],
["purple", "紫色"],
["cyan", "青色"],
["white", "白色"],
],
"dark_mode.pi_pwr_led": [
["off", "关闭"],
["on", "不干预"],
],
"dark_mode.pi_act_led": [
["off", "关闭"],
["on", "不干预"],
],
};
export const numberRules = {
"led.custom_min_hold_ms": [1500, 60000, 100],
"led.normal_r": [0, 255, 1],
"led.normal_g": [0, 255, 1],
"led.normal_b": [0, 255, 1],
"led.normal_flash_on_ms": [50, 60000, 10],
"led.normal_flash_off_ms": [50, 60000, 10],
"led.warning_flash_on_ms": [50, 60000, 10],
"led.warning_flash_off_ms": [50, 60000, 10],
"led.critical_flash_on_ms": [50, 60000, 10],
"led.critical_flash_off_ms": [50, 60000, 10],
"led.emergency_flash_on_ms": [50, 60000, 10],
"led.emergency_flash_off_ms": [50, 60000, 10],
"led.write_delay_ms": [1, 1000, 1],
"alerts.cpu_high": [0, 100, 1],
"alerts.cpu_recover": [0, 100, 1],
"alerts.cpu_high_seconds": [1, 86400, 1],
"alerts.memory_high": [0, 100, 1],
"alerts.memory_recover": [0, 100, 1],
"alerts.memory_high_seconds": [1, 86400, 1],
"alerts.temp_high": [0, 120, 0.1],
"alerts.temp_critical": [0, 120, 0.1],
"alerts.disk_high": [0, 100, 1],
"alerts.disk_critical": [0, 100, 1],
"alerts.wifi_weak": [-120, 0, 1],
"alerts.wifi_recover": [-120, 0, 1],
"alerts.wifi_weak_seconds": [1, 86400, 1],
"alerts.ethernet_min_speed_mbps": [0, 100000, 1],
"alerts.ethernet_speed_seconds": [1, 86400, 1],
"fan.start": [0, 100, 0.1],
"fan.level2": [0, 100, 0.1],
"fan.level3": [0, 100, 0.1],
"fan.level4": [0, 100, 0.1],
"fan.max": [0, 100, 0.1],
"fan.hysteresis": [0, 20, 0.1],
"timing.sensor_interval": [0.2, 3600, 0.1],
"timing.oled_refresh_interval": [0.2, 3600, 0.1],
"timing.page_interval": [1, 3600, 0.1],
"timing.network_interval": [1, 3600, 0.1],
"timing.service_interval": [1, 3600, 0.1],
"timing.health_interval": [0.2, 3600, 0.1],
"display.row1_y": [0, 31, 1],
"display.row2_y": [0, 31, 1],
"display.row3_y": [0, 31, 1],
"display.row4_y": [0, 31, 1],
"api.port": [1, 65535, 1],
"api.log_limit": [1, 1000, 1],
};
["cpu", "power", "memory", "storage", "network", "service"].forEach((g) =>
["r", "g", "b"].forEach((c) => (numberRules[`led.${g}_${c}`] = [0, 255, 1])),
);
export const units = {
"led.custom_min_hold_ms": "毫秒",
"led.normal_flash_on_ms": "毫秒",
"led.normal_flash_off_ms": "毫秒",
"led.warning_flash_on_ms": "毫秒",
"led.warning_flash_off_ms": "毫秒",
"led.critical_flash_on_ms": "毫秒",
"led.critical_flash_off_ms": "毫秒",
"led.emergency_flash_on_ms": "毫秒",
"led.emergency_flash_off_ms": "毫秒",
"led.write_delay_ms": "毫秒",
"alerts.cpu_high": "%",
"alerts.cpu_recover": "%",
"alerts.cpu_high_seconds": "秒",
"alerts.memory_high": "%",
"alerts.memory_recover": "%",
"alerts.memory_high_seconds": "秒",
"alerts.temp_high": "°C",
"alerts.temp_critical": "°C",
"alerts.disk_high": "%",
"alerts.disk_critical": "%",
"alerts.wifi_weak": "dBm",
"alerts.wifi_recover": "dBm",
"alerts.wifi_weak_seconds": "秒",
"alerts.ethernet_min_speed_mbps": "Mbps",
"alerts.ethernet_speed_seconds": "秒",
"fan.start": "°C",
"fan.level2": "°C",
"fan.level3": "°C",
"fan.level4": "°C",
"fan.max": "°C",
"fan.hysteresis": "°C",
"timing.sensor_interval": "秒",
"timing.oled_refresh_interval": "秒",
"timing.page_interval": "秒",
"timing.network_interval": "秒",
"timing.service_interval": "秒",
"timing.health_interval": "秒",
"display.row1_y": "像素",
"display.row2_y": "像素",
"display.row3_y": "像素",
"display.row4_y": "像素",
"api.port": "端口",
"api.log_limit": "条",
};
export const sectionOrder = [
"device",
"plugins",
"alerts",
"timing",
"dark_mode",
"services",
"processes",
"api",
],
bulkSections = sectionOrder.filter(
(s) => !["device", "hosts", "plugins"].includes(s),
),
alertColorGroups = [
["cpu", "处理器、温度与散热"],
["power", "供电与欠压"],
["memory", "内存"],
["storage", "存储"],
["network", "网络与 Wi-Fi"],
["service", "服务与进程"],
];
export const ownerNames = {
NORMAL_HOME: "正常主页",
ROOT_READONLY: "根文件系统只读",
TEMP_CRITICAL: "处理器温度严重",
POWER_UNDERVOLT: "供电欠压",
THROTTLED: "处理器降频",
FREQ_CAPPED: "频率受限",
NETWORK_DOWN: "网络断开",
INTERNET_DOWN: "互联网断开",
SERVICE_DOWN: "服务停止",
PROCESS_DOWN: "进程停止",
DISK_CRITICAL: "磁盘严重不足",
TEMP_HIGH: "处理器温度偏高",
CPU_HIGH: "处理器负载过高",
MEMORY_HIGH: "内存占用过高",
DISK_HIGH: "磁盘空间不足",
WIFI_WEAK: "Wi-Fi 信号弱",
ETHERNET_SPEED_LOW: "有线连接速率降低",
},
rgbNames = {
DISABLED: "未启用",
OFF: "全灭",
NORMAL_SOLID: "正常 · 自定义常亮",
NORMAL_FLASH: "正常 · 自定义闪烁",
NORMAL_FLOW: "正常 · 流水灯",
NORMAL_BREATHE: "正常 · 呼吸灯",
NORMAL_MARQUEE: "正常 · 跑马灯",
NORMAL_RAINBOW: "正常 · 彩虹灯",
NORMAL_COLORFUL: "正常 · 炫彩灯",
},
eventNames = {
HARDWARE_ENABLED: "硬件插件已启用",
HARDWARE_DISABLED: "硬件插件已关闭",
HARDWARE_UNAVAILABLE: "硬件插件不可用",
FAN_LEVEL: "风扇档位变化",
START: "程序启动",
STOP: "程序停止",
ALERT_ACTIVE: "告警出现",
ALERT_RECOVERED: "告警恢复",
DISPLAY_OWNER: "显示对象切换",
INTERNET_DOWN: "互联网断开",
INTERNET_RECOVERED: "互联网恢复",
NET_SWITCH: "网络接口切换",
ETHERNET_SPEED_LOW: "有线连接速率降低",
ETHERNET_SPEED_RECOVERED: "有线连接速率恢复",
NETWORK_DOWN: "网络断开",
NETWORK_RECOVERED: "网络恢复",
POWER_LOW: "供电欠压",
POWER_RECOVERED: "供电恢复",
POWER_HISTORY: "历史电源状态",
HISTORY_FLAG: "历史电源状态",
ROOT_READONLY: "根文件系统只读",
RGB_ERROR: "RGB 控制错误",
RGB_MODE: "RGB 模式切换",
RGB_RECOVERED: "RGB 控制恢复",
SYSTEM: "系统事件",
WATCH_DOWN: "监控对象停止",
WATCH_RECOVERED: "监控对象恢复",
};
export function ownerName(id) {
const [type, suffix] = String(id || "").split("|", 2),
name = ownerNames[type] || type;
return tr(name) + (suffix ? ` · ${suffix}` : "");
}
export function rgbName(mode) {
if (rgbNames[mode]) return tr(rgbNames[mode]);
const p = String(mode || "").split("_"),
groups = {
CPU: "处理器",
POWER: "供电",
MEMORY: "内存",
STORAGE: "存储",
NETWORK: "网络",
SERVICE: "服务",
},
levels = {
WARNING: "普通告警",
CRITICAL: "严重告警",
EMERGENCY: "紧急告警",
};
return `${tr(groups[p[0]] || p[0])} · ${tr(levels[p[1]] || p[1])}${p[2] === "BREATHE" ? (appState.LANG === "zh" ? "呼吸" : " breathing") : appState.LANG === "zh" ? "闪烁" : " flash"}`;
}
export function eventName(id) {
return tr(
eventNames[id] ||
(appState.LANG === "zh"
? `未知事件(${id})`
: String(id).toLowerCase().replaceAll("_", " ")),
);
}
export function field(section, key, value, extra = "") {
const id = `${section}.${key}`,
opts = options[id],
rule = numberRules[id],
label = tr(labels[id] || key),
help = tr(hints[id] || ""),
unit = tr(units[id] || "");
let control;
if (opts)
control = `<select data-section="${esc(section)}" data-key="${esc(key)}">${opts.map(([v, l]) => `<option value="${v}" ${String(value) === v ? "selected" : ""}>${tr(l)}</option>`).join("")}</select>`;
else {
const input = `<input ${rule ? 'type="number"' : ""} ${rule ? `min="${rule[0]}" max="${rule[1]}" step="${rule[2]}"` : ""} data-section="${esc(section)}" data-key="${esc(key)}" value="${esc(value)}">`;
control = unit
? `<div class="input-unit">${input}<span class="unit">${unit}</span></div>`
: input;
}
return `<div class="field ${extra}"><label>${esc(label)}${control}</label>${help ? `<div class="hint">${esc(help)}</div>` : ""}</div>`;
}