ios-projects/AIStudyApp/AIStudyApp/Core/Services/FileUploadService.swift
wangdl 1a88aaeecb feat(ios): 头像上传功能接入 COS
- 新增 FileUploadService:获取预签名URL → PUT到COS → confirm → 拿下载链接
- 新增 FileUploadUrlRequest/Response 等文件上传相关模型
- EditProfilePage 新增头像区域:
  - PhotosPicker 选择照片
  - 正方形裁剪 + 缩放到 256x256
  - 上传中显示 ProgressView
  - 上传完成后自动更新 profile avatarUrl
- ProfileView 支持显示真实头像图片(AsyncImage)
- 保存时携带 avatarUrl 不再写死 nil

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 21:44:07 +08:00

63 lines
2.0 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
import UIKit
@MainActor
class FileUploadService {
static let shared = FileUploadService()
private let client = APIClient.shared
/// COS ID
func uploadImage(_ image: UIImage, filename: String = "avatar.jpg") async throws -> String {
// JPEG 512KB
guard let imageData = image.jpegData(compressionQuality: 0.7) else {
throw FileUploadError.compressFailed
}
// URL
let urlReq = FileUploadUrlRequest(
filename: filename,
mimeType: "image/jpeg",
sizeBytes: imageData.count
)
let urlResp: FileUploadUrlResponse = try await client.request(
"/files/upload-url", method: "POST", body: urlReq
)
// PUT COS
var request = URLRequest(url: URL(string: urlResp.uploadUrl)!)
request.httpMethod = "PUT"
request.setValue("image/jpeg", forHTTPHeaderField: "Content-Type")
request.httpBody = imageData
let (_, response) = try await URLSession.shared.data(for: request)
guard let httpResp = response as? HTTPURLResponse, httpResp.statusCode == 200 else {
throw FileUploadError.uploadFailed
}
//
let confirmResp: FileConfirmUploadResponse = try await client.request(
"/files/confirm-upload", method: "POST",
body: FileConfirmUploadRequest(objectKey: urlResp.objectKey, checksum: nil)
)
return confirmResp.id
}
/// URL
func getDownloadUrl(fileId: String) async throws -> String {
let detail: FileDetailResponse = try await client.request("/files/\(fileId)")
return detail.downloadUrl
}
}
enum FileUploadError: LocalizedError {
case compressFailed
case uploadFailed
var errorDescription: String? {
switch self {
case .compressFailed: return "图片压缩失败"
case .uploadFailed: return "上传失败,请重试"
}
}
}