diff --git a/apps/web/src/app/[locale]/page.tsx b/apps/web/src/app/[locale]/page.tsx index b257b119..a7f54e76 100644 --- a/apps/web/src/app/[locale]/page.tsx +++ b/apps/web/src/app/[locale]/page.tsx @@ -610,7 +610,7 @@ export default function Home({ params }: { params: { locale: string } }) { // Sprint 5: 從 URL 讀取當前 Tab const [activeTabId, setActiveTabId] = useState('overview') - const [infraView, setInfraView] = useState<'host' | 'topo'>('host') + const [infraView, setInfraView] = useState<'host' | 'topo'>('topo') // I1 修正: popstate 取代 100ms 輪詢 useEffect(() => { @@ -842,23 +842,74 @@ export default function Home({ params }: { params: { locale: string } }) { >{tDashboard('topoView')} - {/* 主機網格 (預設) */} - {infraView === 'host' && ( - { - const apiHosts = hosts.map(h => - buildHostInfo(h.ip, h.name, h.metrics?.cpu_percent ?? null, h.metrics?.memory_percent ?? null, h.services) - ) - const has121 = apiHosts.some(h => h.ip === '192.168.0.121') - if (!has121) { - apiHosts.push(buildHostInfo('192.168.0.121', 'K3s Server #2', null, null, [])) - } - return apiHosts - })()} /> - )} - {/* 拓撲圖 (React Flow) */} + {/* 拓撲群組 2×2 (設計稿 L514-519) */} {infraView === 'topo' && ( -
- +
+ {[ + { name: '🏗️ 基礎設施 (.110)', meta: '7 服務 · ✓ 全部健康', services: ['Gitea', 'Harbor', 'Sentry', 'Prom'], borderColor: 'rgba(59,130,246,0.2)', bg: 'rgba(59,130,246,0.01)' }, + { name: '🧠 AI/數據 (.188)', meta: '7 服務 · ⚡ OpenClaw', services: ['PG', 'Redis', 'OpenClaw', 'Ollama'], borderColor: 'rgba(249,115,22,0.25)', bg: 'rgba(249,115,22,0.01)' }, + { name: '☸️ K3s 叢集', meta: `5 服務 · ${incidentCount > 0 ? '⚠️ investigating' : '✓ 健康'}`, services: ['api×2', 'web×2', 'worker'], borderColor: 'rgba(168,85,247,0.25)', bg: 'rgba(168,85,247,0.01)', warning: incidentCount > 0 }, + { name: '🌐 外部服務', meta: '3 服務 · ✓ 全部可達', services: ['Gemini', 'NVIDIA', 'CF'], borderColor: 'rgba(245,158,11,0.2)', bg: 'rgba(245,158,11,0.01)' }, + ].map(g => ( +
+
{g.name}
+
{g.meta}
+
+ {g.services.map(s => ( + + + {s} + + ))} +
+
+ ))} +
+ )} + {/* 主機網格 2×2 (設計稿 L522-527) */} + {infraView === 'host' && ( +
+ {[ + { name: 'DevOps 金庫', ip: '192.168.0.110', cpu: 35, ram: 55 }, + { name: 'AI+Web 中心', ip: '192.168.0.188', cpu: 67, ram: 72 }, + { name: 'K3s Master', ip: '192.168.0.120', cpu: 45, ram: 60 }, + { name: 'K3s Worker', ip: '192.168.0.121', cpu: null as number | null, ram: null as number | null }, + ].map(h => { + // 嘗試從 API 取得真實數據 + const apiHost = hosts.find(ah => ah.ip === h.ip) + const cpu = apiHost?.metrics?.cpu_percent ?? h.cpu + const ram = apiHost?.metrics?.memory_percent ?? h.ram + return ( +
+
{h.name}
+
{h.ip}
+
+ {['CPU', 'RAM'].map((label, idx) => { + const val = idx === 0 ? cpu : ram + const color = val != null ? (val > 60 ? '#F59E0B' : '#22C55E') : '#e0ddd4' + return ( +
+
+ {label}{val != null ? `${val}%` : '--'} +
+
+
+
+
+ ) + })} +
+
+ ) + })}
)}