实现我的 Tab、对齐 Android 流程并接入 OSS 上传
This commit is contained in:
353
suixinkan/Features/Profile/Models/ProfileModels.swift
Normal file
353
suixinkan/Features/Profile/Models/ProfileModels.swift
Normal file
@ -0,0 +1,353 @@
|
||||
//
|
||||
// ProfileModels.swift
|
||||
// suixinkan
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 用户资料响应实体,表示“我的”页面展示的账号基础信息。
|
||||
struct UserInfoResponse: Decodable, Equatable {
|
||||
let avatar: String
|
||||
let realName: String
|
||||
let phone: String
|
||||
let nickname: String
|
||||
let roleName: String
|
||||
let status: Int
|
||||
let statusName: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case avatar
|
||||
case realName = "real_name"
|
||||
case phone
|
||||
case nickname
|
||||
case roleName = "role_name"
|
||||
case status
|
||||
case statusName = "status_name"
|
||||
}
|
||||
|
||||
init(
|
||||
avatar: String = "",
|
||||
realName: String = "",
|
||||
phone: String = "",
|
||||
nickname: String = "",
|
||||
roleName: String = "",
|
||||
status: Int = 0,
|
||||
statusName: String = ""
|
||||
) {
|
||||
self.avatar = avatar
|
||||
self.realName = realName
|
||||
self.phone = phone
|
||||
self.nickname = nickname
|
||||
self.roleName = roleName
|
||||
self.status = status
|
||||
self.statusName = statusName
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
avatar = try container.decodeLossyString(forKey: .avatar)
|
||||
realName = try container.decodeLossyString(forKey: .realName)
|
||||
phone = try container.decodeLossyString(forKey: .phone)
|
||||
nickname = try container.decodeLossyString(forKey: .nickname)
|
||||
roleName = try container.decodeLossyString(forKey: .roleName)
|
||||
status = try container.decodeLossyInt(forKey: .status) ?? 0
|
||||
statusName = try container.decodeLossyString(forKey: .statusName)
|
||||
}
|
||||
}
|
||||
|
||||
/// 用户资料更新请求实体,表示昵称、密码和头像修改参数。
|
||||
struct UpdateInfoRequest: Encodable {
|
||||
let nickname: String?
|
||||
let password: String?
|
||||
let avatar: String?
|
||||
}
|
||||
|
||||
/// 实名认证响应实体,包裹当前用户的认证详情。
|
||||
struct RealNameInfoResponse: Decodable, Equatable {
|
||||
let realNameInfo: RealNameInfo?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case realNameInfo = "real_name_info"
|
||||
}
|
||||
}
|
||||
|
||||
/// 实名认证信息实体,表示当前用户实名审核状态和失败原因。
|
||||
struct RealNameInfo: Decodable, Equatable {
|
||||
let realName: String
|
||||
let idCardNo: String
|
||||
let auditStatus: Int
|
||||
let auditStatusText: String?
|
||||
let rejectReason: String?
|
||||
let startDate: String?
|
||||
let endDate: String?
|
||||
let isLongValid: Bool
|
||||
let frontUrl: String?
|
||||
let backUrl: String?
|
||||
let auditorId: Int?
|
||||
let auditor: RealNameAuditor?
|
||||
let auditAt: String?
|
||||
|
||||
var verified: Bool {
|
||||
auditStatus == 2
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case realName = "real_name"
|
||||
case idCardNo = "id_card_no"
|
||||
case auditStatus = "audit_status"
|
||||
case auditStatusText = "audit_status_text"
|
||||
case rejectReason = "reject_reason"
|
||||
case startDate = "start_date"
|
||||
case endDate = "end_date"
|
||||
case isLongValid = "is_long_valid"
|
||||
case frontUrl = "front_url"
|
||||
case backUrl = "back_url"
|
||||
case auditorId = "auditor_id"
|
||||
case auditor
|
||||
case auditAt = "audit_at"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
realName = try container.decodeLossyString(forKey: .realName)
|
||||
idCardNo = try container.decodeLossyString(forKey: .idCardNo)
|
||||
auditStatus = try container.decodeLossyInt(forKey: .auditStatus) ?? 0
|
||||
auditStatusText = try container.decodeIfPresent(String.self, forKey: .auditStatusText)
|
||||
rejectReason = try container.decodeIfPresent(String.self, forKey: .rejectReason)
|
||||
startDate = try container.decodeIfPresent(String.self, forKey: .startDate)
|
||||
endDate = try container.decodeIfPresent(String.self, forKey: .endDate)
|
||||
isLongValid = (try container.decodeLossyInt(forKey: .isLongValid) ?? 0) == 1
|
||||
frontUrl = try container.decodeIfPresent(String.self, forKey: .frontUrl)
|
||||
backUrl = try container.decodeIfPresent(String.self, forKey: .backUrl)
|
||||
auditorId = try container.decodeLossyInt(forKey: .auditorId)
|
||||
auditor = try container.decodeIfPresent(RealNameAuditor.self, forKey: .auditor)
|
||||
auditAt = try container.decodeIfPresent(String.self, forKey: .auditAt)
|
||||
}
|
||||
}
|
||||
|
||||
/// 实名认证审核人实体,表示后台审核人的基础展示信息。
|
||||
struct RealNameAuditor: Decodable, Equatable {
|
||||
let id: Int
|
||||
let name: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try container.decodeLossyInt(forKey: .id) ?? 0
|
||||
name = try container.decodeLossyString(forKey: .name)
|
||||
}
|
||||
}
|
||||
|
||||
/// 实名认证提交请求实体,表示用户填写的姓名、证件号、短信和证件图片。
|
||||
struct RealNameAuthRequest: Encodable, Equatable {
|
||||
let realName: String
|
||||
let idCardNo: String
|
||||
let smsVerifyCode: String
|
||||
let startDate: String
|
||||
let endDate: String
|
||||
let isLongValid: Int
|
||||
let frontUrl: String
|
||||
let backUrl: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case realName = "real_name"
|
||||
case idCardNo = "id_card_no"
|
||||
case smsVerifyCode = "sms_verify_code"
|
||||
case startDate = "start_date"
|
||||
case endDate = "end_date"
|
||||
case isLongValid = "is_long_valid"
|
||||
case frontUrl = "front_url"
|
||||
case backUrl = "back_url"
|
||||
}
|
||||
}
|
||||
|
||||
/// 银行卡信息响应实体。
|
||||
struct BankCardInfoResponse: Decodable, Equatable {
|
||||
let bankCard: BankCardInfo?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case bankCard = "bank_card"
|
||||
}
|
||||
}
|
||||
|
||||
/// 银行卡信息实体,表示提现设置与审核状态。
|
||||
struct BankCardInfo: Decodable, Equatable {
|
||||
let realName: String
|
||||
let bankName: String
|
||||
let branchName: String
|
||||
let cardNumber: String
|
||||
let frontUrl: String?
|
||||
let backUrl: String?
|
||||
let provinceCode: String?
|
||||
let cityCode: String?
|
||||
let rejectReason: String
|
||||
let auditStatus: Int
|
||||
let auditStatusLabel: String
|
||||
let auditAt: String?
|
||||
let auditorId: Int?
|
||||
let auditor: RealNameAuditor?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case realName = "real_name"
|
||||
case bankName = "bank_name"
|
||||
case branchName = "branch_name"
|
||||
case cardNumber = "card_number"
|
||||
case frontUrl = "front_url"
|
||||
case backUrl = "back_url"
|
||||
case provinceCode = "province_code"
|
||||
case cityCode = "city_code"
|
||||
case rejectReason = "reject_reason"
|
||||
case auditStatus = "audit_status"
|
||||
case auditStatusLabel = "audit_status_label"
|
||||
case auditAt = "audit_at"
|
||||
case auditorId = "auditor_id"
|
||||
case auditor
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
realName = try container.decodeLossyString(forKey: .realName)
|
||||
bankName = try container.decodeLossyString(forKey: .bankName)
|
||||
branchName = try container.decodeLossyString(forKey: .branchName)
|
||||
cardNumber = try container.decodeLossyString(forKey: .cardNumber)
|
||||
frontUrl = try container.decodeIfPresent(String.self, forKey: .frontUrl)
|
||||
backUrl = try container.decodeIfPresent(String.self, forKey: .backUrl)
|
||||
provinceCode = try container.decodeIfPresent(String.self, forKey: .provinceCode)
|
||||
cityCode = try container.decodeIfPresent(String.self, forKey: .cityCode)
|
||||
rejectReason = try container.decodeLossyString(forKey: .rejectReason)
|
||||
auditStatus = try container.decodeLossyInt(forKey: .auditStatus) ?? 0
|
||||
auditStatusLabel = try container.decodeLossyString(forKey: .auditStatusLabel)
|
||||
auditAt = try container.decodeIfPresent(String.self, forKey: .auditAt)
|
||||
auditorId = try container.decodeLossyInt(forKey: .auditorId)
|
||||
auditor = try container.decodeIfPresent(RealNameAuditor.self, forKey: .auditor)
|
||||
}
|
||||
}
|
||||
|
||||
/// 银行列表响应实体。
|
||||
struct BankListResponse: Decodable, Equatable {
|
||||
let banks: [String]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case banks
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
banks = try container.decodeIfPresent([String].self, forKey: .banks) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
/// 省市区响应实体。
|
||||
struct AreasResponse: Decodable, Equatable, Identifiable {
|
||||
let id: Int
|
||||
let code: String
|
||||
let name: String
|
||||
let children: [AreasResponse]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case code
|
||||
case name
|
||||
case children
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try container.decodeLossyInt(forKey: .id)
|
||||
?? container.decodeLossyInt(forKey: .code)
|
||||
?? 0
|
||||
let decodedCode = try container.decodeLossyString(forKey: .code)
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
code = decodedCode.isEmpty ? "\(id)" : decodedCode
|
||||
name = try container.decodeLossyString(forKey: .name)
|
||||
children = try container.decodeIfPresent([AreasResponse].self, forKey: .children) ?? []
|
||||
}
|
||||
|
||||
init(id: Int, code: String, name: String, children: [AreasResponse] = []) {
|
||||
self.id = id
|
||||
self.code = code
|
||||
self.name = name
|
||||
self.children = children
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新银行卡信息请求实体。
|
||||
struct UpdateBankInfoRequest: Encodable, Equatable {
|
||||
let realName: String
|
||||
let cardNumber: String
|
||||
let bankName: String
|
||||
let branchName: String
|
||||
let frontUrl: String
|
||||
let backUrl: String
|
||||
let provinceCode: String
|
||||
let cityCode: String
|
||||
let smsVerifyCode: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case realName = "real_name"
|
||||
case cardNumber = "card_number"
|
||||
case bankName = "bank_name"
|
||||
case branchName = "branch_name"
|
||||
case frontUrl = "front_url"
|
||||
case backUrl = "back_url"
|
||||
case provinceCode = "province_code"
|
||||
case cityCode = "city_code"
|
||||
case smsVerifyCode = "sms_verify_code"
|
||||
}
|
||||
}
|
||||
|
||||
/// 个人信息页校验错误实体。
|
||||
enum ProfileValidationError: LocalizedError, Equatable {
|
||||
case emptyNickname
|
||||
case shortPassword
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .emptyNickname:
|
||||
"请输入昵称"
|
||||
case .shortPassword:
|
||||
"密码至少 6 位"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 String(value)
|
||||
}
|
||||
if let value = try? decodeIfPresent(Bool.self, forKey: key) {
|
||||
return value ? "true" : "false"
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user