Initial commit: suixinkan_ios UIKit rewrite project.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
166
suixinkan_ios/Core/Models/SharedBusinessModels.swift
Normal file
166
suixinkan_ios/Core/Models/SharedBusinessModels.swift
Normal file
@ -0,0 +1,166 @@
|
||||
//
|
||||
// SharedBusinessModels.swift
|
||||
// suixinkan
|
||||
//
|
||||
// Created by Codex on 2026/6/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 可关联订单实体,表示任务、排班等业务表单中可选择的订单。
|
||||
struct AvailableOrderResponse: Decodable, Identifiable, Hashable {
|
||||
var id: String { orderNumber }
|
||||
let projectName: String
|
||||
let orderNumber: String
|
||||
let orderStatus: Int
|
||||
let orderStatusLabel: String
|
||||
let payTime: String
|
||||
let userPhone: String
|
||||
|
||||
/// 可关联订单字段映射,兼容后端下划线命名。
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case projectName = "project_name"
|
||||
case orderNumber = "order_number"
|
||||
case orderStatus = "order_status"
|
||||
case orderStatusLabel = "order_status_label"
|
||||
case payTime = "pay_time"
|
||||
case userPhone = "user_phone"
|
||||
}
|
||||
|
||||
/// 宽松解码可关联订单字段。
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
projectName = try container.decodeSharedLossyString(forKey: .projectName)
|
||||
orderNumber = try container.decodeSharedLossyString(forKey: .orderNumber)
|
||||
orderStatus = try container.decodeSharedLossyInt(forKey: .orderStatus) ?? 0
|
||||
orderStatusLabel = try container.decodeSharedLossyString(forKey: .orderStatusLabel)
|
||||
payTime = try container.decodeSharedLossyString(forKey: .payTime)
|
||||
userPhone = try container.decodeSharedLossyString(forKey: .userPhone)
|
||||
}
|
||||
}
|
||||
|
||||
/// 摄影项目列表项实体,表示项目管理列表和样片上传时可关联的项目。
|
||||
struct PhotographerProjectItem: Decodable, Identifiable, Hashable {
|
||||
let id: Int
|
||||
let type: Int
|
||||
let typeName: String
|
||||
let status: Int
|
||||
let statusName: String
|
||||
let name: String
|
||||
let coverProject: String
|
||||
let coverVideo: String
|
||||
let price: String
|
||||
let otPrice: String
|
||||
let priceDeposit: String
|
||||
let attrLabel: [String]
|
||||
let label: String
|
||||
|
||||
/// 创建摄影项目列表项,主要用于详情页摘要和测试替身。
|
||||
init(
|
||||
id: Int,
|
||||
type: Int = 0,
|
||||
typeName: String = "",
|
||||
status: Int = 0,
|
||||
statusName: String = "",
|
||||
name: String,
|
||||
coverProject: String = "",
|
||||
coverVideo: String = "",
|
||||
price: String = "",
|
||||
otPrice: String = "",
|
||||
priceDeposit: String = "",
|
||||
attrLabel: [String] = [],
|
||||
label: String = ""
|
||||
) {
|
||||
self.id = id
|
||||
self.type = type
|
||||
self.typeName = typeName
|
||||
self.status = status
|
||||
self.statusName = statusName
|
||||
self.name = name
|
||||
self.coverProject = coverProject
|
||||
self.coverVideo = coverVideo
|
||||
self.price = price
|
||||
self.otPrice = otPrice
|
||||
self.priceDeposit = priceDeposit
|
||||
self.attrLabel = attrLabel
|
||||
self.label = label
|
||||
}
|
||||
|
||||
/// 字段映射,兼容后端下划线命名。
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case type
|
||||
case typeName = "type_name"
|
||||
case status
|
||||
case statusName = "status_name"
|
||||
case name
|
||||
case coverProject = "cover_project"
|
||||
case coverVideo = "cover_video"
|
||||
case price
|
||||
case otPrice = "ot_price"
|
||||
case priceDeposit = "price_deposit"
|
||||
case attrLabel = "attr_label"
|
||||
case label
|
||||
}
|
||||
|
||||
/// 宽松解码项目列表项。
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try container.decodeSharedLossyInt(forKey: .id) ?? 0
|
||||
type = try container.decodeSharedLossyInt(forKey: .type) ?? 0
|
||||
typeName = try container.decodeSharedLossyString(forKey: .typeName)
|
||||
status = try container.decodeSharedLossyInt(forKey: .status) ?? 0
|
||||
statusName = try container.decodeSharedLossyString(forKey: .statusName)
|
||||
name = try container.decodeSharedLossyString(forKey: .name)
|
||||
coverProject = try container.decodeSharedLossyString(forKey: .coverProject)
|
||||
coverVideo = try container.decodeSharedLossyString(forKey: .coverVideo)
|
||||
price = try container.decodeSharedLossyString(forKey: .price)
|
||||
otPrice = try container.decodeSharedLossyString(forKey: .otPrice)
|
||||
priceDeposit = try container.decodeSharedLossyString(forKey: .priceDeposit)
|
||||
label = try container.decodeSharedLossyString(forKey: .label)
|
||||
if let labels = try? container.decodeIfPresent([String].self, forKey: .attrLabel) {
|
||||
attrLabel = labels
|
||||
} else if let text = try? container.decodeIfPresent(String.self, forKey: .attrLabel) {
|
||||
attrLabel = text
|
||||
.components(separatedBy: CharacterSet(charactersIn: ",,"))
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
.filter { !$0.isEmpty }
|
||||
} else {
|
||||
attrLabel = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension KeyedDecodingContainer {
|
||||
/// 将 String、数字和 Bool 宽松解码为字符串。
|
||||
func decodeSharedLossyString(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 ""
|
||||
}
|
||||
|
||||
/// 将 String、Double 和 Int 宽松解码为 Int。
|
||||
func decodeSharedLossyInt(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