feat(timeline): merge bp.systolic + bp.diastolic into single entry

- TimelineEntry.from(indicators:) 批处理:找 bp.systolic 配对同 capturedAt
  (±5s)的 bp.diastolic,合并成 '血压 120/80 mmHg' 一行
- 未配对的 systolic 单独退回 from(indicator:)
- 非 bp.* series 不动
- ArchiveListView + HomeView 改用 from(indicators:) 批处理
- 6 个新测试覆盖配对/未配对/异常标记/非 bp 不动/不同时间不合并
This commit is contained in:
link2026
2026-05-26 07:50:00 +08:00
parent 0f38bf585b
commit e2fb631b96
4 changed files with 159 additions and 2 deletions

View File

@@ -57,6 +57,47 @@ struct TimelineEntry: Identifiable, Hashable {
)
}
/// Indicator , bp.systolic + bp.diastolic capturedAt
/// " 120/80 mmHg" timeline entry series from(indicator:)
/// :capturedAt 5 ()
static func from(indicators: [Indicator]) -> [TimelineEntry] {
var entries: [TimelineEntry] = []
var consumed = Set<PersistentIdentifier>()
// bp.systolic, bp.diastolic
for sys in indicators where sys.seriesKey == "bp.systolic" {
if consumed.contains(sys.persistentModelID) { continue }
guard let dia = indicators.first(where: {
$0.seriesKey == "bp.diastolic" &&
!consumed.contains($0.persistentModelID) &&
abs($0.capturedAt.timeIntervalSince(sys.capturedAt)) <= 5
}) else { continue }
consumed.insert(sys.persistentModelID)
consumed.insert(dia.persistentModelID)
entries.append(mergedBP(systolic: sys, diastolic: dia))
}
// indicator( systolic/diastolic series)
for i in indicators where !consumed.contains(i.persistentModelID) {
entries.append(from(indicator: i))
}
return entries
}
private static func mergedBP(systolic sys: Indicator, diastolic dia: Indicator) -> TimelineEntry {
let abnormal = sys.status != .normal || dia.status != .normal
return TimelineEntry(
id: "bp-\(sys.persistentModelID)-\(dia.persistentModelID)",
kind: .indicator,
date: sys.capturedAt,
title: "血压",
subtitle: "长期监测",
trailing: "\(sys.value)/\(dia.value) mmHg" + (abnormal ? "" : ""),
trailingIsAlert: abnormal,
isOngoing: false
)
}
static func from(report r: Report) -> TimelineEntry {
let abnormal = r.indicators.filter { $0.status != .normal }.count
return TimelineEntry(