// // TravelAlbumAPI.swift // suixinkan // import Foundation @MainActor /// 旅拍相册服务协议,抽象相册列表、创建、详情与素材接口。 protocol TravelAlbumServing { /// 拉取可绑定订单。 func availableOrders() async throws -> [TravelAlbumAvailableOrder] /// 创建旅拍相册。 func create(_ request: TravelAlbumCreateRequest) async throws -> TravelAlbumCreateResponse /// 拉取旅拍相册列表。 func list(page: Int, pageSize: Int) async throws -> TravelAlbumListResponse /// 拉取旅拍相册详情。 func info(id: Int) async throws -> TravelAlbum /// 拉取旅拍相册素材列表。 func materialList( userEquityTravelId: Int, page: Int, pageSize: Int, orderBy: Int, isPurchased: Int? ) async throws -> TravelAlbumListResponse /// 拉取单个相册素材及其最新关联图片信息。 func materialInfo(userEquityTravelId: Int, materialId: Int) async throws -> TravelAlbumMaterial /// 上传并登记旅拍相册素材。 func uploadMaterial(_ request: TravelAlbumUploadMaterialRequest) async throws -> TravelAlbumMaterial /// 拉取相册内已登记素材的客户端照片 ID。 func materialClientPhotoIds(userEquityTravelId: Int) async throws -> TravelAlbumMaterialClientPhotoIDsResponse /// 删除旅拍相册。 func deleteAlbum(id: Int) async throws /// 批量删除旅拍相册素材。 func batchDeleteMaterials(ids: [Int]) async throws /// 拉取相册小程序码。 func mpCode(id: Int) async throws -> TravelAlbumMpCodeResponse /// 拉取当前景区可用的 AI 修图模板。 func aiRetouchTemplates(scenicId: Int) async throws -> TravelAlbumAIRetouchTemplatesResponse /// 提交相册素材 AI 修图任务。 func submitAIRetouch(_ request: TravelAlbumAIRetouchRequest) async throws /// 提交单张素材重新修图任务。 func submitAIReretouch(_ request: TravelAlbumAIReretouchRequest) async throws } @MainActor /// 旅拍相册 API,封装 Android `photog/travel-album` 接口组。 final class TravelAlbumAPI: TravelAlbumServing { private let client: APIClient private let basePath = "/api/yf-handset-app/photog/travel-album" /// 初始化旅拍相册 API。 init(client: APIClient) { self.client = client } /// 拉取可绑定订单。 func availableOrders() async throws -> [TravelAlbumAvailableOrder] { try await client.send(APIRequest(method: .get, path: "\(basePath)/available-order")) } /// 创建旅拍相册。 func create(_ request: TravelAlbumCreateRequest) async throws -> TravelAlbumCreateResponse { try await client.send(APIRequest(method: .post, path: "\(basePath)/create", body: request)) } /// 拉取旅拍相册列表。 func list(page: Int = 1, pageSize: Int = 20) async throws -> TravelAlbumListResponse { try await client.send( APIRequest( method: .get, path: "\(basePath)/list", queryItems: [ URLQueryItem(name: "page", value: String(max(page, 1))), URLQueryItem(name: "page_size", value: String(max(pageSize, 1))), ] ) ) } /// 拉取旅拍相册详情。 func info(id: Int) async throws -> TravelAlbum { try await client.send( APIRequest( method: .get, path: "\(basePath)/info", queryItems: [URLQueryItem(name: "id", value: String(id))] ) ) } /// 拉取旅拍相册素材列表。 func materialList( userEquityTravelId: Int, page: Int = 1, pageSize: Int = 20, orderBy: Int = 2, isPurchased: Int? = nil ) async throws -> TravelAlbumListResponse { var items = [ URLQueryItem(name: "user_equity_travel_id", value: String(userEquityTravelId)), URLQueryItem(name: "page", value: String(max(page, 1))), URLQueryItem(name: "page_size", value: String(max(pageSize, 1))), URLQueryItem(name: "order_by", value: String(orderBy)), ] if let isPurchased { items.append(URLQueryItem(name: "is_purchased", value: String(isPurchased))) } return try await client.send( APIRequest(method: .get, path: "\(basePath)/material-list", queryItems: items) ) } /// 拉取单个相册素材及其最新关联图片信息。 func materialInfo(userEquityTravelId: Int, materialId: Int) async throws -> TravelAlbumMaterial { try await client.send( APIRequest( method: .get, path: "\(basePath)/material-info", queryItems: [ URLQueryItem(name: "user_equity_travel_id", value: String(userEquityTravelId)), URLQueryItem(name: "material_id", value: String(materialId)), ] ) ) } /// 上传并登记旅拍相册素材。 func uploadMaterial(_ request: TravelAlbumUploadMaterialRequest) async throws -> TravelAlbumMaterial { try await client.send(APIRequest(method: .post, path: "\(basePath)/upload-material", body: request)) } /// 拉取相册内已登记素材的客户端照片 ID。 func materialClientPhotoIds(userEquityTravelId: Int) async throws -> TravelAlbumMaterialClientPhotoIDsResponse { try await client.send( APIRequest( method: .get, path: "\(basePath)/material-client-photo-ids", queryItems: [ URLQueryItem(name: "user_equity_travel_id", value: String(userEquityTravelId)), ] ) ) } /// 删除旅拍相册。 func deleteAlbum(id: Int) async throws { let _: EmptyPayload = try await client.send( APIRequest(method: .post, path: "\(basePath)/delete", body: TravelAlbumIDRequest(id: id)) ) } /// 批量删除旅拍相册素材。 func batchDeleteMaterials(ids: [Int]) async throws { let _: EmptyPayload = try await client.send( APIRequest( method: .post, path: "\(basePath)/batch-delete-material", body: TravelAlbumBatchDeleteMaterialRequest(ids: ids) ) ) } /// 拉取相册小程序码。 func mpCode(id: Int) async throws -> TravelAlbumMpCodeResponse { try await client.send( APIRequest( method: .get, path: "\(basePath)/mp-code", queryItems: [URLQueryItem(name: "id", value: String(id))] ) ) } /// 拉取当前景区可用的 AI 修图模板。 func aiRetouchTemplates(scenicId: Int) async throws -> TravelAlbumAIRetouchTemplatesResponse { try await client.send( APIRequest( method: .get, path: "\(basePath)/ai-retouch-templates", queryItems: [URLQueryItem(name: "scenic_id", value: String(scenicId))] ) ) } /// 提交相册素材 AI 修图任务;服务端 data 内容无需客户端消费。 func submitAIRetouch(_ request: TravelAlbumAIRetouchRequest) async throws { let _: EmptyPayload = try await client.send( APIRequest(method: .post, path: "\(basePath)/ai-retouch", body: request) ) } /// 提交重新修图任务;服务端返回的批次与额度信息当前无需消费。 func submitAIReretouch(_ request: TravelAlbumAIReretouchRequest) async throws { let _: EmptyPayload = try await client.send( APIRequest(method: .post, path: "\(basePath)/ai-reretouch", body: request) ) } } /// 旅拍相册 ID 请求体。 private struct TravelAlbumIDRequest: Encodable, Sendable { let id: Int } /// 旅拍相册素材批量删除请求体。 private struct TravelAlbumBatchDeleteMaterialRequest: Encodable, Sendable { let ids: [Int] }