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:
@@ -19,7 +19,7 @@ struct ArchiveListView: View {
|
||||
@MainActor
|
||||
private var allEntries: [TimelineEntry] {
|
||||
let mapped =
|
||||
indicators.map(TimelineEntry.from(indicator:)) +
|
||||
TimelineEntry.from(indicators: indicators) +
|
||||
reports.map(TimelineEntry.from(report:)) +
|
||||
diaries.map(TimelineEntry.from(diary:)) +
|
||||
symptoms.map(TimelineEntry.from(symptom:))
|
||||
|
||||
@@ -19,7 +19,7 @@ struct HomeView: View {
|
||||
@MainActor
|
||||
private var recentEntries: [TimelineEntry] {
|
||||
let all =
|
||||
indicators.map(TimelineEntry.from(indicator:)) +
|
||||
TimelineEntry.from(indicators: indicators) +
|
||||
reports.map(TimelineEntry.from(report:)) +
|
||||
diaries.map(TimelineEntry.from(diary:)) +
|
||||
symptoms.map(TimelineEntry.from(symptom:))
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user