docs: Sprint 5R 前端重構批准 — ADR-065 + 設計稿 + Skills + LOGBOOK
- ADR-065: Sprint 5R 前端重構決策(版本 A 批准) - sprint5r-approved-design.html: 統帥批准的設計稿存檔 - Skills 01 v1.7: 品牌 Logo/AwoooI 一致性鐵律 - LOGBOOK: Sprint 5R 開始實施 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
| v1.4 | 2026-03-28 | Claude Code | ✅ Phase 19 Wave 0-5 完成 (~95% + Telemetry 整合) |
|
||||
| v1.5 | 2026-03-30 | Claude Code | 🔴🔴🔴 前端建置禁止內網 IP (瀏覽器權限事故) |
|
||||
| v1.6 | 2026-03-31 | Claude Code | 🚀 ADR-042 效能優化模式 (DOM Bypass + Optimistic Updates) |
|
||||
| v1.7 | 2026-04-09 | Claude Opus 4.6 | 🔴 Sprint 5R 前端重構 — 品牌一致性鐵律 + 設計稿對齊規範 |
|
||||
|
||||
---
|
||||
|
||||
@@ -55,6 +56,31 @@ grep "NEXT_PUBLIC" .gitea/workflows/cd.yaml | grep -v "192.168"
|
||||
|
||||
---
|
||||
|
||||
## 🔴🔴 品牌 Logo 與文字一致性 (2026-04-09)
|
||||
|
||||
> **統帥多次糾正**: 所有設計稿和頁面中的 Logo SVG 和 AwoooI 文字必須與正式環境完全一致
|
||||
|
||||
### Logo SVG(螺旋眼睛)
|
||||
- 來源:`header.tsx` L82-111,viewBox `0 0 140 140`
|
||||
- 漸層:陶瓷白 + 藍色 LED + 觸鬚 + 旋轉虛線圓
|
||||
- 禁止簡化、禁止替代、禁止自創
|
||||
|
||||
### AwoooI 品牌文字
|
||||
- `A`:DM Mono 20px fw-700 #141413 margin-right:-4px
|
||||
- `wooo`:VT323 26px #d97757 letterSpacing:0 margin:0 -2px
|
||||
- `I`:DM Mono 20px fw-700 #141413 margin-left:-3px
|
||||
- 字母間必須緊湊,整體像一個字
|
||||
|
||||
### 設計稿 HTML Mockup
|
||||
- 直接從 header.tsx 複製 SVG 和文字結構
|
||||
- OpenClaw 面板也用同款螺旋眼睛 SVG
|
||||
|
||||
### 流程圖 icon
|
||||
- 使用 dashboardicons.com OpenClaw PNG(取代圓圈,不是浮動)
|
||||
- URL: `https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/openclaw.png`
|
||||
|
||||
---
|
||||
|
||||
## 核心約束 (Iron Laws)
|
||||
|
||||
### 1. Nothing.tech 純白工業風 (絕對標準)
|
||||
|
||||
783
.playwright-mcp/sprint5r-approved-design.html
Normal file
783
.playwright-mcp/sprint5r-approved-design.html
Normal file
@@ -0,0 +1,783 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1440">
|
||||
<title>AWOOOI AI 戰情指揮中心 — 版本 A:忠實還原 + 微增強</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Syne:wght@400;600;700;800&family=JetBrains+Mono:wght@300;400;500&family=VT323&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
: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;
|
||||
}
|
||||
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
|
||||
body {
|
||||
font-family: 'DM Mono', monospace;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
width: 1440px;
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* SIDEBAR */
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
min-width: 200px;
|
||||
background: var(--card);
|
||||
border-right: 0.5px solid var(--bdr);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
}
|
||||
.brand {
|
||||
height: 72px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 16px;
|
||||
border-bottom: 0.5px solid var(--bdr);
|
||||
}
|
||||
.brand-text {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
.brand-text .a { font-family: 'DM Mono', monospace; font-size: 20px; font-weight: 700; color: #141413; margin-right: -4px; }
|
||||
.brand-text .w { font-family: 'VT323', monospace; font-size: 26px; color: var(--accent); letter-spacing: -1px; line-height: 1; }
|
||||
.brand-text .i { font-family: 'DM Mono', monospace; font-size: 20px; font-weight: 700; color: #141413; margin-left: -3px; }
|
||||
|
||||
.nav { flex:1; padding: 12px 8px; display:flex; flex-direction:column; gap:2px; }
|
||||
.nav-item {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 8px 12px; border-radius: 6px; cursor: pointer;
|
||||
font-size: 12px; color: var(--text2); text-decoration: none;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.nav-item:hover { background: var(--surface); }
|
||||
.nav-item.active { background: rgba(217,119,87,0.08); color: var(--accent); font-weight: 500; }
|
||||
.nav-item .dot { width:6px; height:6px; border-radius:50%; flex-shrink:0; }
|
||||
|
||||
.nav-sep { height:0.5px; background:var(--bdr); margin:8px 12px; }
|
||||
.nav-label { font-size:9px; color:var(--text3); padding:4px 12px; text-transform:uppercase; letter-spacing:1px; }
|
||||
|
||||
.nav-bottom { padding:8px; border-top:0.5px solid var(--bdr); }
|
||||
|
||||
/* CONTENT */
|
||||
.content { flex:1; display:flex; flex-direction:column; height:100vh; overflow:hidden; }
|
||||
|
||||
/* TITLE BAR */
|
||||
.titlebar {
|
||||
height: 48px; min-height:48px;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
border-bottom: 0.5px solid var(--bdr);
|
||||
background: var(--card);
|
||||
}
|
||||
.titlebar h1 { font-family:'Syne',sans-serif; font-size:20px; font-weight:800; }
|
||||
.titlebar-right { display:flex; align-items:center; gap:12px; }
|
||||
.pulse-dot { width:8px;height:8px;border-radius:50%;background:var(--green);display:inline-block;animation:blink 2s infinite; }
|
||||
.model-badge { font-size:11px; color:var(--text2); display:flex; align-items:center; gap:6px; }
|
||||
.lang-btn { font-size:11px; padding:2px 8px; border-radius:4px; border:0.5px solid var(--bdr); background:transparent; cursor:pointer; color:var(--text3); }
|
||||
.lang-btn.active { background:var(--text); color:var(--card); border-color:var(--text); }
|
||||
.avatar { width:28px;height:28px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;color:#fff;font-size:12px;font-weight:700; }
|
||||
|
||||
/* TAB BAR */
|
||||
.tabbar {
|
||||
height:36px; min-height:36px;
|
||||
display:flex; align-items:stretch;
|
||||
padding:0 20px; gap:0;
|
||||
border-bottom:0.5px solid var(--bdr);
|
||||
background:var(--card);
|
||||
}
|
||||
.tab {
|
||||
padding:0 16px; display:flex; align-items:center; gap:6px;
|
||||
font-size:12px; color:var(--text3); cursor:pointer;
|
||||
border-bottom:2px solid transparent; position:relative;
|
||||
}
|
||||
.tab.active { color:var(--accent); border-bottom-color:var(--accent); font-weight:500; }
|
||||
.tab-badge { background:var(--red);color:#fff;font-size:9px;padding:1px 5px;border-radius:8px;font-weight:500; }
|
||||
|
||||
/* LOBSTER SWIM */
|
||||
.swim-lane {
|
||||
height:14px; min-height:14px;
|
||||
background:var(--surface);
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
border-bottom:0.5px solid var(--bdr);
|
||||
}
|
||||
.swim-lobster {
|
||||
position:absolute;
|
||||
top:1px;
|
||||
animation: swim-wide 25s linear infinite, chibi-bob 0.7s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* KPI STRIP */
|
||||
.kpi-strip {
|
||||
display:flex; gap:8px; padding:8px 20px;
|
||||
border-bottom:0.5px solid var(--bdr);
|
||||
background:var(--surface);
|
||||
min-height:60px;
|
||||
}
|
||||
.kpi-card {
|
||||
flex:1; background:var(--card); border:0.5px solid var(--bdr);
|
||||
border-radius:8px; padding:8px 12px;
|
||||
display:flex; flex-direction:column; gap:2px;
|
||||
}
|
||||
.kpi-label { font-size:10px; color:var(--text3); }
|
||||
.kpi-val { font-size:18px; font-weight:500; }
|
||||
.kpi-sub { font-size:9px; color:var(--text3); }
|
||||
.kpi-bar { height:3px; border-radius:2px; background:#eee; margin-top:2px; }
|
||||
.kpi-bar-fill { height:100%; border-radius:2px; }
|
||||
.trend-up { color:var(--green); font-size:10px; }
|
||||
|
||||
/* MAIN BODY */
|
||||
.main-body {
|
||||
flex:1; display:flex; gap:12px; padding:12px 20px; overflow:hidden;
|
||||
}
|
||||
.col-left { flex:6; display:flex; flex-direction:column; gap:10px; overflow:hidden; }
|
||||
.col-right { flex:4; display:flex; flex-direction:column; gap:10px; overflow:hidden; }
|
||||
|
||||
/* CARDS */
|
||||
.card {
|
||||
background:var(--card);
|
||||
border:0.5px solid var(--bdr);
|
||||
border-radius:10px;
|
||||
overflow:hidden;
|
||||
}
|
||||
.card-header {
|
||||
display:flex; align-items:center; gap:8px;
|
||||
padding:8px 12px;
|
||||
border-bottom:0.5px solid var(--bdr);
|
||||
font-size:12px; font-weight:500;
|
||||
}
|
||||
.card-header .hdot { width:6px;height:6px;border-radius:50%;background:var(--accent);flex-shrink:0; }
|
||||
.card-header .link { margin-left:auto; font-size:10px; color:var(--accent); text-decoration:none; cursor:pointer; }
|
||||
.card-header .cnt-badge { font-size:9px; background:var(--orange); color:#fff; padding:1px 6px; border-radius:8px; }
|
||||
.card-body { padding:10px 12px; }
|
||||
|
||||
/* INCIDENT */
|
||||
.incident {
|
||||
border-left:3px solid var(--orange);
|
||||
padding:8px 10px;
|
||||
margin-bottom:8px;
|
||||
background:var(--surface);
|
||||
border-radius:0 6px 6px 0;
|
||||
}
|
||||
.incident.p2 { border-left-color:var(--blue); }
|
||||
.sev-badge {
|
||||
display:inline-block; font-size:9px; font-weight:700; padding:1px 6px; border-radius:4px; color:#fff;
|
||||
}
|
||||
.sev-p1 { background:var(--orange); }
|
||||
.sev-p2 { background:var(--blue); }
|
||||
.incident-title { font-size:13px; font-weight:500; margin:4px 0 2px; }
|
||||
.incident-meta { font-size:10px; color:var(--text3); margin-bottom:6px; }
|
||||
|
||||
/* FLOW PIPELINE */
|
||||
.flow-pipe {
|
||||
display:flex; align-items:center; gap:0; margin:6px 0;
|
||||
font-size:9px; position:relative;
|
||||
}
|
||||
.flow-step {
|
||||
display:flex; flex-direction:column; align-items:center; gap:2px;
|
||||
position:relative; flex:1;
|
||||
}
|
||||
.flow-step .circle {
|
||||
width:18px;height:18px;border-radius:50%;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:8px; border:1.5px solid #ccc; background:#fff; color:var(--text3);
|
||||
position:relative; z-index:1;
|
||||
}
|
||||
.flow-step.done .circle { background:var(--orange); border-color:var(--orange); color:#fff; }
|
||||
.flow-step.active .circle { background:#fff; border-color:var(--orange); color:var(--orange); }
|
||||
.flow-step.p2-done .circle { background:var(--blue); border-color:var(--blue); color:#fff; }
|
||||
.flow-step.p2-active .circle {
|
||||
background:#fff; border-color:var(--blue); color:var(--blue);
|
||||
animation: card-glow-p2 1.5s ease-in-out infinite;
|
||||
}
|
||||
.flow-step .label { font-size:8px; color:var(--text3); }
|
||||
.flow-line {
|
||||
height:2px; flex:1; background:#e0ddd4; margin:0 -2px; position:relative; top:-6px; z-index:0;
|
||||
}
|
||||
.flow-line.done { background:var(--orange); }
|
||||
.flow-line.p2-done { background:var(--blue); }
|
||||
|
||||
.flow-openclaw-icon {
|
||||
width:20px; height:20px; border-radius:50%; overflow:hidden;
|
||||
animation: lobster-bob 1.5s ease-in-out infinite;
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
}
|
||||
.flow-openclaw-icon img { width:20px; height:20px; }
|
||||
|
||||
/* AI PROPOSAL */
|
||||
.ai-proposal {
|
||||
background:rgba(245,158,11,0.08);
|
||||
border:0.5px solid rgba(245,158,11,0.25);
|
||||
border-radius:6px; padding:6px 10px;
|
||||
font-size:11px; color:var(--text); margin:6px 0;
|
||||
}
|
||||
.btn-row { display:flex; gap:6px; margin-top:6px; }
|
||||
.btn {
|
||||
padding:4px 12px; border-radius:6px; font-size:11px; cursor:pointer;
|
||||
border:0.5px solid var(--bdr); font-family:'DM Mono',monospace;
|
||||
}
|
||||
.btn-approve { background:var(--green); color:#fff; border-color:var(--green); }
|
||||
.btn-reject { background:transparent; color:var(--text3); }
|
||||
.btn-approve-orange { background:var(--orange); color:#fff; border-color:var(--orange); }
|
||||
|
||||
/* DONUT */
|
||||
.donut-area { display:flex; align-items:center; gap:16px; }
|
||||
.donut-stats { display:grid; grid-template-columns:1fr 1fr; gap:4px 16px; font-size:11px; }
|
||||
.donut-stat { display:flex; align-items:center; gap:6px; }
|
||||
.donut-stat .d-dot { width:6px;height:6px;border-radius:50%;flex-shrink:0; }
|
||||
|
||||
/* ACTIVITY */
|
||||
.activity-item {
|
||||
display:flex; align-items:flex-start; gap:8px; padding:3px 0;
|
||||
font-size:11px; line-height:1.4;
|
||||
}
|
||||
.activity-item .time { font-family:'JetBrains Mono',monospace; font-size:10px; color:var(--text3); flex-shrink:0; }
|
||||
.activity-item .a-dot { width:4px;height:4px;border-radius:50%;flex-shrink:0;margin-top:5px; }
|
||||
.activity-item code { font-family:'JetBrains Mono',monospace; font-size:10px; background:var(--surface); padding:0 3px; border-radius:2px; }
|
||||
|
||||
/* OPENCLAW ENGINE */
|
||||
.oc-panel { display:flex; gap:12px; }
|
||||
.oc-right { flex:1; }
|
||||
.oc-brand { display:flex; align-items:baseline; gap:0; margin-bottom:4px; line-height:1; }
|
||||
.oc-brand .w { 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:1px; line-height:1; }
|
||||
.oc-brand .c { font-family:'DM Mono',monospace; font-size:15px; font-weight:700; color:var(--text); }
|
||||
.oc-badge { display:inline-block; font-size:9px; padding:2px 8px; border-radius:4px; background:rgba(74,144,217,0.1); color:var(--blue); margin-bottom:4px; }
|
||||
.oc-status { font-size:11px; color:var(--text2); margin-bottom:4px; }
|
||||
.oc-dots { display:inline-flex; gap:3px; }
|
||||
.oc-dots span { width:4px;height:4px;border-radius:50%;background:var(--blue);animation:oc-p 1.4s infinite; }
|
||||
.oc-dots span:nth-child(2) { animation-delay:0.2s; }
|
||||
.oc-dots span:nth-child(3) { animation-delay:0.4s; }
|
||||
.oc-sep { height:0.5px; background:var(--bdr); margin:6px 0; }
|
||||
.oc-stats { font-size:10px; color:var(--text3); display:flex; gap:8px; flex-wrap:wrap; }
|
||||
.oc-stats b { color:var(--text2); font-weight:500; }
|
||||
|
||||
/* AI TERMINAL */
|
||||
.ai-terminal {
|
||||
background:#141413; color:#a0e8a0; font-family:'JetBrains Mono',monospace;
|
||||
font-size:10px; border-radius:6px; padding:8px; margin-top:6px;
|
||||
max-height:80px; overflow:hidden; line-height:1.5;
|
||||
}
|
||||
.ai-terminal .cursor { color:#F59E0B; animation:cursor-blink 1s step-end infinite; }
|
||||
|
||||
/* PENDING APPROVALS */
|
||||
.card.pending { border-color:rgba(245,158,11,0.3); }
|
||||
.approval-item {
|
||||
padding:8px; margin-bottom:6px; background:var(--surface); border-radius:6px;
|
||||
}
|
||||
.approval-item .ap-title { font-size:12px; font-weight:500; margin-bottom:2px; }
|
||||
.approval-item .ap-target { font-family:'JetBrains Mono',monospace; font-size:10px; color:var(--text3); margin-bottom:4px; }
|
||||
.risk-badge { font-size:9px; padding:1px 6px; border-radius:4px; font-weight:600; }
|
||||
.risk-low { background:rgba(34,197,94,0.1); color:var(--green); }
|
||||
.risk-med { background:rgba(245,158,11,0.1); color:var(--orange); }
|
||||
|
||||
/* INFRA */
|
||||
.infra-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; }
|
||||
.infra-node {
|
||||
border:0.5px solid var(--bdr); border-radius:6px; padding:8px;
|
||||
font-size:10px;
|
||||
}
|
||||
.infra-node .in-title { font-size:11px; font-weight:500; margin-bottom:2px; }
|
||||
.infra-node .in-sub { font-size:9px; color:var(--text3); margin-bottom:4px; }
|
||||
.infra-node .in-services { display:flex; flex-wrap:wrap; gap:3px; }
|
||||
.in-svc {
|
||||
font-size:9px; padding:1px 5px; border-radius:3px;
|
||||
background:var(--surface); border:0.5px solid var(--bdr);
|
||||
}
|
||||
.in-svc.warn { border-color:var(--orange); background:rgba(245,158,11,0.06); }
|
||||
.in-svc.diag { border-color:var(--blue); background:rgba(74,144,217,0.06); }
|
||||
.infra-node.glow-warn { background:rgba(245,158,11,0.03); }
|
||||
|
||||
/* HOST VIEW */
|
||||
.host-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; }
|
||||
.host-node { border:0.5px solid var(--bdr); border-radius:6px; padding:8px; font-size:10px; }
|
||||
.host-node .hn-title { font-size:11px; font-weight:500; margin-bottom:2px; }
|
||||
.host-node .hn-ip { font-size:9px; color:var(--text3); font-family:'JetBrains Mono',monospace; margin-bottom:4px; }
|
||||
.prog-row { display:flex; align-items:center; gap:4px; margin-bottom:2px; font-size:9px; }
|
||||
.prog-bar { flex:1; height:4px; background:#eee; border-radius:2px; }
|
||||
.prog-fill { height:100%;border-radius:2px; }
|
||||
|
||||
/* AI MODEL */
|
||||
.model-grid { display:grid; grid-template-columns:1fr 1fr; gap:4px; }
|
||||
.model-item {
|
||||
display:flex; align-items:center; gap:6px; font-size:10px;
|
||||
padding:4px 6px; background:var(--surface); border-radius:4px;
|
||||
}
|
||||
.model-item .m-dot { width:5px;height:5px;border-radius:50%;background:var(--green); }
|
||||
|
||||
/* MONITOR TOOLS */
|
||||
.tool-grid { display:grid; grid-template-columns:1fr 1fr 1fr; gap:4px; }
|
||||
.tool-item {
|
||||
display:flex; align-items:center; gap:6px; font-size:10px; padding:4px 6px;
|
||||
background:var(--surface); border-radius:4px;
|
||||
}
|
||||
.tool-item .t-bar { width:3px; height:20px; border-radius:2px; flex-shrink:0; }
|
||||
.tool-item .t-name { font-weight:500; font-size:10px; }
|
||||
.tool-item .t-meta { font-size:9px; color:var(--text3); }
|
||||
|
||||
/* FLOATING */
|
||||
.fab {
|
||||
position:fixed; bottom:16px; right:16px;
|
||||
background:var(--text); color:var(--card);
|
||||
padding:8px 16px; border-radius:8px; font-size:12px;
|
||||
font-family:'JetBrains Mono',monospace;
|
||||
cursor:pointer; z-index:100;
|
||||
border:0.5px solid var(--text3);
|
||||
box-shadow:0 2px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* TOGGLE */
|
||||
.toggle-group { display:flex; margin-left:auto; gap:0; }
|
||||
.toggle-btn {
|
||||
font-size:10px; padding:2px 8px; border:0.5px solid var(--bdr);
|
||||
background:transparent; cursor:pointer; color:var(--text3);
|
||||
font-family:'DM Mono',monospace;
|
||||
}
|
||||
.toggle-btn:first-child { border-radius:4px 0 0 4px; }
|
||||
.toggle-btn:last-child { border-radius:0 4px 4px 0; }
|
||||
.toggle-btn.active { background:var(--text); color:var(--card); border-color:var(--text); }
|
||||
|
||||
/* ANIMATIONS */
|
||||
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.3} }
|
||||
@keyframes swim-wide { 0%{left:-20px;transform:scaleX(1)} 49%{left:calc(100% - 10px);transform:scaleX(1)} 50%{left:calc(100% - 10px);transform:scaleX(-1)} 99%{left:-20px;transform:scaleX(-1)} 100%{left:-20px;transform:scaleX(1)} }
|
||||
@keyframes chibi-bob { 0%,100%{top:1px} 50%{top:-1px} }
|
||||
@keyframes lobster-bob { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-3px)} }
|
||||
@keyframes card-glow-p2 { 0%,100%{box-shadow:0 0 0 0 rgba(74,144,217,0)} 50%{box-shadow:0 0 6px 2px rgba(74,144,217,0.35)} }
|
||||
@keyframes oc-p { 0%,100%{opacity:0.3} 50%{opacity:1} }
|
||||
@keyframes cursor-blink { 0%,100%{opacity:1} 50%{opacity:0} }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- SIDEBAR -->
|
||||
<aside class="sidebar">
|
||||
<div class="brand">
|
||||
<svg width="36" height="36" viewBox="0 0 140 140" fill="none">
|
||||
<defs>
|
||||
<linearGradient id="hdr-ceramic" 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="hdr-led" 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(#hdr-ceramic)" stroke="#E0E0E0" stroke-width="1"/>
|
||||
<circle cx="70" cy="70" r="16" fill="url(#hdr-led)"><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(#hdr-ceramic)" 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(#hdr-ceramic)" 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(#hdr-ceramic)" 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(#hdr-ceramic)" stroke-width="6" stroke-linecap="round" fill="none"/>
|
||||
<path d="M92 92L112 112L124 116" stroke="url(#hdr-ceramic)" 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>
|
||||
<span class="brand-text"><span class="a">A</span><span class="w">wooo</span><span class="i">I</span></span>
|
||||
</div>
|
||||
<nav class="nav">
|
||||
<a class="nav-item active"><span class="dot" style="background:var(--accent)"></span>指令中心</a>
|
||||
<a class="nav-item"><span class="dot" style="background:var(--blue)"></span>可觀測性</a>
|
||||
<a class="nav-item"><span class="dot" style="background:var(--green)"></span>自動化</a>
|
||||
<a class="nav-item"><span class="dot" style="background:var(--purple)"></span>營運</a>
|
||||
<a class="nav-item"><span class="dot" style="background:var(--red)"></span>安全合規</a>
|
||||
<a class="nav-item"><span class="dot" style="background:var(--text3)"></span>知識</a>
|
||||
<div class="nav-sep"></div>
|
||||
<div class="nav-label">LEGACY</div>
|
||||
<a class="nav-item" style="color:#c0bfb8">經典 AI 中心</a>
|
||||
</nav>
|
||||
<div class="nav-bottom">
|
||||
<a class="nav-item"><span class="dot" style="background:var(--text3)"></span>終端</a>
|
||||
<a class="nav-item"><span class="dot" style="background:var(--text3)"></span>設定</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<main class="content">
|
||||
|
||||
<!-- TITLE BAR -->
|
||||
<div class="titlebar">
|
||||
<h1>AI中心</h1>
|
||||
<div class="titlebar-right">
|
||||
<button class="lang-btn active">繁</button>
|
||||
<button class="lang-btn">EN</button>
|
||||
<div class="avatar">OG</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TAB BAR -->
|
||||
<div class="tabbar">
|
||||
<div class="tab active">戰情總覽</div>
|
||||
<div class="tab">告警 & 授權 <span class="tab-badge">2</span></div>
|
||||
<div class="tab">活動串流</div>
|
||||
<div class="tab">處置統計</div>
|
||||
</div>
|
||||
|
||||
<!-- KPI STRIP -->
|
||||
<div class="kpi-strip">
|
||||
<div class="kpi-card">
|
||||
<span class="kpi-label">系統健康</span>
|
||||
<span class="kpi-val" style="color:var(--green)">98.5%</span>
|
||||
<div class="kpi-bar"><div class="kpi-bar-fill" style="width:98.5%;background:var(--green)"></div></div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<span class="kpi-label">活動事件</span>
|
||||
<span class="kpi-val" style="color:var(--orange)">2</span>
|
||||
<span class="kpi-sub">P1:1 P2:1</span>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<span class="kpi-label">自動修復率</span>
|
||||
<span class="kpi-val" style="color:var(--green)">72% <span class="trend-up">↑5%</span></span>
|
||||
<div class="kpi-bar"><div class="kpi-bar-fill" style="width:72%;background:linear-gradient(90deg,var(--green),#6ee7b7)"></div></div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<span class="kpi-label">待審批</span>
|
||||
<span class="kpi-val" style="color:var(--orange)">3</span>
|
||||
<span class="kpi-sub">等待決策</span>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<span class="kpi-label">本週操作</span>
|
||||
<span class="kpi-val">1,245</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MAIN BODY -->
|
||||
<div class="main-body">
|
||||
|
||||
<!-- LEFT COLUMN -->
|
||||
<div class="col-left">
|
||||
|
||||
<!-- ACTIVE INCIDENTS -->
|
||||
<div class="card" style="flex-shrink:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot"></span>
|
||||
<span>活躍事件</span>
|
||||
<span class="cnt-badge">2</span>
|
||||
<a class="link">查看全部告警 →</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- P1 -->
|
||||
<div class="incident">
|
||||
<span class="sev-badge sev-p1">P1</span>
|
||||
<div class="incident-title">API 回應延遲超標</div>
|
||||
<div class="incident-meta">awoooi-api @ awoooi-prod · 3 alerts · investigating</div>
|
||||
<div class="flow-pipe">
|
||||
<div class="flow-step done"><div class="circle">●</div><div class="label">告警</div></div>
|
||||
<div class="flow-line done"></div>
|
||||
<div class="flow-step done"><div class="circle">●</div><div class="label">偵測</div></div>
|
||||
<div class="flow-line done"></div>
|
||||
<div class="flow-step done"><div class="circle">●</div><div class="label">分析</div></div>
|
||||
<div class="flow-line done"></div>
|
||||
<div class="flow-step active"><div class="flow-openclaw-icon"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/openclaw.png" alt="OpenClaw"/></div><div class="label" style="font-weight:700">提案</div></div>
|
||||
<div class="flow-line"></div>
|
||||
<div class="flow-step"><div class="circle">○</div><div class="label">授權</div></div>
|
||||
<div class="flow-line"></div>
|
||||
<div class="flow-step"><div class="circle">○</div><div class="label">執行</div></div>
|
||||
<div class="flow-line"></div>
|
||||
<div class="flow-step"><div class="circle">○</div><div class="label">完成</div></div>
|
||||
</div>
|
||||
<div class="ai-proposal">▶ AI 提案:restart_deployment awoooi-api (信心度 91%)</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn btn-approve">批准執行</button>
|
||||
<button class="btn btn-reject">拒絕</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- P2 -->
|
||||
<div class="incident p2">
|
||||
<span class="sev-badge sev-p2">P2</span>
|
||||
<div class="incident-title">Redis 連線數偏高</div>
|
||||
<div class="incident-meta">redis @ 192.168.0.188 · investigating</div>
|
||||
<div class="flow-pipe">
|
||||
<div class="flow-step p2-done"><div class="circle">■</div><div class="label">告警</div></div>
|
||||
<div class="flow-line p2-done"></div>
|
||||
<div class="flow-step p2-done"><div class="circle">■</div><div class="label">偵測</div></div>
|
||||
<div class="flow-line p2-done"></div>
|
||||
<div class="flow-step p2-active"><div class="flow-openclaw-icon"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/openclaw.png" alt="OpenClaw"/></div><div class="label" style="font-weight:700">分析</div></div>
|
||||
<div class="flow-line"></div>
|
||||
<div class="flow-step"><div class="circle">□</div><div class="label">提案</div></div>
|
||||
<div class="flow-line"></div>
|
||||
<div class="flow-step"><div class="circle">□</div><div class="label">授權</div></div>
|
||||
<div class="flow-line"></div>
|
||||
<div class="flow-step"><div class="circle">□</div><div class="label">執行</div></div>
|
||||
<div class="flow-line"></div>
|
||||
<div class="flow-step"><div class="circle">□</div><div class="label">完成</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DISPOSITION STATS -->
|
||||
<div class="card" style="flex-shrink:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot"></span>
|
||||
<span>處置統計</span>
|
||||
<a class="link">查看完整報表 →</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="donut-area">
|
||||
<svg width="56" height="56" viewBox="0 0 56 56">
|
||||
<circle cx="28" cy="28" r="22" fill="none" stroke="#eee" stroke-width="6"/>
|
||||
<!-- green 70% = 252deg -->
|
||||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--green)" stroke-width="6" stroke-dasharray="96.8 41.2" stroke-dashoffset="34.6" stroke-linecap="round"/>
|
||||
<!-- orange 22% -->
|
||||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--orange)" stroke-width="6" stroke-dasharray="30.4 107.6" stroke-dashoffset="131.8" stroke-linecap="round"/>
|
||||
<!-- purple 6% -->
|
||||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--purple)" stroke-width="6" stroke-dasharray="8.3 129.7" stroke-dashoffset="101.4" stroke-linecap="round"/>
|
||||
<!-- blue 2% -->
|
||||
<circle cx="28" cy="28" r="22" fill="none" stroke="var(--blue)" stroke-width="6" stroke-dasharray="2.8 135.2" stroke-dashoffset="93.1" stroke-linecap="round"/>
|
||||
<text x="28" y="30" text-anchor="middle" font-size="11" font-family="DM Mono" font-weight="500" fill="var(--text)">72%</text>
|
||||
</svg>
|
||||
<div class="donut-stats">
|
||||
<div class="donut-stat"><span class="d-dot" style="background:var(--green)"></span> 自動修復 <b>142</b></div>
|
||||
<div class="donut-stat"><span class="d-dot" style="background:var(--orange)"></span> 人工核准 <b>45</b></div>
|
||||
<div class="donut-stat"><span class="d-dot" style="background:var(--purple)"></span> 手動處理 <b>12</b></div>
|
||||
<div class="donut-stat"><span class="d-dot" style="background:var(--blue)"></span> 冷啟動 <b>5</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RECENT ACTIVITY -->
|
||||
<div class="card" style="flex:1;min-height:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot"></span>
|
||||
<span>最近活動</span>
|
||||
<a class="link">查看活動串流 →</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="activity-item"><span class="time">18:05</span><span class="a-dot" style="background:var(--green)"></span><span>心跳確認 <code>mon/mon1</code> Ready</span></div>
|
||||
<div class="activity-item"><span class="time">18:04</span><span class="a-dot" style="background:var(--blue)"></span><span><b>OpenClaw</b> 匹配 Playbook <code>restart_worker</code> (91%)</span></div>
|
||||
<div class="activity-item"><span class="time">18:02</span><span class="a-dot" style="background:var(--red)"></span><span><b>Prometheus</b> Worker CPU 89%</span></div>
|
||||
<div class="activity-item"><span class="time">17:58</span><span class="a-dot" style="background:var(--green)"></span><span>自動修復完成 <code>restart: api</code> (12s)</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RIGHT COLUMN -->
|
||||
<div class="col-right">
|
||||
|
||||
<!-- OPENCLAW ENGINE -->
|
||||
<div class="card" style="flex-shrink:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot"></span>
|
||||
<span>OPENCLAW 認知引擎</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="oc-panel">
|
||||
<svg width="68" height="68" viewBox="0 0 140 140" fill="none" style="flex-shrink:0">
|
||||
<defs>
|
||||
<linearGradient id="oc-ceramic" 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-led" 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-ceramic)" stroke="#E0E0E0" stroke-width="1"/>
|
||||
<circle cx="70" cy="70" r="16" fill="url(#oc-led)"><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-ceramic)" 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-ceramic)" 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-ceramic)" 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-ceramic)" stroke-width="6" stroke-linecap="round" fill="none"/>
|
||||
<path d="M92 92L112 112L124 116" stroke="url(#oc-ceramic)" 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-right">
|
||||
<div class="oc-brand"><span class="w">W</span><span class="o">○○○</span><span class="c">Claw</span></div>
|
||||
<div class="oc-badge">WoooClaw Pipeline</div>
|
||||
<div class="oc-status">[AGENT] patrolling... <span class="oc-dots"><span></span><span></span><span></span></span></div>
|
||||
<div class="oc-sep"></div>
|
||||
<div class="oc-stats">
|
||||
<span>模型: <b>openclaw_nemo</b></span> <span>● 運行中</span>
|
||||
</div>
|
||||
<div class="oc-stats" style="margin-top:2px">
|
||||
<span>今日分析: <b>23</b></span>
|
||||
<span>成功率: <b>91%</b></span>
|
||||
<span>MTTR: <b>8.2m</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ai-terminal">
|
||||
<div>[18:03] Analyzing worker CPU spike...</div>
|
||||
<div>[18:03] Root cause: OOM pressure</div>
|
||||
<div>[18:03] Matched: restart_worker (91%)</div>
|
||||
<div>[18:03] Awaiting approval <span class="cursor">▎</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PENDING APPROVALS -->
|
||||
<div class="card pending" style="flex-shrink:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot" style="background:var(--orange)"></span>
|
||||
<span>待審批任務</span>
|
||||
<span class="cnt-badge">3</span>
|
||||
<a class="link">查看全部授權 →</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="approval-item">
|
||||
<div class="ap-title" style="color:var(--red)">Worker 高負載警告</div>
|
||||
<div class="ap-target">ssh://wooo@192.168.0.110/restart</div>
|
||||
<span class="risk-badge risk-low">LOW RISK</span>
|
||||
<div class="btn-row">
|
||||
<button class="btn btn-approve" title="點擊批准">批准</button>
|
||||
<button class="btn btn-reject">拒絕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="approval-item">
|
||||
<div class="ap-title" style="color:var(--orange)">Redis 記憶體壓力</div>
|
||||
<div class="ap-target">ansible://188/clear_redis_cache.yml</div>
|
||||
<span class="risk-badge risk-med">MEDIUM</span>
|
||||
<div class="btn-row">
|
||||
<button class="btn btn-approve-orange" title="高風險操作需長按確認">長按批准</button>
|
||||
<button class="btn btn-reject">拒絕</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- INFRASTRUCTURE -->
|
||||
<div class="card" style="flex-shrink:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot"></span>
|
||||
<span>基礎架構</span>
|
||||
<div class="toggle-group">
|
||||
<button class="toggle-btn" onclick="switchView('host')">主機</button>
|
||||
<button class="toggle-btn active" onclick="switchView('topo')">拓撲</button>
|
||||
</div>
|
||||
<a class="link">展開全圖 →</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- TOPO VIEW -->
|
||||
<div id="view-topo" class="infra-grid">
|
||||
<div class="infra-node" style="border-color:var(--blue)">
|
||||
<div class="in-title">🏗️ 基礎設施 (.110)</div>
|
||||
<div class="in-sub">7 服務 · ✓ 全部健康</div>
|
||||
<div class="in-services">
|
||||
<span class="in-svc">●Gitea</span><span class="in-svc">●Harbor</span><span class="in-svc">●Sentry</span><span class="in-svc">●Prom</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infra-node" style="border-color:var(--orange)">
|
||||
<div class="in-title">🧠 AI/數據 (.188)</div>
|
||||
<div class="in-sub">7 服務 · ⚡ OpenClaw 診斷中</div>
|
||||
<div class="in-services">
|
||||
<span class="in-svc">●PG</span><span class="in-svc">●Redis</span><span class="in-svc diag">●OpenClaw⚡</span><span class="in-svc">●Ollama</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infra-node glow-warn" style="border-color:var(--purple)">
|
||||
<div class="in-title">☸️ K3s 叢集</div>
|
||||
<div class="in-sub">5 服務 · ⚠️ Worker CPU 89%</div>
|
||||
<div class="in-services">
|
||||
<span class="in-svc">●api×2</span><span class="in-svc">●web×2</span><span class="in-svc warn">⚠️worker</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infra-node" style="border-color:var(--orange)">
|
||||
<div class="in-title">🌐 外部服務</div>
|
||||
<div class="in-sub">3 服務 · ✓ 全部可達</div>
|
||||
<div class="in-services">
|
||||
<span class="in-svc">●Gemini</span><span class="in-svc">●NVIDIA</span><span class="in-svc">●CF</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- HOST VIEW -->
|
||||
<div id="view-host" class="host-grid" style="display:none">
|
||||
<div class="host-node">
|
||||
<div class="hn-title">DevOps 金庫</div>
|
||||
<div class="hn-ip">192.168.0.110</div>
|
||||
<div class="prog-row">CPU<div class="prog-bar"><div class="prog-fill" style="width:35%;background:var(--green)"></div></div>35%</div>
|
||||
<div class="prog-row">RAM<div class="prog-bar"><div class="prog-fill" style="width:55%;background:var(--green)"></div></div>55%</div>
|
||||
</div>
|
||||
<div class="host-node">
|
||||
<div class="hn-title">AI+Web 中心</div>
|
||||
<div class="hn-ip">192.168.0.188</div>
|
||||
<div class="prog-row">CPU<div class="prog-bar"><div class="prog-fill" style="width:67%;background:var(--orange)"></div></div>67%</div>
|
||||
<div class="prog-row">RAM<div class="prog-bar"><div class="prog-fill" style="width:72%;background:var(--orange)"></div></div>72%</div>
|
||||
</div>
|
||||
<div class="host-node">
|
||||
<div class="hn-title">K3s Master</div>
|
||||
<div class="hn-ip">192.168.0.120</div>
|
||||
<div class="prog-row">CPU<div class="prog-bar"><div class="prog-fill" style="width:45%;background:var(--green)"></div></div>45%</div>
|
||||
<div class="prog-row">RAM<div class="prog-bar"><div class="prog-fill" style="width:60%;background:var(--green)"></div></div>60%</div>
|
||||
</div>
|
||||
<div class="host-node">
|
||||
<div class="hn-title">K3s Worker</div>
|
||||
<div class="hn-ip">192.168.0.121</div>
|
||||
<div class="prog-row">CPU<div class="prog-bar"><div class="prog-fill" style="width:0;background:#ccc"></div></div>--</div>
|
||||
<div class="prog-row">RAM<div class="prog-bar"><div class="prog-fill" style="width:0;background:#ccc"></div></div>--</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI MODEL STATUS -->
|
||||
<div class="card" style="flex-shrink:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot"></span>
|
||||
<span>AI 模型狀態</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="model-grid">
|
||||
<div class="model-item"><span class="m-dot"></span>OpenClaw Nemo (local)</div>
|
||||
<div class="model-item"><span class="m-dot"></span>Ollama gemma3 (local)</div>
|
||||
<div class="model-item"><span class="m-dot"></span>Gemini Pro (cloud)</div>
|
||||
<div class="model-item"><span class="m-dot"></span>NVIDIA NIM (cloud)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MONITOR TOOLS -->
|
||||
<div class="card" style="flex:1;min-height:0;">
|
||||
<div class="card-header">
|
||||
<span class="hdot"></span>
|
||||
<span>監控工具</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tool-grid">
|
||||
<div class="tool-item"><div class="t-bar" style="background:var(--blue)"></div><div><div class="t-name">SigNoz</div><div class="t-meta">Traces · Logs</div></div></div>
|
||||
<div class="tool-item"><div class="t-bar" style="background:#E85530"></div><div><div class="t-name">Grafana</div><div class="t-meta">3 Dashboards</div></div></div>
|
||||
<div class="tool-item"><div class="t-bar" style="background:var(--green)"></div><div><div class="t-name">Prometheus</div><div class="t-meta">23 targets</div></div></div>
|
||||
<div class="tool-item"><div class="t-bar" style="background:var(--orange)"></div><div><div class="t-name">Langfuse</div><div class="t-meta">LLMOps</div></div></div>
|
||||
<div class="tool-item"><div class="t-bar" style="background:var(--red)"></div><div><div class="t-name">Sentry</div><div class="t-meta">2 Projects</div></div></div>
|
||||
<div class="tool-item"><div class="t-bar" style="background:var(--purple)"></div><div><div class="t-name">Gitea</div><div class="t-meta">CI/CD</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- FLOATING FAB -->
|
||||
<div class="fab">⌨ Omni-Terminal [⌘J]</div>
|
||||
|
||||
<script>
|
||||
function switchView(v) {
|
||||
const topo = document.getElementById('view-topo');
|
||||
const host = document.getElementById('view-host');
|
||||
const btns = document.querySelectorAll('.toggle-btn');
|
||||
if (v === 'host') {
|
||||
topo.style.display = 'none';
|
||||
host.style.display = 'grid';
|
||||
btns[0].classList.add('active');
|
||||
btns[1].classList.remove('active');
|
||||
} else {
|
||||
topo.style.display = 'grid';
|
||||
host.style.display = 'none';
|
||||
btns[0].classList.remove('active');
|
||||
btns[1].classList.add('active');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -6,6 +6,23 @@
|
||||
|
||||
---
|
||||
|
||||
## 📍 當前狀態 (2026-04-09 Sprint 5R 前端重構批准 — 開始實施)
|
||||
|
||||
| 項目 | 狀態 | 說明 |
|
||||
|------|------|------|
|
||||
| QA 全面盤點 (21 頁面截圖) | ✅ | 6 個 P0 + 4 個 P1 + 6 個 P2 |
|
||||
| 設計稿版本 A/B/C 製作 | ✅ | 部署到 188:8765 |
|
||||
| 版本 A 統帥批准 | ✅ | Logo/文字/龍蝦/流程圖 4 輪修正 |
|
||||
| Gemini UI/UX 建議整合 | ✅ | 骨架屏+Terminal+光暈+長按確認 |
|
||||
| ADR-065 Sprint 5R 前端重構 | ✅ | 已批准 |
|
||||
| Memory 更新 | ✅ | brand_logo_consistency + sprint5r_plan |
|
||||
| **Phase 1A 實施中** | 🔄 | S11-S12 修復載入失敗 |
|
||||
|
||||
**批准設計稿**: `.playwright-mcp/sprint5r-approved-design.html`
|
||||
**下一步**: S11 → S12 → S1-S10 → G1 → 建置部署驗收
|
||||
|
||||
---
|
||||
|
||||
## 📍 當前狀態 (2026-04-09 自動修復 L7 完整閉環 — 12 Bug 全修)
|
||||
|
||||
| 項目 | 狀態 | Commit |
|
||||
|
||||
38
docs/adr/ADR-065-sprint5r-frontend-rebuild.md
Normal file
38
docs/adr/ADR-065-sprint5r-frontend-rebuild.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# ADR-065: Sprint 5R 前端重構 — AI 戰情指揮中心
|
||||
|
||||
## 狀態: 已批准 (2026-04-09)
|
||||
|
||||
## 背景
|
||||
|
||||
Sprint 5 完成了前端多頁籤整合和 Panel 抽取,但 QA 發現正式環境首頁與統帥批准的設計稿存在重大差距:
|
||||
- KPI 用分隔線文字而非卡片
|
||||
- 缺少 FlowPipeline 進度條、AI 提案橫幅、處置環形圖、最近活動、AI Terminal、待審批、AI 模型狀態
|
||||
- 多個頁面永遠載入中
|
||||
- 監控工具佈局不對
|
||||
|
||||
## 決策
|
||||
|
||||
全面重構首頁戰情總覽,對齊 `sprint5r-approved-design.html` 設計稿 + Gemini UI/UX 增強建議。
|
||||
|
||||
### 設計稿選擇
|
||||
- 版本 A(忠實還原 + 微增強)— 統帥批准
|
||||
- Title Bar 移除 AI 模型名稱
|
||||
- 龍蝦游泳列移除
|
||||
- 流程圖 icon 改用 dashboardicons.com OpenClaw
|
||||
|
||||
### 實施方案
|
||||
- Phase 1A: 修復載入失敗 (S11-S12)
|
||||
- Phase 1B: 首頁重構 14 個元件 (S1-S10)
|
||||
- Phase 1C: 全局骨架屏 (G1)
|
||||
|
||||
### Gemini 建議採納
|
||||
- 脈動骨架屏取代「載入中」
|
||||
- AI Terminal 打字機動畫
|
||||
- 拓撲群組異常光暈
|
||||
- 高風險操作長按確認
|
||||
|
||||
## 後果
|
||||
|
||||
- 首頁從「傳統儀表板」升級為「AI 戰情指揮中心」
|
||||
- 所有資料串接真實 API,零假數據
|
||||
- 與設計稿像素級對齊
|
||||
Reference in New Issue
Block a user