// // AssetsAPI.swift // suixinkan // // Created by Codex on 2026/6/23. // import Foundation import Observation /// 资产服务协议,抽象云盘和素材管理接口以便 ViewModel 测试替换。 @MainActor protocol AssetsServing { /// 获取云盘文件列表。 func cloudFileList(parentFolderId: Int, name: String, type: Int, orderBy: Int, page: Int, pageSize: Int) async throws -> ListPayload /// 创建云盘文件夹。 func cloudFolderCreate(_ request: CloudFolderCreateRequest) async throws /// 登记已上传到 OSS 的云盘文件。 func cloudFileUpload(_ request: CloudFileUploadRequest) async throws /// 删除云盘文件或文件夹。 func cloudFileDelete(_ request: CloudFileDeleteRequest) async throws /// 移动云盘文件或文件夹。 func cloudFileMove(_ request: CloudFileMoveRequest) async throws /// 重命名云盘文件夹。 func cloudFolderEdit(_ request: CloudFolderModifyRequest) async throws /// 重命名云盘文件。 func cloudFileEdit(_ request: CloudFileModifyRequest) async throws /// 检查当前账号是否允许上传云盘文件。 func checkCloudUploadPermission() async throws -> CheckCloudUploadResponse /// 获取素材列表。 func mediaAlbumList(kind: MediaLibraryKind, keyword: String, status: Int?, page: Int, pageSize: Int) async throws -> MediaLibraryListResponse /// 获取素材详情。 func mediaAlbumDetail(id: Int) async throws -> MediaLibraryDetail /// 更新素材上下架状态。 func mediaAlbumOperation(_ request: MediaAlbumOperationRequest) async throws /// 删除素材。 func mediaAlbumDelete(_ request: MediaAlbumDeleteRequest) async throws /// 新增素材标签。 func mediaAlbumAddTag(_ request: MediaAlbumAddTagRequest) async throws /// 上传素材。 func mediaAlbumUpload(_ request: MediaAlbumUploadRequest) async throws /// 编辑素材。 func mediaAlbumEdit(_ request: MediaAlbumEditRequest) async throws /// 获取相册文件夹列表。 func albumFolderList(scenicId: Int, page: Int, pageSize: Int, name: String, startTime: String?, endTime: String?) async throws -> ListPayload /// 获取相册文件夹详情。 func albumFolderInfo(id: Int) async throws -> AlbumFolderItem /// 获取相册内文件列表。 func albumFileList(scenicId: Int, folderId: Int, fileType: Int, page: Int, pageSize: Int) async throws -> ListPayload /// 新建相册文件夹。 func addAlbumFolder(scenicId: Int, name: String, remark: String) async throws /// 编辑相册文件夹名称、备注或封面。 func editAlbumFolder(folderId: Int, coverFileId: Int?, name: String?, remark: String?) async throws /// 删除相册内文件。 func deleteAlbumFiles(folderId: Int, idList: [Int]) async throws /// 登记已上传到 OSS 的相册文件。 func albumFileUploadURL(scenicId: Int, fileURL: String, folderId: Int) async throws } /// 资产 API,负责封装相册云盘和素材管理相关接口。 @MainActor @Observable final class AssetsAPI: AssetsServing { @ObservationIgnored private let client: APIClient /// 初始化资产 API,并注入共享网络客户端。 init(client: APIClient) { self.client = client } /// 获取云盘文件列表。 func cloudFileList( parentFolderId: Int, name: String = "", type: Int = 0, orderBy: Int = 2, page: Int = 1, pageSize: Int = 20 ) async throws -> ListPayload { try await client.send( APIRequest( method: .get, path: "/api/yf-handset-app/photog/cloud-driver/list", queryItems: [ URLQueryItem(name: "parent_folder_id", value: "\(parentFolderId)"), URLQueryItem(name: "name", value: name), URLQueryItem(name: "type", value: "\(type)"), URLQueryItem(name: "order_by", value: "\(orderBy)"), URLQueryItem(name: "page", value: "\(max(page, 1))"), URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))") ] ) ) } /// 创建云盘文件夹。 func cloudFolderCreate(_ request: CloudFolderCreateRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/yf-handset-app/photog/cloud-driver/folder-create", body: request) ) as EmptyPayload } /// 登记已上传到 OSS 的云盘文件。 func cloudFileUpload(_ request: CloudFileUploadRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/yf-handset-app/photog/cloud-driver/file-upload", body: request) ) as EmptyPayload } /// 删除云盘文件或文件夹。 func cloudFileDelete(_ request: CloudFileDeleteRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/yf-handset-app/photog/cloud-driver/delete", body: request) ) as EmptyPayload } /// 移动云盘文件或文件夹。 func cloudFileMove(_ request: CloudFileMoveRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/yf-handset-app/photog/cloud-driver/move", body: request) ) as EmptyPayload } /// 重命名云盘文件夹。 func cloudFolderEdit(_ request: CloudFolderModifyRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/yf-handset-app/photog/cloud-driver/folder-edit", body: request) ) as EmptyPayload } /// 重命名云盘文件。 func cloudFileEdit(_ request: CloudFileModifyRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/yf-handset-app/photog/cloud-driver/file-edit", body: request) ) as EmptyPayload } /// 检查当前账号是否允许上传云盘文件。 func checkCloudUploadPermission() async throws -> CheckCloudUploadResponse { try await client.send( APIRequest(method: .get, path: "/api/yf-handset-app/photog/cloud-driver/check-upload-permission") ) } /// 获取素材列表。 func mediaAlbumList( kind: MediaLibraryKind = .material, keyword: String = "", status: Int? = nil, page: Int = 1, pageSize: Int = 10 ) async throws -> MediaLibraryListResponse { var query = [ URLQueryItem(name: "type", value: "\(kind.rawValue)"), URLQueryItem(name: "keyword", value: keyword), URLQueryItem(name: "page", value: "\(max(page, 1))"), URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))") ] if let status, status >= 0 { query.append(URLQueryItem(name: "status", value: "\(status)")) } return try await client.send( APIRequest(method: .get, path: "/api/app/media-album/list", queryItems: query) ) } /// 获取素材详情。 func mediaAlbumDetail(id: Int) async throws -> MediaLibraryDetail { try await client.send( APIRequest( method: .get, path: "/api/app/media-album/detail", queryItems: [URLQueryItem(name: "id", value: "\(id)")] ) ) } /// 更新素材上下架状态。 func mediaAlbumOperation(_ request: MediaAlbumOperationRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/app/media-album/operation", body: request) ) as EmptyPayload } /// 删除素材。 func mediaAlbumDelete(_ request: MediaAlbumDeleteRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/app/media-album/delete", body: request) ) as EmptyPayload } /// 新增素材标签。 func mediaAlbumAddTag(_ request: MediaAlbumAddTagRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/app/media-album/add-tag", body: request) ) as EmptyPayload } /// 上传素材。 func mediaAlbumUpload(_ request: MediaAlbumUploadRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/app/media-album/upload", body: request) ) as EmptyPayload } /// 编辑素材。 func mediaAlbumEdit(_ request: MediaAlbumEditRequest) async throws { _ = try await client.send( APIRequest(method: .post, path: "/api/app/media-album/edit", body: request) ) as EmptyPayload } /// 获取相册文件夹列表。 func albumFolderList( scenicId: Int, page: Int = 1, pageSize: Int = 10, name: String = "", startTime: String? = nil, endTime: String? = nil ) async throws -> ListPayload { var query = [ URLQueryItem(name: "scenic_id", value: "\(scenicId)"), URLQueryItem(name: "page", value: "\(max(page, 1))"), URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))"), URLQueryItem(name: "cloud_folder_type", value: "1") ] if !name.isEmpty { query.append(URLQueryItem(name: "name", value: name)) } if let startTime, !startTime.isEmpty { query.append(URLQueryItem(name: "start_time", value: startTime)) } if let endTime, !endTime.isEmpty { query.append(URLQueryItem(name: "end_time", value: endTime)) } return try await client.send( APIRequest(method: .get, path: "/api/yf-handset-app/photog/album/folder-list", queryItems: query) ) } /// 获取相册文件夹详情。 func albumFolderInfo(id: Int) async throws -> AlbumFolderItem { try await client.send( APIRequest( method: .get, path: "/api/yf-handset-app/photog/album/folder-info", queryItems: [URLQueryItem(name: "id", value: "\(id)")] ) ) } /// 获取相册内文件列表。 func albumFileList( scenicId: Int, folderId: Int, fileType: Int, page: Int = 1, pageSize: Int = 20 ) async throws -> ListPayload { try await client.send( APIRequest( method: .get, path: "/api/yf-handset-app/photog/album/file-list", queryItems: [ URLQueryItem(name: "scenic_id", value: "\(scenicId)"), URLQueryItem(name: "folder_id", value: "\(folderId)"), URLQueryItem(name: "file_type", value: "\(fileType)"), URLQueryItem(name: "page", value: "\(max(page, 1))"), URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))") ] ) ) } /// 新建相册文件夹。 func addAlbumFolder(scenicId: Int, name: String, remark: String) async throws { _ = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/album/folder-add", body: AlbumFolderAddRequest( scenicId: "\(scenicId)", name: name, remark: remark, cloudFolderType: 1 ) ) ) as EmptyPayload } /// 编辑相册文件夹名称、备注或封面。 func editAlbumFolder(folderId: Int, coverFileId: Int? = nil, name: String? = nil, remark: String? = nil) async throws { _ = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/album/folder-edit", body: AlbumFolderEditRequest(folderId: folderId, coverFileId: coverFileId, name: name, remark: remark) ) ) as EmptyPayload } /// 删除相册内文件。 func deleteAlbumFiles(folderId: Int, idList: [Int]) async throws { _ = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/album/file-delete", body: AlbumFileDeleteRequest(idList: idList, folderId: folderId) ) ) as EmptyPayload } /// 登记已上传到 OSS 的相册文件。 func albumFileUploadURL(scenicId: Int, fileURL: String, folderId: Int) async throws { _ = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/album/file-upload-url", queryItems: [ URLQueryItem(name: "scenic_id", value: "\(scenicId)"), URLQueryItem(name: "file_url", value: fileURL), URLQueryItem(name: "folder_id", value: "\(folderId)") ] ) ) as EmptyPayload } }