Files
kangkang/docs/superpowers/specs/2026-05-26-hide-monitor-preset-design.md
link2026 599d39af35 docs(spec): 长期监测预设支持隐藏(2026-05-26)
UserProfile 加 hiddenPresetMetrics 字段;IndicatorQuickSheet
长按 tile 出 contextMenu 隐藏,顶部 chip 显示已隐藏数 + 恢复入口。
历史数据/Trends/Reminder 全不动。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 19:37:34 +08:00

123 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Hide Monitor Preset · 设计 v1
> 「记录指标」sheet 长期监测预设(`MonitorMetric`)支持隐藏
>
> 日期:2026-05-26 · 状态:approved by user(2026-05-26 对话)
> 关联:[CLAUDE.md](../../../CLAUDE.md) §7,[Monitor+Profile spec](./2026-05-26-monitor-and-profile-design.md)
---
## 1. 背景
`IndicatorQuickSheet`「长期监测(进趋势)」分组由 `MonitorMetric.allCases` 渲染,目前 6 个硬编码 case(血压/空腹血糖/餐后血糖/体温/心率/血氧)无法隐藏,与下方 `CustomMonitorMetric`(可长按编辑/删除)体验不一致。
用户场景:不测血氧、不测血压的人想清理 grid;但**不能误删历史数据**——已经测过的折线在 Trends 里还要看。
## 2. 目标
- 长按 `MonitorMetric` tile → contextMenu 出"隐藏"
- 已隐藏的 tile 从 grid 过滤掉,但已有 `Indicator` 记录、Trends 折线、`MetricReminder` 全不动
- 提供可逆恢复入口
## 3. 非目标(YAGNI)
- ❌ 化验项快捷预设(labPresets)同款功能 — 本次不动
- ❌ 「我的」里集中管理页 — grid 上就近恢复即可
- ❌ 批量隐藏 / 拖拽排序
- ❌ 二次确认弹窗 — 隐藏可逆,不需要
- ❌ 隐藏时联动关掉对应 `MetricReminder` — 用户没说,保守不动
## 4. 数据模型
`UserProfile` 增加一个字段:
```swift
var hiddenPresetMetrics: [String] = [] // MonitorMetric.rawValue
```
- 类型沿用 `[String]`,跟 `allergies` / `chronicConditions` 一致,SwiftData 自动 transformable
- init 默认 `[]`,无 migration 风险
- 写入用 `UserProfile.updatedAt = .now`
为什么不另开 `@Model HiddenPresetMetric`:8 个 case 的隐藏标记只是 UI 偏好,放 Profile 单例最自然,避免新 entity + 关联查询。
## 5. UI 行为
### 5.1 隐藏入口
`IndicatorQuickSheet.monitorTile(_:)``.contextMenu`:
```swift
.contextMenu {
Button(role: .destructive) {
hideMonitor(m)
} label: {
Label("隐藏", systemImage: "eye.slash")
}
}
```
`hideMonitor``m.rawValue` 加入 `profile.hiddenPresetMetrics`,save,grid 因 `@Query` 重渲染。被隐藏的 tile 若当前选中,要 `clearMonitor()` 复位。
### 5.2 grid 过滤
```swift
ForEach(MonitorMetric.allCases.filter { !hiddenSet.contains($0.rawValue) }) { m in
monitorTile(m)
}
```
`hiddenSet` = `Set(profile?.hiddenPresetMetrics ?? [])`,computed property。
### 5.3 恢复入口
`monitorGridSection` 顶部 section label 一行:
```
长期监测(进趋势) 已隐藏 3
```
- chip 仅当 `hiddenSet.nonEmpty` 显示
- 点 chip → `.sheet` 弹一个轻量列表(`.medium` detent)
- 列表项:每个被隐藏的 `MonitorMetric` 显示 icon + displayName + 右侧"显示"按钮
- 点"显示" → `profile.hiddenPresetMetrics.removeAll { $0 == m.rawValue }` + save
- 列表空了自动 dismiss
### 5.4 边界
- 全部 6 个都隐藏:section 还在(label + chip + addCustomTile),不消失
- 隐藏不影响:Trends 折线、`Indicator` 列表查询、`MetricReminder` 调度
- `UserProfileStore.loadOrCreate` 已保证 profile 存在,无 nil 分支
- `@Query private var profiles: [UserProfile]` 已在 sheet 里,直接取 `profiles.first`
## 6. 文件改动清单
1. `Models/UserProfile.swift` — 加 `hiddenPresetMetrics: [String]` 字段 + init 默认值
2. `Features/Indicator/IndicatorQuickSheet.swift`
- `monitorGridSection`: 过滤 + 顶部 chip
- `monitorTile`: 加 contextMenu
- 新增 `hideMonitor(_:)` / `unhideMonitor(_:)` / `hiddenSet`
- 新增 `HiddenMonitorRestoreSheet` 子 View(同文件内,私有)
不动:`MonitorMetric.swift``CustomMetricEditor.swift`、Trends、`ReminderService``MeView`
## 7. 测试 / 验证手段
无单测目标(全 UI 行为)。手测点:
- [ ] 长按血压 tile → 出现"隐藏",点了 grid 里消失
- [ ] 顶部 chip "已隐藏 1" 出现,数字正确
- [ ] 点 chip → 弹列表,有 1 行血压,点"显示"恢复
- [ ] 全部 6 个隐藏 → grid 只剩 addCustomTile + 自定义指标,不崩
- [ ] 隐藏期间去 Trends,血压折线仍在
- [ ] 隐藏前若血压已选中,隐藏后选中态清空、字段清空
- [ ] 重启 App,隐藏状态持久
## 8. 红线核查(CLAUDE.md §10)
- ✅ 不引入云
- ✅ 不动 AIRuntime / Service 边界
- ✅ 不动 SwiftData 既有 `Indicator` schema
- ✅ Tab / RecordSheet 骨架不动
- ✅ 不是清单外功能,是对 §7 grid 的小改良