From 48a9e96ec2fc1c9593ddcb52d4f26e24723b34a8 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Mon, 11 May 2026 17:04:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=9B=AE=E6=A0=87=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E6=94=B9=E4=B8=BA=E5=9E=82=E7=9B=B4=E4=B8=89=E5=B1=82?= =?UTF-8?q?=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 卡片宽度从 280px 调整为 270px,确保 StatusBar 30 个色块完整显示 - 布局从水平两行改为垂直三层:标题行、StatusBar、Sparkline 各占一行 - Sparkline 从固定 80x32px 改为占满宽度(约 238px x 40px) - 三层之间使用 12px gap 间距 - 类名重构:card-row-1 -> card-header,拆分 card-row-2 为 card-status-bar 和 card-sparkline --- openspec/specs/card-dashboard/spec.md | 20 ++++++++++++-------- src/web/components/MiniSparkline.tsx | 2 +- src/web/components/TargetCard.tsx | 6 ++++-- src/web/styles.css | 20 ++++++++++++++------ 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/openspec/specs/card-dashboard/spec.md b/openspec/specs/card-dashboard/spec.md index 005850c..745b04c 100644 --- a/openspec/specs/card-dashboard/spec.md +++ b/openspec/specs/card-dashboard/spec.md @@ -28,7 +28,7 @@ Dashboard SHALL 使用固定宽度的卡片配合 Flexbox 流动布局,容器 #### Scenario: 卡片固定宽度 - **WHEN** 页面渲染卡片(包括 Summary Cards 和 Target Cards) -- **THEN** 每个卡片 SHALL 固定宽度 280px,使用 `flex-shrink: 0` 防止收缩 +- **THEN** 每个卡片 SHALL 固定宽度 270px,使用 `flex-shrink: 0` 防止收缩 #### Scenario: 流动式布局 - **WHEN** 视口宽度变化 @@ -43,11 +43,11 @@ Dashboard SHALL 使用固定宽度的卡片配合 Flexbox 流动布局,容器 - **THEN** 两种卡片网格 SHALL 使用相同的 gap 间距(16px) ### Requirement: 目标卡片内容 -每个目标卡片 SHALL 展示目标名称、当前状态、类型标签、状态条和迷你耗时趋势线。 +每个目标卡片 SHALL 展示目标名称、当前状态、类型标签、状态条和迷你耗时趋势线,采用垂直三层布局。 -#### Scenario: 卡片第一行内容 +#### Scenario: 卡片第一层内容 - **WHEN** 卡片渲染 -- **THEN** 卡片第一行 SHALL 展示状态指示圆点(UP 绿色 / DOWN 红色)、目标名称和类型标签(HTTP / Command) +- **THEN** 卡片第一层 SHALL 展示状态指示圆点(UP 绿色 / DOWN 红色)、目标名称和类型标签(HTTP / Command) #### Scenario: 卡片状态指示圆点 - **WHEN** 目标最近一次拨测 matched=true @@ -55,13 +55,17 @@ Dashboard SHALL 使用固定宽度的卡片配合 Flexbox 流动布局,容器 - **WHEN** 目标最近一次拨测 matched=false - **THEN** 卡片状态圆点 SHALL 显示为红色 -#### Scenario: 卡片状态条可视化 +#### Scenario: 卡片第二层状态条 - **WHEN** 卡片渲染且 recentSamples 数据可用 -- **THEN** 卡片 SHALL 展示一条 30 方块的状态条,每个采样点为一个色块:UP 显示绿色(#1fbf75),DOWN 显示红色(#e5484d),无数据显示灰色(#e2e8f0) +- **THEN** 卡片第二层 SHALL 独占一行展示状态条,包含 30 个色块,每个采样点为一个色块:UP 显示绿色(#1fbf75),DOWN 显示红色(#e5484d),无数据显示灰色(#e2e8f0) -#### Scenario: 卡片迷你耗时趋势线 +#### Scenario: 卡片第三层迷你耗时趋势线 - **WHEN** 卡片渲染且 recentSamples 中有 durationMs 数据 -- **THEN** 卡片 SHALL 展示基于 recharts 的迷你折线图(80x32px),展示最近 30 次检查的耗时趋势 +- **THEN** 卡片第三层 SHALL 独占一行展示基于 recharts 的迷你折线图,宽度占满卡片内容区(约 238px),高度 40px,展示最近 30 次检查的耗时趋势 + +#### Scenario: 卡片垂直布局间距 +- **WHEN** 卡片渲染 +- **THEN** 卡片三层之间 SHALL 使用 12px 的间距(gap) ### Requirement: 卡片交互 卡片 SHALL 支持 hover 效果和点击打开模态框。 diff --git a/src/web/components/MiniSparkline.tsx b/src/web/components/MiniSparkline.tsx index 0ceba87..e8407b5 100644 --- a/src/web/components/MiniSparkline.tsx +++ b/src/web/components/MiniSparkline.tsx @@ -16,7 +16,7 @@ export function MiniSparkline({ data }: MiniSparklineProps) { } return ( - + diff --git a/src/web/components/TargetCard.tsx b/src/web/components/TargetCard.tsx index c33fea7..3a8d9d6 100644 --- a/src/web/components/TargetCard.tsx +++ b/src/web/components/TargetCard.tsx @@ -13,13 +13,15 @@ export function TargetCard({ target, onClick }: TargetCardProps) { return (
-
+
{target.name} {target.type === "http" ? "HTTP" : "Command"}
-
+
+
+
diff --git a/src/web/styles.css b/src/web/styles.css index 155902b..67e5dd5 100644 --- a/src/web/styles.css +++ b/src/web/styles.css @@ -133,7 +133,7 @@ body { } .target-card { - width: 280px; + width: 270px; flex-shrink: 0; padding: 16px; border: 1px solid rgba(49, 83, 126, 0.12); @@ -144,6 +144,9 @@ body { transition: box-shadow 0.3s ease, transform 0.3s ease; + display: flex; + flex-direction: column; + gap: 12px; } .target-card:hover { @@ -151,11 +154,10 @@ body { transform: translateY(-2px); } -.card-row-1 { +.card-header { display: flex; align-items: center; gap: 8px; - margin-bottom: 12px; } .card-name { @@ -178,10 +180,15 @@ body { letter-spacing: 0.04em; } -.card-row-2 { +.card-status-bar { display: flex; - align-items: center; - justify-content: space-between; + width: 100%; +} + +.card-sparkline { + display: flex; + width: 100%; + height: 40px; } .status-dot { @@ -206,6 +213,7 @@ body { display: flex; gap: 2px; align-items: center; + width: 100%; } .status-bar-block {