docs(health-profile): 添加防编造加固修订记录到导出健康档案设计文档

补充了关于导出摘要出现虚构病例问题的详细分析和修复方案,
包括检索策略优化、空数据兜底处理和prompt重写等三层防护措施。
```
This commit is contained in:
link2026
2026-05-30 20:06:12 +08:00
parent dad9d43486
commit 7ad41c5f09
26 changed files with 9062 additions and 7697 deletions

View File

@@ -14,10 +14,16 @@ struct CustomReminderEditSheet: View {
@State private var title = ""
@State private var note = ""
@State private var pickedTime: Date = .now
@State private var frequency: CustomReminder.Frequency = .daily
@State private var weekdays: Set<Int> = Set(1...7)
@State private var dayOfMonth = 1
@State private var month = 1
@State private var hydrated = false
@State private var showAuthDeniedAlert = false
/// (, ): / / /
private let timePresets: [(h: Int, m: Int)] = [(8, 0), (12, 0), (18, 0), (22, 0)]
init(reminder: CustomReminder? = nil) {
self.reminder = reminder
}
@@ -26,7 +32,11 @@ struct CustomReminderEditSheet: View {
private var trimmedTitle: String {
title.trimmingCharacters(in: .whitespacesAndNewlines)
}
private var canSave: Bool { !trimmedTitle.isEmpty && !weekdays.isEmpty }
private var canSave: Bool {
guard !trimmedTitle.isEmpty else { return false }
if frequency == .weekly { return !weekdays.isEmpty }
return true
}
var body: some View {
NavigationStack {
@@ -41,14 +51,26 @@ struct CustomReminderEditSheet: View {
}
Section {
DatePicker(String(appLoc: "时间"), selection: $pickedTime,
displayedComponents: .hourAndMinute)
Picker(String(appLoc: "重复"), selection: $frequency) {
Text(String(appLoc: "每日")).tag(CustomReminder.Frequency.daily)
Text(String(appLoc: "每周")).tag(CustomReminder.Frequency.weekly)
Text(String(appLoc: "每月")).tag(CustomReminder.Frequency.monthly)
Text(String(appLoc: "每年")).tag(CustomReminder.Frequency.yearly)
}
.pickerStyle(.segmented)
.listRowBackground(Color.clear)
frequencyDetail
} header: {
Text("重复")
}
Section {
weekdayRow
timePresetRow
DatePicker(String(appLoc: "时间"), selection: $pickedTime,
displayedComponents: .hourAndMinute)
} header: {
Text("重复")
Text("时间")
}
if isEditing {
@@ -74,6 +96,11 @@ struct CustomReminderEditSheet: View {
}
}
.onAppear(perform: hydrate)
.onChange(of: month) { _, newMonth in
// ,(231)
let maxD = Self.daysInMonth(newMonth)
if dayOfMonth > maxD { dayOfMonth = maxD }
}
.alert(String(appLoc: "通知未开启"), isPresented: $showAuthDeniedAlert) {
Button(String(appLoc: "")) { dismiss() }
} message: {
@@ -82,6 +109,84 @@ struct CustomReminderEditSheet: View {
}
}
// MARK: -
@ViewBuilder
private var frequencyDetail: some View {
switch frequency {
case .daily:
EmptyView()
case .weekly:
weekdayRow
case .monthly:
Picker(String(appLoc: "日期"), selection: $dayOfMonth) {
ForEach(1...31, id: \.self) { d in
Text(String(appLoc: "\(d)")).tag(d)
}
}
if dayOfMonth >= 29 { skipHint }
case .yearly:
Picker(String(appLoc: "月份"), selection: $month) {
ForEach(1...12, id: \.self) { mo in
Text(String(appLoc: "\(mo)")).tag(mo)
}
}
Picker(String(appLoc: "日期"), selection: $dayOfMonth) {
ForEach(1...Self.daysInMonth(month), id: \.self) { d in
Text(String(appLoc: "\(d)")).tag(d)
}
}
if month == 2 && dayOfMonth == 29 { skipHint } // 2/29
}
}
private var skipHint: some View {
Text(String(appLoc: "部分月份无此日,该月将跳过"))
.font(.system(size: 11))
.foregroundStyle(Tj.Palette.text3)
}
/// (2 29, 2/29)
private static func daysInMonth(_ month: Int) -> Int {
switch month {
case 2: return 29
case 4, 6, 9, 11: return 30
default: return 31
}
}
// MARK: -
private var timePresetRow: some View {
let cal = Calendar.current
let curH = cal.component(.hour, from: pickedTime)
let curM = cal.component(.minute, from: pickedTime)
return HStack(spacing: 8) {
ForEach(Array(timePresets.enumerated()), id: \.offset) { _, preset in
let on = curH == preset.h && curM == preset.m
Button {
pickedTime = cal.date(bySettingHour: preset.h, minute: preset.m,
second: 0, of: pickedTime) ?? pickedTime
} label: {
Text(String(format: "%d:%02d", preset.h, preset.m))
.font(.system(size: 13, weight: on ? .semibold : .regular))
.foregroundStyle(on ? Tj.Palette.paper : Tj.Palette.text)
.frame(maxWidth: .infinity, minHeight: 30)
.background(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(on ? Tj.Palette.ink : Tj.Palette.paper)
)
.overlay(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.strokeBorder(Tj.Palette.line, lineWidth: on ? 0 : 1)
)
}
.buttonStyle(.plain)
}
}
.listRowBackground(Color.clear)
}
// MARK: - ( RemindersListView )
private var weekdayRow: some View {
@@ -124,7 +229,10 @@ struct CustomReminderEditSheet: View {
if let r = reminder {
title = r.title
note = r.note
frequency = r.frequency
weekdays = Set(r.weekdays)
dayOfMonth = r.dayOfMonth
month = r.month
pickedTime = Calendar.current.date(
bySettingHour: r.hour, minute: r.minute, second: 0, of: .now
) ?? .now
@@ -145,6 +253,9 @@ struct CustomReminderEditSheet: View {
r.hour = hour
r.minute = minute
r.weekdays = sortedDays
r.frequency = frequency
r.dayOfMonth = dayOfMonth
r.month = month
r.updatedAt = .now
target = r
} else {
@@ -153,7 +264,10 @@ struct CustomReminderEditSheet: View {
note: note.trimmingCharacters(in: .whitespacesAndNewlines),
hour: hour,
minute: minute,
weekdays: sortedDays
weekdays: sortedDays,
frequency: frequency,
dayOfMonth: dayOfMonth,
month: month
)
ctx.insert(new)
target = new