Initial commit: suixinkan_ios UIKit rewrite project.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-26 14:33:31 +08:00
commit 9edf993432
297 changed files with 47151 additions and 0 deletions

View File

@ -0,0 +1,291 @@
//
// TaskModels.swift
// suixinkan
//
// Created by Codex on 2026/6/23.
//
import Foundation
///
struct PhotographerTaskItem: Decodable, Identifiable, Hashable {
let id: Int
let name: String
let type: Int
let orderNumber: String
let taskStatus: Int
let statusName: String
let createdAt: String
let updatedAt: String
let photogRemark: String
let editorName: String
let operateTime: String
let orderUserNickname: String
let orderUserPhone: String
let orderUserId: String
let media: [TaskMediaItem]
/// 线
enum CodingKeys: String, CodingKey {
case id
case name
case type
case orderNumber = "order_number"
case taskStatus = "task_status"
case statusName = "status_name"
case createdAt = "created_at"
case updatedAt = "updated_at"
case photogRemark = "photog_remark"
case editorName = "editor_name"
case operateTime = "operate_time"
case orderUserNickname = "order_user_nickname"
case orderUserPhone = "order_user_phone"
case orderUserId = "order_user_id"
case media
}
///
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)
type = try container.decodeLossyInt(forKey: .type) ?? 0
orderNumber = try container.decodeLossyString(forKey: .orderNumber)
taskStatus = try container.decodeLossyInt(forKey: .taskStatus) ?? 0
statusName = try container.decodeLossyString(forKey: .statusName)
createdAt = try container.decodeLossyString(forKey: .createdAt)
updatedAt = try container.decodeLossyString(forKey: .updatedAt)
photogRemark = try container.decodeLossyString(forKey: .photogRemark)
editorName = try container.decodeLossyString(forKey: .editorName)
operateTime = try container.decodeLossyString(forKey: .operateTime)
orderUserNickname = try container.decodeLossyString(forKey: .orderUserNickname)
orderUserPhone = try container.decodeLossyString(forKey: .orderUserPhone)
orderUserId = try container.decodeLossyString(forKey: .orderUserId)
media = (try? container.decode([TaskMediaItem].self, forKey: .media)) ?? []
}
}
///
struct TaskMediaItem: Decodable, Identifiable, Hashable {
let id: Int
let photogTaskId: Int
let userId: Int
let fileName: String
let fileType: Int
let fileUrl: String
let fileSize: Int64
let coverUrl: String
let duration: Int
let remark: String
let createdAt: String
let updatedAt: String
///
var isVideo: Bool {
fileType == 1 || Self.hasVideoExtension(fileName) || Self.hasVideoExtension(fileUrl)
}
/// URL使
var displayURL: String {
coverUrl.isEmpty ? fileUrl : coverUrl
}
///
private static func hasVideoExtension(_ value: String) -> Bool {
["mp4", "mov", "m4v", "avi"].contains(URL(string: value)?.pathExtension.lowercased() ?? URL(fileURLWithPath: value).pathExtension.lowercased())
}
/// 线
enum CodingKeys: String, CodingKey {
case id
case photogTaskId = "photog_task_id"
case userId = "user_id"
case fileName = "file_name"
case fileType = "file_type"
case fileUrl = "file_url"
case fileSize = "file_size"
case coverUrl = "cover_url"
case duration
case remark
case createdAt = "created_at"
case updatedAt = "updated_at"
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeLossyInt(forKey: .id) ?? 0
photogTaskId = try container.decodeLossyInt(forKey: .photogTaskId) ?? 0
userId = try container.decodeLossyInt(forKey: .userId) ?? 0
fileName = try container.decodeLossyString(forKey: .fileName)
fileType = try container.decodeLossyInt(forKey: .fileType) ?? 0
fileUrl = try container.decodeLossyString(forKey: .fileUrl)
fileSize = Int64(try container.decodeLossyInt(forKey: .fileSize) ?? 0)
coverUrl = try container.decodeLossyString(forKey: .coverUrl)
duration = try container.decodeLossyInt(forKey: .duration) ?? 0
remark = try container.decodeLossyString(forKey: .remark)
createdAt = try container.decodeLossyString(forKey: .createdAt)
updatedAt = try container.decodeLossyString(forKey: .updatedAt)
}
}
///
struct TaskDetailResponse: Decodable, Identifiable, Hashable {
let id: Int
let name: String
let createdAt: String
let taskStatus: Int
let taskStatusLabel: String
let acceptedAt: String
let editorName: String
let editorPhone: String
let urgentHour: Int
let photogRemark: String
let order: TaskDetailOrder?
let taskResult: [TaskMediaItem]
/// 线
enum CodingKeys: String, CodingKey {
case id
case name
case createdAt = "created_at"
case taskStatus = "task_status"
case taskStatusLabel = "task_status_label"
case acceptedAt = "accepted_at"
case editorName = "editor_name"
case editorPhone = "editor_phone"
case urgentHour = "urgent_hour"
case photogRemark = "photog_remark"
case order
case taskResult = "task_result"
}
///
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)
createdAt = try container.decodeLossyString(forKey: .createdAt)
taskStatus = try container.decodeLossyInt(forKey: .taskStatus) ?? 0
taskStatusLabel = try container.decodeLossyString(forKey: .taskStatusLabel)
acceptedAt = try container.decodeLossyString(forKey: .acceptedAt)
editorName = try container.decodeLossyString(forKey: .editorName)
editorPhone = try container.decodeLossyString(forKey: .editorPhone)
urgentHour = try container.decodeLossyInt(forKey: .urgentHour) ?? 0
photogRemark = try container.decodeLossyString(forKey: .photogRemark)
order = try? container.decode(TaskDetailOrder.self, forKey: .order)
taskResult = (try? container.decode([TaskMediaItem].self, forKey: .taskResult)) ?? []
}
}
///
struct TaskDetailOrder: Decodable, Hashable {
let projectName: String
let orderNumber: String
let payTime: String
let userPhone: String
/// 线
enum CodingKeys: String, CodingKey {
case projectName = "project_name"
case orderNumber = "order_number"
case payTime = "pay_time"
case userPhone = "user_phone"
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
projectName = try container.decodeLossyString(forKey: .projectName)
orderNumber = try container.decodeLossyString(forKey: .orderNumber)
payTime = try container.decodeLossyString(forKey: .payTime)
userPhone = try container.decodeLossyString(forKey: .userPhone)
}
}
///
struct AddTaskRequest: Encodable, Equatable {
let scenicId: String
let name: String
let orderNumber: String?
let remark: String
let urgentHour: Int
let cloudFile: [CloudFileItem]
let uploadFile: [UploadFileItem]
/// 线
enum CodingKeys: String, CodingKey {
case scenicId = "scenic_id"
case name
case orderNumber = "order_number"
case remark = "photog_remark"
case urgentHour = "urgent_hour"
case cloudFile = "cloud_file"
case uploadFile = "upload_file"
}
}
///
struct CloudFileItem: Encodable, Equatable {
let fileId: Int
let remark: String
/// 线
enum CodingKeys: String, CodingKey {
case fileId = "file_id"
case remark
}
}
/// OSS
struct UploadFileItem: Encodable, Equatable {
let fileUrl: String
let fileName: String
let remark: String
/// 线
enum CodingKeys: String, CodingKey {
case fileUrl = "file_url"
case fileName = "file_name"
case remark
}
}
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
}
}