hardware-dashboard/static/index.html

82 lines
23 KiB
HTML
Raw 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.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="color-scheme" content="dark"><title>设备监控 · 192.168.1.37</title>
<link rel="icon" href="/favicon.svg"><link rel="stylesheet" href="/style.css">
<script src="/app.js" defer></script><script src="/tasks.js" defer></script>
</head>
<body>
<svg class="sprite" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
<symbol id="pulse" viewBox="0 0 24 24"><path d="M2 13h5l3-8 5 15 3-9h4"/></symbol>
<symbol id="grid" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></symbol>
<symbol id="trend" viewBox="0 0 24 24"><path d="M3 3v18h18M6 15l5-5 4 3 6-8"/></symbol>
<symbol id="logs" viewBox="0 0 24 24"><path d="M7 3H4v18h16V3h-3M9 3h6v4H9zM8 11h8M8 15h8"/></symbol>
<symbol id="help" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M9 9a3 3 0 0 1 6 0c0 2-3 2-3 4M12 17h.01"/></symbol>
<symbol id="cpu" viewBox="0 0 24 24"><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 1v5m6-5v5M9 18v5m6-5v5M1 9h5m-5 6h5m12-6h5m-5 6h5M9 9h6v6H9z"/></symbol>
<symbol id="memory" viewBox="0 0 24 24"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 10v4m4-4v4m4-4v4m4-4v4M6 18v3m4-3v3m4-3v3m4-3v3"/></symbol>
<symbol id="gpu" viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="13" rx="2"/><circle cx="10" cy="11.5" r="3.5"/><path d="M16 9h2m-2 4h2M6 18v3m3-3v3m3-3v3m3-3v3M3 8H1"/></symbol>
<symbol id="disk" viewBox="0 0 24 24"><path d="m5 3-3 13v5h20v-5L19 3zM2 16h20M6 18.5h.01m4-.01h.01"/></symbol>
<symbol id="full" viewBox="0 0 24 24"><path d="M3 9V3h6m6 0h6v6M3 15v6h6m6 0h6v-6"/></symbol>
<symbol id="check" viewBox="0 0 24 24"><path d="m5 12 4 4L19 6"/></symbol>
<symbol id="alert" viewBox="0 0 24 24"><path d="M12 3 2 21h20zM12 9v5m0 3v.1"/></symbol>
<symbol id="clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 6v6l4 2"/></symbol>
<symbol id="download" viewBox="0 0 24 24"><path d="M12 3v12m-4-4 4 4 4-4M4 16v5h16v-5"/></symbol>
</svg>
<aside class="sidebar">
<a class="brand" href="#overview" data-section-link="overview"><span class="brand-mark"><svg><use href="#pulse"/></svg></span><span>设备监控<small>HARDWARE WATCH</small></span></a>
<div class="nav-caption">工作空间</div>
<nav aria-label="主导航">
<a href="#overview" class="active" data-section-link="overview" aria-current="location"><svg><use href="#grid"/></svg>设备总览</a>
<a href="#trends" data-section-link="trends"><svg><use href="#trend"/></svg>性能趋势</a>
<a href="#events" data-section-link="events"><svg><use href="#logs"/></svg>问题与维护<span id="nav-alert" class="nav-count" hidden></span></a>
<a href="#tasks" data-section-link="tasks"><svg><use href="#clock"/></svg>定时任务</a>
<a href="#guide" data-section-link="guide"><svg><use href="#help"/></svg>使用说明</a>
</nav>
<div class="sidebar-node"><span class="tiny-label">正在监控</span><strong><i class="dot"></i> NODE / 037</strong><span>192.168.1.37</span><div class="node-rule"></div><p>实时状态 · 性能历史<br>设备告警 · 维护建议</p></div>
<div class="sidebar-footer"><span class="dot"></span> 局域网设备监控</div>
</aside>
<main>
<header class="page-header" id="overview"><div><div class="eyebrow">基础设施 / 设备总览</div><h1>设备运行,一目了然<span class="title-dot">.</span></h1><p>192.168.1.37 <span class="separator">/</span> <span id="host-name">正在连接设备</span></p></div><div class="header-actions"><span class="live-badge" id="connection"><i class="dot"></i>连接中</span><button id="fullscreen" class="icon-button" aria-label="切换全屏"><svg><use href="#full"/></svg></button></div></header>
<div class="section-context"><div><span class="context-label">正在查看</span><strong id="current-section">设备总览</strong></div><div class="context-actions"><button id="back-to-top" class="context-button" hidden>↑ 回到顶部</button><button id="next-section" class="context-button">下一项:性能趋势 ↓</button></div><div class="reading-progress"><i id="reading-progress"></i></div></div>
<section class="health-banner loading" id="health-banner" aria-live="polite"><div class="health-icon"><svg id="health-icon"><use href="#pulse"/></svg></div><div class="health-text"><strong id="health-title">正在读取设备状态</strong><p id="health-description">首次连接可能需要几秒,请稍候。</p></div><div class="health-time"><span>最近更新</span><strong id="last-update">—</strong></div></section>
<section id="current-issues" class="current-issues" aria-label="当前需要处理的问题" hidden></section>
<section class="overview-grid" aria-label="设备关键指标">
<article class="metric-card"><div class="card-top"><span>CPU 使用率</span><svg><use href="#cpu"/></svg></div><div class="metric-value" id="cpu-value">—<small>%</small></div><div class="meter"><i id="cpu-bar"></i></div><div class="metric-bottom"><span id="cpu-threads">正在读取</span><strong id="cpu-temp">— °C</strong></div></article>
<article class="metric-card"><div class="card-top"><span>内存占用</span><svg><use href="#memory"/></svg></div><div class="metric-value" id="memory-value">—<small>%</small></div><div class="meter violet"><i id="memory-bar"></i></div><div class="metric-bottom"><span id="memory-used">— / — GiB</span><strong id="memory-free">— 可用</strong></div></article>
<article class="metric-card"><div class="card-top"><span>计算显卡</span><svg><use href="#gpu"/></svg></div><div class="metric-value" id="gpu-count">—<small>/ — 在线</small></div><div class="gpu-online-label" id="gpu-online-text"><i class="dot"></i>正在确认显卡状态</div><div class="metric-bottom"><span>按 UUID 识别显卡</span><strong id="gpu-type">NVIDIA</strong></div></article>
<article class="metric-card"><div class="card-top"><span>系统磁盘</span><svg><use href="#disk"/></svg></div><div class="metric-value word" id="disk-health">—</div><div class="disk-health-detail" id="disk-health-detail">正在读取健康状态</div><div class="metric-bottom"><span id="disk-space">— / — GiB</span><strong id="disk-temp">— °C</strong></div></article>
</section>
<section class="section-heading compact"><div><h2>显卡实时状态</h2><span>高使用率表示正在计算,不等于硬件故障。</span></div><span class="subtle-pill">每 10 秒采样</span></section>
<section class="gpu-grid" id="gpu-grid" aria-label="计算显卡实时状态"><article class="gpu-card skeleton">正在读取显卡…</article><article class="gpu-card skeleton">正在读取显卡…</article></section>
<section class="system-strip" aria-label="其他实时指标"><span><svg><use href="#clock"/></svg>连续运行 <strong id="uptime">—</strong></span><span>磁盘读取 <strong id="disk-read">— MB/s</strong></span><span>磁盘写入 <strong id="disk-write">— MB/s</strong></span><span>网络接收 <strong id="net-rx">— MB/s</strong></span><span>网络发送 <strong id="net-tx">— MB/s</strong></span></section>
<section id="trends" class="section-heading"><div><div class="eyebrow">PERFORMANCE</div><h2>性能趋势</h2><p id="history-caption">正在加载历史数据</p></div><div class="segmented" id="ranges" role="group" aria-label="曲线时间范围"><button data-range="1h">1 小时</button><button data-range="6h">6 小时</button><button data-range="24h" class="selected">24 小时</button><button data-range="7d">7 天</button><button data-range="30d">30 天</button></div></section>
<div class="history-note" id="history-note">历史曲线显示真实采样数据;没有采集到的时段留空。</div>
<section class="chart-grid" aria-label="历史性能曲线">
<article class="chart-card"><div class="chart-heading"><h3>CPU 与内存</h3><span>%</span></div><div class="chart-legend" id="legend-system"></div><div class="chart" id="chart-system" role="img" aria-label="CPU 和内存占用历史曲线"></div></article>
<article class="chart-card"><div class="chart-heading"><h3>显卡使用率</h3><span>%</span></div><div class="chart-legend" id="legend-gpu"></div><div class="chart" id="chart-gpu" role="img" aria-label="显卡使用率历史曲线"></div></article>
<article class="chart-card"><div class="chart-heading"><h3>硬件温度</h3><span>°C</span></div><div class="chart-legend" id="legend-temp"></div><div class="chart" id="chart-temp" role="img" aria-label="CPU 与显卡温度历史曲线"></div></article>
<article class="chart-card"><div class="chart-heading"><h3>显卡功耗</h3><span>W</span></div><div class="chart-legend" id="legend-power"></div><div class="chart" id="chart-power" role="img" aria-label="显卡功耗历史曲线"></div></article>
</section>
<section id="events" class="section-heading"><div><div class="eyebrow">EVENTS & MAINTENANCE</div><h2>问题与维护</h2><p>先看设备现在能不能用,再看什么时候出现、下一步怎么处理。</p></div><button class="text-button" id="export-events"><svg><use href="#download"/></svg>导出本页</button></section>
<div class="event-explainer"><strong>重复日志已合并,不代表设备坏了很多次。</strong><span>同一设备、同类问题在 5 分钟内继续报告,会归在同一段记录中。黄色表示需要观察或安排检查,不等于显卡已经损坏。</span></div>
<section class="event-panel"><form class="event-toolbar" id="event-filter"><label>展示方式<select id="event-view"><option value="issues">按问题合并(推荐)</option><option value="raw">逐条技术记录</option></select></label><label>问题类型<select id="category"><option value="">全部问题</option></select></label><label>级别<select id="severity"><option value="problem">需要关注与处理</option><option value="ERROR">需要处理</option><option value="WARN">需要关注</option><option value="INFO">开机等运行记录</option><option value="">所有记录</option></select></label><label>开始日期<input type="date" id="date-from"></label><label>结束日期<input type="date" id="date-to"></label><label class="search-label">搜索<input type="search" id="event-search" placeholder="例如:供电、连接重试、磁盘"></label><button class="primary-button" type="submit">查询日志</button></form><div class="event-caption"><span id="event-count">正在读取问题记录…</span><span>展开看中文说明;技术详情默认收起</span></div><div id="event-list" aria-live="polite"></div><div class="pagination"><span id="page-label">第 1 页</span><div><button id="previous-page" class="text-button" disabled>上一页</button><button id="next-page" class="text-button" disabled>下一页</button></div></div></section>
<section id="tasks" class="section-heading"><div><div class="eyebrow">SCHEDULED TASKS</div><h2>定时任务</h2><p>到点自动执行命令或脚本,关闭网页也会继续运行。时间均为北京时间。</p></div><button class="primary-button" id="task-create" disabled>+ 新增任务</button></section>
<section class="task-panel" aria-label="服务器定时任务管理">
<div class="task-authbar"><div><strong id="task-auth-title">正在连接任务管理服务</strong><p id="task-auth-description">监控页面可直接查看,管理任务需要登录。</p></div><div class="task-auth-actions"><button id="task-login-open" class="primary-button">登录管理</button><button id="task-change-password" class="text-button" hidden>修改密码</button><button id="task-logout" class="text-button" hidden>退出管理</button></div></div>
<div id="task-locked" class="task-empty"><svg><use href="#clock"/></svg><h3>把重复维护交给计划任务</h3><p>支持命令、Bash/Python 脚本和服务器已有脚本。<br>可用于定时检查、备份、证书续签或计划重启。</p><span>初始管理员登录信息见交付的登录说明文件,账号与 SSH 密码相互独立。</span></div>
<div id="task-manager" hidden><div class="task-toolbar"><div><strong id="task-count">任务列表</strong><span id="task-server-time"></span></div><div><button id="task-refresh" class="text-button">刷新</button><button id="task-all-runs" class="text-button">全部执行记录</button></div></div><div class="task-table-heading"><span>任务名称</span><span>执行周期 / 下次执行</span><span>状态 / 最近结果</span><span>操作</span></div><div id="task-list"></div><div class="task-footnote">执行身份为 root。新任务默认停用;启用后才会按计划执行。同一任务不会重叠运行,错过时间不补跑。</div></div>
</section>
<section class="guide" id="guide"><div><svg><use href="#help"/></svg><h2>第一次使用?先看状态,再看问题</h2></div><div class="guide-grid"><article><span class="guide-number">01</span><h3>顶部看现在是否正常</h3><p>绿色表示当前检查未发现异常。黄色表示需要关注,红色表示有故障需要处理。断开连接时会单独提示,不继续显示“正常”。</p></article><article><span class="guide-number">02</span><h3>曲线看何时开始变化</h3><p>选择时间范围,移到曲线上查看具体时刻。使用率高通常说明任务繁忙;温度、掉卡和通信错误才需要结合告警判断。</p></article><article><span class="guide-number">03</span><h3>维护操作先看执行内容</h3><p>问题记录有处理建议。定时任务可以真正执行服务器操作,保存前请检查脚本、周期和启用状态;重启类任务会中断正在进行的计算。</p></article></div></section>
<footer><span>设备监控 / NODE 037</span><span>性能数据保留 30 天 · 故障记录最长保留 90 天 · 北京时间 UTC+8</span></footer>
</main>
<div class="toast" role="status" id="toast" hidden></div>
<nav class="mobile-section-nav" aria-label="页面分区导航"><a href="#overview" data-section-link="overview" class="active"><svg><use href="#grid"/></svg>总览</a><a href="#trends" data-section-link="trends"><svg><use href="#trend"/></svg>趋势</a><a href="#events" data-section-link="events"><svg><use href="#logs"/></svg>问题</a><a href="#tasks" data-section-link="tasks"><svg><use href="#clock"/></svg>任务</a><a href="#guide" data-section-link="guide"><svg><use href="#help"/></svg>说明</a></nav>
<dialog id="task-login-dialog" class="task-dialog small-dialog" aria-labelledby="task-login-heading"><form id="task-login-form"><div class="dialog-heading"><div><h2 id="task-login-heading">登录任务管理</h2><p>只有管理员可以创建和执行服务器任务。</p></div><button type="button" class="dialog-close" data-close-dialog="task-login-dialog" aria-label="关闭登录窗口">×</button></div><div class="dialog-content task-form-grid"><label class="full-field">账号<input id="task-login-user" value="admin" autocomplete="username" required></label><label class="full-field">管理密码<input id="task-login-password" type="password" autocomplete="current-password" required></label><p class="form-error full-field" id="task-login-error" role="alert" hidden></p></div><div class="dialog-footer"><span>此处不是 SSH root 密码。</span><button class="primary-button" type="submit">登录</button></div></form></dialog>
<dialog id="task-editor-dialog" class="task-dialog" aria-labelledby="task-editor-heading"><form id="task-editor-form"><div class="dialog-heading"><div><h2 id="task-editor-heading">新增定时任务</h2><p>先填写执行内容,再设置周期。新任务默认停用,可先手动测试。</p></div><button type="button" class="dialog-close" data-close-dialog="task-editor-dialog" aria-label="关闭任务编辑">×</button></div><div class="dialog-content task-form-grid"><input id="task-id" type="hidden"><label>任务名称<input id="task-name" placeholder="例如:每天检查显卡" maxlength="80" required></label><label>快速模板<select id="task-template"><option value="custom">自定义任务</option><option value="hardware">显卡状态检查</option><option value="reboot">服务器定时重启</option><option value="certificate">SSL 证书续签示例</option></select></label><div class="template-hint full-field" id="task-template-hint" hidden></div><label>执行方式<select id="task-mode"><option value="command">直接输入命令</option><option value="script">粘贴脚本内容</option><option value="file">服务器上的脚本文件</option></select></label><label id="task-language-field">脚本解释器<select id="task-interpreter"><option value="bash">Bash / Shell</option><option value="python3">Python 3</option><option value="auto">按文件自身方式执行</option></select></label><label class="full-field" id="task-body-field"><span class="field-label-row"><span id="task-body-label">执行命令</span><button type="button" id="task-import-file" class="inline-button">导入本地脚本</button></span><textarea id="task-body" rows="7" spellcheck="false" placeholder="例如:/usr/bin/nvidia-smi" required></textarea><input id="task-upload" type="file" accept=".sh,.py,.txt" hidden></label><label class="full-field" id="task-path-field" hidden>服务器脚本的绝对路径<input id="task-path" placeholder="例如:/root/renew-cert.sh"></label><label class="full-field" id="task-arguments-field" hidden>脚本参数(可选)<input id="task-arguments" placeholder="例如:--check,带空格的参数请加引号"></label><div class="task-form-divider full-field"><strong>什么时候执行</strong><span>北京时间 UTC+8</span></div><label>执行周期<select id="task-cycle"><option value="daily">每天</option><option value="weekly">每周</option><option value="monthly">每月</option><option value="minutes">每隔若干分钟</option><option value="hours">每隔若干小时</option><option value="once">指定日期,仅执行一次</option><option value="cron">自定义 Cron(五段)</option></select></label><label data-task-cycle="daily weekly monthly">执行时间<input type="time" id="task-time" value="03:00"></label><label data-task-cycle="monthly" hidden>每月几日<input id="task-day" type="number" value="1" min="1" max="31"><small>当月没有该日期时会跳过。</small></label><label data-task-cycle="minutes hours" hidden>间隔数值<input id="task-every" type="number" value="60" min="1" max="1440"><small>从启用任务开始计时。</small></label><label class="full-field" data-task-cycle="once" hidden>指定执行时间<input id="task-once" type="datetime-local"></label><div class="weekday-field full-field" data-task-cycle="weekly" hidden><span>选择星期</span><div id="task-weekdays"><label><input type="checkbox" value="0" checked>一</label><label><input type="checkbox" value="1">二</label><label><input type="checkbox" value="2">三</label><label><input type="checkbox" value="3">四</label><label><input type="checkbox" value="4">五</label><label><input type="checkbox" value="5">六</label><label><input type="checkbox" value="6">日</label></div></div><label class="full-field" data-task-cycle="cron" hidden>Cron 表达式<input id="task-cron" value="0 3 * * *" spellcheck="false"><small>分 时 日 月 周,例如 0 3 * * * 表示每天 03:00。支持范围、列表和 */步长。</small></label><div class="schedule-preview full-field"><button type="button" class="text-button" id="task-preview">检查执行周期</button><span id="task-preview-text">错过执行时间不补跑;同一任务不会重叠执行。</span></div><details class="full-field task-advanced"><summary>高级设置(可选)</summary><div class="task-form-grid"><label>工作目录<input id="task-cwd" value="/root"></label><label>最长执行秒数<input id="task-timeout" type="number" value="1800" min="10" max="86400"></label><label class="full-field">备注<input id="task-notes" maxlength="400" placeholder="记录维护用途、域名或注意事项"></label></div></details><label class="task-enabled-field full-field"><input id="task-enabled" type="checkbox"><span>保存后启用,到计划时间自动执行<small>不勾选时仅保存,可先手动测试。执行身份:root。</small></span></label><p class="form-error full-field" id="task-editor-error" role="alert" hidden></p></div><div class="dialog-footer"><span>保存不会立即执行脚本。</span><div><button type="button" class="text-button" data-close-dialog="task-editor-dialog">取消</button><button type="submit" class="primary-button" id="task-save">保存任务</button></div></div></form></dialog>
<dialog id="task-confirm-dialog" class="task-dialog small-dialog" aria-labelledby="task-confirm-heading"><div class="dialog-heading"><h2 id="task-confirm-heading">确认操作</h2></div><div class="dialog-content"><p id="task-confirm-message"></p><pre id="task-confirm-code" class="raw-log" hidden></pre></div><div class="dialog-footer"><button id="task-confirm-no" class="text-button">取消</button><button id="task-confirm-yes" class="primary-button">确认</button></div></dialog>
<dialog id="task-runs-dialog" class="task-dialog log-dialog" aria-labelledby="task-runs-heading"><div class="dialog-heading"><div><h2 id="task-runs-heading">任务执行记录</h2><p>成功表示命令退出码为 0,具体业务结果仍以输出为准。</p></div><button type="button" class="dialog-close" data-close-dialog="task-runs-dialog" aria-label="关闭执行记录">×</button></div><div class="run-layout"><div id="task-runs-list" class="task-runs-list"></div><div class="task-run-output"><div id="task-run-meta" class="task-run-meta">选择一次执行,查看输出和错误。</div><pre id="task-run-output">尚未选择执行记录。</pre></div></div></dialog>
<dialog id="task-password-dialog" class="task-dialog small-dialog" aria-labelledby="task-password-heading"><form id="task-password-form"><div class="dialog-heading"><h2 id="task-password-heading">修改任务管理密码</h2><button type="button" class="dialog-close" data-close-dialog="task-password-dialog" aria-label="关闭密码窗口">×</button></div><div class="dialog-content task-form-grid"><label class="full-field">原管理密码<input type="password" id="task-old-password" autocomplete="current-password" required></label><label class="full-field">新密码(至少 12 个字符)<input type="password" id="task-new-password" autocomplete="new-password" minlength="12" required></label><label class="full-field">再次输入新密码<input type="password" id="task-repeat-password" autocomplete="new-password" minlength="12" required></label><p class="form-error full-field" id="task-password-error" hidden></p></div><div class="dialog-footer"><span>修改后需要重新登录。</span><button type="submit" class="primary-button">保存新密码</button></div></form></dialog>
</body>
</html>