173 lines
5.4 KiB
Swift
173 lines
5.4 KiB
Swift
//
|
|
// InviteModels.swift
|
|
// suixinkan
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// 邀请信息响应实体,表示邀请码、邀请链接和规则文案。
|
|
struct InviteInfoResponse: Decodable, Equatable {
|
|
let enableInvite: Bool
|
|
let inviteCode: String
|
|
let inviteUrl: String
|
|
let description: [String]
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case enableInvite = "enable_invite"
|
|
case inviteCode = "invite_code"
|
|
case inviteUrl = "invite_url"
|
|
case description
|
|
}
|
|
|
|
/// 创建邀请信息响应实体。
|
|
init(enableInvite: Bool, inviteCode: String, inviteUrl: String, description: [String]) {
|
|
self.enableInvite = enableInvite
|
|
self.inviteCode = inviteCode
|
|
self.inviteUrl = inviteUrl
|
|
self.description = description
|
|
}
|
|
|
|
/// 宽松解码邀请信息,兼容后端字符串/数字/布尔混用。
|
|
init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
enableInvite = try container.decodeInviteLossyBool(forKey: .enableInvite) ?? true
|
|
inviteCode = try container.decodeInviteLossyString(forKey: .inviteCode)
|
|
inviteUrl = try container.decodeInviteLossyString(forKey: .inviteUrl)
|
|
description = (try? container.decodeIfPresent([String].self, forKey: .description)) ?? []
|
|
}
|
|
}
|
|
|
|
/// 邀请用户实体,表示邀请记录里的摄影师。
|
|
struct InviteUserItem: Decodable, Hashable {
|
|
let id: Int
|
|
let realName: String
|
|
let phone: String
|
|
let avatar: String
|
|
let createdAt: String
|
|
let inviteLevel: Int
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case id
|
|
case realName = "real_name"
|
|
case phone
|
|
case avatar
|
|
case createdAt = "created_at"
|
|
case inviteLevel = "invite_level"
|
|
}
|
|
|
|
/// 创建邀请用户实体。
|
|
init(id: Int, realName: String, phone: String, avatar: String, createdAt: String, inviteLevel: Int) {
|
|
self.id = id
|
|
self.realName = realName
|
|
self.phone = phone
|
|
self.avatar = avatar
|
|
self.createdAt = createdAt
|
|
self.inviteLevel = inviteLevel
|
|
}
|
|
|
|
/// 宽松解码邀请用户字段。
|
|
init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
id = try container.decodeInviteLossyInt(forKey: .id) ?? 0
|
|
realName = try container.decodeInviteLossyString(forKey: .realName)
|
|
phone = try container.decodeInviteLossyString(forKey: .phone)
|
|
avatar = try container.decodeInviteLossyString(forKey: .avatar)
|
|
createdAt = try container.decodeInviteLossyString(forKey: .createdAt)
|
|
inviteLevel = try container.decodeInviteLossyInt(forKey: .inviteLevel) ?? 1
|
|
}
|
|
}
|
|
|
|
/// 邀请记录分段类型。
|
|
enum InviteRecordTab: Int, CaseIterable, Equatable {
|
|
case invite = 0
|
|
case reward = 1
|
|
|
|
/// 分段标题。
|
|
var title: String {
|
|
switch self {
|
|
case .invite:
|
|
return "邀请记录"
|
|
case .reward:
|
|
return "奖励记录"
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 邀请记录行展示实体。
|
|
struct InviteDisplayRow: Hashable {
|
|
let id: String
|
|
let title: String
|
|
let phone: String
|
|
let avatar: String
|
|
let time: String
|
|
let inviteLevel: Int
|
|
|
|
/// 邀请层级文案。
|
|
var levelText: String {
|
|
inviteLevel == 1 ? "一级" : "二级"
|
|
}
|
|
|
|
/// 邀请层级是否为一级。
|
|
var isPrimaryLevel: Bool {
|
|
inviteLevel == 1
|
|
}
|
|
|
|
/// 头像缺省显示文字。
|
|
var avatarPlaceholder: String {
|
|
if let first = title.first {
|
|
return String(first)
|
|
}
|
|
if let first = phone.first {
|
|
return String(first)
|
|
}
|
|
return "?"
|
|
}
|
|
}
|
|
|
|
private extension KeyedDecodingContainer {
|
|
func decodeInviteLossyString(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 ? "1" : "0"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func decodeInviteLossyInt(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 decodeInviteLossyBool(forKey key: Key) throws -> Bool? {
|
|
if let value = try? decodeIfPresent(Bool.self, forKey: key) {
|
|
return value
|
|
}
|
|
if let value = try? decodeIfPresent(Int.self, forKey: key) {
|
|
return value != 0
|
|
}
|
|
if let value = try? decodeIfPresent(String.self, forKey: key) {
|
|
let text = value.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
if ["1", "true", "yes"].contains(text) { return true }
|
|
if ["0", "false", "no"].contains(text) { return false }
|
|
}
|
|
return nil
|
|
}
|
|
}
|