feat: 素材上传成

This commit is contained in:
jinyaqiu 2025-08-19 18:53:17 +08:00
parent c828ff786a
commit f40828484c
3 changed files with 149 additions and 34 deletions

View File

@ -1,6 +1,12 @@
import SwiftUI import SwiftUI
import PhotosUI import PhotosUI
///
struct UploadResults {
let original: ImageUploaderGetID.UploadResult
let compressed: ImageUploaderGetID.UploadResult
}
/// ///
/// 使UIViewControllerRepresentablePHPickerViewControllerSwiftUI /// 使UIViewControllerRepresentablePHPickerViewControllerSwiftUI
struct PhotoPicker: UIViewControllerRepresentable { struct PhotoPicker: UIViewControllerRepresentable {
@ -16,7 +22,7 @@ struct PhotoPicker: UIViewControllerRepresentable {
let filter: PHPickerFilter let filter: PHPickerFilter
/// ///
var onImageUploaded: ((Result<ImageUploaderGetID.UploadResult, Error>) -> Void)? var onImageUploaded: ((Result<UploadResults, Error>) -> Void)?
// MARK: - Initialization // MARK: - Initialization
@ -30,7 +36,7 @@ struct PhotoPicker: UIViewControllerRepresentable {
selectedImages: Binding<[UIImage]>, selectedImages: Binding<[UIImage]>,
selectionLimit: Int = 1, selectionLimit: Int = 1,
filter: PHPickerFilter = .images, filter: PHPickerFilter = .images,
onImageUploaded: ((Result<ImageUploaderGetID.UploadResult, Error>) -> Void)? = nil onImageUploaded: ((Result<UploadResults, Error>) -> Void)? = nil
) { ) {
self._selectedImages = selectedImages self._selectedImages = selectedImages
self.selectionLimit = selectionLimit self.selectionLimit = selectionLimit
@ -75,66 +81,113 @@ struct PhotoPicker: UIViewControllerRepresentable {
} }
/// ///
/// - Parameters:
/// - picker:
/// - results:
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// //
parent.selectedImages.removeAll() parent.selectedImages.removeAll()
// 使DispatchGroup // 使DispatchGroup
let group = DispatchGroup() let group = DispatchGroup()
var loadedImages: [Int: UIImage] = [:] // var loadedImages: [Int: UIImage] = [:] //
var uploadResults: [Int: (original: ImageUploaderGetID.UploadResult?,
compressed: ImageUploaderGetID.UploadResult?)] = [:]
// //
for (index, result) in results.enumerated() { for (index, result) in results.enumerated() {
group.enter() // group.enter() //
//
if result.itemProvider.canLoadObject(ofClass: UIImage.self) { if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
//
result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (image, error) in result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (image, error) in
if let image = image as? UIImage { guard let self = self, let image = image as? UIImage else {
// group.leave()
loadedImages[index] = image return
}
// 1.
loadedImages[index] = image
// 2. 50%
guard let compressedImage = image.jpegData(compressionQuality: 0.5).flatMap(UIImage.init(data:)) else {
group.leave()
return
}
// 3.
self.uploader.uploadImage(image) { [weak self] originalResult in
guard let self = self else {
group.leave()
return
}
// switch originalResult {
self?.uploader.uploadImage(image) { result in case .success(let originalUploadResult):
// 线 // 4.
DispatchQueue.main.async { self.uploader.uploadImage(compressedImage) { compressedResult in
switch result { defer { group.leave() }
case .success(let uploadResult):
print("✅ 上传成功fileId: \(uploadResult.fileId)") switch compressedResult {
print("📂 文件信息:") case .success(let compressedUploadResult):
print(" - 文件名: \(uploadResult.fileName)") //
print(" - 文件大小: \(uploadResult.fileSize) 字节") uploadResults[index] = (originalUploadResult, compressedUploadResult)
print(" - 文件URL: \(uploadResult.fileUrl)") print("✅ 原图和压缩图上传成功!")
print("📂 原图信息:")
print(" - 文件ID: \(originalUploadResult.fileId)")
print(" - 文件大小: \(originalUploadResult.fileSize) 字节")
print("📦 压缩图信息:")
print(" - 文件ID: \(compressedUploadResult.fileId)")
print(" - 文件大小: \(compressedUploadResult.fileSize) 字节")
// // 使MaterialService
self?.parent.onImageUploaded?(.success(uploadResult)) MaterialService.shared.uploadMaterialInfo(
fileId: originalUploadResult.fileId,
previewFileId: compressedUploadResult.fileId
) { success, errorMessage in
if success {
print("✅ 文件信息上传成功 素材上传成功!!!!!")
} else if let errorMessage = errorMessage {
print("❌ 文件信息上传失败: \(errorMessage)")
}
}
case .failure(let error): case .failure(let error):
print("❌ 上传失败: \(error.localizedDescription)") print("❌ 压缩图上传失败: \(error.localizedDescription)")
// uploadResults[index] = (originalUploadResult, nil)
self?.parent.onImageUploaded?(.failure(error))
} }
} }
case .failure(let error):
print("❌ 原图上传失败: \(error.localizedDescription)")
group.leave()
} }
} }
group.leave() //
} }
} else { } else {
group.leave() // group.leave()
} }
} }
// //
group.notify(queue: .main) { group.notify(queue: .main) { [weak self] in
// guard let self = self else { return }
// 1.
let sortedImages = loadedImages.sorted { $0.key < $1.key }.map { $0.value } let sortedImages = loadedImages.sorted { $0.key < $1.key }.map { $0.value }
self.parent.selectedImages.append(contentsOf: sortedImages) self.parent.selectedImages.append(contentsOf: sortedImages)
// // 2.
if let firstResult = uploadResults.first?.value,
let original = firstResult.original,
let compressed = firstResult.compressed {
// 3.
let results = UploadResults(original: original, compressed: compressed)
self.parent.onImageUploaded?(.success(results))
} else {
// 4.
self.parent.onImageUploaded?(.failure(NSError(domain: "com.wake.upload",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "上传过程中出现错误"])))
}
// 5.
picker.dismiss(animated: true) picker.dismiss(animated: true)
} }
} }
@ -155,7 +208,7 @@ struct AvatarUploader: View {
let size: CGFloat let size: CGFloat
/// ///
var onUploadComplete: ((Result<ImageUploaderGetID.UploadResult, Error>) -> Void)? var onUploadComplete: ((Result<UploadResults, Error>) -> Void)?
// MARK: - State // MARK: - State

View File

@ -0,0 +1,62 @@
import Foundation
///
class MaterialService {
///
static let shared = MaterialService()
private init() {}
///
/// - Parameters:
/// - fileId: ID
/// - previewFileId: ID
/// - completion:
func uploadMaterialInfo(fileId: String,
previewFileId: String,
completion: @escaping (Bool, String?) -> Void) {
let materialData: [[String: String]] = [[
"file_id": fileId,
"preview_file_id": previewFileId
]]
guard let url = URL(string: "\(APIConfig.baseURL)/material") else {
completion(false, "无效的URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.allHTTPHeaderFields = APIConfig.authHeaders
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
request.httpBody = try JSONSerialization.data(withJSONObject: materialData)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(false, "上传失败: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
if (200...299).contains(httpResponse.statusCode) {
completion(true, nil)
} else {
let statusCode = httpResponse.statusCode
completion(false, "服务器返回错误状态码: \(statusCode)")
}
} else {
completion(false, "无效的服务器响应")
}
}
task.resume()
} catch {
completion(false, "请求数据序列化失败: \(error.localizedDescription)")
}
}
}