feat: 素材上传成

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

View File

@ -1,6 +1,12 @@
import SwiftUI
import PhotosUI
///
struct UploadResults {
let original: ImageUploaderGetID.UploadResult
let compressed: ImageUploaderGetID.UploadResult
}
///
/// 使UIViewControllerRepresentablePHPickerViewControllerSwiftUI
struct PhotoPicker: UIViewControllerRepresentable {
@ -16,7 +22,7 @@ struct PhotoPicker: UIViewControllerRepresentable {
let filter: PHPickerFilter
///
var onImageUploaded: ((Result<ImageUploaderGetID.UploadResult, Error>) -> Void)?
var onImageUploaded: ((Result<UploadResults, Error>) -> Void)?
// MARK: - Initialization
@ -30,7 +36,7 @@ struct PhotoPicker: UIViewControllerRepresentable {
selectedImages: Binding<[UIImage]>,
selectionLimit: Int = 1,
filter: PHPickerFilter = .images,
onImageUploaded: ((Result<ImageUploaderGetID.UploadResult, Error>) -> Void)? = nil
onImageUploaded: ((Result<UploadResults, Error>) -> Void)? = nil
) {
self._selectedImages = selectedImages
self.selectionLimit = selectionLimit
@ -75,66 +81,113 @@ struct PhotoPicker: UIViewControllerRepresentable {
}
///
/// - Parameters:
/// - picker:
/// - results:
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
//
parent.selectedImages.removeAll()
// 使DispatchGroup
// 使DispatchGroup
let group = DispatchGroup()
var loadedImages: [Int: UIImage] = [:] //
var uploadResults: [Int: (original: ImageUploaderGetID.UploadResult?,
compressed: ImageUploaderGetID.UploadResult?)] = [:]
//
for (index, result) in results.enumerated() {
group.enter() //
//
if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
//
result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (image, error) in
if let image = image as? UIImage {
//
loadedImages[index] = image
guard let self = self, let image = image as? UIImage else {
group.leave()
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
}
//
self?.uploader.uploadImage(image) { result in
// 线
DispatchQueue.main.async {
switch result {
case .success(let uploadResult):
print("✅ 上传成功fileId: \(uploadResult.fileId)")
print("📂 文件信息:")
print(" - 文件名: \(uploadResult.fileName)")
print(" - 文件大小: \(uploadResult.fileSize) 字节")
print(" - 文件URL: \(uploadResult.fileUrl)")
switch originalResult {
case .success(let originalUploadResult):
// 4.
self.uploader.uploadImage(compressedImage) { compressedResult in
defer { group.leave() }
switch compressedResult {
case .success(let compressedUploadResult):
//
uploadResults[index] = (originalUploadResult, compressedUploadResult)
print("✅ 原图和压缩图上传成功!")
print("📂 原图信息:")
print(" - 文件ID: \(originalUploadResult.fileId)")
print(" - 文件大小: \(originalUploadResult.fileSize) 字节")
print("📦 压缩图信息:")
print(" - 文件ID: \(compressedUploadResult.fileId)")
print(" - 文件大小: \(compressedUploadResult.fileSize) 字节")
//
self?.parent.onImageUploaded?(.success(uploadResult))
// 使MaterialService
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):
print("❌ 上传失败: \(error.localizedDescription)")
//
self?.parent.onImageUploaded?(.failure(error))
print("❌ 压缩图上传失败: \(error.localizedDescription)")
uploadResults[index] = (originalUploadResult, nil)
}
}
case .failure(let error):
print("❌ 原图上传失败: \(error.localizedDescription)")
group.leave()
}
}
group.leave() //
}
} 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 }
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)
}
}
@ -155,7 +208,7 @@ struct AvatarUploader: View {
let size: CGFloat
///
var onUploadComplete: ((Result<ImageUploaderGetID.UploadResult, Error>) -> Void)?
var onUploadComplete: ((Result<UploadResults, Error>) -> Void)?
// 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)")
}
}
}