feat(capture): 统一报告捕获流程并集成视觉语言模型识别

- 替换 QuickCaptureFlow 和 ArchiveFlow 为 UnifiedCaptureFlow 统一流程
- 新增 VLSession 封装 Qwen2.5-VL 模型进行图像文本推理
- 实现 AIRuntime 中 VL 模型的准备和分析功能
- 添加 VLPrompts 定义体检化验单识别的 JSON 输出模板
- 创建 CaptureReviewForm 提供 VL 解析结果的可编辑表单界面
- 集成 VisionKit 文档扫描器支持真机多页文档扫描
- 为模拟器实现 PhotosPicker 回退方案选择已有照片
- 在 RootView 中统一使用 UnifiedCaptureFlow 处理快速和归档流程
- 添加 CustomMetricEditor 支持自定义监测指标的创建编辑删除
- 扩展 KangkangApp 模型配置以支持新数据类型
- 实现档案列表中症状结束功能通过时间线行点击触发
This commit is contained in:
link2026
2026-05-26 11:18:00 +08:00
parent 39edc25dc1
commit 1b01923c8e
27 changed files with 3128 additions and 29 deletions

View File

@@ -0,0 +1,79 @@
import Testing
import SwiftData
import Foundation
@testable import
struct MetricReminderTests {
private func makeContainer() throws -> ModelContainer {
let schema = Schema([MetricReminder.self])
let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)
return try ModelContainer(for: schema, configurations: [config])
}
@Test func defaultsToEveryDayAt8AM() {
let r = MetricReminder(metricId: "bloodPressure", displayName: "血压")
#expect(r.hour == 8)
#expect(r.minute == 0)
#expect(r.weekdays == [1, 2, 3, 4, 5, 6, 7])
#expect(r.enabled == true)
#expect(r.isEveryDay)
#expect(r.frequencyLabel == "每天")
}
@Test func hourMinuteClampedToValidRange() {
let early = MetricReminder(metricId: "x", displayName: "x", hour: -5, minute: 80)
#expect(early.hour == 0)
#expect(early.minute == 59)
let late = MetricReminder(metricId: "y", displayName: "y", hour: 25, minute: -3)
#expect(late.hour == 23)
#expect(late.minute == 0)
}
@Test func weekdaysRoundtripThroughSwiftData() throws {
let container = try makeContainer()
let ctx = ModelContext(container)
let r = MetricReminder(
metricId: "bloodPressure",
displayName: "血压",
hour: 7, minute: 30,
weekdays: [2, 4, 6]
)
ctx.insert(r)
try ctx.save()
let fetched = try #require(try ctx.fetch(FetchDescriptor<MetricReminder>()).first)
#expect(fetched.weekdays == [2, 4, 6])
#expect(fetched.isEveryDay == false)
#expect(fetched.frequencyLabel == "每周 一三五")
#expect(fetched.timeLabel == "07:30")
}
@Test func disabledFrequencyLabel() {
let r = MetricReminder(metricId: "x", displayName: "x", enabled: false)
#expect(r.frequencyLabel == "已关闭")
}
@Test func emptyWeekdaysNotEveryDay() {
let r = MetricReminder(metricId: "x", displayName: "x", weekdays: [])
#expect(!r.isEveryDay)
#expect(r.frequencyLabel == "未选日")
}
@Test func metricIdUniquenessEnforced() throws {
let container = try makeContainer()
let ctx = ModelContext(container)
let r1 = MetricReminder(metricId: "bp", displayName: "血压")
ctx.insert(r1)
try ctx.save()
let r2 = MetricReminder(metricId: "bp", displayName: "血压重复")
ctx.insert(r2)
try ctx.save()
// SwiftData @Attribute(.unique) /();
// fetch 1
let all = try ctx.fetch(FetchDescriptor<MetricReminder>())
#expect(all.count == 1)
}
}