```
docs(health-profile): 添加防编造加固修订记录到导出健康档案设计文档 补充了关于导出摘要出现虚构病例问题的详细分析和修复方案, 包括检索策略优化、空数据兜底处理和prompt重写等三层防护措施。 ```
This commit is contained in:
118
康康/Features/Home/TodayRemindersCard.swift
Normal file
118
康康/Features/Home/TodayRemindersCard.swift
Normal file
@@ -0,0 +1,118 @@
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
import Combine
|
||||
|
||||
/// 主页「今日提醒」卡:汇总今天会触发的自由提醒(CustomReminder)+ 指标提醒(MetricReminder),
|
||||
/// 按时间升序展示;已过点的行淡化(只表示「时间已过」,不代表已完成——本期不追踪打卡)。
|
||||
/// 今天没有任何提醒 → 整卡隐藏(返回 EmptyView,与「持续中症状」卡同款)。
|
||||
/// 卡内只读;点右上「全部 ›」打开提醒中心(RemindersListView)管理。
|
||||
struct TodayRemindersCard: View {
|
||||
@Query(sort: \CustomReminder.updatedAt, order: .reverse)
|
||||
private var customReminders: [CustomReminder]
|
||||
@Query(sort: \MetricReminder.updatedAt, order: .reverse)
|
||||
private var metricReminders: [MetricReminder]
|
||||
|
||||
@State private var showingCenter = false
|
||||
/// 每分钟自走一次,用于刷新「今天」判定与「已过点」淡化(与 OngoingSymptomsCard 同款)。
|
||||
@State private var tick: Date = .now
|
||||
private let timer = Timer.publish(every: 60, on: .main, in: .common).autoconnect()
|
||||
|
||||
/// 今天会触发的提醒,自由提醒 + 指标提醒合并成统一行模型,按时间升序。
|
||||
private var items: [TodayItem] {
|
||||
let cal = Calendar.current
|
||||
var arr: [TodayItem] = []
|
||||
for r in customReminders where r.occurs(on: tick, calendar: cal) {
|
||||
arr.append(TodayItem(id: "c-\(r.id.uuidString)",
|
||||
hour: r.hour, minute: r.minute, title: r.title))
|
||||
}
|
||||
for r in metricReminders where r.occurs(on: tick, calendar: cal) {
|
||||
arr.append(TodayItem(id: "m-\(r.metricId)",
|
||||
hour: r.hour, minute: r.minute, title: r.displayName))
|
||||
}
|
||||
return arr.sorted { ($0.hour, $0.minute) < ($1.hour, $1.minute) }
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let rows = items
|
||||
if rows.isEmpty {
|
||||
EmptyView()
|
||||
} else {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
header(count: rows.count)
|
||||
VStack(spacing: 8) {
|
||||
ForEach(rows) { row($0) }
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 18)
|
||||
.onReceive(timer) { now in tick = now }
|
||||
.sheet(isPresented: $showingCenter) {
|
||||
// 列表页依赖外层 NavigationStack 提供标题栏;sheet 形态补「完成」按钮。
|
||||
NavigationStack { RemindersListView(presentedAsSheet: true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func header(count: Int) -> some View {
|
||||
HStack(spacing: 8) {
|
||||
Circle()
|
||||
.fill(Tj.Palette.amber)
|
||||
.frame(width: 7, height: 7)
|
||||
Text("今日提醒")
|
||||
.font(.tjH2())
|
||||
.foregroundStyle(Tj.Palette.text)
|
||||
Text("\(count) 项")
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(Tj.Palette.text3)
|
||||
Spacer()
|
||||
Button { showingCenter = true } label: {
|
||||
Text("全部 ›")
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(Tj.Palette.text3)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
|
||||
private func row(_ item: TodayItem) -> some View {
|
||||
let isPast = item.isPast(now: tick)
|
||||
return HStack(spacing: 12) {
|
||||
Text(item.timeLabel)
|
||||
.font(.system(size: 14, weight: .semibold).monospacedDigit())
|
||||
.foregroundStyle(isPast ? Tj.Palette.text3 : Tj.Palette.ink)
|
||||
.frame(width: 46, alignment: .leading)
|
||||
Image(systemName: "bell.fill")
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(isPast ? Tj.Palette.text3 : Tj.Palette.amber)
|
||||
Text(item.title)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(isPast ? Tj.Palette.text3 : Tj.Palette.text)
|
||||
.lineLimit(1)
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
.padding(.horizontal, 14)
|
||||
.padding(.vertical, 12)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
|
||||
.fill(Tj.Palette.paper)
|
||||
)
|
||||
.shadow(color: Color(red: 0.196, green: 0.157, blue: 0.098).opacity(0.04),
|
||||
radius: 2, x: 0, y: 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// 「今日提醒」行的统一展示模型(自由提醒与指标提醒共用)。
|
||||
private struct TodayItem: Identifiable {
|
||||
let id: String
|
||||
let hour: Int
|
||||
let minute: Int
|
||||
let title: String
|
||||
|
||||
var timeLabel: String { String(format: "%02d:%02d", hour, minute) }
|
||||
|
||||
/// 该提醒的时分是否早于此刻(同一天内「已过点」)。
|
||||
func isPast(now: Date) -> Bool {
|
||||
let c = Calendar.current.dateComponents([.hour, .minute], from: now)
|
||||
let nowMinutes = (c.hour ?? 0) * 60 + (c.minute ?? 0)
|
||||
return hour * 60 + minute < nowMinutes
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user