// // TaskModels.swift // suixinkan // import Foundation /// 创建任务请求体,对齐 Android `AddTaskRequest`。 struct AddTaskRequest: Encodable, Sendable, Equatable { let scenicId: Int let name: String let orderNumber: String? let remark: String let urgentHour: Int let cloudFile: [TaskCloudFileItem] let uploadFile: [TaskUploadFileItem] enum CodingKeys: String, CodingKey { case scenicId = "scenic_id" case name case orderNumber = "order_number" case remark = "photog_remark" case urgentHour = "urgent_hour" case cloudFile = "cloud_file" case uploadFile = "upload_file" } } /// 云盘文件引用,对齐 Android `CloudFileItem`。 struct TaskCloudFileItem: Encodable, Sendable, Equatable { let fileId: Int let remark: String enum CodingKeys: String, CodingKey { case fileId = "file_id" case remark } } /// 本地上传文件引用,对齐 Android `UploadFileItem`。 struct TaskUploadFileItem: Encodable, Sendable, Equatable { let fileUrl: String let fileName: String let remark: String enum CodingKeys: String, CodingKey { case fileUrl = "file_url" case fileName = "file_name" case remark } } /// 可选关联订单,对齐 Android `AvailableOrderResponse`。 struct AvailableOrder: Decodable, Sendable, Equatable, Hashable { let projectName: String let orderNumber: String let orderStatus: Int let orderStatusLabel: String let payTime: String let userId: Int let userPhone: String enum CodingKeys: String, CodingKey { case projectName = "project_name" case orderNumber = "order_number" case orderStatus = "order_status" case orderStatusLabel = "order_status_label" case payTime = "pay_time" case userId = "user_id" case userPhone = "user_phone" } init( projectName: String = "", orderNumber: String = "", orderStatus: Int = 0, orderStatusLabel: String = "", payTime: String = "", userId: Int = 0, userPhone: String = "" ) { self.projectName = projectName self.orderNumber = orderNumber self.orderStatus = orderStatus self.orderStatusLabel = orderStatusLabel self.payTime = payTime self.userId = userId self.userPhone = userPhone } } /// 云盘文件/文件夹实体,对齐 Android `CloudFileEntity`。 struct CloudFile: Decodable, Sendable, Equatable, Hashable { let id: Int let parentFolderId: Int let fileUrl: String let coverUrl: String let updatedAt: String let name: String let createdAt: String let childNum: Int let type: Int let fileSize: Int64 enum CodingKeys: String, CodingKey { case id case parentFolderId = "parent_folder_id" case fileUrl = "file_url" case coverUrl = "cover_url" case updatedAt = "updated_at" case name case createdAt = "created_at" case childNum = "child_num" case type case fileSize = "file_size" } init( id: Int = 0, parentFolderId: Int = 0, fileUrl: String = "", coverUrl: String = "", updatedAt: String = "", name: String = "", createdAt: String = "", childNum: Int = 0, type: Int = 0, fileSize: Int64 = 0 ) { self.id = id self.parentFolderId = parentFolderId self.fileUrl = fileUrl self.coverUrl = coverUrl self.updatedAt = updatedAt self.name = name self.createdAt = createdAt self.childNum = childNum self.type = type self.fileSize = fileSize } /// 是否为文件夹。 var isFolder: Bool { type == 99 } /// 是否为图片。 var isImage: Bool { type == 2 } /// 是否为视频。 var isVideo: Bool { type == 1 } /// 是否为可导入的媒体文件。 var isSelectableMedia: Bool { isImage || isVideo } } /// 云盘列表响应。 struct CloudFileListResponse: Decodable, Sendable, Equatable { let total: Int let list: [CloudFile] init(total: Int = 0, list: [CloudFile] = []) { self.total = total self.list = list } } /// 云盘路径节点,用于面包屑导航。 struct CloudPathItem: Sendable, Equatable, Hashable { let id: Int let name: String } /// 任务素材来源。 enum TaskFileSource: String, Sendable, Equatable { case cloud case upload } /// 任务素材项,对齐 Android `TaskFileItem`。 struct TaskFileItem: Sendable, Equatable, Hashable, Identifiable { let id: String let source: TaskFileSource let cloudFile: CloudFile? let uploadFileName: String? let uploadFileType: Int let uploadTaskId: String? var uploadFileUrl: String? var uploadCoverUrl: String? var remark: String var isUploading: Bool var uploadProgress: Int init( id: String? = nil, source: TaskFileSource, cloudFile: CloudFile? = nil, uploadFileUrl: String? = nil, uploadFileName: String? = nil, uploadFileType: Int = 0, uploadCoverUrl: String? = nil, remark: String = "", uploadTaskId: String? = nil, isUploading: Bool = false, uploadProgress: Int = 0 ) { if let id { self.id = id } else if source == .cloud, let cloudFile { self.id = "cloud_\(cloudFile.id)" } else if let uploadTaskId { self.id = "upload_\(uploadTaskId)" } else { self.id = UUID().uuidString } self.source = source self.cloudFile = cloudFile self.uploadFileUrl = uploadFileUrl self.uploadFileName = uploadFileName self.uploadFileType = uploadFileType self.uploadCoverUrl = uploadCoverUrl self.remark = remark self.uploadTaskId = uploadTaskId self.isUploading = isUploading self.uploadProgress = uploadProgress } /// 展示用缩略图 URL。 var previewURLString: String { switch source { case .cloud: let cover = cloudFile?.coverUrl ?? "" if !cover.isEmpty { return cover } return cloudFile?.fileUrl ?? "" case .upload: if uploadFileType == 1 { return uploadCoverUrl ?? uploadFileUrl ?? "" } return uploadFileUrl ?? "" } } /// 文件类型:1=视频,2=图片。 var fileType: Int { switch source { case .cloud: return cloudFile?.type ?? 0 case .upload: return uploadFileType } } /// 展示文件名。 var displayName: String { switch source { case .cloud: return cloudFile?.name ?? "" case .upload: return uploadFileName ?? "" } } }