Files
kangkang/康康/Features/Capture/PhotoPickerSheet.swift
link2026 1b01923c8e feat(capture): 统一报告捕获流程并集成视觉语言模型识别
- 替换 QuickCaptureFlow 和 ArchiveFlow 为 UnifiedCaptureFlow 统一流程
- 新增 VLSession 封装 Qwen2.5-VL 模型进行图像文本推理
- 实现 AIRuntime 中 VL 模型的准备和分析功能
- 添加 VLPrompts 定义体检化验单识别的 JSON 输出模板
- 创建 CaptureReviewForm 提供 VL 解析结果的可编辑表单界面
- 集成 VisionKit 文档扫描器支持真机多页文档扫描
- 为模拟器实现 PhotosPicker 回退方案选择已有照片
- 在 RootView 中统一使用 UnifiedCaptureFlow 处理快速和归档流程
- 添加 CustomMetricEditor 支持自定义监测指标的创建编辑删除
- 扩展 KangkangApp 模型配置以支持新数据类型
- 实现档案列表中症状结束功能通过时间线行点击触发
2026-05-26 11:18:00 +08:00

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) }
}
}
}
}