diff --git a/apps/web/src/app/[locale]/page.tsx b/apps/web/src/app/[locale]/page.tsx
index 5930fba4..f4763a70 100644
--- a/apps/web/src/app/[locale]/page.tsx
+++ b/apps/web/src/app/[locale]/page.tsx
@@ -650,96 +650,24 @@ export default function Home({ params }: { params: { locale: string } }) {
const podHealthStr = totalServices > 0 ? `${healthyServices}/${totalServices}` : '--'
const podAllRunning = totalServices > 0 && healthyServices === totalServices
- // ── 7 Metrics Strip ─────────────────────────────────────────────────────────
- // figma-v2 順序: 活躍事件 | 服務健康 | 待處理授權 | 今日事件 | 自動處置率 | MTTR 均值 | Pod 健康
+ // ── 5 KPI Cards (Sprint 5R 設計稿批准版) ────────────────────────────────────
const hasPendingApprovals = pendingApprovals !== null && pendingApprovals !== undefined && pendingApprovals > 0
-
const incidentCount = incidents?.length ?? 0
- const todayIncidentCount = incidentCount
- // P2 count
+ const p1Count = incidents?.filter(i => i.severity === 'P1').length ?? 0
const p2Count = incidents?.filter(i => i.severity === 'P2').length ?? 0
- const metrics: MetricItem[] = [
- {
- label: tDashboard('activeIncidents'),
- value: incidentCount > 0 ? incidentCount : '--',
- sub: incidentCount === 0 ? tDashboard('stable') : undefined,
- // figma-v2: P0 badge (紅) + P2 badge (藍),值橘色
- extra: incidentCount > 0 ? (
-
- {p0Count > 0 && (
- P0×{p0Count}
- )}
- {p2Count > 0 && (
- P2×{p2Count}
- )}
-
- ) : undefined,
- valueColor: incidentCount > 0 ? '#d97757' : undefined,
- },
- {
- label: tDashboard('serviceHealth'),
- value: totalServices > 0 ? `${healthyServices}/${totalServices}` : '--',
- valueColor: '#22C55E',
- // 固定4條,按比例顯示健康數
- extra: totalServices > 0 ? (
-
- {Array.from({ length: 4 }).map((_, idx) => (
-
- ))}
-
- ) : undefined,
- },
- {
- label: tDashboard('pendingApprovals'),
- value: pendingApprovals ?? '--',
- sub: hasPendingApprovals ? undefined : tDashboard('stable'),
- badge: hasPendingApprovals ? { text: tDashboard('awaitingConfirm'), color: '#F59E0B', bg: 'rgba(245,158,11,0.08)' } : undefined,
- valueColor: hasPendingApprovals ? '#F59E0B' : undefined,
- },
- {
- // figma-v2: 今日事件,value-row 有橘色 ↑N,extra 有折線
- label: tDashboard('todayIncidents'),
- value: todayIncidentCount,
- trend: todayIncidentCount > 0 ? { text: `↑${todayIncidentCount > 0 ? Math.max(1, Math.round(todayIncidentCount * 0.2)) : 0}`, color: '#d97757' } : undefined,
- extra: todaySparkValues ? (
-
- ) : undefined,
- },
- {
- label: tDashboard('autoRemediationRate'),
- value: autoRemediationRate,
- trend: autoRemediationPct > 0 ? { text: `↑${autoRemediationPct > 5 ? 5 : autoRemediationPct}%`, color: '#22C55E' } : undefined,
- extra: (
-
- ),
- },
- {
- label: tDashboard('mttrAvg'),
- value: mttrAvg,
- trend: mttrTrend,
- extra: mttrSparkValues ? (
-
- ) : undefined,
- },
- {
- label: tDashboard('podHealth'),
- value: podHealthStr,
- sub: podAllRunning
- ? tDashboard('allRunning')
- : totalServices > 0 ? `${totalServices - healthyServices} down` : undefined,
- valueColor: podAllRunning ? '#22C55E' : totalServices > 0 ? '#cc2200' : undefined,
- },
- ]
+ // 本週操作數
+ const [weeklyOps, setWeeklyOps] = useState(null)
+ useEffect(() => {
+ fetch(`${API_BASE}/api/v1/audit-logs/stats`)
+ .then(r => r.ok ? r.json() : null)
+ .then(d => { if (d?.total_executions != null) setWeeklyOps(d.total_executions) })
+ .catch(() => {})
+ }, [])
+
+ // 系統健康百分比
+ const systemHealthPct = totalServices > 0 ? Math.round((healthyServices / totalServices) * 100) : 0
// Sprint 5: 4 Tab 配置 (統帥批准 2026-04-08)
const alertsCount = incidents?.length ?? 0
@@ -787,104 +715,51 @@ export default function Home({ params }: { params: { locale: string } }) {
overflow: 'hidden',
}}>
- {/* ── Metrics Strip ─────────────────────────────────────────────────── */}
-
- {/* Chibi 龍蝦游泳列 */}
-
-
-
-
-
+ {/* ── KPI Strip (5 卡片 — Sprint 5R 設計稿) ──────────────────────── */}
+
+ {/* 系統健康 */}
+
+
{tDashboard('serviceHealth')}
+
+ {totalServices > 0 ? `${Math.round((healthyServices / totalServices) * 100)}%` : '--'}
+
+ {totalServices > 0 && (
+
+ )}
+
+ {/* 活動事件 */}
+
+
{tDashboard('activeIncidents')}
+
+ 0 ? '#d97757' : '#141413' }}>{incidentCount || '--'}
+ {incidentCount > 0 && P1:{p1Count} P2:{p2Count}}
- {/* Metrics Row — figma-v2 完整複製 */}
-
- {metrics.map((m, i) => (
-
-
- {/* Label — figma: font-size:11px */}
-
- {m.label}
-
- {/* Value row — figma: height:32px,值 + trend 箭頭同行 */}
-
-
- {String(m.value)}
-
- {m.trend && (
- {m.trend.text}
- )}
-
- {/* Extra row — figma: height:20px margin-top:4px */}
-
- {m.extra ? m.extra : m.badge ? (
-
- {m.badge.text}
-
- ) : m.sub ? (
- {m.sub}
- ) : null}
-
-
- {/* Divider — figma: 獨立元素 width:0.5px height:36px */}
- {i < metrics.length - 1 && (
-
- )}
-
- ))}
+ {/* 自動修復率 */}
+
+
{tDashboard('autoRemediationRate')}
+
+ {autoRemediationRate}
+ {autoRemediationPct > 0 && ↑5%}
+
+
+
+ {/* 待審批 */}
+
+
{tDashboard('pendingApprovals')}
+
+ {pendingApprovals ?? '--'}
+ {hasPendingApprovals && {tDashboard('awaitingConfirm')}}
+
+
+ {/* 本週操作 */}
+
+
{tDashboard('todayIncidents')}
+
{weeklyOps != null ? weeklyOps.toLocaleString() : '--'}