feat: update wallet punch point and report success

This commit is contained in:
2026-07-09 14:27:18 +08:00
parent 2970f1514b
commit 43e6133c21
34 changed files with 6671 additions and 71 deletions

View File

@ -45,6 +45,90 @@ struct WalletTransactionListResponse: Decodable, Equatable {
}
}
/// 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
@ -97,6 +181,392 @@ struct WalletTransactionItem: Decodable, Hashable {
}
}
///
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) {
@ -124,4 +594,18 @@ private extension KeyedDecodingContainer {
}
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
}
}