// // TravelAlbumModels.swift // suixinkan // import Foundation /// 旅拍相册用户信息,对齐 Android `TravelAlbumUserEntity`。 struct TravelAlbumUser: Decodable, Sendable, Equatable, Hashable { let id: Int let phone: String init(id: Int = 0, phone: String = "") { self.id = id self.phone = phone } } /// 旅拍相册实体,对齐 Android `TravelAlbumEntity`。 struct TravelAlbum: Decodable, Sendable, Equatable, Hashable, Identifiable { let id: Int let storeUserId: Int let name: String let type: Int let orderNumber: String let materialNum: Int let materialPrice: Int let materialPackagePrice: Int let photoPrice: Int let coverUrl: String let userId: Int let status: Int let createdAt: String let updatedAt: String let user: TravelAlbumUser? enum CodingKeys: String, CodingKey { case id case storeUserId = "store_user_id" case name case type case orderNumber = "order_number" case materialNum = "material_num" case materialPrice = "material_price" case materialPackagePrice = "material_package_price" case photoPrice = "photo_price" case coverUrl = "cover_url" case userId = "user_id" case status case createdAt = "created_at" case updatedAt = "updated_at" case user } init( id: Int = 0, storeUserId: Int = 0, name: String = "", type: Int = 0, orderNumber: String = "", materialNum: Int = 0, materialPrice: Int = 0, materialPackagePrice: Int = 0, photoPrice: Int = 0, coverUrl: String = "", userId: Int = 0, status: Int = 0, createdAt: String = "", updatedAt: String = "", user: TravelAlbumUser? = nil ) { self.id = id self.storeUserId = storeUserId self.name = name self.type = type self.orderNumber = orderNumber self.materialNum = materialNum self.materialPrice = materialPrice self.materialPackagePrice = materialPackagePrice self.photoPrice = photoPrice self.coverUrl = coverUrl self.userId = userId self.status = status self.createdAt = createdAt self.updatedAt = updatedAt self.user = user } /// 展示用手机号。 var displayPhone: String { user?.phone ?? "" } } /// 旅拍相册可绑定订单,对齐 Android `TravelAlbumAvailableOrderEntity`。 struct TravelAlbumAvailableOrder: Decodable, Sendable, Equatable, Hashable { let projectName: String let orderNumber: String let userPhone: String let userId: Int enum CodingKeys: String, CodingKey { case projectName = "project_name" case orderNumber = "order_number" case userPhone = "user_phone" case userId = "user_id" } init(projectName: String = "", orderNumber: String = "", userPhone: String = "", userId: Int = 0) { self.projectName = projectName self.orderNumber = orderNumber self.userPhone = userPhone self.userId = userId } } /// 旅拍相册素材实体,对齐 Android `TravelAlbumMaterialEntity`。 struct TravelAlbumMaterial: Decodable, Sendable, Equatable, Hashable, Identifiable { let id: Int let userEquityTravelId: Int let status: Int let orderNumber: String let userId: Int let fileName: String let fileType: Int let fileUrl: String let fileSize: Int let coverUrl: String let isPurchased: Bool let createdAt: String let updatedAt: String enum CodingKeys: String, CodingKey { case id case userEquityTravelId = "user_equity_travel_id" case status case orderNumber = "order_number" case userId = "user_id" case fileName = "file_name" case fileType = "file_type" case fileUrl = "file_url" case fileSize = "file_size" case coverUrl = "cover_url" case isPurchased = "is_purchased" case createdAt = "created_at" case updatedAt = "updated_at" } init( id: Int = 0, userEquityTravelId: Int = 0, status: Int = 0, orderNumber: String = "", userId: Int = 0, fileName: String = "", fileType: Int = 0, fileUrl: String = "", fileSize: Int = 0, coverUrl: String = "", isPurchased: Bool = false, createdAt: String = "", updatedAt: String = "" ) { self.id = id self.userEquityTravelId = userEquityTravelId self.status = status self.orderNumber = orderNumber self.userId = userId self.fileName = fileName self.fileType = fileType self.fileUrl = fileUrl self.fileSize = fileSize self.coverUrl = coverUrl self.isPurchased = isPurchased self.createdAt = createdAt self.updatedAt = updatedAt } } /// 旅拍相册创建请求体,对齐 Android `TravelAlbumCreateRequest`。 struct TravelAlbumCreateRequest: Encodable, Sendable, Equatable { let name: String let type: Int let orderNumber: String? let materialNum: Int? let materialPrice: Double? let materialPackagePrice: Double? let photoPrice: Double? enum CodingKeys: String, CodingKey { case name case type case orderNumber = "order_number" case materialNum = "material_num" case materialPrice = "material_price" case materialPackagePrice = "material_package_price" case photoPrice = "photo_price" } } /// 旅拍相册素材上传登记请求体,对齐 Android `TravelAlbumUploadMaterialRequest`。 struct TravelAlbumUploadMaterialRequest: Encodable, Sendable, Equatable { let userEquityTravelId: Int let fileName: String let fileUrl: String let clientPhotoId: String enum CodingKeys: String, CodingKey { case userEquityTravelId = "user_equity_travel_id" case fileName = "file_name" case fileUrl = "file_url" case clientPhotoId = "client_photo_id" } } /// 旅拍相册服务端已登记的客户端照片 ID 集合。 struct TravelAlbumMaterialClientPhotoIDsResponse: Decodable, Sendable, Equatable { let clientPhotoIds: [String] enum CodingKeys: String, CodingKey { case clientPhotoIds = "client_photo_ids" } } /// 旅拍相册通用分页响应。 struct TravelAlbumListResponse: Decodable, Sendable, Equatable { let total: Int let list: [Item] init(total: Int = 0, list: [Item] = []) { self.total = total self.list = list } } /// 旅拍相册创建响应。 struct TravelAlbumCreateResponse: Decodable, Sendable, Equatable { let id: Int } /// 旅拍相册小程序码响应。 struct TravelAlbumMpCodeResponse: Decodable, Sendable, Equatable { let mpCodeOssUrl: String enum CodingKeys: String, CodingKey { case mpCodeOssUrl = "mp_code_oss_url" } } /// 旅拍相册展示格式化工具。 enum TravelAlbumDisplayFormatter { /// 脱敏手机号。 static func maskPhone(_ phone: String) -> String { guard phone.count >= 7 else { return phone.isEmpty ? "--" : phone } return "\(phone.prefix(3))****\(phone.suffix(4))" } /// 生成文件大小文本。 static func fileSizeText(_ bytes: Int) -> String { let value = Double(max(bytes, 0)) if value >= 1024 * 1024 * 1024 { return String(format: "%.1fGB", value / 1024 / 1024 / 1024) } if value >= 1024 * 1024 { return String(format: "%.1fMB", value / 1024 / 1024) } if value >= 1024 { return String(format: "%.1fKB", value / 1024) } return "\(Int(value))B" } /// 创建时间短展示。 static func shortTaskTime(_ text: String) -> String { if text.count >= 16 { return String(text.prefix(16)) } return text } }