// // OrdersAPI.swift // suixinkan // // Created by Codex on 2026/6/22. // import Foundation import Combine @MainActor /// 订单服务协议,抽象订单列表、核销列表和核销操作以便测试替换。 protocol OrderServing { /// 获取订单管理列表。 func orderList( scenicId: Int, page: Int, pageSize: Int, orderStatus: Int?, userPhone: String?, startTime: String?, endTime: String?, isRefined: Int?, isScenicAdmin: Bool ) async throws -> ListPayload /// 获取核销订单列表。 func writeOffList(scenicId: Int, storeId: Int?, page: Int, pageSize: Int) async throws -> ListPayload /// 核销指定订单号。 func writeOff(orderNumber: String) async throws /// 获取门店订单详情。 func storeOrderDetail(storeId: Int, orderNumber: String) async throws -> StoreOrderDetailResponse /// 获取押金订单列表。 func depositOrderList(scenicId: Int, page: Int, pageSize: Int) async throws -> ListPayload /// 核销押金订单。 func depositOrderWriteOff(orderNumber: String) async throws /// 申请押金订单退款。 func depositOrderRefund(orderNumber: String, refundReason: String) async throws /// 获取订单某个拍摄点的底片、成片和评价信息。 func storeOrderShootingDetail(storeId: Int, orderNumber: String, scenicSpotId: Int, photogUid: Int) async throws -> StoreOrderShootingDetailResponse /// 申请普通订单退款。 func orderRefund(orderNumber: String, refundType: OrderRefundMode, refundAmount: String, refundReason: String) async throws /// 获取订单历史拍摄信息。 func multiTravelShootHistory(orderNumber: String) async throws -> MultiTravelShootHistoryResponse /// 获取多点旅拍订单已核销打卡点列表。 func multiTravelVerifiedScenicSpotList(orderNumber: String) async throws -> [MultiTravelVerifiedScenicSpotItem] /// 提交多点旅拍任务素材。 func multiTravelUploadMaterial(_ request: MultiTravelUploadMaterialRequest) async throws } @MainActor /// 订单 API,封装订单管理、核销订单和订单核销接口。 final class OrdersAPI: OrderServing { private let client: APIClient /// 初始化订单 API,并注入共享网络客户端。 init(client: APIClient) { self.client = client } /// 获取订单管理列表。 func orderList( scenicId: Int, page: Int = 1, pageSize: Int = 20, orderStatus: Int? = nil, userPhone: String? = nil, startTime: String? = nil, endTime: String? = nil, isRefined: Int? = nil, isScenicAdmin: Bool = false ) 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))") ] if let orderStatus, orderStatus > 0 { query.append(URLQueryItem(name: "order_status", value: "\(orderStatus)")) } if let userPhone, !userPhone.isEmpty { query.append(URLQueryItem(name: "user_phone", value: userPhone)) } 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)) } if let isRefined, isRefined > 0 { query.append(URLQueryItem(name: "is_refined", value: "\(isRefined)")) } return try await client.send( APIRequest( method: .get, path: isScenicAdmin ? "/api/app/scenic-admin/order/list" : "/api/yf-handset-app/photog/order/listv2", queryItems: query ) ) } /// 获取核销订单列表。 func writeOffList(scenicId: Int, storeId: Int? = nil, page: Int = 1, pageSize: Int = 20) async throws -> ListPayload { var queryItems = [ URLQueryItem(name: "scenic_id", value: "\(scenicId)"), URLQueryItem(name: "page", value: "\(max(page, 1))"), URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))") ] if let storeId, storeId > 0 { queryItems.append(URLQueryItem(name: "store_id", value: "\(storeId)")) } return try await client.send( APIRequest( method: .get, path: "/api/yf-handset-app/photog/order/order-verification-list", queryItems: queryItems ) ) } /// 核销指定订单号。 func writeOff(orderNumber: String) async throws { let _: EmptyPayload = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/order/order-verify", body: WriteOffRequest(orderNumber: orderNumber) ) ) } /// 获取门店订单详情。 func storeOrderDetail(storeId: Int, orderNumber: String) async throws -> StoreOrderDetailResponse { try await client.send( APIRequest( method: .get, path: "/api/app/store/order/detail", queryItems: [ URLQueryItem(name: "store_id", value: "\(storeId)"), URLQueryItem(name: "order_number", value: orderNumber) ] ) ) } /// 获取押金订单列表。 func depositOrderList(scenicId: Int, page: Int = 1, pageSize: Int = 10) async throws -> ListPayload { try await client.send( APIRequest( method: .get, path: "/api/yf-handset-app/photog/order/deposit-list", queryItems: [ URLQueryItem(name: "scenic_id", value: "\(scenicId)"), URLQueryItem(name: "page", value: "\(max(page, 1))"), URLQueryItem(name: "page_size", value: "\(max(pageSize, 1))") ] ) ) } /// 核销押金订单。 func depositOrderWriteOff(orderNumber: String) async throws { let _: EmptyPayload = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/order/deposit-writeoff", body: DepositOrderWriteOffRequest(orderNumber: orderNumber) ) ) } /// 申请押金订单退款。 func depositOrderRefund(orderNumber: String, refundReason: String) async throws { let _: EmptyPayload = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/order/deposit-refund", body: DepositOrderRefundRequest(orderNumber: orderNumber, refundReason: refundReason) ) ) } /// 获取订单某个拍摄点的底片、成片和评价信息。 func storeOrderShootingDetail(storeId: Int, orderNumber: String, scenicSpotId: Int, photogUid: Int) async throws -> StoreOrderShootingDetailResponse { try await client.send( APIRequest( method: .get, path: "/api/app/store/order/shooting-detail", queryItems: [ URLQueryItem(name: "store_id", value: "\(storeId)"), URLQueryItem(name: "order_number", value: orderNumber), URLQueryItem(name: "scenic_spot_id", value: "\(scenicSpotId)"), URLQueryItem(name: "photog_uid", value: "\(photogUid)") ] ) ) } /// 申请普通订单退款。 func orderRefund(orderNumber: String, refundType: OrderRefundMode, refundAmount: String, refundReason: String) async throws { let _: EmptyPayload = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/order/refund", body: OrderRefundRequest( orderNumber: orderNumber, refundType: refundType.rawValue, refundAmount: refundAmount, refundReason: refundReason ) ) ) } /// 获取订单历史拍摄信息。 func multiTravelShootHistory(orderNumber: String) async throws -> MultiTravelShootHistoryResponse { try await client.send( APIRequest( method: .get, path: "/api/yf-handset-app/photog/order/multi-travel/shoot-history", queryItems: [URLQueryItem(name: "order_number", value: orderNumber)] ) ) } /// 获取多点旅拍订单已核销打卡点列表。 func multiTravelVerifiedScenicSpotList(orderNumber: String) async throws -> [MultiTravelVerifiedScenicSpotItem] { try await client.send( APIRequest( method: .get, path: "/api/yf-handset-app/photog/order/multi-travel/verified-scenic-spot-list", queryItems: [URLQueryItem(name: "order_number", value: orderNumber)] ) ) } /// 提交多点旅拍任务素材。 func multiTravelUploadMaterial(_ request: MultiTravelUploadMaterialRequest) async throws { let _: EmptyPayload = try await client.send( APIRequest( method: .post, path: "/api/yf-handset-app/photog/order/multi-travel/upload-material", body: request ) ) } }