// // WalletModels.swift // suixinkan // import Foundation /// 钱包汇总响应,用于展示累计金额、当前余额和可提现金额。 struct WalletSummaryResponse: Decodable, Equatable { let amountTotal: String let amountCurrentBalance: String let amountWithdrawable: String enum CodingKeys: String, CodingKey { case amountTotal = "amount_total" case amountCurrentBalance = "amount_current_balance" case amountWithdrawable = "amount_withdrawable" } /// 创建钱包汇总响应。 init(amountTotal: String = "", amountCurrentBalance: String = "", amountWithdrawable: String = "") { self.amountTotal = amountTotal self.amountCurrentBalance = amountCurrentBalance self.amountWithdrawable = amountWithdrawable } /// 宽松解码钱包汇总金额字段。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) amountTotal = try container.decodeWalletLossyString(forKey: .amountTotal) amountCurrentBalance = try container.decodeWalletLossyString(forKey: .amountCurrentBalance) amountWithdrawable = try container.decodeWalletLossyString(forKey: .amountWithdrawable) } } /// 钱包流水列表响应,用于邀请奖励记录。 struct WalletTransactionListResponse: Decodable, Equatable { let total: Int let list: [WalletTransactionItem] /// 创建钱包流水列表响应。 init(total: Int = 0, list: [WalletTransactionItem] = []) { self.total = total self.list = list } } /// 提现记录列表响应,用于钱包首页提现记录 Tab。 struct WalletWithdrawListResponse: Decodable, Equatable { let total: Int let item: [WalletWithdrawItem] /// 创建提现记录列表响应。 init(total: Int = 0, item: [WalletWithdrawItem] = []) { self.total = total self.item = item } } /// 钱包提现记录实体,表示一笔提现申请和结算状态。 struct WalletWithdrawItem: Decodable, Hashable { let id: Int let amount: String let createdAt: String let settlementStatus: Int let withdrawStatus: Int let expectedAt: String let auditTime: String let auditRemark: String let completedAt: String let errorReason: String let statusLabel: String enum CodingKeys: String, CodingKey { case id case amount case createdAt = "created_at" case settlementStatus = "settlement_status" case withdrawStatus = "withdraw_status" case expectedAt = "expected_at" case auditTime = "audit_time" case auditRemark = "audit_remark" case completedAt = "completed_at" case errorReason = "error_reason" case statusLabel = "status_label" } /// 创建钱包提现记录实体。 init( id: Int = 0, amount: String = "", createdAt: String = "", settlementStatus: Int = 0, withdrawStatus: Int = 0, expectedAt: String = "", auditTime: String = "", auditRemark: String = "", completedAt: String = "", errorReason: String = "", statusLabel: String = "" ) { self.id = id self.amount = amount self.createdAt = createdAt self.settlementStatus = settlementStatus self.withdrawStatus = withdrawStatus self.expectedAt = expectedAt self.auditTime = auditTime self.auditRemark = auditRemark self.completedAt = completedAt self.errorReason = errorReason self.statusLabel = statusLabel } /// 宽松解码提现记录字段。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decodeWalletLossyInt(forKey: .id) ?? 0 amount = try container.decodeWalletLossyString(forKey: .amount) createdAt = try container.decodeWalletLossyString(forKey: .createdAt) settlementStatus = try container.decodeWalletLossyInt(forKey: .settlementStatus) ?? 0 withdrawStatus = try container.decodeWalletLossyInt(forKey: .withdrawStatus) ?? 0 expectedAt = try container.decodeWalletLossyString(forKey: .expectedAt) auditTime = try container.decodeWalletLossyString(forKey: .auditTime) auditRemark = try container.decodeWalletLossyString(forKey: .auditRemark) completedAt = try container.decodeWalletLossyString(forKey: .completedAt) errorReason = try container.decodeWalletLossyString(forKey: .errorReason) statusLabel = try container.decodeWalletLossyString(forKey: .statusLabel) } } /// 钱包流水实体,表示一条收入或提现相关记录。 struct WalletTransactionItem: Decodable, Hashable { let id: Int let amount: String let transactionType: Int let transactionTypeLabel: String let createdAt: String let orderNumberSuffix: String let withdrawLabel: String enum CodingKeys: String, CodingKey { case id case amount case transactionType = "transaction_type" case transactionTypeLabel = "transaction_type_label" case createdAt = "created_at" case orderNumberSuffix = "order_number_suffix" case withdrawLabel = "withdraw_label" } /// 创建钱包流水实体。 init( id: Int, amount: String, transactionType: Int = 0, transactionTypeLabel: String = "", createdAt: String, orderNumberSuffix: String = "", withdrawLabel: String = "" ) { self.id = id self.amount = amount self.transactionType = transactionType self.transactionTypeLabel = transactionTypeLabel self.createdAt = createdAt self.orderNumberSuffix = orderNumberSuffix self.withdrawLabel = withdrawLabel } /// 宽松解码钱包流水字段。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decodeWalletLossyInt(forKey: .id) ?? 0 amount = try container.decodeWalletLossyString(forKey: .amount) transactionType = try container.decodeWalletLossyInt(forKey: .transactionType) ?? 0 transactionTypeLabel = try container.decodeWalletLossyString(forKey: .transactionTypeLabel) createdAt = try container.decodeWalletLossyString(forKey: .createdAt) orderNumberSuffix = try container.decodeWalletLossyString(forKey: .orderNumberSuffix) withdrawLabel = try container.decodeWalletLossyString(forKey: .withdrawLabel) } } /// 收益明细响应,包含总金额、总积分和按日期分组的明细。 struct EarningDetailResponse: Decodable, Equatable { let totalAmount: String let totalPoints: Int let total: Int let list: [EarningDetailGroup] enum CodingKeys: String, CodingKey { case totalAmount = "total_amount" case totalPoints = "total_points" case total case list } /// 创建收益明细响应。 init(totalAmount: String = "", totalPoints: Int = 0, total: Int = 0, list: [EarningDetailGroup] = []) { self.totalAmount = totalAmount self.totalPoints = totalPoints self.total = total self.list = list } /// 宽松解码收益明细响应。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) totalAmount = try container.decodeWalletLossyString(forKey: .totalAmount) totalPoints = try container.decodeWalletLossyInt(forKey: .totalPoints) ?? 0 total = try container.decodeWalletLossyInt(forKey: .total) ?? 0 list = try container.decodeIfPresent([EarningDetailGroup].self, forKey: .list) ?? [] } } /// 按日期分组的收益明细。 struct EarningDetailGroup: Decodable, Hashable { let date: String let dayAmount: String let dayPoints: Int let items: [EarningDetailItem] enum CodingKeys: String, CodingKey { case date case dayAmount = "day_amount" case dayPoints = "day_points" case items } /// 创建收益明细分组。 init(date: String = "", dayAmount: String = "", dayPoints: Int = 0, items: [EarningDetailItem] = []) { self.date = date self.dayAmount = dayAmount self.dayPoints = dayPoints self.items = items } /// 宽松解码收益明细分组。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) date = try container.decodeWalletLossyString(forKey: .date) dayAmount = try container.decodeWalletLossyString(forKey: .dayAmount) dayPoints = try container.decodeWalletLossyInt(forKey: .dayPoints) ?? 0 items = try container.decodeIfPresent([EarningDetailItem].self, forKey: .items) ?? [] } } /// 收益明细条目,融合钱包流水和积分流水。 struct EarningDetailItem: Decodable, Hashable { let id: Int let amount: String let points: Int let type: String let typeLabel: String let orderNumberSuffix: String let createdAt: String let withdrawLabel: String let source: String enum CodingKeys: String, CodingKey { case id case amount case points case type case typeLabel = "type_label" case orderNumberSuffix = "order_number_suffix" case createdAt = "created_at" case withdrawLabel = "withdraw_label" case source } /// 创建收益明细条目。 init( id: Int = 0, amount: String = "", points: Int = 0, type: String = "", typeLabel: String = "", orderNumberSuffix: String = "", createdAt: String = "", withdrawLabel: String = "", source: String = "" ) { self.id = id self.amount = amount self.points = points self.type = type self.typeLabel = typeLabel self.orderNumberSuffix = orderNumberSuffix self.createdAt = createdAt self.withdrawLabel = withdrawLabel self.source = source } /// 宽松解码收益明细字段。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decodeWalletLossyInt(forKey: .id) ?? 0 amount = try container.decodeWalletLossyString(forKey: .amount) points = try container.decodeWalletLossyInt(forKey: .points) ?? 0 type = try container.decodeWalletLossyString(forKey: .type) typeLabel = try container.decodeWalletLossyString(forKey: .typeLabel) orderNumberSuffix = try container.decodeWalletLossyString(forKey: .orderNumberSuffix) createdAt = try container.decodeWalletLossyString(forKey: .createdAt) withdrawLabel = try container.decodeWalletLossyString(forKey: .withdrawLabel) source = try container.decodeWalletLossyString(forKey: .source) } } /// 提现申请页响应,包含可提现金额、限制、银行卡和说明。 struct WithdrawInfoResponse: Decodable, Equatable { let amountWithdrawable: String let minWithdrawAmount: String let maxSingleWithdrawAmount: String let maxDailyWithdrawAmount: String let userPhone: String let bankCard: WithdrawBankCardInfo let settlement: String let withdrawInfo: [String] enum CodingKeys: String, CodingKey { case amountWithdrawable = "amount_withdrawable" case minWithdrawAmount = "min_withdraw_amount" case maxSingleWithdrawAmount = "max_single_withdraw_amount" case maxDailyWithdrawAmount = "max_daily_withdraw_amount" case userPhone = "user_phone" case bankCard = "bank_card" case settlement case withdrawInfo = "withdraw_info" } /// 创建提现申请页响应。 init( amountWithdrawable: String = "", minWithdrawAmount: String = "", maxSingleWithdrawAmount: String = "", maxDailyWithdrawAmount: String = "", userPhone: String = "", bankCard: WithdrawBankCardInfo = WithdrawBankCardInfo(), settlement: String = "", withdrawInfo: [String] = [] ) { self.amountWithdrawable = amountWithdrawable self.minWithdrawAmount = minWithdrawAmount self.maxSingleWithdrawAmount = maxSingleWithdrawAmount self.maxDailyWithdrawAmount = maxDailyWithdrawAmount self.userPhone = userPhone self.bankCard = bankCard self.settlement = settlement self.withdrawInfo = withdrawInfo } /// 宽松解码提现申请页响应。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) amountWithdrawable = try container.decodeWalletLossyString(forKey: .amountWithdrawable) minWithdrawAmount = try container.decodeWalletLossyString(forKey: .minWithdrawAmount) maxSingleWithdrawAmount = try container.decodeWalletLossyString(forKey: .maxSingleWithdrawAmount) maxDailyWithdrawAmount = try container.decodeWalletLossyString(forKey: .maxDailyWithdrawAmount) userPhone = try container.decodeWalletLossyString(forKey: .userPhone) bankCard = try container.decodeIfPresent(WithdrawBankCardInfo.self, forKey: .bankCard) ?? WithdrawBankCardInfo() settlement = try container.decodeWalletLossyString(forKey: .settlement) withdrawInfo = try container.decodeIfPresent([String].self, forKey: .withdrawInfo) ?? [] } } /// 提现申请页银行卡展示实体。 struct WithdrawBankCardInfo: Decodable, Equatable { let realName: String let bankName: String let cardNumber: String enum CodingKeys: String, CodingKey { case realName = "real_name" case bankName = "bank_name" case cardNumber = "card_number" } /// 创建提现申请页银行卡实体。 init(realName: String = "", bankName: String = "", cardNumber: String = "") { self.realName = realName self.bankName = bankName self.cardNumber = cardNumber } /// 宽松解码银行卡信息。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) realName = try container.decodeWalletLossyString(forKey: .realName) bankName = try container.decodeWalletLossyString(forKey: .bankName) cardNumber = try container.decodeWalletLossyString(forKey: .cardNumber) } } /// 提现申请请求。 struct WithdrawApplyRequest: Encodable, Equatable { let amount: String let smsCode: String enum CodingKeys: String, CodingKey { case amount case smsCode = "sms_code" } } /// 积分概览响应。 struct PointOverviewResponse: Decodable, Equatable { let totalPoints: Int let availablePoints: Int let withdrawnPoints: Int let pendingPoints: Int let time: String enum CodingKeys: String, CodingKey { case totalPoints = "total_points" case availablePoints = "available_points" case withdrawnPoints = "withdrawn_points" case pendingPoints = "pending_points" case time } /// 创建积分概览响应。 init(totalPoints: Int = 0, availablePoints: Int = 0, withdrawnPoints: Int = 0, pendingPoints: Int = 0, time: String = "") { self.totalPoints = totalPoints self.availablePoints = availablePoints self.withdrawnPoints = withdrawnPoints self.pendingPoints = pendingPoints self.time = time } /// 宽松解码积分概览。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) totalPoints = try container.decodeWalletLossyInt(forKey: .totalPoints) ?? 0 availablePoints = try container.decodeWalletLossyInt(forKey: .availablePoints) ?? 0 withdrawnPoints = try container.decodeWalletLossyInt(forKey: .withdrawnPoints) ?? 0 pendingPoints = try container.decodeWalletLossyInt(forKey: .pendingPoints) ?? 0 time = try container.decodeWalletLossyString(forKey: .time) } } /// 积分提现记录实体。 struct PointWithdrawItem: Decodable, Hashable { let id: Int let applyNo: String let merchantType: Int let merchantId: Int let merchantName: String let points: Int let amount: Double? let status: Int let rejectReason: String let paymentVoucher: String let paymentTime: String let estimatedReceiptTime: String let reviewedAt: String let reviewedBy: String let createdAt: String let updatedAt: String enum CodingKeys: String, CodingKey { case id case applyNo = "apply_no" case merchantType = "merchant_type" case merchantId = "merchant_id" case merchantName = "merchant_name" case points case amount case status case rejectReason = "reject_reason" case paymentVoucher = "payment_voucher" case paymentTime = "payment_time" case estimatedReceiptTime = "estimated_receipt_time" case reviewedAt = "reviewed_at" case reviewedBy = "reviewed_by" case createdAt = "created_at" case updatedAt = "updated_at" } /// 创建积分提现记录。 init( id: Int = 0, applyNo: String = "", merchantType: Int = 0, merchantId: Int = 0, merchantName: String = "", points: Int = 0, amount: Double? = nil, status: Int = 0, rejectReason: String = "", paymentVoucher: String = "", paymentTime: String = "", estimatedReceiptTime: String = "", reviewedAt: String = "", reviewedBy: String = "", createdAt: String = "", updatedAt: String = "" ) { self.id = id self.applyNo = applyNo self.merchantType = merchantType self.merchantId = merchantId self.merchantName = merchantName self.points = points self.amount = amount self.status = status self.rejectReason = rejectReason self.paymentVoucher = paymentVoucher self.paymentTime = paymentTime self.estimatedReceiptTime = estimatedReceiptTime self.reviewedAt = reviewedAt self.reviewedBy = reviewedBy self.createdAt = createdAt self.updatedAt = updatedAt } /// 宽松解码积分提现记录。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decodeWalletLossyInt(forKey: .id) ?? 0 applyNo = try container.decodeWalletLossyString(forKey: .applyNo) merchantType = try container.decodeWalletLossyInt(forKey: .merchantType) ?? 0 merchantId = try container.decodeWalletLossyInt(forKey: .merchantId) ?? 0 merchantName = try container.decodeWalletLossyString(forKey: .merchantName) points = try container.decodeWalletLossyInt(forKey: .points) ?? 0 amount = try container.decodeWalletLossyDouble(forKey: .amount) status = try container.decodeWalletLossyInt(forKey: .status) ?? 0 rejectReason = try container.decodeWalletLossyString(forKey: .rejectReason) paymentVoucher = try container.decodeWalletLossyString(forKey: .paymentVoucher) paymentTime = try container.decodeWalletLossyString(forKey: .paymentTime) estimatedReceiptTime = try container.decodeWalletLossyString(forKey: .estimatedReceiptTime) reviewedAt = try container.decodeWalletLossyString(forKey: .reviewedAt) reviewedBy = try container.decodeWalletLossyString(forKey: .reviewedBy) createdAt = try container.decodeWalletLossyString(forKey: .createdAt) updatedAt = try container.decodeWalletLossyString(forKey: .updatedAt) } } /// 积分提现列表响应。 struct PointWithdrawListResponse: Decodable, Equatable { let total: Int let list: [PointWithdrawItem] /// 创建积分提现列表响应。 init(total: Int = 0, list: [PointWithdrawItem] = []) { self.total = total self.list = list } } /// 积分提现申请请求。 struct PointWithdrawApplyRequest: Encodable, Equatable { let points: Int let remark: String } /// 积分提现记录查询请求。 struct PointWithdrawListRequest: Encodable, Equatable { let status: Int? let page: Int let pageSize: Int enum CodingKeys: String, CodingKey { case status case page case pageSize = "page_size" } } private extension KeyedDecodingContainer { func decodeWalletLossyString(forKey key: Key) throws -> String { if let value = try? decodeIfPresent(String.self, forKey: key) { return value } if let value = try? decodeIfPresent(Int.self, forKey: key) { return String(value) } if let value = try? decodeIfPresent(Double.self, forKey: key) { return String(value) } return "" } func decodeWalletLossyInt(forKey key: Key) throws -> Int? { if let value = try? decodeIfPresent(Int.self, forKey: key) { return value } if let value = try? decodeIfPresent(Double.self, forKey: key) { return Int(value) } if let value = try? decodeIfPresent(String.self, forKey: key) { let text = value.trimmingCharacters(in: .whitespacesAndNewlines) return Int(text) ?? Double(text).map(Int.init) } return nil } func decodeWalletLossyDouble(forKey key: Key) throws -> Double? { if let value = try? decodeIfPresent(Double.self, forKey: key) { return value } if let value = try? decodeIfPresent(Int.self, forKey: key) { return Double(value) } if let value = try? decodeIfPresent(String.self, forKey: key) { let text = value.trimmingCharacters(in: .whitespacesAndNewlines) return Double(text) } return nil } }