583 lines
45 KiB
HTML
583 lines
45 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-TW">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=1440">
|
||
<title>AWOOOI 指令中心 — 最終版</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=VT323&family=JetBrains+Mono:wght@400;500&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||
<style>
|
||
/*
|
||
方案 2: Sidebar 品牌 + 內容區標題列 (Linear/Notion 風格)
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
- 無獨立 Header 橫條
|
||
- 品牌在 Sidebar 頂部
|
||
- 標題/Tab/操作在內容區頂部
|
||
- 所有元素嚴格對齊
|
||
*/
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
:root{
|
||
--bg:#f5f4ed;--card:#fff;--surface:#faf9f3;--bdr:#e0ddd4;
|
||
--text:#141413;--text2:#555550;--text3:#87867f;
|
||
--accent:#d97757;--green:#22C55E;--red:#cc2200;--blue:#4A90D9;--orange:#F59E0B;--purple:#A855F7;
|
||
--sb-w:200px;--gap:14px;--radius:10px;--border:.5px solid #e0ddd4;
|
||
}
|
||
body{font-family:'DM Mono','Inter',system-ui,monospace;background:var(--bg);color:var(--text);font-size:13px;-webkit-font-smoothing:antialiased;overflow:hidden;height:100vh;line-height:1.5}
|
||
|
||
/* ═══ LAYOUT ═══ */
|
||
.layout{display:flex;height:100vh}
|
||
|
||
/* ═══ SIDEBAR (200px) ═══ */
|
||
.sidebar{width:var(--sb-w);flex-shrink:0;background:var(--surface);border-right:var(--border);display:flex;flex-direction:column;overflow:hidden}
|
||
|
||
/* Brand Area (品牌區, 72px 高) */
|
||
.brand{height:72px;padding:0 16px;display:flex;align-items:center;gap:10px;border-bottom:var(--border);flex-shrink:0}
|
||
.brand svg{flex-shrink:0}
|
||
.brand-text{display:inline-flex;align-items:baseline;gap:0}
|
||
.brand-text .a,.brand-text .i{font-family:'DM Mono',monospace;font-size:22px;font-weight:700;color:var(--text)}
|
||
.brand-text .w{font-family:'VT323',monospace;font-size:30px;color:var(--accent);letter-spacing:0;line-height:1}
|
||
|
||
/* Nav */
|
||
.nav{flex:1;overflow-y:auto;padding:8px}
|
||
.nav-item{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:6px;font-size:13px;color:var(--text2);cursor:pointer;transition:all .12s;margin-bottom:1px}
|
||
.nav-item:hover{background:rgba(0,0,0,.03)}
|
||
.nav-item.on{background:rgba(217,119,87,.08);color:var(--accent);font-weight:500}
|
||
.nav-dot{width:5px;height:5px;border-radius:50%;flex-shrink:0}
|
||
.nav-badge{margin-left:auto;background:var(--red);color:#fff;font-size:7px;padding:1px 5px;border-radius:6px;font-weight:700;min-width:14px;text-align:center}
|
||
.nav-sep{height:var(--border);background:var(--bdr);margin:8px 12px}
|
||
.nav-label{font-size:7px;text-transform:uppercase;letter-spacing:1.2px;color:var(--text3);padding:8px 12px 4px;font-weight:600}
|
||
|
||
/* Nav Bottom */
|
||
.nav-bottom{border-top:var(--border);padding:8px;flex-shrink:0}
|
||
|
||
/* ═══ CONTENT AREA ═══ */
|
||
.content{flex:1;display:flex;flex-direction:column;overflow:hidden}
|
||
|
||
/* Title Bar (內容區頂部, 48px) */
|
||
.title-bar{height:48px;padding:0 20px;display:flex;align-items:center;gap:16px;border-bottom:var(--border);background:var(--surface);flex-shrink:0}
|
||
.page-title{font-family:'Syne','Inter',sans-serif;font-size:20px;font-weight:800;color:var(--text);letter-spacing:-.3px}
|
||
.title-actions{margin-left:auto;display:flex;align-items:center;gap:10px}
|
||
.ai-status{display:flex;align-items:center;gap:5px;padding:4px 10px;border:var(--border);border-radius:20px;font-size:9px;color:var(--text2)}
|
||
.ai-dot{width:5px;height:5px;border-radius:50%;background:var(--green);animation:blink 2s infinite}
|
||
@keyframes blink{0%,100%{opacity:1}50%{opacity:.3}}
|
||
.lang-btn{padding:4px 10px;font-family:'DM Mono',monospace;font-size:10px;border:var(--border);border-radius:16px;cursor:pointer;background:transparent;color:var(--text3)}
|
||
.lang-btn.on{background:var(--text);color:#fff;border-color:var(--text)}
|
||
.avatar{width:24px;height:24px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;color:#fff}
|
||
|
||
/* Tab Bar (36px) */
|
||
.tab-bar{height:36px;padding:0 20px;display:flex;align-items:stretch;border-bottom:var(--border);background:var(--card);flex-shrink:0}
|
||
.tab{padding:0 14px;font-size:12px;font-weight:500;color:var(--text3);cursor:pointer;border-bottom:2px solid transparent;display:flex;align-items:center;gap:4px;transition:all .12s}
|
||
.tab:hover{color:var(--text2)}
|
||
.tab.on{color:var(--accent);border-bottom-color:var(--accent);font-weight:600}
|
||
.tab-badge{background:var(--red);color:#fff;font-size:7px;padding:0 4px;border-radius:4px;font-weight:700;min-width:14px;text-align:center}
|
||
|
||
/* ═══ KPI Strip (融入背景, 不反白) ═══ */
|
||
.kpi-strip{display:flex;padding:10px 20px;gap:12px;flex-shrink:0}
|
||
.kpi-card{flex:1;background:var(--card);border:var(--border);border-radius:8px;padding:8px 12px}
|
||
.kpi-label{font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:var(--text3);font-weight:500}
|
||
.kpi-row{display:flex;align-items:baseline;gap:4px;margin-top:2px}
|
||
.kpi-val{font-size:22px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1}
|
||
.kpi-sub{font-size:9px;color:var(--text2)}
|
||
.kpi-trend{font-size:9px;font-weight:500}
|
||
.kpi-bar{height:2px;border-radius:1px;background:#ebe8df;margin-top:4px;overflow:hidden}
|
||
.kpi-bar-f{height:100%;border-radius:1px}
|
||
|
||
/* ═══ MAIN BODY (2 欄) ═══ */
|
||
.main-body{flex:1;display:flex;gap:var(--gap);padding:0 20px var(--gap);overflow:hidden}
|
||
|
||
/* Left Column (60%) */
|
||
.col-left{flex:6;min-width:0;overflow-y:auto;display:flex;flex-direction:column;gap:var(--gap);padding-top:var(--gap);padding-bottom:40px}
|
||
.col-left .card{flex-shrink:0}
|
||
|
||
/* Right Column (40%) — 整欄可捲動,卡片自然撐開不截斷 */
|
||
.col-right{flex:4;min-width:0;overflow-y:auto;display:flex;flex-direction:column;gap:var(--gap);padding-top:var(--gap);padding-bottom:40px}
|
||
.col-right .card{flex-shrink:0}
|
||
|
||
/* ═══ SHARED CARD ═══ */
|
||
.card{background:var(--card);border:var(--border);border-radius:var(--radius);overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,.04)}
|
||
.card-header{padding:10px 14px;border-bottom:var(--border);display:flex;align-items:center;gap:8px;background:var(--surface)}
|
||
.card-dot{width:5px;height:5px;border-radius:50%;background:var(--accent);flex-shrink:0}
|
||
.card-title{font-size:14px;font-weight:700;letter-spacing:.3px}
|
||
.card-action{margin-left:auto;font-size:11px;color:var(--blue);cursor:pointer;font-weight:500;white-space:nowrap}
|
||
.card-action:hover{text-decoration:underline}
|
||
.card-body{padding:14px}
|
||
|
||
/* ═══ INCIDENT CARD ═══ */
|
||
.inc{border:var(--border);border-radius:8px;overflow:hidden;margin-bottom:12px;box-shadow:0 1px 2px rgba(0,0,0,.03)}
|
||
.inc:last-child{margin-bottom:0}
|
||
.inc-bar{height:3px}
|
||
.inc-body{padding:10px 12px}
|
||
.inc-top{display:flex;align-items:center;gap:6px;margin-bottom:4px}
|
||
.inc-sev{font-size:9px;font-weight:700;padding:2px 6px;border-radius:3px}
|
||
.inc-name{font-size:13px;font-weight:600}
|
||
.inc-meta{font-size:11px;color:var(--text2);margin-bottom:6px}
|
||
|
||
/* FlowPipeline Animations */
|
||
@keyframes lobster-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
|
||
@keyframes card-glow-p2{0%,100%{box-shadow:0 0 0 0 rgba(74,144,217,.3)}50%{box-shadow:0 0 6px 2px rgba(74,144,217,.3)}}
|
||
|
||
/* AI 提案 */
|
||
.ai-proposal{background:rgba(217,119,87,.06);border:var(--border);border-color:rgba(217,119,87,.15);border-radius:6px;padding:6px 10px;font-size:10px;color:var(--accent);display:flex;align-items:center;gap:4px;margin-top:6px}
|
||
.inc-actions{display:flex;gap:6px;margin-top:8px}
|
||
.btn-approve{padding:5px 14px;border:none;border-radius:5px;font-size:10px;font-weight:600;cursor:pointer;background:var(--green);color:#fff}
|
||
.btn-reject{padding:5px 14px;border:var(--border);border-radius:5px;font-size:10px;cursor:pointer;background:var(--card);color:var(--text2)}
|
||
|
||
/* ═══ DISPOSITION MINI ═══ */
|
||
.disp-mini{display:flex;gap:10px;align-items:center}
|
||
.disp-ring{position:relative;width:56px;height:56px;flex-shrink:0}
|
||
.disp-ring svg{transform:rotate(-90deg)}
|
||
.disp-ring-center{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;color:var(--green)}
|
||
.disp-list{flex:1;display:grid;grid-template-columns:1fr 1fr;gap:2px 12px}
|
||
.disp-item{display:flex;align-items:center;gap:5px;font-size:12px;color:var(--text2)}
|
||
.disp-dot{width:5px;height:5px;border-radius:50%;flex-shrink:0}
|
||
.disp-num{margin-left:auto;font-weight:700;font-variant-numeric:tabular-nums}
|
||
|
||
/* ═══ STREAM MINI ═══ */
|
||
.stream-item{display:flex;gap:8px;padding:6px 0;border-bottom:.5px solid #f0ede5;font-size:12px}
|
||
.stream-item:last-child{border-bottom:none}
|
||
.stream-time{font-size:10px;color:var(--text2);font-family:'JetBrains Mono',monospace;width:40px;flex-shrink:0}
|
||
.stream-dot{width:4px;height:4px;border-radius:50%;margin-top:5px;flex-shrink:0}
|
||
.stream-msg{flex:1;line-height:1.4}
|
||
.stream-msg b{font-weight:600}
|
||
.stream-msg code{background:rgba(0,0,0,.04);padding:0 2px;border-radius:2px;font-family:'JetBrains Mono',monospace;font-size:9px}
|
||
|
||
/* ═══ OPENCLAW PANEL ═══ */
|
||
.oc-body{display:flex;gap:12px;align-items:flex-start}
|
||
.oc-info{flex:1;min-width:0}
|
||
.oc-brand{display:inline-flex;align-items:baseline;gap:0;margin-bottom:2px}
|
||
.oc-brand .w,.oc-brand .c{font-family:'DM Mono',monospace;font-size:15px;font-weight:700;color:var(--text)}
|
||
.oc-brand .o{font-family:'VT323',monospace;font-size:24px;color:var(--accent);letter-spacing:0;line-height:1}
|
||
.oc-badge{display:inline-block;font-size:8px;padding:2px 6px;background:rgba(74,144,217,.1);color:var(--blue);border-radius:2px;text-transform:uppercase;letter-spacing:1.2px;margin-bottom:6px}
|
||
.oc-status{font-size:11px;color:var(--text2);display:flex;align-items:center;gap:4px}
|
||
.oc-pulse{display:inline-flex;gap:3px}
|
||
.oc-pulse span{width:4px;height:4px;border-radius:50%;background:var(--blue)}
|
||
.oc-pulse span:nth-child(1){animation:oc-p 1.4s 0s infinite}
|
||
.oc-pulse span:nth-child(2){animation:oc-p 1.4s .2s infinite}
|
||
.oc-pulse span:nth-child(3){animation:oc-p 1.4s .4s infinite}
|
||
@keyframes oc-p{0%,60%,100%{opacity:.2}30%{opacity:1}}
|
||
|
||
/* ═══ TOPO GROUPS ═══ */
|
||
.topo-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
|
||
.topo-g{border:var(--border);border-radius:8px;padding:8px 10px;cursor:pointer;transition:all .12s}
|
||
.topo-g:hover{transform:translateY(-1px);box-shadow:0 2px 6px rgba(0,0,0,.05)}
|
||
.tg-name{font-size:12px;font-weight:600;margin-bottom:2px}
|
||
.tg-meta{font-size:10px;color:var(--text2)}
|
||
.tg-svcs{display:flex;flex-wrap:wrap;gap:2px;margin-top:4px}
|
||
.tg-svc{display:flex;align-items:center;gap:3px;padding:2px 7px;background:var(--card);border:var(--border);border-radius:4px;font-size:10px}
|
||
.tg-sdot{width:3px;height:3px;border-radius:50%}
|
||
.tg-infra{border-color:rgba(59,130,246,.2);background:rgba(59,130,246,.01)}
|
||
.tg-ai{border-color:rgba(249,115,22,.25);background:rgba(249,115,22,.01)}
|
||
.tg-k3s{border-color:rgba(168,85,247,.25);background:rgba(168,85,247,.01)}
|
||
.tg-ext{border-color:rgba(245,158,11,.2);background:rgba(245,158,11,.01)}
|
||
|
||
/* ═══ TOGGLE ═══ */
|
||
.toggle-bar{display:flex;background:var(--bg);border-radius:5px;padding:2px}
|
||
.toggle-opt{padding:3px 10px;border-radius:3px;font-size:8px;font-weight:500;cursor:pointer;color:var(--text3);transition:all .12s}
|
||
.toggle-opt.on{background:var(--card);color:var(--accent);box-shadow:0 1px 2px rgba(0,0,0,.06);font-weight:600}
|
||
|
||
/* ═══ HOST GRID ═══ */
|
||
.host-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
|
||
.host-card{border:var(--border);border-radius:8px;padding:8px 10px;background:var(--surface)}
|
||
.host-name{font-size:12px;font-weight:600;margin-bottom:2px}
|
||
.host-ip{font-size:10px;color:var(--text2);font-family:'JetBrains Mono',monospace}
|
||
.host-bars{display:flex;gap:6px;margin-top:5px}
|
||
.host-bar-w{flex:1}
|
||
.host-bar-l{font-size:7px;color:var(--text3);margin-bottom:2px;display:flex;justify-content:space-between}
|
||
.host-bar{height:3px;border-radius:2px;background:#ebe8df;overflow:hidden}
|
||
.host-bar-f{height:100%;border-radius:2px}
|
||
|
||
/* ═══ TOOL GRID ═══ */
|
||
.tool-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px}
|
||
.tool{display:flex;overflow:hidden;border:var(--border);border-radius:6px;background:var(--surface);cursor:pointer;transition:all .1s}
|
||
.tool:hover{border-color:var(--blue)}
|
||
.tool-bar{width:3px;flex-shrink:0}
|
||
.tool-body{padding:5px 7px;flex:1;min-width:0}
|
||
.tool-name{font-size:11px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.tool-meta{font-size:10px;color:var(--text2);margin-top:2px}
|
||
|
||
/* ═══ APPROVAL MINI ═══ */
|
||
.appr-item{background:var(--surface);border:var(--border);border-radius:6px;padding:8px 10px;margin-bottom:6px}
|
||
.appr-item:last-child{margin-bottom:0}
|
||
.appr-alert{font-size:13px;font-weight:600}
|
||
.appr-target{font-size:11px;color:var(--text2);margin-top:2px;font-family:'JetBrains Mono',monospace}
|
||
.appr-risk{display:inline-block;font-size:10px;padding:2px 8px;border-radius:3px;margin-top:3px;font-weight:600}
|
||
.risk-low{background:rgba(34,197,94,.08);color:var(--green)}
|
||
.risk-med{background:rgba(249,115,22,.08);color:var(--orange)}
|
||
.appr-btns{display:flex;gap:4px;margin-top:5px}
|
||
.btn-sm-ok{flex:1;padding:6px;border:none;border-radius:5px;font-size:11px;font-weight:600;cursor:pointer;background:var(--green);color:#fff}
|
||
.btn-sm-no{flex:1;padding:6px;border:var(--border);border-radius:5px;font-size:11px;cursor:pointer;background:var(--card);color:var(--text2)}
|
||
|
||
/* ═══ AI MODEL STATUS ═══ */
|
||
.model-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px}
|
||
.model{border:var(--border);border-radius:6px;padding:6px 8px;display:flex;align-items:center;gap:6px}
|
||
.model-dot{width:5px;height:5px;border-radius:50%;flex-shrink:0}
|
||
.model-name{font-size:12px;font-weight:500}
|
||
.model-tag{font-size:10px;color:var(--text3);margin-left:auto}
|
||
|
||
/* ═══ TERMINAL FLOAT ═══ */
|
||
.terminal-float{position:fixed;bottom:14px;right:14px;display:flex;align-items:center;gap:5px;padding:6px 14px;background:var(--card);border:var(--border);border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,.08);cursor:pointer;font-size:10px;color:var(--text2);z-index:40;transition:all .12s}
|
||
.terminal-float:hover{border-color:var(--accent);color:var(--accent)}
|
||
|
||
/* 龍蝦動畫 */
|
||
.chibi-strip{height:14px;position:relative;overflow:hidden;border-bottom:.5px dashed rgba(232,85,48,.06);flex-shrink:0}
|
||
@keyframes swim{0%{transform:translateX(0) scaleX(1)}47%{transform:translateX(900px) scaleX(1)}50%{transform:translateX(900px) scaleX(-1)}97%{transform:translateX(0) scaleX(-1)}100%{transform:translateX(0) scaleX(1)}}
|
||
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-2px)}}
|
||
.chibi-swim{animation:swim 25s linear infinite;position:absolute;top:0;left:0}
|
||
.chibi-bob{animation:bob .7s ease-in-out infinite;display:inline-block}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="layout">
|
||
|
||
<!-- ═══ SIDEBAR ═══ -->
|
||
<div class="sidebar">
|
||
|
||
<!-- Brand Area (72px) -->
|
||
<div class="brand">
|
||
<svg width="32" height="32" viewBox="0 0 140 140" fill="none">
|
||
<defs><linearGradient id="c1" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#FFF"/><stop offset="40%" stop-color="#F8F8F8"/><stop offset="70%" stop-color="#E8E8E8"/><stop offset="100%" stop-color="#D8D8D8"/></linearGradient><radialGradient id="l1" cx="40%" cy="35%" r="60%"><stop offset="0%" stop-color="#7AB8F5"/><stop offset="100%" stop-color="#2B6CB0"/></radialGradient></defs>
|
||
<circle cx="70" cy="70" r="32" fill="url(#c1)" stroke="#E0E0E0" stroke-width="1"/>
|
||
<circle cx="70" cy="70" r="16" fill="url(#l1)"><animate attributeName="r" values="14;17;14" dur="2s" repeatCount="indefinite"/></circle>
|
||
<circle cx="70" cy="70" r="8" fill="white" opacity=".8"/>
|
||
<path d="M70 38L70 18L58 6M70 18L82 6" stroke="url(#c1)" stroke-width="6" stroke-linecap="round" fill="none"/><path d="M70 38L70 18L58 6M70 18L82 6" stroke="#4A90D9" stroke-width="3" stroke-linecap="round" fill="none" opacity=".5"/>
|
||
<path d="M38 70L18 70L6 58M18 70L6 82" stroke="url(#c1)" stroke-width="6" stroke-linecap="round" fill="none"/><path d="M38 70L18 70L6 58M18 70L6 82" stroke="#4A90D9" stroke-width="3" stroke-linecap="round" fill="none" opacity=".5"/>
|
||
<path d="M102 70L122 70L134 58M122 70L134 82" stroke="url(#c1)" stroke-width="6" stroke-linecap="round" fill="none"/><path d="M102 70L122 70L134 58M122 70L134 82" stroke="#4A90D9" stroke-width="3" stroke-linecap="round" fill="none" opacity=".5"/>
|
||
<path d="M48 92L28 112L16 116" stroke="url(#c1)" stroke-width="6" stroke-linecap="round" fill="none"/>
|
||
<path d="M92 92L112 112L124 116" stroke="url(#c1)" stroke-width="6" stroke-linecap="round" fill="none"/>
|
||
<circle cx="70" cy="70" r="42" fill="none" stroke="#4A90D9" stroke-width="1" stroke-dasharray="6 6" opacity=".3"><animateTransform attributeName="transform" type="rotate" from="0 70 70" to="360 70 70" dur="8s" repeatCount="indefinite"/></circle>
|
||
</svg>
|
||
<div class="brand-text"><span class="a">A</span><span class="w">wooo</span><span class="i">I</span></div>
|
||
</div>
|
||
|
||
<!-- Nav -->
|
||
<div class="nav">
|
||
<div class="nav-item on"><span class="nav-dot" style="background:var(--accent)"></span>指令中心<span style="margin-left:auto;font-size:9px;color:var(--text3)">4 tab</span></div>
|
||
<div class="nav-item"><span class="nav-dot" style="background:var(--blue)"></span>可觀測性<span style="margin-left:auto;font-size:9px;color:var(--text3)">5 tab</span></div>
|
||
<div class="nav-item"><span class="nav-dot" style="background:var(--green)"></span>自動化<span style="margin-left:auto;font-size:9px;color:var(--text3)">3 tab</span></div>
|
||
<div class="nav-item"><span class="nav-dot" style="background:var(--purple)"></span>營運<span style="margin-left:auto;font-size:9px;color:var(--text3)">5 tab</span></div>
|
||
<div class="nav-item"><span class="nav-dot" style="background:var(--red)"></span>安全合規<span style="margin-left:auto;font-size:9px;color:var(--text3)">2 tab</span></div>
|
||
<div class="nav-item"><span class="nav-dot" style="background:var(--text3)"></span>知識</div>
|
||
<div class="nav-sep"></div>
|
||
<div class="nav-label">legacy</div>
|
||
<div class="nav-item" style="opacity:.5"><span class="nav-dot" style="background:var(--text3)"></span>經典 AI 中心</div>
|
||
</div>
|
||
|
||
<!-- Nav Bottom -->
|
||
<div class="nav-bottom">
|
||
<div class="nav-item"><span class="nav-dot" style="background:var(--text3)"></span>終端</div>
|
||
<div class="nav-item"><span class="nav-dot" style="background:var(--text3)"></span>設定</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ CONTENT AREA ═══ -->
|
||
<div class="content">
|
||
|
||
<!-- Title Bar -->
|
||
<div class="title-bar">
|
||
<span class="page-title">AI中心</span>
|
||
<div class="title-actions">
|
||
<div class="ai-status"><span class="ai-dot"></span>OpenClaw · openclaw_nemo</div>
|
||
<button class="lang-btn on">繁</button>
|
||
<button class="lang-btn">EN</button>
|
||
<div class="avatar">OG</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab Bar -->
|
||
<div class="tab-bar">
|
||
<div class="tab on">戰情總覽</div>
|
||
<div class="tab">告警 & 授權 <span class="tab-badge">2</span></div>
|
||
<div class="tab">活動串流</div>
|
||
<div class="tab">處置統計</div>
|
||
</div>
|
||
|
||
<!-- 龍蝦游泳列 -->
|
||
<div class="chibi-strip">
|
||
<div class="chibi-swim"><div class="chibi-bob">
|
||
<svg width="16" height="12" viewBox="0 0 18 14" fill="none"><ellipse cx="9" cy="10" rx="5" ry="4" fill="#E85530" opacity=".9"/><circle cx="9" cy="6" r="3.5" fill="#E85530" opacity=".9"/><circle cx="7.5" cy="5.2" r=".9" fill="#fff" opacity=".8"/><circle cx="10.5" cy="5.2" r=".9" fill="#fff" opacity=".8"/><path d="M3 8.5Q.5 7.5 1 10Q1.5 11.5 3.5 11" stroke="#E85530" stroke-width="1.2" fill="none" stroke-linecap="round"/><ellipse cx="1" cy="10" rx="1.2" ry="1.5" fill="#E85530" opacity=".7" transform="rotate(-10 1 10)"/><path d="M15 8.5Q17.5 7.5 17 10Q16.5 11.5 14.5 11" stroke="#E85530" stroke-width="1.2" fill="none" stroke-linecap="round"/><ellipse cx="17" cy="10" rx="1.2" ry="1.5" fill="#E85530" opacity=".7" transform="rotate(10 17 10)"/><path d="M6.5 2.5Q5 .5 3.5 1" stroke="#b03a1a" stroke-width=".8" fill="none" stroke-linecap="round"/><path d="M11.5 2.5Q13 .5 14.5 1" stroke="#b03a1a" stroke-width=".8" fill="none" stroke-linecap="round"/></svg>
|
||
</div></div>
|
||
</div>
|
||
|
||
<!-- KPI Strip (卡片式,融入背景) -->
|
||
<div class="kpi-strip">
|
||
<div class="kpi-card"><div class="kpi-label">系統健康</div><div class="kpi-row"><span class="kpi-val" style="color:var(--green)">98.5%</span></div><div class="kpi-bar"><div class="kpi-bar-f" style="width:98.5%;background:var(--green)"></div></div></div>
|
||
<div class="kpi-card"><div class="kpi-label">活動事件</div><div class="kpi-row"><span class="kpi-val" style="color:var(--accent)">2</span><span class="kpi-sub">P1:1 P2:1</span></div></div>
|
||
<div class="kpi-card"><div class="kpi-label">自動修復率</div><div class="kpi-row"><span class="kpi-val" style="color:var(--green)">72%</span><span class="kpi-trend" style="color:var(--green)">↑5%</span></div><div class="kpi-bar"><div class="kpi-bar-f" style="width:72%;background:linear-gradient(90deg,var(--green),#4ade80)"></div></div></div>
|
||
<div class="kpi-card"><div class="kpi-label">待審批</div><div class="kpi-row"><span class="kpi-val" style="color:var(--orange)">3</span><span class="kpi-sub">等待決策</span></div></div>
|
||
<div class="kpi-card"><div class="kpi-label">本週操作</div><div class="kpi-row"><span class="kpi-val">1,245</span></div></div>
|
||
</div>
|
||
|
||
<!-- ═══ MAIN BODY ═══ -->
|
||
<div class="main-body">
|
||
|
||
<!-- ═══ LEFT COLUMN ═══ -->
|
||
<div class="col-left">
|
||
|
||
<!-- 活躍事件 -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-dot"></div>
|
||
<span class="card-title">活躍事件</span>
|
||
<span style="font-size:11px;background:rgba(217,119,87,.1);color:#a04010;padding:2px 8px;font-weight:700;border:.5px solid rgba(217,119,87,.25);border-radius:10px">2</span>
|
||
<span class="card-action">查看全部告警 →</span>
|
||
</div>
|
||
<div class="card-body">
|
||
|
||
<!-- Incident 1: P1 進度條 -->
|
||
<div class="inc">
|
||
<div class="inc-bar" style="background:var(--orange)"></div>
|
||
<div class="inc-body">
|
||
<div class="inc-top">
|
||
<span class="inc-sev" style="background:rgba(245,158,11,.12);color:#d97000">P1</span>
|
||
<span class="inc-name">重新探測 #10exiconFast: 通過</span>
|
||
</div>
|
||
<div class="inc-meta">awoooi-api @ awoooi-prod · 3 alerts · investigating</div>
|
||
<!-- P1 FlowPipeline: 進度條 + 龍蝦 -->
|
||
<div style="position:relative;height:54px;margin:4px 0">
|
||
<div style="position:absolute;bottom:16px;left:0;right:0;height:4px;background:#e8e5dc;border-radius:2px"></div>
|
||
<div style="position:absolute;bottom:16px;left:0;height:4px;background:#F59E0B;border-radius:2px;width:43%"></div>
|
||
<div style="position:absolute;bottom:0;left:0%;transform:translateX(-50%);text-align:center"><div style="height:20px"></div><div style="width:8px;height:8px;border-radius:50%;background:#F59E0B;margin:0 auto"></div><div style="font-size:9px;color:#F59E0B;margin-top:2px">告警</div></div>
|
||
<div style="position:absolute;bottom:0;left:16.7%;transform:translateX(-50%);text-align:center"><div style="height:20px"></div><div style="width:8px;height:8px;border-radius:50%;background:#F59E0B;margin:0 auto"></div><div style="font-size:9px;color:#F59E0B;margin-top:2px">偵測</div></div>
|
||
<div style="position:absolute;bottom:0;left:33.3%;transform:translateX(-50%);text-align:center"><div style="height:20px"></div><div style="width:8px;height:8px;border-radius:50%;background:#F59E0B;margin:0 auto"></div><div style="font-size:9px;color:#F59E0B;margin-top:2px">分析</div></div>
|
||
<div style="position:absolute;bottom:0;left:50%;transform:translateX(-50%);text-align:center"><div style="animation:lobster-bob 1.5s ease-in-out infinite;margin-bottom:2px"><svg width="14" height="16" viewBox="0 0 18 20" fill="none"><ellipse cx="9" cy="13" rx="5.5" ry="6.5" fill="#F59E0B"/><circle cx="9" cy="7.5" r="4.5" fill="#F59E0B"/><circle cx="7" cy="6.5" r="1" fill="#b03a1a"/><circle cx="11" cy="6.5" r="1" fill="#b03a1a"/></svg></div><div style="width:8px;height:8px;border-radius:50%;background:#fff;border:2px solid #F59E0B;margin:0 auto"></div><div style="font-size:9px;color:var(--text);font-weight:700;margin-top:2px">提案</div></div>
|
||
<div style="position:absolute;bottom:0;left:66.7%;transform:translateX(-50%);text-align:center"><div style="height:20px"></div><div style="width:8px;height:8px;border-radius:50%;background:#f8f9fc;border:1.5px solid #e0ddd4;margin:0 auto"></div><div style="font-size:9px;color:var(--text3);margin-top:2px">授權</div></div>
|
||
<div style="position:absolute;bottom:0;left:83.3%;transform:translateX(-50%);text-align:center"><div style="height:20px"></div><div style="width:8px;height:8px;border-radius:50%;background:#f8f9fc;border:1.5px solid #e0ddd4;margin:0 auto"></div><div style="font-size:9px;color:var(--text3);margin-top:2px">執行</div></div>
|
||
<div style="position:absolute;bottom:0;left:100%;transform:translateX(-50%);text-align:center"><div style="height:20px"></div><div style="width:8px;height:8px;border-radius:50%;background:#f8f9fc;border:1.5px solid #e0ddd4;margin:0 auto"></div><div style="font-size:9px;color:var(--text3);margin-top:2px">完成</div></div>
|
||
</div>
|
||
<div class="ai-proposal">▶ AI 提案:restart_deployment awoooi-api (信心度 91%)</div>
|
||
<div class="inc-actions">
|
||
<button class="btn-approve">批准執行</button>
|
||
<button class="btn-reject">拒絕</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Incident 2: P2 卡片步驟 -->
|
||
<div class="inc">
|
||
<div class="inc-bar" style="background:var(--blue)"></div>
|
||
<div class="inc-body">
|
||
<div class="inc-top">
|
||
<span class="inc-sev" style="background:rgba(74,144,217,.12);color:var(--blue)">P2</span>
|
||
<span class="inc-name">awoooi-api: 服務異常</span>
|
||
</div>
|
||
<div class="inc-meta">awoooi-api @ awoooi-prod · investigating</div>
|
||
<!-- P2 FlowPipeline: 卡片步驟 + 光暈 -->
|
||
<div style="display:flex;align-items:flex-end;gap:3px;margin:4px 0;overflow-x:auto">
|
||
<div style="text-align:center"><div style="height:20px"></div><div style="padding:3px 5px;background:#4A90D9;border-radius:4px"><span style="font-size:9px;color:#fff;font-weight:700">告警</span></div></div>
|
||
<div style="width:6px;height:1.5px;background:#4A90D9;margin-bottom:10px"></div>
|
||
<div style="text-align:center"><div style="height:20px"></div><div style="padding:3px 5px;background:#4A90D9;border-radius:4px"><span style="font-size:9px;color:#fff;font-weight:700">偵測</span></div></div>
|
||
<div style="width:6px;height:1.5px;background:#e0ddd4;margin-bottom:10px"></div>
|
||
<div style="text-align:center"><div style="animation:lobster-bob 1.5s ease-in-out infinite"><svg width="14" height="16" viewBox="0 0 18 20" fill="none"><ellipse cx="9" cy="13" rx="5.5" ry="6.5" fill="#4A90D9"/><circle cx="9" cy="7.5" r="4.5" fill="#4A90D9"/><circle cx="7" cy="6.5" r="1" fill="#1a4a7a"/><circle cx="11" cy="6.5" r="1" fill="#1a4a7a"/></svg></div><div style="padding:3px 5px;background:#fff;border:1.5px solid #4A90D9;border-radius:4px;animation:card-glow-p2 1.5s infinite"><span style="font-size:9px;color:#4A90D9;font-weight:700">分析</span></div></div>
|
||
<div style="width:6px;height:1.5px;background:#e0ddd4;margin-bottom:10px"></div>
|
||
<div style="text-align:center"><div style="height:20px"></div><div style="padding:3px 5px;background:#f8f9fc;border:1px solid #e0ddd4;border-radius:4px"><span style="font-size:9px;color:#b0ad9f">提案</span></div></div>
|
||
<div style="width:6px;height:1.5px;background:#e0ddd4;margin-bottom:10px"></div>
|
||
<div style="text-align:center"><div style="height:20px"></div><div style="padding:3px 5px;background:#f8f9fc;border:1px solid #e0ddd4;border-radius:4px"><span style="font-size:9px;color:#b0ad9f">授權</span></div></div>
|
||
<div style="width:6px;height:1.5px;background:#e0ddd4;margin-bottom:10px"></div>
|
||
<div style="text-align:center"><div style="height:20px"></div><div style="padding:3px 5px;background:#f8f9fc;border:1px solid #e0ddd4;border-radius:4px"><span style="font-size:9px;color:#b0ad9f">執行</span></div></div>
|
||
<div style="width:6px;height:1.5px;background:#e0ddd4;margin-bottom:10px"></div>
|
||
<div style="text-align:center"><div style="height:20px"></div><div style="padding:3px 5px;background:#f8f9fc;border:1px solid #e0ddd4;border-radius:4px"><span style="font-size:9px;color:#b0ad9f">完成</span></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 處置統計迷你版 -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-dot"></div>
|
||
<span class="card-title">處置統計</span>
|
||
<span class="card-action">查看完整報表 →</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="disp-mini">
|
||
<!-- 環形圖 SVG -->
|
||
<div class="disp-ring">
|
||
<svg width="56" height="56" viewBox="0 0 56 56">
|
||
<circle cx="28" cy="28" r="22" fill="none" stroke="#ebe8df" stroke-width="5"/>
|
||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--green)" stroke-width="5" stroke-dasharray="96.6 41.7" stroke-linecap="round"/>
|
||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--blue)" stroke-width="5" stroke-dasharray="3.5 134.8" stroke-dashoffset="-96.6" stroke-linecap="round"/>
|
||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--orange)" stroke-width="5" stroke-dasharray="30.5 107.8" stroke-dashoffset="-100.1" stroke-linecap="round"/>
|
||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--purple)" stroke-width="5" stroke-dasharray="8.1 130.2" stroke-dashoffset="-130.6" stroke-linecap="round"/>
|
||
</svg>
|
||
<div class="disp-ring-center">72%</div>
|
||
</div>
|
||
<div class="disp-list">
|
||
<div class="disp-item"><span class="disp-dot" style="background:var(--green)"></span>自動修復<span class="disp-num" style="color:var(--green)">142</span></div>
|
||
<div class="disp-item"><span class="disp-dot" style="background:var(--orange)"></span>人工核准<span class="disp-num" style="color:var(--orange)">45</span></div>
|
||
<div class="disp-item"><span class="disp-dot" style="background:var(--purple)"></span>手動處理<span class="disp-num" style="color:var(--purple)">12</span></div>
|
||
<div class="disp-item"><span class="disp-dot" style="background:var(--blue)"></span>冷啟動<span class="disp-num" style="color:var(--blue)">5</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 最近活動 -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-dot"></div>
|
||
<span class="card-title">最近活動</span>
|
||
<span class="card-action">查看活動串流 →</span>
|
||
</div>
|
||
<div class="card-body" style="padding:10px 14px">
|
||
<div class="stream-item"><span class="stream-time">18:05</span><span class="stream-dot" style="background:var(--green)"></span><span class="stream-msg">心跳確認 <code>mon/mon1</code> Ready</span></div>
|
||
<div class="stream-item"><span class="stream-time">18:04</span><span class="stream-dot" style="background:var(--blue)"></span><span class="stream-msg"><b>OpenClaw</b> 匹配 Playbook <code>restart_worker</code> (91%)</span></div>
|
||
<div class="stream-item"><span class="stream-time">18:02</span><span class="stream-dot" style="background:var(--red)"></span><span class="stream-msg"><b>Prometheus</b> Worker CPU 89%</span></div>
|
||
<div class="stream-item"><span class="stream-time">17:58</span><span class="stream-dot" style="background:var(--green)"></span><span class="stream-msg">自動修復完成 <code>restart: api</code> (12s)</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ═══ RIGHT COLUMN (480px) ═══ -->
|
||
<div class="col-right">
|
||
|
||
<!-- OpenClaw 認知引擎 (最上方,品牌錨點) -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-dot"></div>
|
||
<span class="card-title">OPENCLAW 認知引擎</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="oc-body">
|
||
<svg width="68" height="68" viewBox="0 0 140 140" fill="none" style="flex-shrink:0">
|
||
<defs><linearGradient id="oc-c" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#FFF"/><stop offset="40%" stop-color="#F8F8F8"/><stop offset="70%" stop-color="#E8E8E8"/><stop offset="100%" stop-color="#D8D8D8"/></linearGradient><radialGradient id="oc-l" cx="40%" cy="35%" r="60%"><stop offset="0%" stop-color="#7AB8F5"/><stop offset="100%" stop-color="#2B6CB0"/></radialGradient></defs>
|
||
<circle cx="70" cy="70" r="32" fill="url(#oc-c)" stroke="#E0E0E0" stroke-width="1"/><circle cx="70" cy="70" r="16" fill="url(#oc-l)"><animate attributeName="r" values="14;17;14" dur="2s" repeatCount="indefinite"/></circle><circle cx="70" cy="70" r="8" fill="white" opacity=".8"/>
|
||
<path d="M70 38L70 18L58 6M70 18L82 6" stroke="url(#oc-c)" stroke-width="6" stroke-linecap="round" fill="none"/><path d="M70 38L70 18L58 6M70 18L82 6" stroke="#4A90D9" stroke-width="3" stroke-linecap="round" fill="none" opacity=".5"/>
|
||
<path d="M38 70L18 70L6 58M18 70L6 82" stroke="url(#oc-c)" stroke-width="6" stroke-linecap="round" fill="none"/><path d="M38 70L18 70L6 58M18 70L6 82" stroke="#4A90D9" stroke-width="3" stroke-linecap="round" fill="none" opacity=".5"/>
|
||
<path d="M102 70L122 70L134 58M122 70L134 82" stroke="url(#oc-c)" stroke-width="6" stroke-linecap="round" fill="none"/><path d="M102 70L122 70L134 58M122 70L134 82" stroke="#4A90D9" stroke-width="3" stroke-linecap="round" fill="none" opacity=".5"/>
|
||
<path d="M48 92L28 112L16 116" stroke="url(#oc-c)" stroke-width="6" stroke-linecap="round" fill="none"/><path d="M92 92L112 112L124 116" stroke="url(#oc-c)" stroke-width="6" stroke-linecap="round" fill="none"/>
|
||
<circle cx="70" cy="70" r="42" fill="none" stroke="#4A90D9" stroke-width="1" stroke-dasharray="6 6" opacity=".3"><animateTransform attributeName="transform" type="rotate" from="0 70 70" to="360 70 70" dur="8s" repeatCount="indefinite"/></circle>
|
||
</svg>
|
||
<div class="oc-info">
|
||
<div class="oc-brand"><span class="w">W</span><span class="o">ooo</span><span class="c">Claw</span></div>
|
||
<div><div class="oc-badge">WoooClaw Pipeline</div></div>
|
||
<div class="oc-status">[AGENT] patrolling... <span class="oc-pulse"><span></span><span></span><span></span></span></div>
|
||
<!-- 豐富內容: AI 即時狀態 -->
|
||
<div style="margin-top:8px;padding-top:8px;border-top:.5px solid var(--bdr)">
|
||
<div style="display:flex;gap:8px;margin-bottom:4px">
|
||
<div style="flex:1;font-size:10px;color:var(--text2)">模型: <span style="font-weight:600;color:var(--text)">openclaw_nemo</span></div>
|
||
<div style="font-size:10px;color:var(--green);font-weight:500">● 運行中</div>
|
||
</div>
|
||
<div style="display:flex;gap:12px;font-size:10px;color:var(--text2)">
|
||
<span>今日分析: <b style="color:var(--text)">23</b></span>
|
||
<span>成功率: <b style="color:var(--green)">91%</b></span>
|
||
<span>MTTR: <b style="color:var(--text)">8.2m</b></span>
|
||
</div>
|
||
<!-- AI 推理終端 -->
|
||
<div style="background:#141413;border-radius:6px;padding:8px 10px;margin-top:8px;font-family:'JetBrains Mono',monospace;font-size:10px;color:#a0e8a0;line-height:1.6;max-height:80px;overflow-y:auto">
|
||
<span style="color:#555">[18:03]</span> Analyzing worker CPU spike...
|
||
<span style="color:#555">[18:03]</span> Root cause: OOM pressure
|
||
<span style="color:#555">[18:03]</span> Matched: restart_worker (91%)
|
||
<span style="color:#ffd700">[18:03] Awaiting approval ▎</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 待審批任務 -->
|
||
<div class="card" style="border-color:rgba(249,115,22,.3)">
|
||
<div class="card-header" style="background:rgba(249,115,22,.04)">
|
||
<div class="card-dot" style="background:var(--orange)"></div>
|
||
<span class="card-title">待審批任務</span>
|
||
<span style="font-size:11px;background:rgba(249,115,22,.1);color:var(--orange);padding:2px 8px;font-weight:700;border-radius:10px">3</span>
|
||
<span class="card-action">查看全部授權 →</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="appr-item">
|
||
<div class="appr-alert" style="color:var(--red)">Worker 高負載警告</div>
|
||
<div class="appr-target">ssh://wooo@192.168.0.110/restart</div>
|
||
<span class="appr-risk risk-low">LOW RISK</span>
|
||
<div class="appr-btns"><button class="btn-sm-ok">批准</button><button class="btn-sm-no">拒絕</button></div>
|
||
</div>
|
||
<div class="appr-item">
|
||
<div class="appr-alert" style="color:var(--orange)">Redis 記憶體壓力</div>
|
||
<div class="appr-target">ansible://188/clear_redis_cache.yml</div>
|
||
<span class="appr-risk risk-med">MEDIUM</span>
|
||
<div class="appr-btns"><button class="btn-sm-ok">批准</button><button class="btn-sm-no">拒絕</button></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 拓撲 / 主機 Toggle -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-dot"></div>
|
||
<span class="card-title">基礎架構</span>
|
||
<div style="margin-left:auto"><div class="toggle-bar"><div class="toggle-opt" id="t-host" onclick="switchView('host')">主機</div><div class="toggle-opt on" id="t-topo" onclick="switchView('topo')">拓撲</div></div></div>
|
||
<span class="card-action" style="margin-left:8px">展開全圖 →</span>
|
||
</div>
|
||
<div class="card-body" id="view-topo">
|
||
<div class="topo-grid">
|
||
<div class="topo-g tg-infra"><div class="tg-name">🏗️ 基礎設施 (.110)</div><div class="tg-meta">7 服務 · ✓ 全部健康</div><div class="tg-svcs"><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>Gitea</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>Harbor</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>Sentry</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>Prom</span></div></div>
|
||
<div class="topo-g tg-ai"><div class="tg-name">🧠 AI/數據 (.188)</div><div class="tg-meta">7 服務 · ⚡ OpenClaw 診斷中</div><div class="tg-svcs"><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>PG</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>Redis</span><span class="tg-svc" style="border-color:var(--blue)"><span class="tg-sdot" style="background:var(--blue)"></span>OpenClaw⚡</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>Ollama</span></div></div>
|
||
<div class="topo-g tg-k3s"><div class="tg-name">☸️ K3s 叢集</div><div class="tg-meta">5 服務 · ⚠️ Worker CPU 89%</div><div class="tg-svcs"><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>api×2</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>web×2</span><span class="tg-svc" style="border-color:var(--orange)"><span class="tg-sdot" style="background:var(--orange)"></span>worker⚠️</span></div></div>
|
||
<div class="topo-g tg-ext"><div class="tg-name">🌐 外部服務</div><div class="tg-meta">3 服務 · ✓ 全部可達</div><div class="tg-svcs"><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>Gemini</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>NVIDIA</span><span class="tg-svc"><span class="tg-sdot" style="background:var(--green)"></span>CF</span></div></div>
|
||
</div>
|
||
</div>
|
||
<div class="card-body" id="view-host" style="display:none">
|
||
<div class="host-grid">
|
||
<div class="host-card"><div class="host-name">DevOps 金庫</div><div class="host-ip">192.168.0.110</div><div class="host-bars"><div class="host-bar-w"><div class="host-bar-l"><span>CPU</span><span>35%</span></div><div class="host-bar"><div class="host-bar-f" style="width:35%;background:var(--green)"></div></div></div><div class="host-bar-w"><div class="host-bar-l"><span>RAM</span><span>55%</span></div><div class="host-bar"><div class="host-bar-f" style="width:55%;background:var(--green)"></div></div></div></div></div>
|
||
<div class="host-card"><div class="host-name">AI+Web 中心</div><div class="host-ip">192.168.0.188</div><div class="host-bars"><div class="host-bar-w"><div class="host-bar-l"><span>CPU</span><span>67%</span></div><div class="host-bar"><div class="host-bar-f" style="width:67%;background:var(--orange)"></div></div></div><div class="host-bar-w"><div class="host-bar-l"><span>RAM</span><span>72%</span></div><div class="host-bar"><div class="host-bar-f" style="width:72%;background:var(--orange)"></div></div></div></div></div>
|
||
<div class="host-card"><div class="host-name">K3s Master</div><div class="host-ip">192.168.0.120</div><div class="host-bars"><div class="host-bar-w"><div class="host-bar-l"><span>CPU</span><span>45%</span></div><div class="host-bar"><div class="host-bar-f" style="width:45%;background:var(--green)"></div></div></div><div class="host-bar-w"><div class="host-bar-l"><span>RAM</span><span>60%</span></div><div class="host-bar"><div class="host-bar-f" style="width:60%;background:var(--green)"></div></div></div></div></div>
|
||
<div class="host-card"><div class="host-name">K3s Worker</div><div class="host-ip">192.168.0.121</div><div class="host-bars"><div class="host-bar-w"><div class="host-bar-l"><span>CPU</span><span>--</span></div><div class="host-bar"><div class="host-bar-f" style="width:0%"></div></div></div><div class="host-bar-w"><div class="host-bar-l"><span>RAM</span><span>--</span></div><div class="host-bar"><div class="host-bar-f" style="width:0%"></div></div></div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- AI 模型狀態 -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-dot"></div>
|
||
<span class="card-title">AI 模型狀態</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="model-grid">
|
||
<div class="model"><span class="model-dot" style="background:var(--green)"></span><span class="model-name">OpenClaw Nemo</span><span class="model-tag">local</span></div>
|
||
<div class="model"><span class="model-dot" style="background:var(--green)"></span><span class="model-name">Ollama qwen2.5</span><span class="model-tag">local</span></div>
|
||
<div class="model"><span class="model-dot" style="background:var(--green)"></span><span class="model-name">Gemini Pro</span><span class="model-tag">cloud</span></div>
|
||
<div class="model"><span class="model-dot" style="background:var(--green)"></span><span class="model-name">NVIDIA NIM</span><span class="model-tag">cloud</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 監控工具 -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-dot"></div>
|
||
<span class="card-title">監控工具</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="tool-grid">
|
||
<div class="tool"><div class="tool-bar" style="background:#4A90D9"></div><div class="tool-body"><div class="tool-name">SigNoz</div><div class="tool-meta">Traces · Logs</div></div></div>
|
||
<div class="tool"><div class="tool-bar" style="background:#E85530"></div><div class="tool-body"><div class="tool-name">Grafana</div><div class="tool-meta">3 Dashboards</div></div></div>
|
||
<div class="tool"><div class="tool-bar" style="background:var(--green)"></div><div class="tool-body"><div class="tool-name">Prometheus</div><div class="tool-meta">22 targets</div></div></div>
|
||
<div class="tool"><div class="tool-bar" style="background:var(--orange)"></div><div class="tool-body"><div class="tool-name">Langfuse</div><div class="tool-meta">LLMOps</div></div></div>
|
||
<div class="tool"><div class="tool-bar" style="background:var(--red)"></div><div class="tool-body"><div class="tool-name">Sentry</div><div class="tool-meta">2 Projects</div></div></div>
|
||
<div class="tool"><div class="tool-bar" style="background:var(--purple)"></div><div class="tool-body"><div class="tool-name">Gitea</div><div class="tool-meta">CI/CD</div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Terminal Float -->
|
||
<div class="terminal-float">⌨ Omni-Terminal</div>
|
||
|
||
<script>
|
||
function switchView(v){
|
||
document.getElementById('view-host').style.display=v==='host'?'block':'none'
|
||
document.getElementById('view-topo').style.display=v==='topo'?'block':'none'
|
||
document.getElementById('t-host').classList.toggle('on',v==='host')
|
||
document.getElementById('t-topo').classList.toggle('on',v==='topo')
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|