1261 lines
96 KiB
HTML
1261 lines
96 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN" class="">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>monitor-ai — 告警监控中心 (预览)</title>
|
||
<style>
|
||
/* ==================== 设计令牌(来自 tlyq-design-system.css) ==================== */
|
||
:root {
|
||
--bg: #f8fafc;
|
||
--bg-subtle: #f1f5f9;
|
||
--surface: #ffffff;
|
||
--surface-raised: #ffffff;
|
||
--fg: #0f172a;
|
||
--fg-subtle: #334155;
|
||
--muted: #475569;
|
||
--muted-subtle: #94a3b8;
|
||
--border: #e2e8f0;
|
||
--border-subtle: #f1f5f9;
|
||
|
||
--accent: #4f46e5;
|
||
--accent-hover: #4338ca;
|
||
--accent-active: #3730a3;
|
||
--accent-subtle: #eef2ff;
|
||
--accent-text: #ffffff;
|
||
|
||
--success: #059669;
|
||
--success-subtle: #ecfdf5;
|
||
--warning: #d97706;
|
||
--warning-subtle: #fffbeb;
|
||
--danger: #dc2626;
|
||
--danger-subtle: #fef2f2;
|
||
--info: #4f46e5;
|
||
--info-subtle: #eef2ff;
|
||
|
||
--font-display: -apple-system, BlinkMacSystemFont, 'SF Pro Display', system-ui, sans-serif;
|
||
--font-body: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
|
||
--font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;
|
||
|
||
--text-xs: 0.75rem; --text-sm: 0.875rem; --text-base: 1rem; --text-lg: 1.125rem;
|
||
--text-xl: 1.25rem; --text-2xl: 1.5rem; --text-3xl: 1.875rem;
|
||
|
||
--space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem; --space-4: 1rem;
|
||
--space-5: 1.25rem; --space-6: 1.5rem; --space-8: 2rem;
|
||
|
||
--radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px; --radius-xl: 16px; --radius-full: 9999px;
|
||
|
||
--shadow-sm: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
|
||
--shadow-md: 0 4px 6px -1px rgba(0,0,0,.08);
|
||
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,.1);
|
||
|
||
--transition-fast: 150ms cubic-bezier(0.4,0,0.2,1);
|
||
--transition-normal: 200ms cubic-bezier(0.4,0,0.2,1);
|
||
|
||
--z-sticky: 200;
|
||
--z-overlay: 300;
|
||
|
||
--sidebar-width: 240px;
|
||
--header-height: 56px;
|
||
}
|
||
|
||
:root.dark {
|
||
--bg: #020617; --bg-subtle: #0f172a; --surface: #0f172a; --surface-raised: #1e293b;
|
||
--fg: #f8fafc; --fg-subtle: #cbd5e1; --muted: #94a3b8; --muted-subtle: #64748b;
|
||
--border: #1e293b; --border-subtle: #0f172a;
|
||
--accent: #6366f1; --accent-hover: #818cf8; --accent-active: #4f46e5; --accent-subtle: rgba(79,70,229,.15);
|
||
--accent-text: #ffffff;
|
||
--success: #34d399; --success-subtle: rgba(52,211,153,.1);
|
||
--warning: #fbbf24; --warning-subtle: rgba(251,191,36,.1);
|
||
--danger: #f87171; --danger-subtle: rgba(248,113,113,.1);
|
||
--info: #818cf8; --info-subtle: rgba(99,102,241,.1);
|
||
--shadow-sm: 0 1px 3px rgba(0,0,0,.3); --shadow-md: 0 4px 6px -1px rgba(0,0,0,.3);
|
||
}
|
||
|
||
/* ==================== 全局重置 ==================== */
|
||
*,*::before,*::after { box-sizing:border-box; margin:0; padding:0; }
|
||
html { font-size:16px; -webkit-font-smoothing:antialiased; }
|
||
body { font-family:var(--font-body); font-size:var(--text-sm); line-height:1.5; color:var(--fg); background:var(--bg); }
|
||
|
||
/* ==================== 布局 ==================== */
|
||
.app { display:flex; height:100vh; overflow:hidden; }
|
||
|
||
.sidebar {
|
||
width:var(--sidebar-width); height:100vh; background:var(--surface);
|
||
border-right:1px solid var(--border); display:flex; flex-direction:column;
|
||
flex-shrink:0; position:fixed; left:0; top:0; bottom:0; z-index:var(--z-sticky);
|
||
}
|
||
.sidebar-brand { display:flex; align-items:center; gap:var(--space-3); padding:0 var(--space-6); height:var(--header-height); border-bottom:1px solid var(--border); }
|
||
.sidebar-logo { width:32px; height:32px; border-radius:var(--radius-lg); background:var(--accent); color:var(--accent-text); display:flex; align-items:center; justify-content:center; font-weight:700; font-size:var(--text-sm); flex-shrink:0; }
|
||
.sidebar-title { font-family:var(--font-display); font-size:var(--text-base); font-weight:600; color:var(--fg); }
|
||
.sidebar-nav { flex:1; overflow-y:auto; padding:var(--space-4) var(--space-3); }
|
||
.sidebar-section { margin-bottom:var(--space-6); }
|
||
.sidebar-section-title { font-size:var(--text-xs); font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:0.1em; padding:var(--space-2) var(--space-3); margin-bottom:var(--space-1); }
|
||
.sidebar-item { display:flex; align-items:center; gap:var(--space-3); padding:var(--space-2) var(--space-3); font-size:var(--text-sm); color:var(--fg-subtle); text-decoration:none; border-radius:var(--radius-md); transition:all var(--transition-fast); margin-bottom:var(--space-1); }
|
||
.sidebar-item:hover { background:var(--bg-subtle); color:var(--fg); }
|
||
.sidebar-item.active { background:var(--accent-subtle); color:var(--accent); font-weight:500; }
|
||
.sidebar-item-icon { width:20px; height:20px; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
|
||
.sidebar-user { padding:var(--space-3); border-top:1px solid var(--border); }
|
||
.sidebar-user-inner { display:flex; align-items:center; gap:var(--space-3); padding:var(--space-2); border-radius:var(--radius-md); }
|
||
.sidebar-user-avatar { width:32px; height:32px; border-radius:var(--radius-full); background:var(--accent-subtle); color:var(--accent); display:flex; align-items:center; justify-content:center; font-weight:600; font-size:var(--text-xs); }
|
||
.sidebar-user-name { font-size:var(--text-sm); font-weight:500; color:var(--fg); }
|
||
.sidebar-user-role { font-size:var(--text-xs); color:var(--muted); }
|
||
|
||
.main { flex:1; margin-left:var(--sidebar-width); overflow-y:auto; }
|
||
|
||
.header { height:var(--header-height); background:var(--surface); border-bottom:1px solid var(--border); position:sticky; top:0; z-index:var(--z-sticky); backdrop-filter:blur(10px); }
|
||
.header-inner { display:flex; align-items:center; justify-content:space-between; height:100%; padding:0 var(--space-6); }
|
||
.header-left { display:flex; align-items:center; gap:var(--space-3); }
|
||
.header-breadcrumb { font-size:var(--text-sm); color:var(--muted); }
|
||
.header-breadcrumb span { color:var(--fg); font-weight:500; }
|
||
.header-right { display:flex; align-items:center; gap:var(--space-4); }
|
||
|
||
.content { padding:var(--space-6); max-width:1440px; }
|
||
|
||
/* ==================== 统计卡片 ==================== */
|
||
.stats-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--space-6); margin-bottom:var(--space-6); }
|
||
.stat-card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-xl); padding:var(--space-6); transition:all var(--transition-fast); }
|
||
.stat-card:hover { border-color:var(--accent); box-shadow:var(--shadow-md); }
|
||
.stat-card-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-4); }
|
||
.stat-card-title { font-size:var(--text-sm); font-weight:500; color:var(--muted); }
|
||
.stat-card-icon { width:40px; height:40px; border-radius:var(--radius-lg); display:flex; align-items:center; justify-content:center; font-size:var(--text-lg); }
|
||
.stat-card-value { font-family:var(--font-display); font-size:var(--text-3xl); font-weight:600; color:var(--fg); margin-bottom:var(--space-2); }
|
||
.stat-card-sub { font-size:var(--text-xs); color:var(--muted); }
|
||
|
||
/* ==================== 服务状态列表 ==================== */
|
||
.service-list { display:flex; flex-direction:column; gap:var(--space-2); }
|
||
.service-card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg); overflow:hidden; transition:all var(--transition-fast); }
|
||
.service-card:hover { border-color:var(--accent-subtle); }
|
||
.service-card-header { display:flex; align-items:center; justify-content:space-between; padding:var(--space-4) var(--space-6); cursor:pointer; user-select:none; }
|
||
.service-card-header:hover { background:var(--bg-subtle); }
|
||
.service-card-left { display:flex; align-items:center; gap:var(--space-4); }
|
||
.service-card-right { display:flex; align-items:center; gap:var(--space-4); font-size:var(--text-sm); color:var(--muted); }
|
||
.service-card-body { display:none; padding:0 var(--space-6) var(--space-4); border-top:1px solid var(--border-subtle); }
|
||
.service-card.open .service-card-body { display:block; }
|
||
.service-card-body-inner { padding-top:var(--space-4); display:flex; flex-direction:column; gap:var(--space-3); }
|
||
.check-detail { display:flex; align-items:center; gap:var(--space-3); padding:var(--space-2) var(--space-3); background:var(--bg-subtle); border-radius:var(--radius-md); font-size:var(--text-sm); }
|
||
|
||
/* ==================== 状态徽标 ==================== */
|
||
.status-badge { display:inline-flex; align-items:center; gap:var(--space-1); padding:2px var(--space-2); font-size:var(--text-xs); font-weight:500; border-radius:var(--radius-full); }
|
||
.status-normal { background:var(--success-subtle); color:var(--success); }
|
||
.status-abnormal { background:var(--danger-subtle); color:var(--danger); }
|
||
.status-unknown { background:var(--warning-subtle); color:var(--warning); }
|
||
|
||
.status-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
|
||
.status-dot-normal { background:var(--success); }
|
||
.status-dot-abnormal { background:var(--danger); animation:pulse 2s infinite; }
|
||
.status-dot-unknown { background:var(--warning); }
|
||
|
||
@keyframes pulse { 0%,100% { opacity:1; } 50% { opacity:0.4; } }
|
||
|
||
/* ==================== 按钮 ==================== */
|
||
.btn { display:inline-flex; align-items:center; justify-content:center; gap:var(--space-2); padding:var(--space-2) var(--space-4); font-family:var(--font-body); font-size:var(--text-sm); font-weight:500; border-radius:var(--radius-md); border:1px solid transparent; cursor:pointer; transition:all var(--transition-fast); white-space:nowrap; }
|
||
.btn-primary { background:var(--accent); color:var(--accent-text); border-color:var(--accent); }
|
||
.btn-primary:hover { background:var(--accent-hover); }
|
||
.btn-secondary { background:transparent; color:var(--fg); border-color:var(--border); }
|
||
.btn-secondary:hover { background:var(--bg-subtle); }
|
||
.btn-sm { padding:var(--space-1) var(--space-3); font-size:var(--text-xs); }
|
||
.btn-ghost { background:transparent; color:var(--fg-subtle); }
|
||
.btn-ghost:hover { background:var(--bg-subtle); color:var(--fg); }
|
||
|
||
/* ==================== 设置页 ==================== */
|
||
.section-title { font-family:var(--font-display); font-size:var(--text-2xl); font-weight:600; color:var(--fg); margin-bottom:var(--space-6); }
|
||
.channel-health { display:flex; gap:var(--space-6); margin-bottom:var(--space-6); }
|
||
.health-item { display:flex; align-items:center; gap:var(--space-2); font-size:var(--text-sm); }
|
||
.health-dot { width:8px; height:8px; border-radius:50%; }
|
||
.health-ok { background:var(--success); }
|
||
.health-fail { background:var(--danger); }
|
||
|
||
.card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-xl); overflow:hidden; }
|
||
.card-header { padding:var(--space-4) var(--space-6); border-bottom:1px solid var(--border); display:flex; align-items:center; justify-content:space-between; }
|
||
.card-title { font-size:var(--text-base); font-weight:600; color:var(--fg); }
|
||
.card-body { padding:var(--space-6); }
|
||
|
||
.form-group { margin-bottom:var(--space-4); }
|
||
.form-label { display:block; font-size:var(--text-sm); font-weight:500; color:var(--fg); margin-bottom:var(--space-2); }
|
||
.form-input { width:100%; padding:var(--space-2) var(--space-3); font-size:var(--text-sm); background:var(--surface); color:var(--fg); border:1px solid var(--border); border-radius:var(--radius-md); transition:all var(--transition-fast); font-family:var(--font-mono); }
|
||
.form-input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-subtle); }
|
||
.form-checkbox { display:flex; align-items:center; gap:var(--space-2); cursor:pointer; }
|
||
.form-checkbox input[type="checkbox"] { width:16px; height:16px; accent-color:var(--accent); }
|
||
.form-row { display:grid; grid-template-columns:1fr 1fr 1fr; gap:var(--space-4); }
|
||
.form-actions { display:flex; justify-content:flex-end; gap:var(--space-3); margin-top:var(--space-6); }
|
||
|
||
/* ==================== 主题切换 ==================== */
|
||
.theme-toggle { width:36px; height:36px; border-radius:var(--radius-md); border:1px solid var(--border); background:var(--surface); cursor:pointer; display:flex; align-items:center; justify-content:center; color:var(--fg-subtle); font-size:var(--text-lg); transition:all var(--transition-fast); }
|
||
.theme-toggle:hover { background:var(--bg-subtle); }
|
||
|
||
/* ==================== 标签 ==================== */
|
||
.tag { display:inline-flex; align-items:center; padding:1px var(--space-2); font-size:var(--text-xs); font-weight:500; border-radius:var(--radius-full); }
|
||
.tag-indigo { background:var(--accent-subtle); color:var(--accent); }
|
||
.tag-green { background:var(--success-subtle); color:var(--success); }
|
||
.tag-red { background:var(--danger-subtle); color:var(--danger); }
|
||
|
||
/* ==================== Toast ==================== */
|
||
.toast { position:fixed; top:var(--space-4); right:var(--space-4); min-width:300px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg); box-shadow:var(--shadow-lg); z-index:700; padding:var(--space-4); transform:translateX(100%); opacity:0; transition:all var(--transition-normal); }
|
||
.toast.show { transform:translateX(0); opacity:1; }
|
||
.toast-title { font-size:var(--text-sm); font-weight:600; color:var(--fg); margin-bottom:var(--space-1); }
|
||
.toast-body { font-size:var(--text-sm); color:var(--fg-subtle); }
|
||
|
||
.badge { display:inline-flex; align-items:center; justify-content:center; min-width:20px; height:20px; padding:0 var(--space-2); font-size:var(--text-xs); font-weight:600; border-radius:var(--radius-full); }
|
||
.badge-success { background:var(--success); color:#fff; }
|
||
.badge-danger { background:var(--danger); color:#fff; }
|
||
|
||
/* ==================== 卡片式仪表盘 ==================== */
|
||
.card-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--space-4); margin-bottom:var(--space-6); }
|
||
@media (max-width:1200px) { .card-grid { grid-template-columns:repeat(2,1fr); } }
|
||
@media (max-width:768px) { .card-grid { grid-template-columns:1fr; } }
|
||
|
||
.svc-card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-xl); padding:var(--space-5); transition:all var(--transition-fast); cursor:pointer; }
|
||
.svc-card:hover { box-shadow:var(--shadow-sm); }
|
||
.svc-card.abnormal { background:var(--danger-subtle); border-color:var(--danger); }
|
||
.svc-card.abnormal:hover { border-color:var(--danger); box-shadow:0 0 0 4px var(--danger-subtle); }
|
||
.svc-card-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-2); }
|
||
.svc-card-name { display:flex; align-items:center; gap:var(--space-2); font-weight:600; font-size:var(--text-sm); color:var(--fg); }
|
||
.svc-card-error { font-size:var(--text-xs); color:var(--danger); line-height:1.3; }
|
||
.svc-card-body-expand { display:none; margin-top:var(--space-2); padding-top:var(--space-2); border-top:1px solid var(--border); }
|
||
.svc-card.open .svc-card-body-expand { display:block; }
|
||
.svc-card-footer { display:flex; align-items:center; justify-content:space-between; margin-top:var(--space-2); }
|
||
.svc-card-countdown { font-size:var(--text-lg); font-weight:600; color:var(--danger); font-family:var(--font-mono); }
|
||
.svc-card-label { font-size:var(--text-xs); color:var(--muted); }
|
||
|
||
|
||
/* ==================== 方案 A:统计条 ==================== */
|
||
.stat-bar { display:flex; align-items:center; gap:var(--space-8); padding:var(--space-4) var(--space-6); background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-xl); margin-bottom:var(--space-6); }
|
||
.stat-bar-item { display:flex; align-items:center; gap:var(--space-3); }
|
||
.stat-bar-dot { width:10px; height:10px; border-radius:50%; flex-shrink:0; }
|
||
.stat-bar-dot-success { background:var(--success); }
|
||
.stat-bar-dot-danger { background:var(--danger); animation:pulse 2s infinite; }
|
||
.stat-bar-dot-warning { background:var(--warning); }
|
||
.stat-bar-value { font-family:var(--font-display); font-size:var(--text-2xl); font-weight:600; color:var(--fg); }
|
||
.stat-bar-label { font-size:var(--text-sm); color:var(--muted); }
|
||
.stat-bar-divider { width:1px; height:32px; background:var(--border); }
|
||
.stat-bar-right { margin-left:auto; font-size:var(--text-sm); color:var(--muted); }
|
||
|
||
/* ==================== Pro 仪表盘(Dark-First / 专业监控风格) ==================== */
|
||
.page-pro { background:var(--bg); min-height:100%; }
|
||
.page-pro .content-area { padding:var(--space-8) var(--space-8); max-width:1440px; }
|
||
|
||
/* 页面标题区 */
|
||
.pro-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-8); }
|
||
.pro-title { font-family:var(--font-display); font-size:var(--text-3xl); font-weight:700; color:var(--fg); letter-spacing:var(--tracking-tight); }
|
||
.pro-title-sub { font-size:var(--text-sm); color:var(--muted); margin-top:var(--space-1); font-weight:400; }
|
||
.pro-actions { display:flex; align-items:center; gap:var(--space-3); }
|
||
|
||
/* 统计条 */
|
||
.pro-statbar { display:grid; grid-template-columns:1fr 1px 1fr 1px 1fr 1fr; gap:var(--space-6); align-items:center; padding:var(--space-6) var(--space-8); background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-2xl); margin-bottom:var(--space-8); }
|
||
.pro-statbar-divider { width:100%; height:1px; background:var(--border); }
|
||
@media (min-width:768px) { .pro-statbar-divider { width:1px; height:48px; } }
|
||
.pro-stat-item { display:flex; flex-direction:column; gap:var(--space-1); }
|
||
.pro-stat-item-label { font-size:var(--text-xs); color:var(--muted); font-weight:500; text-transform:uppercase; letter-spacing:var(--tracking-widest); }
|
||
.pro-stat-item-value { font-family:var(--font-display); font-size:var(--text-2xl); font-weight:700; color:var(--fg); }
|
||
.pro-stat-item-sub { font-size:var(--text-xs); color:var(--muted-subtle); }
|
||
|
||
/* 服务网格 */
|
||
.pro-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--space-4); }
|
||
@media (max-width:1200px) { .pro-grid { grid-template-columns:repeat(3,1fr); } }
|
||
@media (max-width:900px) { .pro-grid { grid-template-columns:repeat(2,1fr); } }
|
||
@media (max-width:600px) { .pro-grid { grid-template-columns:1fr; } }
|
||
|
||
.pro-svc { position:relative; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-xl); padding:var(--space-5); transition:all var(--transition-normal); cursor:pointer; overflow:hidden; }
|
||
.pro-svc::before { content:''; position:absolute; top:0; left:0; right:0; height:3px; background:transparent; transition:background var(--transition-normal); border-radius:var(--radius-xl) var(--radius-xl) 0 0; }
|
||
.pro-svc:hover { border-color:var(--accent); box-shadow:var(--shadow-lg); transform:translateY(-2px); }
|
||
.pro-svc.abnormal { border-color:var(--danger); background:var(--danger-subtle); }
|
||
.pro-svc.abnormal::before { background:var(--danger); }
|
||
|
||
.pro-svc-top { display:flex; align-items:flex-start; justify-content:space-between; margin-bottom:var(--space-3); }
|
||
.pro-svc-name { font-weight:600; font-size:var(--text-sm); color:var(--fg); display:flex; align-items:center; gap:var(--space-2); }
|
||
.pro-svc-status-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
|
||
.pro-svc-status-dot.ok { background:var(--success); box-shadow:0 0 8px var(--success); }
|
||
.pro-svc-status-dot.err { background:var(--danger); box-shadow:0 0 12px var(--danger); animation:pro-pulse 2s infinite; }
|
||
@keyframes pro-pulse { 0%,100% { box-shadow:0 0 8px var(--danger); } 50% { box-shadow:0 0 20px var(--danger); } }
|
||
|
||
.pro-svc-body { display:flex; flex-direction:column; gap:var(--space-2); }
|
||
.pro-svc-status-text { font-family:var(--font-mono); font-size:var(--text-xl); font-weight:700; }
|
||
.pro-svc-status-text.ok { color:var(--success); }
|
||
.pro-svc-status-text.err { color:var(--danger); }
|
||
.pro-svc-desc { font-size:var(--text-xs); color:var(--muted); line-height:1.4; }
|
||
.pro-svc-footer { display:flex; align-items:center; justify-content:space-between; margin-top:var(--space-3); padding-top:var(--space-3); border-top:1px solid var(--border-subtle); }
|
||
.pro-svc-footer-label { font-size:var(--text-xs); color:var(--muted-subtle); }
|
||
|
||
.pro-svc-expand { display:none; margin-top:var(--space-3); padding-top:var(--space-3); border-top:1px solid var(--border); }
|
||
.pro-svc.open .pro-svc-expand { display:block; }
|
||
.pro-svc-expand-item { display:flex; align-items:center; gap:var(--space-2); padding:var(--space-1) 0; font-size:var(--text-xs); color:var(--fg-subtle); }
|
||
|
||
/* ==================== Design 仪表盘(精密仪器风格,复用设计系统变量) ==================== */
|
||
/* 仅覆盖仪表盘特有的风格,基础色/间距/圆角等均使用 :root 变量 */
|
||
|
||
.ds-root {
|
||
position:relative; min-height:calc(100vh - var(--header-height));
|
||
background:var(--bg); color:var(--fg);
|
||
font-family:var(--font-body);
|
||
padding:40px 48px;
|
||
overflow:hidden;
|
||
}
|
||
/* 暗色模式点阵网格(亮色模式不加,保持干净) */
|
||
:root.dark .ds-root::before {
|
||
content:''; position:absolute; inset:0; pointer-events:none; z-index:0;
|
||
background-image:radial-gradient(circle, var(--border) 1px, transparent 1px);
|
||
background-size:24px 24px; opacity:0.3;
|
||
}
|
||
|
||
.ds-inner { position:relative; z-index:1; max-width:1400px; margin:0 auto; }
|
||
|
||
/* 标题 */
|
||
.ds-header { margin-bottom:44px; }
|
||
.ds-header h1 { font-family:var(--font-display); font-size:var(--text-2xl); font-weight:700; color:var(--fg); }
|
||
.ds-header h1 span { color:var(--muted); font-weight:400; }
|
||
.ds-header p { font-size:var(--text-sm); color:var(--muted); margin-top:4px; }
|
||
|
||
/* 统计条 — 无缝分段,使用设计系统字体和间距 */
|
||
.ds-stats { display:flex; gap:1px; background:var(--border); border-radius:var(--radius-xl); overflow:hidden; }
|
||
.ds-stat { flex:1; background:var(--surface); padding:var(--space-4) var(--space-6); display:flex; flex-direction:column; gap:var(--space-1); }
|
||
.ds-stat-label { font-size:var(--text-xs); font-weight:500; color:var(--muted); text-transform:uppercase; letter-spacing:var(--tracking-widest); }
|
||
.ds-stat-value { font-family:var(--font-display); font-size:var(--text-2xl); font-weight:600; line-height:var(--leading-tight); }
|
||
.ds-stat-sub { font-size:var(--text-xs); color:var(--muted-subtle); }
|
||
|
||
/* 卡片网格 */
|
||
.ds-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--space-3); }
|
||
@media (max-width:1280px) { .ds-grid { grid-template-columns:repeat(3,1fr); } }
|
||
@media (max-width:900px) { .ds-grid { grid-template-columns:repeat(2,1fr); } }
|
||
@media (max-width:560px) { .ds-grid { grid-template-columns:1fr; } }
|
||
|
||
/* 卡片 */
|
||
.ds-card { position:relative; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-xl); padding:var(--space-5); transition:all var(--transition-normal); cursor:pointer; }
|
||
.ds-card:hover { border-color:var(--accent); box-shadow:var(--shadow-md); transform:translateY(-1px); }
|
||
.ds-card.open { border-color:var(--accent); }
|
||
|
||
/* 异常卡片 — 唯一使用独立颜色的地方(精密仪器风格的核心) */
|
||
.ds-card.abnormal { border-color:var(--danger); background:var(--danger-subtle); box-shadow:0 0 0 1px var(--danger), 0 0 24px rgba(220,38,38,.15); }
|
||
|
||
/* 状态指示器 — 页面唯一的装饰性动画 */
|
||
.ds-dot { width:10px; height:10px; border-radius:50%; position:relative; flex-shrink:0; }
|
||
.ds-dot::after { content:''; position:absolute; inset:-4px; border-radius:50%; z-index:-1; }
|
||
.ds-dot.ok { background:var(--success); }
|
||
.ds-dot.ok::after { background:var(--success-subtle); }
|
||
.ds-dot.err { background:var(--danger); animation:ds-breathe 3s ease-in-out infinite; }
|
||
.ds-dot.err::after { background:var(--danger-subtle); animation:ds-breathe-glow 3s ease-in-out infinite; }
|
||
@keyframes ds-breathe { 0%,100%{box-shadow:0 0 4px var(--danger)}50%{box-shadow:0 0 14px var(--danger)} }
|
||
@keyframes ds-breathe-glow { 0%,100%{transform:scale(1);opacity:.5}50%{transform:scale(1.8);opacity:1} }
|
||
|
||
.ds-card-top { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-4); }
|
||
.ds-card-name { display:flex; align-items:center; gap:var(--space-2); font-weight:500; font-size:var(--text-sm); color:var(--fg); }
|
||
|
||
/* 状态数值 — 等宽数字,Precision 核心 */
|
||
.ds-card-value { font-family:var(--font-mono); font-size:var(--text-2xl); font-weight:600; margin-bottom:var(--space-2); }
|
||
.ds-card-value.ok { color:var(--success); }
|
||
.ds-card-value.err { color:var(--danger); }
|
||
|
||
.ds-card-meta { font-size:var(--text-xs); color:var(--muted); line-height:1.5; margin-bottom:var(--space-3); }
|
||
|
||
.ds-card-footer { display:flex; align-items:center; justify-content:space-between; padding-top:var(--space-3); border-top:1px solid var(--border-subtle); }
|
||
.ds-card-footer span { font-size:var(--text-xs); color:var(--muted-subtle); }
|
||
|
||
.ds-card-expand { display:none; margin-top:var(--space-3); padding-top:var(--space-3); border-top:1px solid var(--border-subtle); }
|
||
.ds-card.open .ds-card-expand { display:block; }
|
||
.ds-check { display:flex; align-items:center; gap:var(--space-2); padding:3px 0; font-size:var(--text-xs); color:var(--fg-subtle); }
|
||
.ds-check-dot { width:6px; height:6px; border-radius:50%; flex-shrink:0; }
|
||
.ds-check-dot.ok { background:var(--success); }
|
||
.ds-check-dot.err { background:var(--danger); }
|
||
|
||
/* 底部状态 */
|
||
.ds-footer { margin-top:36px; display:flex; align-items:center; justify-content:center; gap:32px; font-size:var(--text-xs); color:var(--muted); }
|
||
.ds-footer-sep { width:1px; height:12px; background:var(--border); }
|
||
|
||
/* 页面切换 */
|
||
.page { display:none; }
|
||
.page.active { display:block; }
|
||
|
||
@media (max-width:768px) {
|
||
.sidebar { display:none; }
|
||
.main { margin-left:0; }
|
||
.stats-grid { grid-template-columns:1fr 1fr; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app">
|
||
<!-- ==================== 侧边栏 ==================== -->
|
||
<aside class="sidebar">
|
||
<div class="sidebar-brand">
|
||
<div class="sidebar-logo">M</div>
|
||
<span class="sidebar-title">monitor-ai</span>
|
||
</div>
|
||
<nav class="sidebar-nav">
|
||
<div class="sidebar-section">
|
||
<p class="sidebar-section-title">监控</p>
|
||
<a class="sidebar-item active" href="#" onclick="showPage('dashboard');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="9"/><rect x="14" y="3" width="7" height="5"/><rect x="14" y="12" width="7" height="9"/><rect x="3" y="16" width="7" height="5"/></svg></span> 仪表盘(行式)
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('dashboard-cards');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><rect x="7" y="7" width="3" height="3"/><rect x="14" y="7" width="3" height="3"/><rect x="7" y="14" width="3" height="3"/><rect x="14" y="14" width="3" height="3"/></svg></span> 仪表盘(卡片式)
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('dashboard-plan-a');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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"/></svg></span> 仪表盘(方案A)⭐
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('dashboard-pro');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></span> 仪表盘(Pro)
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('dashboard-final');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg></span> 仪表盘(最终)⭐
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('dashboard-design');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/></svg></span> 仪表盘(Design)🆕
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('services');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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"/><circle cx="6" cy="18" r="1"/></svg></span> 服务管理
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-section">
|
||
<p class="sidebar-section-title">告警</p>
|
||
<a class="sidebar-item" href="#" onclick="showPage('settings');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.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-4 0v-.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-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 0-4h.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 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.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 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 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span> 告警设置
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('alerts');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg></span> 告警历史
|
||
</a>
|
||
<a class="sidebar-item" href="#" onclick="showPage('history');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></span> 状态历史
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-section">
|
||
<p class="sidebar-section-title">管理</p>
|
||
<a class="sidebar-item" href="#" onclick="showPage('users');return false">
|
||
<span class="sidebar-item-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg></span> 用户管理
|
||
</a>
|
||
</div>
|
||
</nav>
|
||
<div class="sidebar-user">
|
||
<div class="sidebar-user-inner">
|
||
<div class="sidebar-user-avatar">A</div>
|
||
<div>
|
||
<div class="sidebar-user-name">admin</div>
|
||
<div class="sidebar-user-role">管理员</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ==================== 主内容区 ==================== -->
|
||
<main class="main">
|
||
<header class="header">
|
||
<div class="header-inner">
|
||
<div class="header-left">
|
||
<span class="header-breadcrumb">monitor-ai / <span id="breadcrumb-page">仪表盘</span></span>
|
||
</div>
|
||
<div class="header-right">
|
||
<span style="font-size:var(--text-sm);color:var(--muted)">
|
||
Worker: <span style="color:var(--success);font-weight:500">运行中</span> · 自动刷新: 30s
|
||
</span>
|
||
<button class="theme-toggle" onclick="toggleTheme()" title="切换主题">🌓</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="content">
|
||
|
||
<!-- ==================== 页面 1: 仪表盘 ==================== -->
|
||
<div id="page-dashboard" class="page active">
|
||
|
||
<!-- 统计卡片 -->
|
||
<div class="stats-grid">
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">正常服务</span>
|
||
<div class="stat-card-icon" style="background:var(--success-subtle);color:var(--success)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value">10</div>
|
||
<div class="stat-card-sub">共 11 个监控服务</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">异常服务</span>
|
||
<div class="stat-card-icon" style="background:var(--danger-subtle);color:var(--danger)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value" style="color:var(--danger)">1</div>
|
||
<div class="stat-card-sub">Authelia SSO 异常</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">未知状态</span>
|
||
<div class="stat-card-icon" style="background:var(--warning-subtle);color:var(--warning)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value">0</div>
|
||
<div class="stat-card-sub">所有服务已检查</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">最后检查</span>
|
||
<div class="stat-card-icon" style="background:var(--accent-subtle);color:var(--accent)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value" style="font-size:var(--text-xl)">3 秒前</div>
|
||
<div class="stat-card-sub">2026-07-01 14:35:00</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 服务状态列表 -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<span class="card-title">服务状态</span>
|
||
<button class="btn btn-sm btn-secondary" onclick="showToast('已手动刷新所有服务状态')">立即刷新</button>
|
||
</div>
|
||
<div class="card-body" style="padding:0;">
|
||
<div class="service-list" style="padding:0;">
|
||
|
||
<!-- 异常服务(展开) -->
|
||
<div class="service-card open">
|
||
<div class="service-card-header" onclick="this.parentElement.classList.toggle('open')">
|
||
<div class="service-card-left">
|
||
<span class="status-dot status-dot-abnormal"></span>
|
||
<span style="font-weight:600;color:var(--fg)">Authelia SSO</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="service-card-right">
|
||
<span style="color:var(--danger);font-weight:500;">异常 5m 23s</span>
|
||
<span style="color:var(--muted-subtle)">▶</span>
|
||
</div>
|
||
</div>
|
||
<div class="service-card-body">
|
||
<div class="service-card-body-inner">
|
||
<div class="check-detail">
|
||
<span class="status-dot status-dot-abnormal"></span>
|
||
<span style="flex:1">HTTP GET http://authelia:9091/api/health</span>
|
||
<span class="tag tag-red">连接超时 (10s)</span>
|
||
</div>
|
||
<div class="check-detail">
|
||
<span class="status-dot status-dot-normal"></span>
|
||
<span style="flex:1">Docker check: authelia</span>
|
||
<span class="tag tag-green">running</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 正常服务 -->
|
||
<div class="service-card">
|
||
<div class="service-card-header" onclick="this.parentElement.classList.toggle('open')">
|
||
<div class="service-card-left">
|
||
<span class="status-dot status-dot-normal"></span>
|
||
<span style="font-weight:500;color:var(--fg)">Redis</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="service-card-right">
|
||
<span style="color:var(--muted)">正常</span>
|
||
<span style="color:var(--muted-subtle)">▶</span>
|
||
</div>
|
||
</div>
|
||
<div class="service-card-body">
|
||
<div class="service-card-body-inner">
|
||
<div class="check-detail">
|
||
<span class="status-dot status-dot-normal"></span>
|
||
<span>Docker check: redis</span>
|
||
<span class="tag tag-green">running</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="service-card">
|
||
<div class="service-card-header" onclick="this.parentElement.classList.toggle('open')">
|
||
<div class="service-card-left">
|
||
<span class="status-dot status-dot-normal"></span>
|
||
<span style="font-weight:500;color:var(--fg)">LLDAP</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="service-card-right"><span style="color:var(--muted)">正常</span><span style="color:var(--muted-subtle)">▶</span></div>
|
||
</div>
|
||
<div class="service-card-body">
|
||
<div class="service-card-body-inner">
|
||
<div class="check-detail"><span class="status-dot status-dot-normal"></span><span>HTTP GET http://ldap-ai:17170</span><span class="tag tag-green">200 OK</span></div>
|
||
<div class="check-detail"><span class="status-dot status-dot-normal"></span><span>Docker check: ldap-ai</span><span class="tag tag-green">running</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">OA 门户</span><span class="tag tag-green">warning</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">资产管理</span><span class="tag tag-green">warning</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">工单系统</span><span class="tag tag-green">warning</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">Gitea 代码托管</span><span class="tag tag-green">warning</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">Nginx 代理</span><span class="tag tag-red">critical</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">官网 (www-ai)</span><span class="tag tag-green">warning</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">云平台 (cloud-ai)</span><span class="tag tag-green">warning</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
<div class="service-card"><div class="service-card-header" onclick="this.parentElement.classList.toggle('open')"><div class="service-card-left"><span class="status-dot status-dot-normal"></span><span style="font-weight:500;color:var(--fg)">Token 工厂 (token-ai)</span><span class="tag tag-green">warning</span></div><div class="service-card-right"><span style="color:var(--muted)">正常</span></div></div></div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 1b: 卡片式仪表盘 ==================== -->
|
||
<div id="page-dashboard-cards" class="page">
|
||
|
||
<!-- 统计卡片(同上) -->
|
||
<div class="stats-grid">
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">正常服务</span>
|
||
<div class="stat-card-icon" style="background:var(--success-subtle);color:var(--success)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value">10</div>
|
||
<div class="stat-card-sub">共 11 个监控服务</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">异常服务</span>
|
||
<div class="stat-card-icon" style="background:var(--danger-subtle);color:var(--danger)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value" style="color:var(--danger)">1</div>
|
||
<div class="stat-card-sub">Authelia SSO 异常</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">未知状态</span>
|
||
<div class="stat-card-icon" style="background:var(--warning-subtle);color:var(--warning)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value">0</div>
|
||
<div class="stat-card-sub">所有服务已检查</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-card-header">
|
||
<span class="stat-card-title">最后检查</span>
|
||
<div class="stat-card-icon" style="background:var(--accent-subtle);color:var(--accent)"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div>
|
||
</div>
|
||
<div class="stat-card-value" style="font-size:var(--text-xl)">3 秒前</div>
|
||
<div class="stat-card-sub">2026-07-01 14:35:00</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 卡片式服务网格 -->
|
||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-4)">
|
||
<span style="font-size:var(--text-lg);font-weight:600;color:var(--fg)">服务状态</span>
|
||
<span style="font-size:var(--text-sm);color:var(--muted)">点击卡片展开检查详情</span>
|
||
</div>
|
||
|
||
<div class="card-grid">
|
||
|
||
<!-- 异常服务 -->
|
||
<div class="svc-card abnormal open" onclick="this.classList.toggle('open')">
|
||
<div class="svc-card-header">
|
||
<span class="svc-card-name"><span class="status-dot status-dot-abnormal"></span> Authelia SSO</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="svc-card-countdown">5m 23s</div>
|
||
<div class="svc-card-label">异常持续时长</div>
|
||
<div class="svc-card-error">HTTP GET http://authelia:9091/api/health → 连接超时 (10s)</div>
|
||
<div class="svc-card-body-expand">
|
||
<div class="check-detail"><span class="status-dot status-dot-abnormal"></span><span>HTTP 检查</span><span class="tag tag-red">连接超时</span></div>
|
||
<div class="check-detail"><span class="status-dot status-dot-normal"></span><span>Docker 检查</span><span class="tag tag-green">running</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 正常服务 × 10 -->
|
||
<div class="svc-card" onclick="this.classList.toggle('open')">
|
||
<div class="svc-card-header">
|
||
<span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Redis</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="svc-card-countdown" style="color:var(--success);">正常</div>
|
||
<div class="svc-card-label">运行中</div>
|
||
<div class="svc-card-body-expand"><div class="check-detail"><span class="status-dot status-dot-normal"></span><span>Docker check</span><span class="tag tag-green">running</span></div></div>
|
||
</div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')">
|
||
<div class="svc-card-header">
|
||
<span class="svc-card-name"><span class="status-dot status-dot-normal"></span> LLDAP</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="svc-card-countdown" style="color:var(--success);">正常</div>
|
||
<div class="svc-card-label">HTTP + Docker 均正常</div>
|
||
<div class="svc-card-body-expand"><div class="check-detail"><span class="status-dot status-dot-normal"></span><span>HTTP GET http://ldap-ai:17170</span><span class="tag tag-green">200 OK</span></div><div class="check-detail"><span class="status-dot status-dot-normal"></span><span>Docker check</span><span class="tag tag-green">running</span></div></div>
|
||
</div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> OA 门户</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 资产管理</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 工单系统</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Gitea 代码托管</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Nginx 代理</span><span class="tag tag-red">critical</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 官网 (www-ai)</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 云平台 (cloud-ai)</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Token 工厂 (token-ai)</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">运行中</div></div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 1f: 最终(Design统计条 + 4大卡片 + 4列服务网格) ==================== -->
|
||
<div id="page-dashboard-final" class="page">
|
||
|
||
<!-- 标题行(最顶部) -->
|
||
<div class="ds-header" style="margin-bottom:32px;">
|
||
<h1>服务状态监控 <span>· 11 个服务</span></h1>
|
||
<p>实时健康检查 · 本月可用率 99.8% · 30 秒轮询</p>
|
||
</div>
|
||
|
||
<!-- 状态统计条 -->
|
||
<div class="ds-stats" style="margin-bottom:var(--space-5);">
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">正常</span>
|
||
<span class="ds-stat-value" style="color:var(--success)">10</span>
|
||
<span class="ds-stat-sub">共 11 个监控服务</span>
|
||
</div>
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">异常</span>
|
||
<span class="ds-stat-value" style="color:var(--danger)">1</span>
|
||
<span class="ds-stat-sub">Authelia SSO</span>
|
||
</div>
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">未知</span>
|
||
<span class="ds-stat-value" style="color:var(--muted)">0</span>
|
||
</div>
|
||
<div class="ds-stat" style="text-align:right">
|
||
<span class="ds-stat-label">最后检查</span>
|
||
<span class="ds-stat-value" style="font-size:var(--text-base);font-weight:500">3 秒前</span>
|
||
<span class="ds-stat-sub">Worker 运行中 · 30s 轮询</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- KPI 统计条 -->
|
||
<div class="ds-stats" style="margin-bottom:32px;">
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">本月可用率</span>
|
||
<span class="ds-stat-value" style="color:var(--success)">99.8%</span>
|
||
<span class="ds-stat-sub">本月故障 3 次</span>
|
||
</div>
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">平均恢复时间</span>
|
||
<span class="ds-stat-value" style="color:var(--fg)">2m 30s</span>
|
||
<span class="ds-stat-sub">较上月缩短 15s</span>
|
||
</div>
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">本月告警</span>
|
||
<span class="ds-stat-value" style="color:var(--fg)">12</span>
|
||
<span class="ds-stat-sub">推送成功率 95.8%</span>
|
||
</div>
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">活跃渠道</span>
|
||
<span class="ds-stat-value" style="color:var(--fg)">2</span>
|
||
<span class="ds-stat-sub">运维群 · 开发群</span>
|
||
</div>
|
||
</div>
|
||
|
||
<hr style="border:none;border-top:1px solid var(--border);margin:0 0 32px 0;">
|
||
|
||
<div class="card-grid" style="grid-template-columns:repeat(4,1fr);gap:var(--space-5);">
|
||
<div class="svc-card abnormal open" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-abnormal"></span> Authelia SSO</span><span class="tag tag-red">critical</span></div><div class="svc-card-countdown">5m 23s</div><div class="svc-card-label">异常持续时长</div><div class="svc-card-error">HTTP 连接超时 (10s)</div><div class="svc-card-body-expand"><div class="check-detail"><span class="status-dot status-dot-abnormal"></span><span>HTTP 检查</span><span class="tag tag-red">超时</span></div><div class="check-detail"><span class="status-dot status-dot-normal"></span><span>Docker 检查</span><span class="tag tag-green">running</span></div></div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Redis</span><span class="tag tag-red">critical</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> LLDAP</span><span class="tag tag-red">critical</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> OA 门户</span><span class="tag tag-green">warning</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 资产管理</span><span class="tag tag-green">warning</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 工单系统</span><span class="tag tag-green">warning</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Gitea</span><span class="tag tag-green">warning</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Nginx</span><span class="tag tag-red">critical</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> www-ai</span><span class="tag tag-green">warning</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> cloud-ai</span><span class="tag tag-green">warning</span></div><div class="svc-card-label">运行中</div></div>
|
||
<div class="svc-card"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> token-ai</span><span class="tag tag-green">warning</span></div><div class="svc-card-label">运行中</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 1c: 方案 A(统计条 + 统一卡片网格) ==================== -->
|
||
<div id="page-dashboard-plan-a" class="page">
|
||
|
||
<!-- 统计条(无卡片边框,轻量文字) -->
|
||
<div class="stat-bar">
|
||
<div class="stat-bar-item">
|
||
<span class="stat-bar-dot stat-bar-dot-success"></span>
|
||
<div><div class="stat-bar-value">10</div><div class="stat-bar-label">正常</div></div>
|
||
</div>
|
||
<div class="stat-bar-divider"></div>
|
||
<div class="stat-bar-item">
|
||
<span class="stat-bar-dot stat-bar-dot-danger"></span>
|
||
<div><div class="stat-bar-value" style="color:var(--danger)">1</div><div class="stat-bar-label">异常</div></div>
|
||
</div>
|
||
<div class="stat-bar-divider"></div>
|
||
<div class="stat-bar-item">
|
||
<span class="stat-bar-dot stat-bar-dot-warning"></span>
|
||
<div><div class="stat-bar-value">0</div><div class="stat-bar-label">未知</div></div>
|
||
</div>
|
||
<div class="stat-bar-right">
|
||
<span style="color:var(--muted)">最后检查 3 秒前 · Worker 运行中 · 自动刷新 30s</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 统一卡片网格(所有卡片相同尺寸) -->
|
||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-4)">
|
||
<span style="font-size:var(--text-base);font-weight:600;color:var(--fg)">服务状态</span>
|
||
<span style="font-size:var(--text-sm);color:var(--muted)">11 个服务 · 点击卡片展开详情</span>
|
||
</div>
|
||
|
||
<div class="card-grid">
|
||
|
||
<div class="svc-card abnormal open" onclick="this.classList.toggle('open')">
|
||
<div class="svc-card-header">
|
||
<span class="svc-card-name"><span class="status-dot status-dot-abnormal"></span> Authelia SSO</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="svc-card-countdown">5m 23s</div>
|
||
<div class="svc-card-label">异常持续时长</div>
|
||
<div class="svc-card-error">HTTP GET authelia:9091/api/health → 连接超时 (10s)</div>
|
||
<div class="svc-card-body-expand">
|
||
<div class="check-detail"><span class="status-dot status-dot-abnormal"></span><span>HTTP 检查</span><span class="tag tag-red">连接超时</span></div>
|
||
<div class="check-detail"><span class="status-dot status-dot-normal"></span><span>Docker 检查</span><span class="tag tag-green">running</span></div>
|
||
</div>
|
||
<div class="svc-card-footer"><span class="svc-card-label">展开详情 ▴</span></div>
|
||
</div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Redis</span><span class="tag tag-red">critical</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">Docker: running</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> LLDAP</span><span class="tag tag-red">critical</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP + Docker 均正常</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> OA 门户</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP: 200 OK</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 资产管理</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP: 200 OK</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 工单系统</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP: 200 OK</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Gitea 代码托管</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP + Docker 均正常</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Nginx 代理</span><span class="tag tag-red">critical</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">Docker: running</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 官网 (www-ai)</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP: 200 OK</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> 云平台 (cloud-ai)</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP: 200 OK</div></div>
|
||
|
||
<div class="svc-card" onclick="this.classList.toggle('open')"><div class="svc-card-header"><span class="svc-card-name"><span class="status-dot status-dot-normal"></span> Token 工厂 (token-ai)</span><span class="tag tag-green">warning</span></div><div class="svc-card-countdown" style="color:var(--success);">正常</div><div class="svc-card-label">HTTP: 200 OK</div></div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 1d: Pro 仪表盘(Dark-First 专业监控风格) ==================== -->
|
||
<div id="page-dashboard-pro" class="page">
|
||
<div class="content-area">
|
||
|
||
<!-- 标题 -->
|
||
<div class="pro-header">
|
||
<div>
|
||
<h1 class="pro-title">服务状态监控</h1>
|
||
<p class="pro-title-sub">实时健康检查 · 11 个服务 · 30 秒轮询</p>
|
||
</div>
|
||
<div class="pro-actions">
|
||
<span style="font-size:var(--text-sm);color:var(--muted);display:flex;align-items:center;gap:var(--space-2)">
|
||
<span style="width:8px;height:8px;border-radius:50%;background:var(--success);display:inline-block;"></span> Worker 运行中
|
||
</span>
|
||
<button class="btn btn-sm btn-secondary" onclick="showToast('已手动刷新')">立即刷新</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 统计条 -->
|
||
<div class="pro-statbar">
|
||
<div class="pro-stat-item">
|
||
<span class="pro-stat-item-label">正常</span>
|
||
<span class="pro-stat-item-value" style="color:var(--success)">10</span>
|
||
<span class="pro-stat-item-sub">90.9% 可用率</span>
|
||
</div>
|
||
<div class="pro-statbar-divider"></div>
|
||
<div class="pro-stat-item">
|
||
<span class="pro-stat-item-label">异常</span>
|
||
<span class="pro-stat-item-value" style="color:var(--danger)">1</span>
|
||
<span class="pro-stat-item-sub">Authelia SSO</span>
|
||
</div>
|
||
<div class="pro-statbar-divider"></div>
|
||
<div class="pro-stat-item">
|
||
<span class="pro-stat-item-label">未知</span>
|
||
<span class="pro-stat-item-value" style="color:var(--muted)">0</span>
|
||
</div>
|
||
<div class="pro-stat-item" style="text-align:right">
|
||
<span class="pro-stat-item-label">最后检查</span>
|
||
<span class="pro-stat-item-value" style="font-size:var(--text-lg);font-weight:500">3 秒前</span>
|
||
<span class="pro-stat-item-sub">2026-07-01 14:35:00</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 服务卡片网格 -->
|
||
<div class="pro-grid">
|
||
|
||
<!-- 异常 -->
|
||
<div class="pro-svc abnormal open" onclick="this.classList.toggle('open')">
|
||
<div class="pro-svc-top">
|
||
<span class="pro-svc-name"><span class="pro-svc-status-dot err"></span> Authelia SSO</span>
|
||
<span class="tag tag-red">critical</span>
|
||
</div>
|
||
<div class="pro-svc-body">
|
||
<span class="pro-svc-status-text err">5m 23s</span>
|
||
<span class="pro-svc-desc">HTTP 检查失败:连接超时 (10s)<br>Docker 检查正常</span>
|
||
</div>
|
||
<div class="pro-svc-footer">
|
||
<span class="pro-svc-footer-label">展开详情 ▴</span>
|
||
</div>
|
||
<div class="pro-svc-expand">
|
||
<div class="pro-svc-expand-item"><span class="pro-svc-status-dot err"></span> HTTP GET authelia:9091/api/health — 连接超时</div>
|
||
<div class="pro-svc-expand-item"><span class="pro-svc-status-dot ok" style="box-shadow:none"></span> Docker check — running</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 正常 × 10 -->
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> Redis</span><span class="tag tag-red">critical</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">Docker · running</span></div><div class="pro-svc-footer"><span class="pro-svc-footer-label">详情 ▸</span></div><div class="pro-svc-expand"><div class="pro-svc-expand-item"><span class="pro-svc-status-dot ok" style="box-shadow:none"></span> Docker check — running</div></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> LLDAP</span><span class="tag tag-red">critical</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK<br>Docker · running</span></div><div class="pro-svc-footer"><span class="pro-svc-footer-label">详情 ▸</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> OA 门户</span><span class="tag tag-green">warning</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> 资产管理</span><span class="tag tag-green">warning</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> 工单系统</span><span class="tag tag-green">warning</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> Gitea</span><span class="tag tag-green">warning</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK<br>Docker · running</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> Nginx</span><span class="tag tag-red">critical</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">Docker · running</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> www-ai</span><span class="tag tag-green">warning</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> cloud-ai</span><span class="tag tag-green">warning</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK</span></div></div>
|
||
|
||
<div class="pro-svc" onclick="this.classList.toggle('open')"><div class="pro-svc-top"><span class="pro-svc-name"><span class="pro-svc-status-dot ok"></span> token-ai</span><span class="tag tag-green">warning</span></div><div class="pro-svc-body"><span class="pro-svc-status-text ok">正常</span><span class="pro-svc-desc">HTTP · 200 OK</span></div></div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 1e: Design 仪表盘(精密仪器风格) ==================== -->
|
||
<div id="page-dashboard-design" class="page" style="padding:0;">
|
||
<div class="ds-root">
|
||
<div class="ds-inner">
|
||
|
||
<!-- 标题 -->
|
||
<div class="ds-header">
|
||
<h1>Infrastructure Status <span>· 11 services</span></h1>
|
||
<p>Real-time health monitoring · 30s polling · 99.8% uptime this month</p>
|
||
</div>
|
||
|
||
<!-- 统计 -->
|
||
<div class="ds-stats">
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">Healthy</span>
|
||
<span class="ds-stat-value" style="color:var(--ds-success)">10</span>
|
||
<span class="ds-stat-sub">90.9% available</span>
|
||
</div>
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">Degraded</span>
|
||
<span class="ds-stat-value" style="color:var(--ds-danger)">1</span>
|
||
<span class="ds-stat-sub">Authelia SSO</span>
|
||
</div>
|
||
<div class="ds-stat">
|
||
<span class="ds-stat-label">Unknown</span>
|
||
<span class="ds-stat-value" style="color:var(--ds-muted)">0</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 卡片网格 -->
|
||
<div class="ds-grid">
|
||
|
||
<!-- 异常 -->
|
||
<div class="ds-card abnormal open" onclick="this.classList.toggle('open')">
|
||
<div class="ds-card-top">
|
||
<span class="ds-card-name"><span class="ds-dot err"></span> Authelia SSO</span>
|
||
<span class="tag tag-red" style="opacity:.9">critical</span>
|
||
</div>
|
||
<div class="ds-card-value err">5m 23s</div>
|
||
<div class="ds-card-meta">HTTP connection timeout after 10s.<br>Docker container running normally.</div>
|
||
<div class="ds-card-footer"><span>Details ▴</span></div>
|
||
<div class="ds-card-expand">
|
||
<div class="ds-check"><span class="ds-check-dot err"></span> http://authelia:9091/api/health — timeout</div>
|
||
<div class="ds-check"><span class="ds-check-dot ok"></span> docker ps authelia — running</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 正常 -->
|
||
<div class="ds-card" onclick="this.classList.toggle('open')"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> Redis</span><span class="tag tag-red" style="opacity:.8">critical</span></div><div class="ds-card-value ok">Healthy</div><div class="ds-card-meta">Docker container running</div><div class="ds-card-footer"><span>Details ▸</span></div><div class="ds-card-expand"><div class="ds-check"><span class="ds-check-dot ok"></span> docker ps redis — Up 5 days</div></div></div>
|
||
|
||
<div class="ds-card" onclick="this.classList.toggle('open')"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> LLDAP</span><span class="tag tag-red" style="opacity:.8">critical</span></div><div class="ds-card-value ok">Healthy</div><div class="ds-card-meta">HTTP 200 · Docker running</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> OA</span><span class="tag tag-green" style="opacity:.8">warning</span></div><div class="ds-card-value ok">Healthy</div><div class="ds-card-meta">HTTP 200 OK</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> Assets</span><span class="tag tag-green" style="opacity:.8">warning</span></div><div class="ds-card-value ok">Healthy</div><div class="ds-card-meta">HTTP 200 OK</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> Issue</span><span class="tag tag-green" style="opacity:.8">warning</span></div><div class="ds-card-value ok">Healthy</div><div class="ds-card-meta">HTTP 200 OK</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> Gitea</span><span class="tag tag-green" style="opacity:.8">warning</span></div><div class="ds-card-value ok">Healthy</div><div class="ds-card-meta">HTTP 200 · Docker running</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> Nginx</span><span class="tag tag-red" style="opacity:.8">critical</span></div><div class="ds-card-value ok">Healthy</div><div class="ds-card-meta">Docker running</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> www-ai</span><span class="tag tag-green" style="opacity:.8">warning</span></div><div class="ds-card-value ok">Healthy</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> cloud-ai</span><span class="tag tag-green" style="opacity:.8">warning</span></div><div class="ds-card-value ok">Healthy</div></div>
|
||
|
||
<div class="ds-card"><div class="ds-card-top"><span class="ds-card-name"><span class="ds-dot ok"></span> token-ai</span><span class="tag tag-green" style="opacity:.8">warning</span></div><div class="ds-card-value ok">Healthy</div></div>
|
||
|
||
</div>
|
||
|
||
<div class="ds-footer">
|
||
<span>Last check 3s ago</span><span class="ds-footer-sep"></span>
|
||
<span>Worker running</span><span class="ds-footer-sep"></span>
|
||
<span>Auto-refresh 30s</span>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 2: 告警设置 ==================== -->
|
||
<div id="page-settings" class="page">
|
||
<h2 class="section-title">告警渠道设置</h2>
|
||
|
||
<div class="channel-health">
|
||
<span style="font-size:var(--text-sm);color:var(--muted);">推送通道:</span>
|
||
<div class="health-item"><span class="health-dot health-ok"></span> 运维群 <span class="tag tag-green">正常</span></div>
|
||
<div class="health-item"><span class="health-dot health-ok"></span> 开发群 <span class="tag tag-green">正常</span></div>
|
||
<div class="health-item"><span class="health-dot health-fail"></span> 备用群 <span class="tag tag-red">连续 3 次失败</span></div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-bottom:var(--space-6);">
|
||
<div class="card-header">
|
||
<span class="card-title">渠道 1: 运维群</span>
|
||
<div style="display:flex;gap:var(--space-2);">
|
||
<button class="btn btn-sm btn-primary" onclick="showToast('测试消息已发送到运维群')">测试推送</button>
|
||
<button class="btn btn-sm btn-secondary">删除</button>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="form-group">
|
||
<label class="form-label">Webhook URL</label>
|
||
<input class="form-input" value="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=82bacfb9-****" readonly style="color:var(--muted)">
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">告警级别</label>
|
||
<label class="form-checkbox"><input type="checkbox" checked> critical</label>
|
||
<label class="form-checkbox"><input type="checkbox" checked> warning</label>
|
||
<label class="form-checkbox"><input type="checkbox"> info</label>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">冷却时间(分钟)</label>
|
||
<input class="form-input" value="5" style="width:80px">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">免打扰时段</label>
|
||
<label class="form-checkbox"><input type="checkbox" checked> 启用免打扰</label>
|
||
<div style="display:flex;gap:var(--space-2);align-items:center;margin-top:var(--space-2)">
|
||
<input class="form-input" value="23:00" style="width:80px">
|
||
<span style="color:var(--muted)">至</span>
|
||
<input class="form-input" value="07:00" style="width:80px">
|
||
</div>
|
||
<label class="form-checkbox" style="margin-top:var(--space-2)"><input type="checkbox" checked> critical 仍然推送</label>
|
||
</div>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button class="btn btn-primary" onclick="showToast('运维群设置已保存')">保存设置</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-bottom:var(--space-6);">
|
||
<div class="card-header">
|
||
<span class="card-title">渠道 2: 开发群</span>
|
||
<div style="display:flex;gap:var(--space-2);">
|
||
<button class="btn btn-sm btn-primary" onclick="showToast('测试消息已发送到开发群')">测试推送</button>
|
||
<button class="btn btn-sm btn-secondary">删除</button>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="form-group">
|
||
<label class="form-label">Webhook URL</label>
|
||
<input class="form-input" value="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=********" readonly style="color:var(--muted)">
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">告警级别</label>
|
||
<label class="form-checkbox"><input type="checkbox" checked> critical</label>
|
||
<label class="form-checkbox"><input type="checkbox"> warning</label>
|
||
<label class="form-checkbox"><input type="checkbox"> info</label>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">冷却时间(分钟)</label>
|
||
<input class="form-input" value="10" style="width:80px">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">免打扰时段</label>
|
||
<label class="form-checkbox"><input type="checkbox"> 不启用免打扰</label>
|
||
</div>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button class="btn btn-primary" onclick="showToast('开发群设置已保存')">保存设置</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button class="btn btn-secondary" onclick="showToast('新渠道已添加')">+ 添加渠道</button>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 3: 告警历史 ==================== -->
|
||
<div id="page-alerts" class="page">
|
||
<h2 class="section-title">告警历史</h2>
|
||
<div class="card">
|
||
<div class="card-body">
|
||
<div style="display:flex;gap:var(--space-4);margin-bottom:var(--space-6);">
|
||
<select class="form-input" style="width:auto;"><option>全部级别</option><option>critical</option><option>warning</option><option>info</option></select>
|
||
<select class="form-input" style="width:auto;"><option>全部渠道</option><option>运维群</option><option>开发群</option></select>
|
||
<select class="form-input" style="width:auto;"><option>最近 7 天</option><option>最近 30 天</option></select>
|
||
</div>
|
||
<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm);">
|
||
<thead><tr style="background:var(--bg-subtle);border-bottom:1px solid var(--border);">
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;color:var(--fg-subtle)">时间</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;color:var(--fg-subtle)">级别</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;color:var(--fg-subtle)">渠道</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;color:var(--fg-subtle)">服务</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;color:var(--fg-subtle)">类型</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;color:var(--fg-subtle)">结果</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4)">14:35:00</td><td style="padding:var(--space-3) var(--space-4)"><span class="badge badge-danger">critical</span></td><td style="padding:var(--space-3) var(--space-4)">运维群</td><td style="padding:var(--space-3) var(--space-4)">Authelia SSO</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-red">异常告警</span></td><td style="padding:var(--space-3) var(--space-4);color:var(--success)">✅</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4)">13:20:15</td><td style="padding:var(--space-3) var(--space-4)"><span class="badge badge-danger">critical</span></td><td style="padding:var(--space-3) var(--space-4)">运维群</td><td style="padding:var(--space-3) var(--space-4)">Redis</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-green">恢复通知</span></td><td style="padding:var(--space-3) var(--space-4);color:var(--success)">✅</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4)">13:17:30</td><td style="padding:var(--space-3) var(--space-4)"><span class="badge badge-danger">critical</span></td><td style="padding:var(--space-3) var(--space-4)">运维群</td><td style="padding:var(--space-3) var(--space-4)">Redis</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-red">异常告警</span></td><td style="padding:var(--space-3) var(--space-4);color:var(--success)">✅</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4)">13:02:00</td><td style="padding:var(--space-3) var(--space-4)"><span class="badge badge-danger">critical</span></td><td style="padding:var(--space-3) var(--space-4)">开发群</td><td style="padding:var(--space-3) var(--space-4)">Redis</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-red">异常告警</span></td><td style="padding:var(--space-3) var(--space-4);color:var(--danger)">❌</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4)">09:45:00</td><td style="padding:var(--space-3) var(--space-4)"><span class="badge badge-success">warning</span></td><td style="padding:var(--space-3) var(--space-4)">运维群</td><td style="padding:var(--space-3) var(--space-4)">Nginx 代理</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-indigo">抖动告警</span></td><td style="padding:var(--space-3) var(--space-4);color:var(--success)">✅</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div style="display:flex;justify-content:center;gap:var(--space-1);margin-top:var(--space-6);">
|
||
<button class="btn btn-sm btn-secondary" disabled>上一页</button>
|
||
<button class="btn btn-sm btn-primary">1</button>
|
||
<button class="btn btn-sm btn-secondary">2</button>
|
||
<button class="btn btn-sm btn-secondary">下一页</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 4: 状态历史 ==================== -->
|
||
<div id="page-history" class="page">
|
||
<h2 class="section-title">状态变更历史</h2>
|
||
<div class="card">
|
||
<div class="card-body">
|
||
<div style="display:flex;gap:var(--space-4);margin-bottom:var(--space-6);">
|
||
<select class="form-input" style="width:auto;"><option>全部服务</option></select>
|
||
<select class="form-input" style="width:auto;"><option>最近 7 天</option></select>
|
||
</div>
|
||
<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm);">
|
||
<thead><tr style="background:var(--bg-subtle);">
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;">服务</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;">异常开始</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;">恢复时间</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;">持续</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;font-weight:600;">关联告警</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);background:var(--danger-subtle);"><td style="padding:var(--space-3) var(--space-4);font-weight:500;">Authelia SSO</td><td style="padding:var(--space-3) var(--space-4)">14:30:00</td><td style="padding:var(--space-3) var(--space-4)">—</td><td style="padding:var(--space-3) var(--space-4);color:var(--danger);">进行中</td><td style="padding:var(--space-3) var(--space-4)">1 条</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4)">Redis</td><td style="padding:var(--space-3) var(--space-4)">13:17:30</td><td style="padding:var(--space-3) var(--space-4)">13:20:15</td><td style="padding:var(--space-3) var(--space-4)">2m45s</td><td style="padding:var(--space-3) var(--space-4)">2 条</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4)">Nginx 代理</td><td style="padding:var(--space-3) var(--space-4)">09:40:00</td><td style="padding:var(--space-3) var(--space-4)">09:45:00</td><td style="padding:var(--space-3) var(--space-4)">5m00s</td><td style="padding:var(--space-3) var(--space-4)">1 条(抖动)</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div style="display:flex;gap:var(--space-6);margin-top:var(--space-6);">
|
||
<div class="stat-card" style="flex:1;">
|
||
<div class="stat-card-title">本月可用率</div>
|
||
<div class="stat-card-value" style="color:var(--success);margin:0;">99.8%</div>
|
||
</div>
|
||
<div class="stat-card" style="flex:1;">
|
||
<div class="stat-card-title">平均恢复时间</div>
|
||
<div class="stat-card-value" style="font-size:var(--text-xl);margin:0;">2 分 30 秒</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 5: 服务管理 ==================== -->
|
||
<div id="page-services" class="page">
|
||
<h2 class="section-title">服务管理</h2>
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<span class="card-title">监控服务清单</span>
|
||
<button class="btn btn-primary btn-sm" onclick="showToast('添加服务对话框(预览模式)')">+ 添加服务</button>
|
||
</div>
|
||
<div class="card-body" style="padding:0;">
|
||
<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm);">
|
||
<thead><tr style="background:var(--bg-subtle);">
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">名称</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">类别</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">告警级别</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">检查方式</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">状态</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">操作</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4);font-weight:500;">Authelia SSO</td><td style="padding:var(--space-3) var(--space-4)">endpoint</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-red">critical</span></td><td style="padding:var(--space-3) var(--space-4)">HTTP + Docker</td><td style="padding:var(--space-3) var(--space-4)"><span class="status-badge status-abnormal">异常</span></td><td style="padding:var(--space-3) var(--space-4)"><button class="btn btn-sm btn-ghost">编辑</button><button class="btn btn-sm btn-ghost">检查</button></td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4);font-weight:500;">Redis</td><td style="padding:var(--space-3) var(--space-4)">container</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-red">critical</span></td><td style="padding:var(--space-3) var(--space-4)">Docker</td><td style="padding:var(--space-3) var(--space-4)"><span class="status-badge status-normal">正常</span></td><td style="padding:var(--space-3) var(--space-4)"><button class="btn btn-sm btn-ghost">编辑</button></td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4);font-weight:500;">OA 门户</td><td style="padding:var(--space-3) var(--space-4)">endpoint</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-green">warning</span></td><td style="padding:var(--space-3) var(--space-4)">HTTP</td><td style="padding:var(--space-3) var(--space-4)"><span class="status-badge status-normal">正常</span></td><td style="padding:var(--space-3) var(--space-4)"><button class="btn btn-sm btn-ghost">编辑</button></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 页面 6: 用户管理 ==================== -->
|
||
<div id="page-users" class="page">
|
||
<h2 class="section-title">用户管理</h2>
|
||
<div class="card">
|
||
<div class="card-body" style="padding:0;">
|
||
<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm);">
|
||
<thead><tr style="background:var(--bg-subtle);">
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">用户名</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">显示名</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">邮箱</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">角色</th>
|
||
<th style="padding:var(--space-3) var(--space-4);text-align:left;">操作</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4);font-weight:500;">localadmin</td><td style="padding:var(--space-3) var(--space-4)">超级管理员</td><td style="padding:var(--space-3) var(--space-4)">—</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-indigo">admin</span></td><td style="padding:var(--space-3) var(--space-4);color:var(--muted)">不可修改</td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4);">gaoxiaopei</td><td style="padding:var(--space-3) var(--space-4)">高晓沛</td><td style="padding:var(--space-3) var(--space-4)">gaoxiaopei@tlyq.ai</td><td style="padding:var(--space-3) var(--space-4)"><select class="form-input" style="width:auto;padding:2px var(--space-2);"><option>admin</option><option>viewer</option></select></td><td style="padding:var(--space-3) var(--space-4)"><button class="btn btn-sm btn-primary">保存</button></td></tr>
|
||
<tr style="border-bottom:1px solid var(--border-subtle);"><td style="padding:var(--space-3) var(--space-4);">zhangsan</td><td style="padding:var(--space-3) var(--space-4)">张三</td><td style="padding:var(--space-3) var(--space-4)">zhangsan@tlyq.ai</td><td style="padding:var(--space-3) var(--space-4)"><span class="tag tag-green">viewer</span></td><td style="padding:var(--space-3) var(--space-4)"><button class="btn btn-sm btn-primary">保存</button></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<!-- Toast -->
|
||
<div id="toast" class="toast">
|
||
<div class="toast-title">提示</div>
|
||
<div class="toast-body" id="toast-body"></div>
|
||
</div>
|
||
|
||
<script>
|
||
// 页面切换
|
||
function showPage(name) {
|
||
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||
document.getElementById('page-' + name).classList.add('active');
|
||
document.querySelectorAll('.sidebar-item').forEach(i => i.classList.remove('active'));
|
||
event.target.closest('.sidebar-item').classList.add('active');
|
||
const names = {dashboard:'仪表盘(行式)','dashboard-cards':'仪表盘(卡片式)','dashboard-plan-a':'仪表盘(方案A)','dashboard-pro':'仪表盘(Pro)','dashboard-design':'仪表盘(Design)','dashboard-final':'仪表盘(最终)',services:'服务管理',settings:'告警设置',alerts:'告警历史',history:'状态历史',users:'用户管理'};
|
||
document.getElementById('breadcrumb-page').textContent = names[name] || name;
|
||
}
|
||
|
||
// 主题切换
|
||
function toggleTheme() {
|
||
document.documentElement.classList.toggle('dark');
|
||
}
|
||
|
||
// Toast 提示
|
||
function showToast(msg) {
|
||
const t = document.getElementById('toast');
|
||
document.getElementById('toast-body').textContent = msg;
|
||
t.classList.add('show');
|
||
setTimeout(() => t.classList.remove('show'), 2500);
|
||
}
|
||
|
||
// 键盘切换:1-6 键切换页面
|
||
document.addEventListener('keydown', e => {
|
||
const pages = ['dashboard','services','settings','alerts','history','users'];
|
||
const n = parseInt(e.key);
|
||
if (n >= 1 && n <= 6) showPage(pages[n-1]);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|