import SwiftUI import PhotosUI import os @available(iOS 16.0, *) public struct MultiImageUploader: View { @State var selectedImages: [UIImage] = [] @State private var uploadResults: [UploadResult] = [] @State private var isUploading = false @State private var showingImagePicker = false @State private var uploadProgress: [UUID: Double] = [:] // 跟踪每个上传任务的进度 @State private var needsViewUpdate = false // Add this line to trigger view updates private let maxSelection: Int public var onUploadComplete: ([UploadResult]) -> Void private let uploadService = ImageUploadService.shared private let logger = Logger(subsystem: "com.yourapp.uploader", category: "MultiImageUploader") // 自定义内容 private let content: ((_ isUploading: Bool, _ selectedCount: Int) -> Content)? /// 控制是否显示图片选择器 @Binding var isImagePickerPresented: Bool /// 选中的图片 @Binding var selectedImagesBinding: [UIImage]? /// 控制是否显示图片预览 @State private var showingImagePreview = false // 初始化方法 - 使用自定义视图 public init( maxSelection: Int = 10, isImagePickerPresented: Binding, selectedImagesBinding: Binding<[UIImage]?>, @ViewBuilder content: @escaping (_ isUploading: Bool, _ selectedCount: Int) -> Content, onUploadComplete: @escaping ([UploadResult]) -> Void ) { self.maxSelection = maxSelection self._isImagePickerPresented = isImagePickerPresented self._selectedImagesBinding = selectedImagesBinding self.content = content self.onUploadComplete = onUploadComplete } // 初始化方法 - 使用默认按钮样式(向后兼容) public init( maxSelection: Int = 10, isImagePickerPresented: Binding, selectedImagesBinding: Binding<[UIImage]?>, onUploadComplete: @escaping ([UploadResult]) -> Void ) where Content == EmptyView { self.maxSelection = maxSelection self._isImagePickerPresented = isImagePickerPresented self._selectedImagesBinding = selectedImagesBinding self.content = nil self.onUploadComplete = onUploadComplete } public var body: some View { VStack(spacing: 16) { // 自定义内容或默认按钮 if let content = content { Button(action: { showingImagePicker = true }) { content(isUploading, selectedImages.count) } .buttonStyle(PlainButtonStyle()) } else { // 默认按钮样式 Button(action: { showingImagePicker = true }) { Label( !selectedImages.isEmpty ? "已选择 \(selectedImages.count) 张图片" : "选择图片", systemImage: "photo.on.rectangle" ) .font(.headline) .foregroundColor(.white) .padding() .frame(maxWidth: .infinity) .background(Color.blue) .cornerRadius(10) } .padding(.horizontal) } } .sheet(isPresented: $showingImagePicker) { ImagePicker(images: $selectedImages, selectionLimit: maxSelection) { // 当选择完成时,关闭选择器并开始上传 showingImagePicker = false if !selectedImages.isEmpty { Task { _ = await startUpload() } } } } .onChange(of: isImagePickerPresented) { newValue in if newValue { showingImagePicker = true } } .onChange(of: showingImagePicker) { newValue in if !newValue { isImagePickerPresented = false } } .onChange(of: selectedImages) { newValue in selectedImagesBinding = newValue } .onChange(of: needsViewUpdate) { _ in // Trigger view update } } /// 上传图片方法,由父组件调用 @MainActor public func startUpload() async -> [UploadResult] { guard !isUploading && !selectedImages.isEmpty else { return [] } isUploading = true uploadResults = selectedImages.map { UploadResult(image: $0, status: .uploading(progress: 0)) } let group = DispatchGroup() for (index, image) in selectedImages.enumerated() { group.enter() // 使用 ImageUploadService 上传图片 uploadService.uploadOriginalAndCompressedImage( image, compressionQuality: 0.7, progress: { progress in // 更新上传进度 DispatchQueue.main.async { if index < self.uploadResults.count { self.uploadResults[index].status = .uploading(progress: progress.progress) self.needsViewUpdate.toggle() // Trigger view update } } }, completion: { result in DispatchQueue.main.async { guard index < self.uploadResults.count else { return } switch result { case .success(let uploadResults): self.uploadResults[index].status = .success self.uploadResults[index].fileId = uploadResults.original.fileId self.uploadResults[index].previewFileId = uploadResults.compressed.fileId self.needsViewUpdate.toggle() // Trigger view update case .failure(let error): self.uploadResults[index].status = .failure(error) self.needsViewUpdate.toggle() // Trigger view update self.logger.error("图片上传失败: \(error.localizedDescription)") } group.leave() } } ) } return await withCheckedContinuation { continuation in group.notify(queue: .main) { self.isUploading = false self.needsViewUpdate.toggle() // Trigger view update continuation.resume(returning: self.uploadResults) } } } }