// // CameraTransferModels.swift // suixinkan // import Foundation /// 有线传图任务状态。 enum CameraTransferStatus: String, Codable, Equatable { case pending case downloading case downloaded case uploading case uploaded case failed } /// 有线传图任务,表示单张照片从本地到上传登记的记录。 struct CameraTransferTask: Identifiable, Equatable, Codable { let id: UUID let assetID: String let filename: String var localPath: String? var remoteURL: String? /// 拍摄时间,格式 `yyyy-MM-dd HH:mm:ss`。 var capturedAt: String? var status: CameraTransferStatus var progress: Int var errorMessage: String? /// 初始化传图任务。 init( id: UUID = UUID(), assetID: String, filename: String, localPath: String? = nil, remoteURL: String? = nil, capturedAt: String? = nil, status: CameraTransferStatus = .pending, progress: Int = 0, errorMessage: String? = nil ) { self.id = id self.assetID = assetID self.filename = filename self.localPath = localPath self.remoteURL = remoteURL self.capturedAt = capturedAt self.status = status self.progress = progress self.errorMessage = errorMessage } /// 将日期格式化为列表使用的拍摄时间字符串。 static func capturedAtString(from date: Date?) -> String { Self.capturedAtFormatter.string(from: date ?? Date()) } /// 从本地文件推断拍摄时间。 static func capturedAtString(forLocalPath path: String) -> String? { guard let url = CameraDownloadStorage.resolveLocalURL(from: path), FileManager.default.fileExists(atPath: url.path), let attributes = try? FileManager.default.attributesOfItem(atPath: url.path) else { return nil } let date = (attributes[.creationDate] as? Date) ?? (attributes[.modificationDate] as? Date) return date.map { capturedAtString(from: $0) } } private static let capturedAtFormatter: DateFormatter = { let formatter = DateFormatter() formatter.locale = Locale(identifier: "zh_CN") formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" return formatter }() /// 本地文件 URL,支持相对 Documents 的 scoped 路径与绝对路径。 var localURL: URL? { guard let localPath, !localPath.isEmpty else { return nil } return CameraDownloadStorage.resolveLocalURL(from: localPath) } }