Files
suixinkan_ios_new/suixinkan/Features/Payment/Models/PaymentModels.swift
汉秋 5d4613f317 新增支付与钱包模块,并接入首页路由
引入真实收款与钱包页面替换首页占位入口,通过 RootView 接入 API,并支持银行卡 OSS 上传及二维码保存到相册。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-22 17:46:01 +08:00

183 lines
6.4 KiB
Swift
Raw 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.

//
// PaymentModels.swift
// suixinkan
//
// Created by Codex on 2026/6/22.
//
import Foundation
/// URL URL
struct PayCodeResponse: Decodable, Equatable {
let staticPayUrl: String
let dynamicPayUrl: String
/// JSON
enum CodingKeys: String, CodingKey {
case staticPayUrl = "static_pay_url"
case dynamicPayUrl = "dynamic_pay_url"
}
///
init(staticPayUrl: String = "", dynamicPayUrl: String = "") {
self.staticPayUrl = staticPayUrl
self.dynamicPayUrl = dynamicPayUrl
}
/// URL
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
staticPayUrl = try container.decodeLossyString(forKey: .staticPayUrl)
dynamicPayUrl = try container.decodeLossyString(forKey: .dynamicPayUrl)
}
}
///
struct PaymentCollectionRecordResponse: Decodable, Equatable {
let analyse: [PaymentCollectionRecordAnalyseItem]
let list: [PaymentCollectionRecordItem]
/// JSON
enum CodingKeys: String, CodingKey {
case analyse
case list
}
///
init(analyse: [PaymentCollectionRecordAnalyseItem] = [], list: [PaymentCollectionRecordItem] = []) {
self.analyse = analyse
self.list = list
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
analyse = try container.decodeIfPresent([PaymentCollectionRecordAnalyseItem].self, forKey: .analyse) ?? []
list = try container.decodeIfPresent([PaymentCollectionRecordItem].self, forKey: .list) ?? []
}
}
///
struct PaymentCollectionRecordAnalyseItem: Decodable, Equatable, Identifiable {
let date: String
let orderCount: Int
let orderAmountSum: String
var id: String { date }
/// JSON
enum CodingKeys: String, CodingKey {
case date
case orderCount = "order_count"
case orderAmountSum = "order_amount_sum"
}
///
init(date: String, orderCount: Int, orderAmountSum: String) {
self.date = date
self.orderCount = orderCount
self.orderAmountSum = orderAmountSum
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
date = try container.decodeLossyString(forKey: .date)
orderCount = try container.decodeLossyInt(forKey: .orderCount) ?? 0
orderAmountSum = try container.decodeLossyString(forKey: .orderAmountSum)
}
}
///
struct PaymentCollectionRecordItem: Decodable, Equatable, Identifiable {
let orderNumber: String
let userPhone: String
let orderAmount: String
let createDate: String
let createTime: String
var id: String {
orderNumber.isEmpty ? "\(createDate)-\(createTime)-\(orderAmount)" : orderNumber
}
/// JSON
enum CodingKeys: String, CodingKey {
case orderNumber = "order_number"
case userPhone = "user_phone"
case orderAmount = "order_amount"
case createDate = "create_date"
case createTime = "create_time"
}
///
init(orderNumber: String, userPhone: String, orderAmount: String, createDate: String, createTime: String) {
self.orderNumber = orderNumber
self.userPhone = userPhone
self.orderAmount = orderAmount
self.createDate = createDate
self.createTime = createTime
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
orderNumber = try container.decodeLossyString(forKey: .orderNumber)
userPhone = try container.decodeLossyString(forKey: .userPhone)
orderAmount = try container.decodeLossyString(forKey: .orderAmount)
createDate = try container.decodeLossyString(forKey: .createDate)
createTime = try container.decodeLossyString(forKey: .createTime)
}
}
///
struct PaymentCollectionRecordGroup: Equatable, Identifiable {
let analyse: PaymentCollectionRecordAnalyseItem
let items: [PaymentCollectionRecordItem]
var id: String { analyse.id }
}
///
enum PaymentCollectionStatus: Equatable {
case idle
case waiting
case success(PaymentCollectionRecordItem)
case failed(String)
}
private extension KeyedDecodingContainer {
///
func decodeLossyString(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 value.truncatingRemainder(dividingBy: 1) == 0 ? String(Int(value)) : String(value)
}
return ""
}
///
func decodeLossyInt(forKey key: Key) throws -> Int? {
if let value = try decodeIfPresent(Int.self, forKey: key) {
return value
}
if let value = try decodeIfPresent(String.self, forKey: key) {
let text = value.trimmingCharacters(in: .whitespacesAndNewlines)
if let intValue = Int(text) {
return intValue
}
if let doubleValue = Double(text) {
return Int(doubleValue)
}
}
if let value = try decodeIfPresent(Double.self, forKey: key) {
return Int(value)
}
return nil
}
}