Files
suixinkan_ios_new/suixinkan/Features/Account/Models/AccountContextModels.swift
汉秋 1970572edd 迁移合作订单完整能力,并统一 AppRoleCode 角色权限与首页菜单展示。
新增 CooperationOrder 模块(双 Tab 列表、获客员绑定、主 Tab 扫码)、订单来源/带客单绑定及配套 API 测试;同步引入 roleCode 权限匹配与相关单元测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 13:33:00 +08:00

360 lines
12 KiB
Swift
Raw Permalink 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.

//
// AccountContextModels.swift
// suixinkan
//
// Created by Codex on 2026/6/22.
//
import Foundation
/// 访
struct RolePermissionResponse: Decodable, Equatable {
let role: RoleInfo
let scenic: [ScenicInfo]
}
///
struct RoleInfo: Decodable, Equatable, Identifiable {
let id: Int
let name: String
let roleCode: String
let notes: String?
let permission: [PermissionItem]
/// JSON
enum CodingKeys: String, CodingKey {
case id
case name
case roleCode = "role_code"
case notes
case permission
}
///
init(id: Int, name: String, roleCode: String = "", notes: String? = nil, permission: [PermissionItem] = []) {
self.id = id
self.name = name
self.roleCode = roleCode
self.notes = notes
self.permission = permission
}
/// ID
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)
roleCode = try container.decodeLossyString(forKey: .roleCode)
notes = try container.decodeIfPresent(String.self, forKey: .notes)
permission = try container.decodeIfPresent([PermissionItem].self, forKey: .permission) ?? []
}
}
///
struct PermissionItem: Decodable, Equatable, Identifiable {
let id: Int
let pid: Int
let name: String
let uri: String
let iconSrc: String?
let children: [PermissionItem]
/// JSON
enum CodingKeys: String, CodingKey {
case id
case pid
case name
case uri
case iconSrc = "icon_src"
case children
}
///
init(id: Int, pid: Int = 0, name: String, uri: String = "", iconSrc: String? = nil, children: [PermissionItem] = []) {
self.id = id
self.pid = pid
self.name = name
self.uri = uri
self.iconSrc = iconSrc
self.children = children
}
/// ID children
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeLossyInt(forKey: .id) ?? 0
pid = try container.decodeLossyInt(forKey: .pid) ?? 0
name = try container.decodeLossyString(forKey: .name)
uri = try container.decodeLossyString(forKey: .uri)
iconSrc = try container.decodeIfPresent(String.self, forKey: .iconSrc)
children = try container.decodeIfPresent([PermissionItem].self, forKey: .children) ?? []
}
}
/// 访
struct ScenicInfo: Decodable, Equatable, Identifiable {
let id: Int
let name: String
let status: Int?
let location: ScenicLocationInfo?
let coverImg: String?
/// JSON
enum CodingKeys: String, CodingKey {
case id
case name
case status
case location
case coverImg = "cover_img"
}
///
init(id: Int, name: String, status: Int? = nil, location: ScenicLocationInfo? = nil, coverImg: String? = nil) {
self.id = id
self.name = name
self.status = status
self.location = location
self.coverImg = coverImg
}
/// location JSON
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)
status = try container.decodeLossyInt(forKey: .status)
coverImg = try container.decodeIfPresent(String.self, forKey: .coverImg)
if let value = try? container.decodeIfPresent(ScenicLocationInfo.self, forKey: .location) {
location = value
} else if let rawValue = try? container.decodeIfPresent(String.self, forKey: .location),
let data = rawValue.data(using: .utf8) {
location = try? JSONDecoder().decode(ScenicLocationInfo.self, from: data)
} else {
location = nil
}
}
}
///
struct ScenicLocationInfo: Decodable, Equatable {
let lng: Double
let lat: Double
let address: String
/// JSON
enum CodingKeys: String, CodingKey {
case lng
case lat
case address
}
///
init(lng: Double, lat: Double, address: String) {
self.lng = lng
self.lat = lat
self.address = address
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
lng = try container.decodeLossyDouble(forKey: .lng) ?? 0
lat = try container.decodeLossyDouble(forKey: .lat) ?? 0
address = try container.decodeLossyString(forKey: .address)
}
}
///
struct ScenicListAllResponse: Decodable, Equatable {
let total: Int
let list: [ScenicListItem]
/// JSON
enum CodingKeys: String, CodingKey {
case total
case list
}
///
init(total: Int, list: [ScenicListItem]) {
self.total = total
self.list = list
}
/// total
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
total = try container.decodeLossyInt(forKey: .total) ?? 0
list = try container.decodeIfPresent([ScenicListItem].self, forKey: .list) ?? []
}
}
///
struct ScenicListItem: Decodable, Equatable, Identifiable {
let id: Int
let name: String
/// JSON
enum CodingKeys: String, CodingKey {
case id
case name
}
///
init(id: Int, name: String) {
self.id = id
self.name = name
}
/// ID
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 StoreItem: Decodable, Equatable, Identifiable {
let id: Int
let scenicId: Int
let name: String
let address: String
let status: Int
let statusText: String
let tel: String?
let logo: String?
/// JSON
enum CodingKeys: String, CodingKey {
case id
case scenicId = "scenic_id"
case name
case address
case status
case statusText = "status_text"
case tel
case logo
}
///
init(
id: Int,
scenicId: Int,
name: String,
address: String = "",
status: Int = 0,
statusText: String = "",
tel: String? = nil,
logo: String? = nil
) {
self.id = id
self.scenicId = scenicId
self.name = name
self.address = address
self.status = status
self.statusText = statusText
self.tel = tel
self.logo = logo
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeLossyInt(forKey: .id) ?? 0
scenicId = try container.decodeLossyInt(forKey: .scenicId) ?? 0
name = try container.decodeLossyString(forKey: .name)
address = try container.decodeLossyString(forKey: .address)
status = try container.decodeLossyInt(forKey: .status) ?? 0
statusText = try container.decodeLossyString(forKey: .statusText)
tel = try container.decodeIfPresent(String.self, forKey: .tel)
logo = try container.decodeIfPresent(String.self, forKey: .logo)
}
}
///
struct ScenicSpotItem: Decodable, Equatable, Identifiable {
let id: Int
let name: String
let status: Int
let statusLabel: String
/// JSON
enum CodingKeys: String, CodingKey {
case id
case name
case status
case statusLabel = "status_label"
}
///
init(id: Int, name: String, status: Int = 0, statusLabel: String = "") {
self.id = id
self.name = name
self.status = status
self.statusLabel = statusLabel
}
///
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)
status = try container.decodeLossyInt(forKey: .status) ?? 0
statusLabel = try container.decodeLossyString(forKey: .statusLabel)
}
}
private extension KeyedDecodingContainer {
/// String Bool
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 ""
}
/// IntDouble
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
}
/// DoubleInt
func decodeLossyDouble(forKey key: Key) throws -> Double? {
if let value = try? decodeIfPresent(Double.self, forKey: key) {
return value
}
if let value = try? decodeIfPresent(Int.self, forKey: key) {
return Double(value)
}
if let value = try? decodeIfPresent(String.self, forKey: key) {
return Double(value.trimmingCharacters(in: .whitespacesAndNewlines))
}
return nil
}
}