Files
suixinkan_ios_new/suixinkan/Features/Invite/Models/InviteModels.swift
汉秋 fb8430889b Add Projects, Schedule, and Invite modules with home routing.
Migrate project management, schedule management, and photographer invitation flows from placeholders, including project image OSS upload and shared business models.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-24 15:57:15 +08:00

157 lines
5.0 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.

//
// InviteModels.swift
// suixinkan
//
// Created by Codex on 2026/6/24.
//
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(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, Identifiable, 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(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) ?? 0
}
}
///
struct InviteDisplayRow: Identifiable, Equatable {
let id: String
let title: String
let subtitle: String
let amount: String
let time: String
let phone: String
let avatar: String
let inviteLevel: Int
///
var levelText: String {
inviteLevel == 1 ? "一级" : "二级"
}
///
var avatarPlaceholder: String {
if let first = title.first {
return String(first)
}
if let first = phone.first {
return String(first)
}
return "?"
}
}
///
enum InviteRecordTab: CaseIterable, Equatable {
case invite
case reward
///
var title: String {
switch self {
case .invite: return "邀请记录"
case .reward: return "奖励记录"
}
}
}
private extension KeyedDecodingContainer {
/// String Bool
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 ""
}
/// StringDouble Int Int
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
}
/// String Bool Bool
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
}
}