590 lines
29 KiB
HTML
590 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="description" content="LDNET-GA">
|
||
<title>LDNET-GA</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link
|
||
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
||
rel="stylesheet">
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
||
<script>
|
||
// Prevent theme flicker
|
||
(function () {
|
||
const savedTheme = localStorage.getItem('theme');
|
||
const settings = window.SITE_SETTINGS || {};
|
||
const defaultTheme = settings.default_theme || 'dark';
|
||
let theme = savedTheme || defaultTheme;
|
||
|
||
if (theme === 'auto') {
|
||
theme = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
||
}
|
||
|
||
if (theme === 'light') {
|
||
document.documentElement.classList.add('light-theme');
|
||
}
|
||
|
||
// Also apply title if available to prevent flicker
|
||
if (settings.page_name) {
|
||
document.title = settings.page_name;
|
||
}
|
||
})();
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<!-- Animated Background -->
|
||
<div class="bg-grid"></div>
|
||
<div class="bg-glow bg-glow-1"></div>
|
||
<div class="bg-glow bg-glow-2"></div>
|
||
<div class="bg-glow bg-glow-3"></div>
|
||
|
||
<!-- App Container -->
|
||
<div id="app">
|
||
<!-- Header -->
|
||
<header class="header" id="header">
|
||
<div class="header-left">
|
||
<div class="logo">
|
||
<div id="logoIconContainer">
|
||
<svg class="logo-icon" id="logoSvg" viewBox="0 0 32 32" fill="none">
|
||
<rect x="2" y="2" width="28" height="28" rx="8" stroke="url(#logoGrad)" stroke-width="2.5" />
|
||
<path d="M8 22 L12 14 L16 18 L20 10 L24 16" stroke="url(#logoGrad)" stroke-width="2"
|
||
stroke-linecap="round" stroke-linejoin="round" fill="none" />
|
||
<circle cx="12" cy="14" r="2" fill="url(#logoGrad)" />
|
||
<circle cx="20" cy="10" r="2" fill="url(#logoGrad)" />
|
||
<defs>
|
||
<linearGradient id="logoGrad" x1="0" y1="0" x2="32" y2="32">
|
||
<stop offset="0%" stop-color="#6366f1" />
|
||
<stop offset="100%" stop-color="#06b6d4" />
|
||
</linearGradient>
|
||
</defs>
|
||
</svg>
|
||
</div>
|
||
<h1 class="logo-text" id="logoText">数据可视化展示大屏</h1>
|
||
</div>
|
||
</div>
|
||
<div class="header-right">
|
||
|
||
<div class="theme-switch-wrapper">
|
||
<label class="theme-switch" for="themeToggle">
|
||
<input type="checkbox" id="themeToggle" />
|
||
<div class="slider round">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||
stroke-linejoin="round" class="theme-icon sun-icon">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||
stroke-linejoin="round" class="theme-icon moon-icon" style="display: none;">
|
||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||
</svg>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
<div id="userSection">
|
||
<button class="btn btn-login" id="btnLogin">登录</button>
|
||
</div>
|
||
<button class="btn-settings" id="btnSettings" title="配置管理">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="3"></circle>
|
||
<path
|
||
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z">
|
||
</path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Main Dashboard -->
|
||
<main class="dashboard" id="dashboard">
|
||
<!-- Top Stat Cards -->
|
||
<section class="stat-cards">
|
||
<div class="stat-card stat-card-servers" id="cardServers">
|
||
<div class="stat-card-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||
<rect x="2" y="2" width="20" height="8" rx="2" />
|
||
<rect x="2" y="14" width="20" height="8" rx="2" />
|
||
<circle cx="6" cy="6" r="1" fill="currentColor" />
|
||
<circle cx="6" cy="18" r="1" fill="currentColor" />
|
||
</svg>
|
||
</div>
|
||
<div class="stat-card-content">
|
||
<span class="stat-card-label" id="totalServersLabel">服务器总数</span>
|
||
<span class="stat-card-value" id="totalServers">0</span>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card stat-card-cpu" id="cardCpu">
|
||
<div class="stat-card-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||
<rect x="4" y="4" width="16" height="16" rx="2" />
|
||
<rect x="9" y="9" width="6" height="6" />
|
||
<line x1="9" y1="2" x2="9" y2="4" />
|
||
<line x1="15" y1="2" x2="15" y2="4" />
|
||
<line x1="9" y1="20" x2="9" y2="22" />
|
||
<line x1="15" y1="20" x2="15" y2="22" />
|
||
<line x1="2" y1="9" x2="4" y2="9" />
|
||
<line x1="2" y1="15" x2="4" y2="15" />
|
||
<line x1="20" y1="9" x2="22" y2="9" />
|
||
<line x1="20" y1="15" x2="22" y2="15" />
|
||
</svg>
|
||
</div>
|
||
<div class="stat-card-content">
|
||
<span class="stat-card-label">CPU 使用率</span>
|
||
<span class="stat-card-value" id="cpuPercent">0%</span>
|
||
<span class="stat-card-sub" id="cpuDetail">0 / 0 核心</span>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card stat-card-mem" id="cardMem">
|
||
<div class="stat-card-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||
<path d="M7 7h4v4H7zM13 7h4v4h-4zM7 13h4v4H7zM13 13h4v4h-4z" />
|
||
</svg>
|
||
</div>
|
||
<div class="stat-card-content">
|
||
<span class="stat-card-label">内存使用率</span>
|
||
<span class="stat-card-value" id="memPercent">0%</span>
|
||
<span class="stat-card-sub" id="memDetail">0 / 0 GB</span>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card stat-card-disk" id="cardDisk">
|
||
<div class="stat-card-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||
<ellipse cx="12" cy="5" rx="9" ry="3" />
|
||
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" />
|
||
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" />
|
||
</svg>
|
||
</div>
|
||
<div class="stat-card-content">
|
||
<span class="stat-card-label">磁盘使用率</span>
|
||
<span class="stat-card-value" id="diskPercent">0%</span>
|
||
<span class="stat-card-sub" id="diskDetail">0 / 0 GB</span>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card stat-card-bandwidth" id="cardBandwidth">
|
||
<div class="stat-card-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
|
||
</svg>
|
||
</div>
|
||
<div class="stat-card-content">
|
||
<span class="stat-card-label">实时带宽 (MB/s ↑/↓)</span>
|
||
<div class="stat-card-value-group">
|
||
<span class="stat-card-value" id="totalBandwidthTx">0.00</span>
|
||
<span class="stat-card-separator">/</span>
|
||
<span class="stat-card-value" id="totalBandwidthRx">0.00</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Center Charts -->
|
||
<section class="charts-section">
|
||
<!-- Network Traffic 24h Chart -->
|
||
<div class="chart-card chart-card-wide" id="networkChart">
|
||
<div class="chart-card-header">
|
||
<div class="chart-header-left">
|
||
<h2 class="chart-title">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="chart-title-icon">
|
||
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
|
||
</svg>
|
||
网络流量趋势 (24h)
|
||
</h2>
|
||
</div>
|
||
<div class="chart-legend">
|
||
<span class="legend-item" id="legendRx" style="cursor: pointer;" title="点击切换 接收 (RX) 显示/隐藏"><span class="legend-dot legend-rx"></span>接收 (RX)</span>
|
||
<span class="legend-item" id="legendTx" style="cursor: pointer;" title="点击切换 发送 (TX) 显示/隐藏"><span class="legend-dot legend-tx"></span>发送 (TX)</span>
|
||
<span class="legend-item disabled" id="legendP95" style="cursor: pointer;" title="点击切换 P95 线显示/隐藏">
|
||
<span class="legend-dot legend-p95"></span>95计费 (<span id="p95LabelText">上行</span>)
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="chart-body">
|
||
<canvas id="networkCanvas"></canvas>
|
||
</div>
|
||
<div class="chart-footer">
|
||
<div class="traffic-stat">
|
||
<span class="traffic-label">24h 接收总量</span>
|
||
<span class="traffic-value" id="traffic24hRx">0 B</span>
|
||
</div>
|
||
<div class="traffic-stat">
|
||
<span class="traffic-label">24h 发送总量</span>
|
||
<span class="traffic-value" id="traffic24hTx">0 B</span>
|
||
</div>
|
||
<div class="traffic-stat traffic-stat-p95">
|
||
<span class="traffic-label">95计费 (上行)</span>
|
||
<span class="traffic-value" id="trafficP95">0 B/s</span>
|
||
</div>
|
||
<div class="traffic-stat traffic-stat-total">
|
||
<span class="traffic-label">24h 总流量</span>
|
||
<span class="traffic-value" id="traffic24hTotal">0 B</span>
|
||
</div>
|
||
<div class="traffic-stat traffic-stat-time">
|
||
<span class="traffic-label">当前时间</span>
|
||
<span class="traffic-value" id="footerTime">00:00:00</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Global Traffic 3D Globe -->
|
||
<div class="chart-card globe-card" id="globeCard">
|
||
<div class="chart-card-header">
|
||
<h2 class="chart-title">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="chart-title-icon">
|
||
<circle cx="12" cy="12" r="10" />
|
||
<path
|
||
d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
||
</svg>
|
||
全球服务器分布
|
||
</h2>
|
||
</div>
|
||
<div class="globe-body" id="globeContainer"></div>
|
||
<div class="chart-footer">
|
||
<div class="traffic-stat">
|
||
<span class="traffic-label">全球节点总数</span>
|
||
<span class="traffic-value" id="globeTotalNodes">0</span>
|
||
</div>
|
||
<div class="traffic-stat">
|
||
<span class="traffic-label">覆盖地区/国家</span>
|
||
<span class="traffic-value" id="globeTotalRegions">0</span>
|
||
</div>
|
||
<div class="traffic-stat">
|
||
<span class="traffic-label">实时活跃状态</span>
|
||
<span class="traffic-value" style="color: var(--accent-emerald);">Active</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Server List -->
|
||
<section class="server-list-section" id="serverListSection">
|
||
<div class="chart-card">
|
||
<div class="chart-card-header">
|
||
<h2 class="chart-title">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="chart-title-icon">
|
||
<rect x="2" y="2" width="20" height="8" rx="2" />
|
||
<rect x="2" y="14" width="20" height="8" rx="2" />
|
||
<circle cx="6" cy="6" r="1" fill="currentColor" />
|
||
<circle cx="6" cy="18" r="1" fill="currentColor" />
|
||
</svg>
|
||
服务器详情
|
||
</h2>
|
||
<div class="chart-header-right">
|
||
<div class="search-box">
|
||
<input type="search" id="serverSearchFilter" name="q-filter-server" placeholder="检索服务器名称..." autocomplete="one-time-code"
|
||
spellcheck="false">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||
stroke-linejoin="round" class="search-icon">
|
||
<circle cx="11" cy="11" r="8"></circle>
|
||
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
||
</svg>
|
||
</div>
|
||
<button id="btnResetSort" class="btn-icon-sm" title="重置筛选与排序">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path>
|
||
<path d="M3 3v5h5"></path>
|
||
</svg>
|
||
</button>
|
||
<select id="sourceFilter" class="source-select">
|
||
<option value="all">所有数据源</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="server-table-wrap">
|
||
<table class="server-table" id="serverTable">
|
||
<thead>
|
||
<tr>
|
||
<th class="sortable active" data-sort="up">状态 <span class="sort-icon"></span></th>
|
||
<th class="sortable" data-sort="job">Job / 实例 <span class="sort-icon"></span></th>
|
||
<th class="sortable" data-sort="source">数据源 <span class="sort-icon"></span></th>
|
||
<th class="sortable" data-sort="cpu">CPU <span class="sort-icon"></span></th>
|
||
<th class="sortable" data-sort="mem">内存 <span class="sort-icon"></span></th>
|
||
<th class="sortable" data-sort="disk">磁盘 <span class="sort-icon"></span></th>
|
||
<th class="sortable" data-sort="netRx">网络 ↓ <span class="sort-icon"></span></th>
|
||
<th class="sortable" data-sort="netTx">网络 ↑ <span class="sort-icon"></span></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="serverTableBody">
|
||
<tr class="empty-row">
|
||
<td colspan="8">暂无数据 - 请先配置 Prometheus 数据源</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="pagination-footer">
|
||
<div class="page-size-selector">
|
||
<span>每页显示</span>
|
||
<select id="pageSizeSelect" class="source-select">
|
||
<option value="10">10</option>
|
||
<option value="20" selected>20</option>
|
||
<option value="50">50</option>
|
||
<option value="100">100</option>
|
||
</select>
|
||
<span>条</span>
|
||
</div>
|
||
<div class="pagination-controls" id="paginationControls">
|
||
<!-- Pagination buttons will be injected here -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Settings Modal -->
|
||
<div class="modal-overlay" id="settingsModal">
|
||
<div class="modal">
|
||
<div class="modal-header">
|
||
<div class="modal-tabs">
|
||
<button class="modal-tab active" data-tab="prom">数据源管理</button>
|
||
<button class="modal-tab" data-tab="site">大屏设置</button>
|
||
<button class="modal-tab" data-tab="auth">账号安全</button>
|
||
</div>
|
||
<button class="modal-close" id="modalClose">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<!-- Prometheus Sources Tab -->
|
||
<div class="tab-content active" id="tab-prom">
|
||
<!-- Add Source Form -->
|
||
<div class="add-source-form" id="addSourceForm">
|
||
<h3>添加数据源</h3>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label for="sourceName">名称</label>
|
||
<input type="text" id="sourceName" placeholder="例:生产环境" autocomplete="off">
|
||
</div>
|
||
<div class="form-group form-group-wide">
|
||
<label for="sourceUrl">Prometheus URL</label>
|
||
<input type="url" id="sourceUrl" placeholder="http://prometheus.example.com:9090" autocomplete="off">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group form-group-wide">
|
||
<label for="sourceDesc">描述 (可选)</label>
|
||
<input type="text" id="sourceDesc" placeholder="数据源描述" autocomplete="off">
|
||
</div>
|
||
<div class="form-group" style="display: flex; align-items: flex-end; padding-bottom: 8px;">
|
||
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 0.85rem; color: var(--text-secondary); white-space: nowrap;">
|
||
<input type="checkbox" id="isServerSource" checked style="width: 16px; height: 16px; accent-color: var(--accent-indigo);">
|
||
<span>用于服务器展示</span>
|
||
</label>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button class="btn btn-test" id="btnTest">测试连接</button>
|
||
<button class="btn btn-add" id="btnAdd">添加</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-message" id="formMessage"></div>
|
||
</div>
|
||
|
||
<!-- Source List -->
|
||
<div class="source-list" id="sourceList">
|
||
<h3>已配置数据源</h3>
|
||
<div class="source-items" id="sourceItems">
|
||
<div class="source-empty">暂无数据源</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Site Settings Tab -->
|
||
<div class="tab-content" id="tab-site">
|
||
<div class="site-settings-form">
|
||
<h3>自定义大屏展示</h3>
|
||
<div class="form-group">
|
||
<label for="pageNameInput">页面名称 (浏览器标签页标题)</label>
|
||
<input type="text" id="pageNameInput" placeholder="例:运维监控大屏">
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="siteTitleInput">标题 (大屏左上角显示名称)</label>
|
||
<input type="text" id="siteTitleInput" placeholder="例:数据可视化展示大屏">
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="logoUrlInput">Logo URL (图片链接,为空则显示默认图标)</label>
|
||
<input type="url" id="logoUrlInput" placeholder="https://example.com/logo.png">
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="defaultThemeInput">默认主题</label>
|
||
<select id="defaultThemeInput"
|
||
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary);">
|
||
<option value="dark">默认夜间模式</option>
|
||
<option value="light">默认白天模式</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="show95BandwidthInput">24h趋势图默认显示 95计费线</label>
|
||
<select id="show95BandwidthInput"
|
||
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary);">
|
||
<option value="1">显示</option>
|
||
<option value="0">不显示</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="p95TypeSelect">95带宽计费统计类型</label>
|
||
<select id="p95TypeSelect"
|
||
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary);">
|
||
<option value="tx">仅统计上行 (TX)</option>
|
||
<option value="rx">仅统计下行 (RX)</option>
|
||
<option value="both">统计上行+下行 (Sum)</option>
|
||
</select>
|
||
</div>
|
||
<h3 style="margin-top: 30px; border-top: 1px solid var(--border-color); padding-top: 20px;">Blackbox Exporter & 延迟连线</h3>
|
||
<div class="form-group">
|
||
<label for="blackboxSourceSelect">延迟数据源 (选择已对接 Blackbox 的 Prometheus)</label>
|
||
<select id="blackboxSourceSelect"
|
||
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary);">
|
||
<option value="">-- 请选择数据源 --</option>
|
||
<!-- Sources will be injected here -->
|
||
</select>
|
||
</div>
|
||
<div class="form-row" style="margin-top: 15px;">
|
||
<div class="form-group">
|
||
<label for="latencySourceInput">起航点国家/地区A (地图连线起点)</label>
|
||
<input type="text" id="latencySourceInput" placeholder="例:China">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="latencyDestInput">目的地国家/地区B (地图连线终点)</label>
|
||
<input type="text" id="latencyDestInput" placeholder="例:United States">
|
||
</div>
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="latencyTargetInput">Blackbox 探测目标 (在Prometheus中的instance_name标签值)</label>
|
||
<input type="text" id="latencyTargetInput" placeholder="例:China-USA-Latency">
|
||
</div>
|
||
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
||
<button class="btn btn-add" id="btnSaveSiteSettings">保存设置</button>
|
||
</div>
|
||
<div class="form-message" id="siteSettingsMessage"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Account Security Tab -->
|
||
<div class="tab-content" id="tab-auth">
|
||
<div class="security-settings-form">
|
||
<h3>修改登录密码</h3>
|
||
<div class="form-group">
|
||
<label for="oldPassword">当前密码</label>
|
||
<input type="password" id="oldPassword" placeholder="请输入当前旧密码">
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="newPassword">新密码</label>
|
||
<input type="password" id="newPassword" placeholder="请输入要设置的新密码">
|
||
</div>
|
||
<div class="form-group" style="margin-top: 15px;">
|
||
<label for="confirmNewPassword">确认新密码</label>
|
||
<input type="password" id="confirmNewPassword" placeholder="请再次确认新密码">
|
||
</div>
|
||
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
||
<button class="btn btn-add" id="btnChangePassword">提交修改</button>
|
||
</div>
|
||
<div class="form-message" id="changePasswordMessage"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Server Detail Modal -->
|
||
<div class="modal-overlay" id="serverDetailModal">
|
||
<div class="modal" style="max-width: 800px; width: 95%;">
|
||
<div class="modal-header">
|
||
<div style="display: flex; flex-direction: column;">
|
||
<h2 id="serverDetailTitle" style="margin-bottom: 0;">服务器详情</h2>
|
||
</div>
|
||
<button class="modal-close" id="serverDetailClose">×</button>
|
||
</div>
|
||
<div class="modal-body" id="serverDetailBody" style="padding: 0;">
|
||
<div id="detailLoading" style="text-align: center; padding: 40px; display: none;">
|
||
<div class="dot dot-pulse"
|
||
style="display: inline-block; width: 12px; height: 12px; background: var(--accent-indigo);"></div>
|
||
<span style="margin-left: 10px; color: var(--text-secondary);">正在从数据源读取详情...</span>
|
||
</div>
|
||
<div class="detail-container" id="detailContainer">
|
||
<!-- Metric Items are injected here -->
|
||
<div class="detail-metrics-list" id="detailMetricsList"></div>
|
||
|
||
<div class="detail-partitions-container metric-item" id="detailPartitionsContainer"
|
||
style="display: none;">
|
||
<div class="metric-item-header" id="partitionHeader">
|
||
<div class="metric-label-group">
|
||
<span class="metric-label">磁盘分区详情 (已挂载)</span>
|
||
<span class="metric-value" id="partitionSummary">读取中...</span>
|
||
</div>
|
||
<svg class="chevron-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<polyline points="6 9 12 15 18 9"></polyline>
|
||
</svg>
|
||
</div>
|
||
<div class="metric-item-content" id="partitionContent">
|
||
<div class="detail-partitions-list" id="detailPartitionsList"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="detail-info-grid" id="detailInfoGrid">
|
||
<div class="info-item">
|
||
<span class="info-label">CPU 核心总数</span>
|
||
<span class="info-value" id="detailCpuCores">0 核心</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">物理内存总量</span>
|
||
<span class="info-value" id="detailMemTotal">0 GB</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">运行时间 (Uptime)</span>
|
||
<span class="info-value" id="detailUptime">0天 0小时</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">硬盘总量统计</span>
|
||
<span class="info-value" id="detailDiskTotal">0 GB</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Login Modal -->
|
||
<div class="modal-overlay" id="loginModalOverlay">
|
||
<div class="modal" style="max-width: 400px;">
|
||
<div class="modal-header">
|
||
<h2>用户登录</h2>
|
||
<button class="modal-close" id="closeLoginModal">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="loginForm">
|
||
<div class="form-group">
|
||
<label for="username">用户名</label>
|
||
<input type="text" id="username" placeholder="请输入用户名" required>
|
||
</div>
|
||
<div class="form-group" style="margin-top: 16px;">
|
||
<label for="password">密码</label>
|
||
<input type="password" id="password" placeholder="请输入密码" required>
|
||
</div>
|
||
<div id="loginError" style="color: var(--accent-rose); font-size: 0.8rem; margin-top: 10px; display: none;">
|
||
</div>
|
||
<button type="submit" class="btn btn-primary"
|
||
style="width: 100%; margin-top: 24px; background: var(--gradient-primary); color: white; border: none; padding: 12px; border-radius: 8px; cursor: pointer;">登
|
||
录</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/js/utils.js"></script>
|
||
<script src="/js/chart.js"></script>
|
||
<script src="/js/app.js"></script>
|
||
</body>
|
||
|
||
</html> |