- 替换 QuickCaptureFlow 和 ArchiveFlow 为 UnifiedCaptureFlow 统一流程 - 新增 VLSession 封装 Qwen2.5-VL 模型进行图像文本推理 - 实现 AIRuntime 中 VL 模型的准备和分析功能 - 添加 VLPrompts 定义体检化验单识别的 JSON 输出模板 - 创建 CaptureReviewForm 提供 VL 解析结果的可编辑表单界面 - 集成 VisionKit 文档扫描器支持真机多页文档扫描 - 为模拟器实现 PhotosPicker 回退方案选择已有照片 - 在 RootView 中统一使用 UnifiedCaptureFlow 处理快速和归档流程 - 添加 CustomMetricEditor 支持自定义监测指标的创建编辑删除 - 扩展 KangkangApp 模型配置以支持新数据类型 - 实现档案列表中症状结束功能通过时间线行点击触发
69 lines
2.3 KiB
Swift
69 lines
2.3 KiB
Swift
import SwiftUI
|
|
import PhotosUI
|
|
|
|
/// VisionKit 在模拟器不可用,demo / 验证场景走 PhotosPicker 回退选已有照片。
|
|
/// 真机正式录入走 DocumentScannerView。
|
|
struct PhotoPickerSheet: View {
|
|
let onFinish: ([UIImage]) -> Void
|
|
let onCancel: () -> Void
|
|
|
|
@State private var selection: [PhotosPickerItem] = []
|
|
@State private var loading = false
|
|
|
|
var body: some View {
|
|
VStack(spacing: 20) {
|
|
Image(systemName: "photo.on.rectangle.angled")
|
|
.font(.system(size: 56))
|
|
.foregroundStyle(Tj.Palette.text3)
|
|
Text("模拟器没有摄像头,从相册选一张化验单/体检报告")
|
|
.font(.system(size: 13))
|
|
.foregroundStyle(Tj.Palette.text2)
|
|
.multilineTextAlignment(.center)
|
|
|
|
PhotosPicker(selection: $selection,
|
|
maxSelectionCount: 5,
|
|
matching: .images) {
|
|
Text("从相册选 ≤5 张")
|
|
.font(.system(size: 14, weight: .semibold))
|
|
.frame(maxWidth: .infinity)
|
|
.padding(.vertical, 12)
|
|
.background(Tj.Palette.ink)
|
|
.foregroundStyle(Tj.Palette.paper)
|
|
.clipShape(Capsule())
|
|
}
|
|
|
|
Button("取消", action: onCancel)
|
|
.foregroundStyle(Tj.Palette.text3)
|
|
|
|
if loading {
|
|
ProgressView().tint(Tj.Palette.ink)
|
|
}
|
|
}
|
|
.padding(28)
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
.background(Tj.Palette.sand.ignoresSafeArea())
|
|
.onChange(of: selection) { _, newValue in
|
|
guard !newValue.isEmpty else { return }
|
|
loadImages(from: newValue)
|
|
}
|
|
}
|
|
|
|
private func loadImages(from items: [PhotosPickerItem]) {
|
|
loading = true
|
|
Task {
|
|
var images: [UIImage] = []
|
|
for item in items {
|
|
if let data = try? await item.loadTransferable(type: Data.self),
|
|
let img = UIImage(data: data) {
|
|
images.append(img)
|
|
}
|
|
}
|
|
await MainActor.run {
|
|
loading = false
|
|
if images.isEmpty { onCancel() }
|
|
else { onFinish(images) }
|
|
}
|
|
}
|
|
}
|
|
}
|