Files

1045 lines
35 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// OrderModels.swift
// suixinkan
//
import Foundation
// MARK: - List Response
/// `list` `data`
struct OrderListResponse<T: Decodable>: Decodable {
let total: Int
let list: [T]
init(total: Int = 0, list: [T] = []) {
self.total = total
self.list = list
}
}
// MARK: - Photographer Order
struct OrderEntity: Decodable, Equatable {
let photogUid: Int
let orderNumber: String
let remark: String?
let scenicAreaId: Int
let payTime: String
let completeTime: String
let orderStatus: Int
let orderStatusName: String
let userId: Int
let projectId: Int
let phone: String
let orderAmount: String
let actualPayAmount: String
let actualRefundAmount: String
let payTypeName: String
let payType: Int
let projectName: String
let orderType: Int
let orderTypeLabel: String
let depositPayTime: String
let createdAt: String
let photoTravel: PhotoTravelEntity?
let refundAmount: String
let multiTravel: MultiTravelEntity?
let isNeedEdit: Bool
let isRefined: Int
let canBindReferral: Int
let showOrderSource: Int
let referralOrderNo: String
let referralSalerName: String
let referralSalerPhotogRemarkName: String
let referralOrder: BoundReferralOrderEntity?
var displayReferralSalerName: String {
OrderDisplayName.saleUser(remark: referralSalerPhotogRemarkName, primary: referralSalerName)
}
enum CodingKeys: String, CodingKey {
case photogUid = "photog_uid"
case orderNumber = "order_number"
case remark
case scenicAreaId = "scenic_area_id"
case payTime = "pay_time"
case completeTime = "complete_time"
case orderStatus = "order_status"
case orderStatusName = "order_status_name"
case userId = "user_id"
case projectId = "project_id"
case phone
case orderAmount = "order_amount"
case actualPayAmount = "actual_pay_amount"
case actualRefundAmount = "actual_refund_amount"
case payTypeName = "pay_type_name"
case payType = "pay_type"
case projectName = "project_name"
case orderType = "order_type"
case orderTypeLabel = "order_type_label"
case depositPayTime = "deposit_pay_time"
case createdAt = "created_at"
case photoTravel = "photo_travel"
case refundAmount = "refund_amount"
case multiTravel = "multi_travel"
case isNeedEdit
case isRefined = "is_refined"
case canBindReferral = "can_bind_referral"
case showOrderSource = "show_order_source"
case referralOrderNo = "referral_order_no"
case referralSalerName = "referral_saler_name"
case referralSalerPhotogRemarkName = "photog_remark_name"
case referralOrder = "referral_order"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
photogUid = try container.decodeIfPresent(Int.self, forKey: .photogUid) ?? 0
orderNumber = try container.decodeIfPresent(String.self, forKey: .orderNumber) ?? ""
remark = try container.decodeIfPresent(String.self, forKey: .remark)
scenicAreaId = try container.decodeIfPresent(Int.self, forKey: .scenicAreaId) ?? 0
payTime = try container.decodeIfPresent(String.self, forKey: .payTime) ?? ""
completeTime = try container.decodeIfPresent(String.self, forKey: .completeTime) ?? ""
orderStatus = try container.decodeIfPresent(Int.self, forKey: .orderStatus) ?? 0
orderStatusName = try container.decodeIfPresent(String.self, forKey: .orderStatusName) ?? ""
userId = try container.decodeIfPresent(Int.self, forKey: .userId) ?? 0
projectId = try container.decodeIfPresent(Int.self, forKey: .projectId) ?? 0
phone = try container.decodeIfPresent(String.self, forKey: .phone) ?? ""
orderAmount = try Self.decodeFlexibleString(container: container, key: .orderAmount)
actualPayAmount = try Self.decodeFlexibleString(container: container, key: .actualPayAmount)
actualRefundAmount = try Self.decodeFlexibleString(container: container, key: .actualRefundAmount, defaultValue: "0")
payTypeName = try container.decodeIfPresent(String.self, forKey: .payTypeName) ?? ""
payType = try container.decodeIfPresent(Int.self, forKey: .payType) ?? 0
projectName = try container.decodeIfPresent(String.self, forKey: .projectName) ?? ""
orderType = try container.decodeIfPresent(Int.self, forKey: .orderType) ?? 0
orderTypeLabel = try container.decodeIfPresent(String.self, forKey: .orderTypeLabel) ?? ""
depositPayTime = try container.decodeIfPresent(String.self, forKey: .depositPayTime) ?? ""
createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt) ?? ""
photoTravel = try Self.decodePhotoTravel(from: container)
refundAmount = try Self.decodeFlexibleString(container: container, key: .refundAmount, defaultValue: "0")
multiTravel = try Self.decodeMultiTravel(from: container)
isNeedEdit = try container.decodeIfPresent(Bool.self, forKey: .isNeedEdit) ?? true
isRefined = try container.decodeIfPresent(Int.self, forKey: .isRefined) ?? 0
canBindReferral = try container.decodeIfPresent(Int.self, forKey: .canBindReferral) ?? 0
showOrderSource = try container.decodeIfPresent(Int.self, forKey: .showOrderSource) ?? 0
referralOrderNo = try container.decodeIfPresent(String.self, forKey: .referralOrderNo) ?? ""
referralSalerName = try container.decodeIfPresent(String.self, forKey: .referralSalerName) ?? ""
referralSalerPhotogRemarkName = try container.decodeIfPresent(String.self, forKey: .referralSalerPhotogRemarkName) ?? ""
referralOrder = try container.decodeIfPresent(BoundReferralOrderEntity.self, forKey: .referralOrder)
}
private static func decodeFlexibleString(
container: KeyedDecodingContainer<CodingKeys>,
key: CodingKeys,
defaultValue: String = ""
) throws -> String {
if let string = try? container.decode(String.self, forKey: key) {
return string
}
if let intValue = try? container.decode(Int.self, forKey: key) {
return String(intValue)
}
if let doubleValue = try? container.decode(Double.self, forKey: key) {
return String(doubleValue)
}
return defaultValue
}
private static func decodePhotoTravel(
from container: KeyedDecodingContainer<CodingKeys>
) throws -> PhotoTravelEntity? {
guard container.contains(.photoTravel), try !container.decodeNil(forKey: .photoTravel) else {
return nil
}
let travel = try container.decode(PhotoTravelEntity.self, forKey: .photoTravel)
return travel.isEmpty ? nil : travel
}
private static func decodeMultiTravel(
from container: KeyedDecodingContainer<CodingKeys>
) throws -> MultiTravelEntity? {
guard container.contains(.multiTravel), try !container.decodeNil(forKey: .multiTravel) else {
return nil
}
let travel = try container.decode(MultiTravelEntity.self, forKey: .multiTravel)
return travel.isEmpty ? nil : travel
}
}
struct BoundReferralOrderEntity: Decodable, Equatable {
let id: Int
let orderNo: String
let saleUserId: Int
let salerName: String
let photogRemarkName: String
let salerPhone: String
let displayText: String
let userMobile: String
let remark: String
let bindOrderNumber: String
let sourceType: Int
let sourceTypeLabel: String
let status: Int
let statusLabel: String
let createdAt: String
var displaySalerName: String {
OrderDisplayName.saleUser(remark: photogRemarkName, primary: salerName)
}
enum CodingKeys: String, CodingKey {
case id
case orderNo = "order_no"
case saleUserId = "sale_user_id"
case salerName = "saler_name"
case photogRemarkName = "photog_remark_name"
case salerPhone = "saler_phone"
case displayText = "display_text"
case userMobile = "user_mobile"
case remark
case bindOrderNumber = "bind_order_number"
case sourceType = "source_type"
case sourceTypeLabel = "source_type_label"
case status
case statusLabel = "status_label"
case createdAt = "created_at"
case saleUser = "sale_user"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0
orderNo = try container.decodeIfPresent(String.self, forKey: .orderNo) ?? ""
saleUserId = try container.decodeIfPresent(Int.self, forKey: .saleUserId) ?? 0
salerName = try container.decodeIfPresent(String.self, forKey: .salerName) ?? ""
salerPhone = try container.decodeIfPresent(String.self, forKey: .salerPhone) ?? ""
displayText = try container.decodeIfPresent(String.self, forKey: .displayText) ?? ""
userMobile = try container.decodeIfPresent(String.self, forKey: .userMobile) ?? ""
remark = try container.decodeIfPresent(String.self, forKey: .remark) ?? ""
bindOrderNumber = try container.decodeIfPresent(String.self, forKey: .bindOrderNumber) ?? ""
sourceType = try container.decodeIfPresent(Int.self, forKey: .sourceType) ?? 0
sourceTypeLabel = try container.decodeIfPresent(String.self, forKey: .sourceTypeLabel) ?? ""
status = try container.decodeIfPresent(Int.self, forKey: .status) ?? 0
statusLabel = try container.decodeIfPresent(String.self, forKey: .statusLabel) ?? ""
createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt) ?? ""
let saleUser = try container.decodeIfPresent(ReferralSaleUserEntity.self, forKey: .saleUser)
photogRemarkName = try container.decodeIfPresent(String.self, forKey: .photogRemarkName)
?? saleUser?.photogRemarkName
?? saleUser?.displayName
?? ""
}
}
/// `referral_order.sale_user`
struct ReferralSaleUserEntity: Decodable, Equatable {
let photogRemarkName: String
let displayName: String
let salerName: String
enum CodingKeys: String, CodingKey {
case photogRemarkName = "photog_remark_name"
case displayName = "display_name"
case salerName = "saler_name"
case name
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
photogRemarkName = try container.decodeIfPresent(String.self, forKey: .photogRemarkName) ?? ""
let name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
salerName = try container.decodeIfPresent(String.self, forKey: .salerName) ?? name
displayName = try container.decodeIfPresent(String.self, forKey: .displayName) ?? salerName
}
}
struct PhotoTravelEntity: Decodable, Equatable {
let orderPhotoNum: Int
let orderVideoNum: Int
let canCancelOrder: Bool
let needCheckIn: Bool
let checkInTime: String
let canGiftRetouch: Bool
let retouchGiftTime: String
let retouchGiftPhotoNum: Int
let retouchGiftVideoNum: Int
enum CodingKeys: String, CodingKey {
case orderPhotoNum = "order_photo_num"
case orderVideoNum = "order_video_num"
case canCancelOrder = "can_cancel_order"
case needCheckIn = "need_check_in"
case checkInTime = "check_in_time"
case canGiftRetouch = "can_gift_retouch"
case retouchGiftTime = "retouch_gift_time"
case retouchGiftPhotoNum = "retouch_gift_photo_num"
case retouchGiftVideoNum = "retouch_gift_video_num"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
orderPhotoNum = try container.decodeIfPresent(Int.self, forKey: .orderPhotoNum) ?? 0
orderVideoNum = try container.decodeIfPresent(Int.self, forKey: .orderVideoNum) ?? 0
canCancelOrder = try container.decodeIfPresent(Bool.self, forKey: .canCancelOrder) ?? false
needCheckIn = try container.decodeIfPresent(Bool.self, forKey: .needCheckIn) ?? false
checkInTime = try container.decodeIfPresent(String.self, forKey: .checkInTime) ?? ""
canGiftRetouch = try container.decodeIfPresent(Bool.self, forKey: .canGiftRetouch) ?? false
retouchGiftTime = try container.decodeIfPresent(String.self, forKey: .retouchGiftTime) ?? ""
retouchGiftPhotoNum = try container.decodeIfPresent(Int.self, forKey: .retouchGiftPhotoNum) ?? 0
retouchGiftVideoNum = try container.decodeIfPresent(Int.self, forKey: .retouchGiftVideoNum) ?? 0
}
var isEmpty: Bool {
orderPhotoNum == 0
&& orderVideoNum == 0
&& !canCancelOrder
&& !needCheckIn
&& checkInTime.isEmpty
&& !canGiftRetouch
&& retouchGiftTime.isEmpty
&& retouchGiftPhotoNum == 0
&& retouchGiftVideoNum == 0
}
}
struct MultiTravelEntity: Decodable, Equatable {
let materialList: [MultiTravelMaterialEntity]
enum CodingKeys: String, CodingKey {
case materialList = "material_list"
}
init(materialList: [MultiTravelMaterialEntity] = []) {
self.materialList = materialList
}
var isEmpty: Bool {
materialList.isEmpty
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
materialList = try container.decodeIfPresent([MultiTravelMaterialEntity].self, forKey: .materialList) ?? []
}
}
struct MultiTravelMaterialEntity: Decodable, Equatable {
let fileName: String
let fileUrl: String
let fileType: Int
let fileSize: Int64
let coverUrl: String
enum CodingKeys: String, CodingKey {
case fileName = "file_name"
case fileUrl = "file_url"
case fileType = "file_type"
case fileSize = "file_size"
case coverUrl = "cover_url"
}
}
// MARK: - Store Order
struct StoreOrderListData: Decodable, Equatable {
let total: Int
let list: [StoreOrderItem]
init(total: Int = 0, list: [StoreOrderItem] = []) {
self.total = total
self.list = list
}
}
struct StoreOrderItem: Decodable, Equatable {
let orderNumber: String
let orderType: Int
let orderTypeLabel: String
let createdAt: String
let orderStatus: Int
let orderStatusName: String
let actualPayAmount: String
let actualRefundAmount: String
let payTypeName: String
let payTime: String
let completeTime: String
let userId: Int
let phone: String
let projectId: Int
let projectName: String
let remark: String
enum CodingKeys: String, CodingKey {
case orderNumber = "order_number"
case orderType = "order_type"
case orderTypeLabel = "order_type_label"
case createdAt = "created_at"
case orderStatus = "order_status"
case orderStatusName = "order_status_name"
case actualPayAmount = "actual_pay_amount"
case actualRefundAmount = "actual_refund_amount"
case payTypeName = "pay_type_name"
case payTime = "pay_time"
case completeTime = "complete_time"
case userId = "user_id"
case phone
case projectId = "project_id"
case projectName = "project_name"
case remark
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
orderNumber = try container.decodeIfPresent(String.self, forKey: .orderNumber) ?? ""
orderType = try container.decodeIfPresent(Int.self, forKey: .orderType) ?? 0
orderTypeLabel = try container.decodeIfPresent(String.self, forKey: .orderTypeLabel) ?? ""
createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt) ?? ""
orderStatus = try container.decodeIfPresent(Int.self, forKey: .orderStatus) ?? 0
orderStatusName = try container.decodeIfPresent(String.self, forKey: .orderStatusName) ?? ""
actualPayAmount = try container.decodeIfPresent(String.self, forKey: .actualPayAmount) ?? ""
actualRefundAmount = try container.decodeIfPresent(String.self, forKey: .actualRefundAmount) ?? ""
payTypeName = try container.decodeIfPresent(String.self, forKey: .payTypeName) ?? ""
payTime = try container.decodeIfPresent(String.self, forKey: .payTime) ?? ""
completeTime = try container.decodeIfPresent(String.self, forKey: .completeTime) ?? ""
userId = try container.decodeIfPresent(Int.self, forKey: .userId) ?? 0
phone = try container.decodeIfPresent(String.self, forKey: .phone) ?? ""
projectId = try container.decodeIfPresent(Int.self, forKey: .projectId) ?? 0
projectName = try container.decodeIfPresent(String.self, forKey: .projectName) ?? ""
remark = try container.decodeIfPresent(String.self, forKey: .remark) ?? ""
}
}
enum StoreOrderType {
static let offlineProduct = 4
static let multiTravelShoot = 19
}
// MARK: - Request Bodies
struct CancelRequest: Encodable {
let orderNumber: String
enum CodingKeys: String, CodingKey {
case orderNumber = "order_number"
}
}
struct OrderRefundRequest: Encodable {
var orderNumber: String
var refundType: Int
var refundAmount: String
var refundReason: String
enum CodingKeys: String, CodingKey {
case orderNumber = "order_number"
case refundType = "refund_type"
case refundAmount = "refund_amount"
case refundReason = "refund_reason"
}
}
struct SendGiftRequest: Encodable {
let orderNumber: String
let photoNum: Int
let videoNum: Int
enum CodingKeys: String, CodingKey {
case orderNumber = "order_number"
case photoNum = "photo_num"
case videoNum = "video_num "
}
}
struct StoreOrderRefundRequest: Encodable {
let storeId: Int
let orderNumber: String
let refundType: Int
let refundAmount: String
let refundReason: String
enum CodingKeys: String, CodingKey {
case storeId = "store_id"
case orderNumber = "order_number"
case refundType = "refund_type"
case refundAmount = "refund_amount"
case refundReason = "refund_reason"
}
}
struct StoreOrderVerifyRequest: Encodable {
let method: String
let userId: Int
let orderNumber: String
let time: String
let storeId: Int
enum CodingKeys: String, CodingKey {
case method
case userId = "user_id"
case orderNumber = "order_number"
case time
case storeId = "store_id"
}
init(userId: Int, orderNumber: String, time: String, storeId: Int) {
method = "order_verify"
self.userId = userId
self.orderNumber = orderNumber
self.time = time
self.storeId = storeId
}
}
struct MultiTravelOrderVerifyRequest: Encodable {
let method: String
let orderNumber: String
let userId: Int
let time: Int64
let checkSum: String
let scenicSpotId: Int
enum CodingKeys: String, CodingKey {
case method
case orderNumber = "order_number"
case userId = "user_id"
case time
case checkSum = "check_sum"
case scenicSpotId = "scenic_spot_id"
}
init(orderNumber: String, userId: Int, time: Int64, checkSum: String, scenicSpotId: Int) {
method = "multi_verify"
self.orderNumber = orderNumber
self.userId = userId
self.time = time
self.checkSum = checkSum
self.scenicSpotId = scenicSpotId
}
}
// MARK: - Responses
struct OrderSignInResponse: Decodable, Equatable {
let checkIn: Bool
let orderNumber: String
let projectName: String
let photogName: String
let scenicName: String
let orderAmount: String
let depositAmount: String
let depositPayTime: String
let userPhone: String
enum CodingKeys: String, CodingKey {
case checkIn = "check_in"
case orderNumber = "order_number"
case projectName = "project_name"
case photogName = "photog_name"
case scenicName = "scenic_name"
case orderAmount = "order_amount"
case depositAmount = "deposit_amount"
case depositPayTime = "deposit_pay_time"
case userPhone = "user_phone"
}
}
struct WriteOffOrderResponse: Decodable, Equatable {
let orderVerify: Bool
let orderNumber: String
let projectName: String
let scenicName: String
let orderAmount: String
let payTime: String
let userPhone: String
let verifyTime: String
enum CodingKeys: String, CodingKey {
case orderVerify = "order_verify"
case orderNumber = "order_number"
case projectName = "project_name"
case scenicName = "scenic_name"
case orderAmount = "order_amount"
case payTime = "pay_time"
case userPhone = "user_phone"
case verifyTime = "time"
}
}
struct MultiTravelScenicSpotListResponse: Decodable {
let scenicSpot: [MultiTravelScenicSpotItem]?
enum CodingKeys: String, CodingKey {
case scenicSpot = "scenic_spot"
}
var entityList: [MultiTravelScenicSpotEntity] {
scenicSpot?.map { $0.toEntity() } ?? []
}
}
struct MultiTravelScenicSpotItem: Decodable {
let id: Int
let name: String
let cover: String
let scenicName: String
let scenicId: Int
let distance: Double
enum CodingKeys: String, CodingKey {
case id, name, cover
case scenicName = "scenic_name"
case scenicId = "scenic_id"
case distance
}
func toEntity() -> MultiTravelScenicSpotEntity {
MultiTravelScenicSpotEntity(
scenicSpotId: id,
name: name,
coverUrl: cover,
scenicName: scenicName,
distanceText: Self.formatDistance(distance),
address: scenicName
)
}
private static func formatDistance(_ distance: Double) -> String {
if distance <= 0 { return "当前点位" }
if distance < 1000 { return "\(Int(distance))" }
let km = distance / 1000
let tenths = Int(km * 10)
return "\(tenths / 10).\(tenths % 10)公里"
}
}
struct MultiTravelScenicSpotEntity: Equatable {
let scenicSpotId: Int
let name: String
let coverUrl: String
let scenicName: String
let distanceText: String
let address: String
}
struct MultiTravelShootHistoryResponse: Decodable, Equatable {
let projectName: String
let projectType: Int
let projectTypeName: String
let photogSpotList: [PhotogSpotItem]
enum CodingKeys: String, CodingKey {
case projectName = "project_name"
case projectType = "project_type"
case projectTypeName = "project_type_name"
case photogSpotList = "photog_spot_list"
}
}
struct PhotogSpotItem: Decodable, Equatable {
let scenicSpotId: Int
let photogUid: Int
let scenicSpotName: String
let photogNickname: String
let photogName: String
let files: [ShootHistoryFileItem]
enum CodingKeys: String, CodingKey {
case scenicSpotId = "scenic_spot_id"
case photogUid = "photog_uid"
case scenicSpotName = "scenic_spot_name"
case photogNickname = "photog_nickname"
case photogName = "photog_name"
case files
}
var photographerDisplayName: String {
photogNickname.isEmpty ? photogName : photogNickname
}
var imageUrls: [String] {
files.compactMap { file in
if !file.coverUrl.isEmpty { return file.coverUrl }
if file.fileType == 2, !file.fileUrl.isEmpty { return file.fileUrl }
return file.fileUrl.isEmpty ? nil : file.fileUrl
}
}
}
struct ShootHistoryFileItem: Decodable, Equatable {
let fileName: String
let fileUrl: String
let fileType: Int
let fileSize: Int64
let coverUrl: String
let uploadTime: String
enum CodingKeys: String, CodingKey {
case fileName = "file_name"
case fileUrl = "file_url"
case fileType = "file_type"
case fileSize = "file_size"
case coverUrl = "cover_url"
case uploadTime = "upload_time"
}
}
struct StoreOrderDetailData: Decodable, Equatable {
let orderNumber: String
let orderType: Int
let orderTypeLabel: String
let createdAt: String
let orderStatus: Int
let orderStatusName: String
let actualPayAmount: String
let actualRefundAmount: String
let payTypeName: String
let payTime: String
let completeTime: String
let userId: Int
let phone: String
let projectId: Int
let projectName: String
let remark: String
let multiTravel: StoreMultiTravelInfo?
enum CodingKeys: String, CodingKey {
case orderNumber = "order_number"
case orderType = "order_type"
case orderTypeLabel = "order_type_label"
case createdAt = "created_at"
case orderStatus = "order_status"
case orderStatusName = "order_status_name"
case actualPayAmount = "actual_pay_amount"
case actualRefundAmount = "actual_refund_amount"
case payTypeName = "pay_type_name"
case payTime = "pay_time"
case completeTime = "complete_time"
case userId = "user_id"
case phone
case projectId = "project_id"
case projectName = "project_name"
case remark
case multiTravel = "multi_travel"
}
}
struct StoreMultiTravelInfo: Decodable, Equatable {
let projectInfo: StoreProjectInfo?
let shootingList: [StoreShootingListItem]
enum CodingKeys: String, CodingKey {
case projectInfo = "project_info"
case shootingList = "shooting_list"
}
}
struct StoreProjectInfo: Decodable, Equatable {
let settleSpotNum: Int
let singleSpotMaterialNum: Int
let singleSpotPhotoNum: Int
let singleSpotVideoNum: Int
enum CodingKeys: String, CodingKey {
case settleSpotNum = "settle_spot_num"
case singleSpotMaterialNum = "single_spot_material_num"
case singleSpotPhotoNum = "single_spot_photo_num"
case singleSpotVideoNum = "single_spot_video_num"
}
}
struct StoreShootingListItem: Decodable, Equatable {
let scenicSpotId: Int
let photogUid: Int
let scenicSpotName: String
let staffName: String
let photogName: String
let status: Int
let startAvg: Float?
let start: Float?
enum CodingKeys: String, CodingKey {
case scenicSpotId = "scenic_spot_id"
case photogUid = "photog_uid"
case scenicSpotName = "scenic_spot_name"
case staffName = "staff_name"
case photogName = "photog_name"
case status
case startAvg = "start_avg"
case start
}
var displayStaffName: String {
staffName.isEmpty ? photogName : staffName
}
}
// MARK: - Order Source
struct CooperativeSalerListResponse: Decodable {
let total: Int
let list: [CooperativeSalerEntity]
}
struct CooperativeSalerEntity: Decodable, Equatable {
let saleUserId: Int
let bindingId: Int
let name: String
let salerName: String
let photogRemarkName: String
let phone: String
let salerPhone: String
let commissionRate: Int
let commissionRateLabel: String
let bindTime: String
let boundAt: String
var displayId: Int { saleUserId }
var displayName: String { OrderDisplayName.saleUser(remark: photogRemarkName, primary: name, fallback: salerName) }
var displayPhone: String { salerPhone.isEmpty ? phone : salerPhone }
var displayBindTime: String { bindTime.isEmpty ? boundAt : bindTime }
var displayCommissionRate: String {
if !commissionRateLabel.isEmpty { return commissionRateLabel }
return "\(commissionRate)%"
}
enum CodingKeys: String, CodingKey {
case saleUserId = "sale_user_id"
case bindingId = "binding_id"
case name
case salerName = "saler_name"
case photogRemarkName = "photog_remark_name"
case phone
case salerPhone = "saler_phone"
case commissionRate = "commission_rate"
case commissionRateLabel = "commission_rate_label"
case bindTime = "bind_time"
case boundAt = "bound_at"
}
init(
saleUserId: Int = 0,
bindingId: Int = 0,
name: String = "",
salerName: String = "",
photogRemarkName: String = "",
phone: String = "",
salerPhone: String = "",
commissionRate: Int = 0,
commissionRateLabel: String = "",
bindTime: String = "",
boundAt: String = ""
) {
self.saleUserId = saleUserId
self.bindingId = bindingId
self.name = name
self.salerName = salerName
self.photogRemarkName = photogRemarkName
self.phone = phone
self.salerPhone = salerPhone
self.commissionRate = commissionRate
self.commissionRateLabel = commissionRateLabel
self.bindTime = bindTime
self.boundAt = boundAt
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
saleUserId = try container.decodeIfPresent(Int.self, forKey: .saleUserId) ?? 0
bindingId = try container.decodeIfPresent(Int.self, forKey: .bindingId) ?? 0
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
salerName = try container.decodeIfPresent(String.self, forKey: .salerName) ?? ""
photogRemarkName = try container.decodeIfPresent(String.self, forKey: .photogRemarkName) ?? ""
phone = try container.decodeIfPresent(String.self, forKey: .phone) ?? ""
salerPhone = try container.decodeIfPresent(String.self, forKey: .salerPhone) ?? ""
commissionRate = try container.decodeIfPresent(Int.self, forKey: .commissionRate) ?? 0
commissionRateLabel = try container.decodeIfPresent(String.self, forKey: .commissionRateLabel) ?? ""
bindTime = try container.decodeIfPresent(String.self, forKey: .bindTime) ?? ""
boundAt = try container.decodeIfPresent(String.self, forKey: .boundAt) ?? ""
}
func withRemarkName(_ remark: String) -> CooperativeSalerEntity {
CooperativeSalerEntity(
saleUserId: saleUserId,
bindingId: bindingId,
name: name,
salerName: salerName,
photogRemarkName: remark,
phone: phone,
salerPhone: salerPhone,
commissionRate: commissionRate,
commissionRateLabel: commissionRateLabel,
bindTime: bindTime,
boundAt: boundAt
)
}
}
struct ReferralOrderListResponse: Decodable {
let total: Int
let list: [ReferralOrderEntity]
}
struct ReferralOrderEntity: Decodable, Equatable {
let id: Int
let referralOrderNo: String
let orderNo: String
let userMobile: String
let remark: String
let createdAt: String
let status: Int
let statusLabel: String
let images: [String]
var displayReferralOrderNo: String { referralOrderNo.isEmpty ? orderNo : referralOrderNo }
enum CodingKeys: String, CodingKey {
case id
case referralOrderNo = "referral_order_no"
case orderNo = "order_no"
case userMobile = "user_mobile"
case remark
case createdAt = "created_at"
case status
case statusLabel = "status_label"
case images
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0
referralOrderNo = try container.decodeIfPresent(String.self, forKey: .referralOrderNo) ?? ""
orderNo = try container.decodeIfPresent(String.self, forKey: .orderNo) ?? ""
userMobile = try container.decodeIfPresent(String.self, forKey: .userMobile) ?? ""
remark = try container.decodeIfPresent(String.self, forKey: .remark) ?? ""
createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt) ?? ""
status = try container.decodeIfPresent(Int.self, forKey: .status) ?? 0
statusLabel = try container.decodeIfPresent(String.self, forKey: .statusLabel) ?? ""
images = (try? container.decode([String].self, forKey: .images)) ?? []
}
}
// MARK: - Filters
enum PhotographerOrderFilter: CaseIterable {
case all
case paidDeposit
case completed
case refunded
case needsRefinement
case noRefinement
var label: String {
switch self {
case .all: "全部"
case .paidDeposit: "已付定金"
case .completed: "已完成"
case .refunded: "已退款"
case .needsRefinement: "需要精修"
case .noRefinement: "无需精修"
}
}
var tabIndex: Int {
switch self {
case .all, .needsRefinement, .noRefinement: 0
case .paidDeposit: 18
case .completed: 30
case .refunded: 50
}
}
var rTabIndex: Int {
switch self {
case .needsRefinement: 1
case .noRefinement: 2
default: 0
}
}
static func from(tabIndex: Int, rTabIndex: Int) -> PhotographerOrderFilter {
switch (tabIndex, rTabIndex) {
case (18, 0): .paidDeposit
case (30, 0): .completed
case (50, 0): .refunded
case (0, 1): .needsRefinement
case (0, 2): .noRefinement
default: .all
}
}
}
enum StoreOrderFilter: CaseIterable {
case all
case paid
case completed
case refunded
var label: String {
switch self {
case .all: "全部"
case .paid: "已支付"
case .completed: "已完成"
case .refunded: "已退款"
}
}
var tabIndex: Int {
switch self {
case .all: 0
case .paid: 18
case .completed: 30
case .refunded: 50
}
}
/// UI tab 18 API order_status=20
var apiOrderStatus: Int {
switch self {
case .paid: 20
default: tabIndex
}
}
static func from(tabIndex: Int) -> StoreOrderFilter {
switch tabIndex {
case 18: .paid
case 30: .completed
case 50: .refunded
default: .all
}
}
}
enum OrderTypeCode {
static let photographerFollow = 11
static let photographerFollowOfflineScan = 14
static let multiTravel = 19
}
enum OrderDisplayName {
static func saleUser(remark: String, primary: String, fallback: String = "") -> String {
if !remark.isEmpty { return remark }
if !primary.isEmpty { return primary }
return fallback
}
}
enum OrderListQueryBuilder {
static let photographerPageSize = 10
static let storePageSize = 20
static func orderStatusQuery(tabIndex: Int) -> String? {
tabIndex == 0 ? nil : String(tabIndex)
}
static func isRefinedQuery(rTabIndex: Int) -> Int? {
rTabIndex == 0 ? nil : rTabIndex
}
static func storeOrderStatusQuery(tabIndex: Int) -> Int? {
let status = StoreOrderFilter.from(tabIndex: tabIndex).apiOrderStatus
return status == 0 ? nil : status
}
}