feat: add WeChat sharing and invite flow
This commit is contained in:
67
suixinkan/Features/Wallet/API/WalletAPI.swift
Normal file
67
suixinkan/Features/Wallet/API/WalletAPI.swift
Normal file
@ -0,0 +1,67 @@
|
||||
//
|
||||
// WalletAPI.swift
|
||||
// suixinkan
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
/// 钱包服务协议,提供邀请奖励记录所需的汇总与流水接口。
|
||||
protocol WalletServing {
|
||||
/// 获取钱包汇总金额,`type = 2` 表示邀请奖励。
|
||||
func walletSummary(type: Int) async throws -> WalletSummaryResponse
|
||||
|
||||
/// 获取钱包流水列表。
|
||||
func walletTransactionList(
|
||||
startDate: String,
|
||||
endDate: String,
|
||||
page: Int,
|
||||
pageSize: Int,
|
||||
type: Int
|
||||
) async throws -> WalletTransactionListResponse
|
||||
}
|
||||
|
||||
@MainActor
|
||||
/// 钱包 API,封装邀请奖励记录所需的最小接口集合。
|
||||
final class WalletAPI: WalletServing {
|
||||
private let client: APIClient
|
||||
|
||||
/// 初始化钱包 API。
|
||||
init(client: APIClient) {
|
||||
self.client = client
|
||||
}
|
||||
|
||||
/// 获取钱包汇总金额。
|
||||
func walletSummary(type: Int = 0) async throws -> WalletSummaryResponse {
|
||||
try await client.send(
|
||||
APIRequest(
|
||||
method: .get,
|
||||
path: "/api/yf-handset-app/photog/wallet/summary",
|
||||
queryItems: [URLQueryItem(name: "type", value: String(type))]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/// 获取钱包流水列表。
|
||||
func walletTransactionList(
|
||||
startDate: String,
|
||||
endDate: String,
|
||||
page: Int = 1,
|
||||
pageSize: Int = 10,
|
||||
type: Int = 2
|
||||
) async throws -> WalletTransactionListResponse {
|
||||
try await client.send(
|
||||
APIRequest(
|
||||
method: .get,
|
||||
path: "/api/yf-handset-app/photog/wallet/transaction-list",
|
||||
queryItems: [
|
||||
URLQueryItem(name: "start_date", value: startDate),
|
||||
URLQueryItem(name: "end_date", value: endDate),
|
||||
URLQueryItem(name: "page", value: String(max(page, 1))),
|
||||
URLQueryItem(name: "page_size", value: String(max(pageSize, 1))),
|
||||
URLQueryItem(name: "type", value: String(type)),
|
||||
]
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
127
suixinkan/Features/Wallet/Models/WalletModels.swift
Normal file
127
suixinkan/Features/Wallet/Models/WalletModels.swift
Normal file
@ -0,0 +1,127 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
/// 钱包流水实体,表示一条收入或提现相关记录。
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user