Add scenic application flow aligned with Android.
Implement scenic apply models, API, upload, UI, and tests; wire entry from permission apply pages and include related permission/scenic selection UI fixes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -0,0 +1,199 @@
|
||||
//
|
||||
// ScenicApplicationModels.swift
|
||||
// suixinkan
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 合作类型,对齐 Android `CooperationType`。
|
||||
enum ScenicCooperationType: Int, CaseIterable, Equatable {
|
||||
case photographer = 1
|
||||
case resourceProvider = 2
|
||||
case teamLeader = 3
|
||||
case photoShop = 4
|
||||
case efficiencyImprovement = 5
|
||||
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .photographer:
|
||||
"我是摄影师,我想入驻"
|
||||
case .resourceProvider:
|
||||
"我是景区资源方,可以合作"
|
||||
case .teamLeader:
|
||||
"我有摄影师团队,带队入住"
|
||||
case .photoShop:
|
||||
"我是旅拍店,想合作"
|
||||
case .efficiencyImprovement:
|
||||
"我已经在景区运营旅拍了,想使用软件,提高效率"
|
||||
}
|
||||
}
|
||||
|
||||
static func from(rawValue: Int) -> ScenicCooperationType {
|
||||
ScenicCooperationType(rawValue: rawValue) ?? .photographer
|
||||
}
|
||||
}
|
||||
|
||||
/// 景区申请待审核记录。
|
||||
struct ScenicApplicationPendingResponse: Decodable, Equatable {
|
||||
let id: Int
|
||||
let code: String
|
||||
let staffId: Int
|
||||
let scenicId: Int
|
||||
let scenicName: String
|
||||
let scenicImages: String
|
||||
let scenicProvince: String
|
||||
let scenicCity: String
|
||||
let coopType: Int
|
||||
let remark: String?
|
||||
let status: Int
|
||||
let rejectReason: String?
|
||||
let auditedBy: String?
|
||||
let auditedAt: String?
|
||||
let auditNote: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case code
|
||||
case staffId = "staff_id"
|
||||
case scenicId = "scenic_id"
|
||||
case scenicName = "scenic_name"
|
||||
case scenicImages = "scenic_images"
|
||||
case scenicProvince = "scenic_province"
|
||||
case scenicCity = "scenic_city"
|
||||
case coopType = "coop_type"
|
||||
case remark
|
||||
case status
|
||||
case rejectReason = "reject_reason"
|
||||
case auditedBy = "audited_by"
|
||||
case auditedAt = "audited_at"
|
||||
case auditNote = "audit_note"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0
|
||||
code = try container.decodeIfPresent(String.self, forKey: .code) ?? ""
|
||||
staffId = try container.decodeIfPresent(Int.self, forKey: .staffId) ?? 0
|
||||
scenicId = try container.decodeIfPresent(Int.self, forKey: .scenicId) ?? 0
|
||||
scenicName = try container.decodeIfPresent(String.self, forKey: .scenicName) ?? ""
|
||||
scenicImages = try container.decodeIfPresent(String.self, forKey: .scenicImages) ?? ""
|
||||
scenicProvince = try container.decodeIfPresent(String.self, forKey: .scenicProvince) ?? ""
|
||||
scenicCity = try container.decodeIfPresent(String.self, forKey: .scenicCity) ?? ""
|
||||
coopType = try container.decodeIfPresent(Int.self, forKey: .coopType) ?? 0
|
||||
remark = try container.decodeIfPresent(String.self, forKey: .remark)
|
||||
status = try container.decodeIfPresent(Int.self, forKey: .status) ?? 0
|
||||
rejectReason = try container.decodeIfPresent(String.self, forKey: .rejectReason)
|
||||
auditedBy = try container.decodeIfPresent(String.self, forKey: .auditedBy)
|
||||
auditedAt = try container.decodeIfPresent(String.self, forKey: .auditedAt)
|
||||
auditNote = try container.decodeIfPresent(String.self, forKey: .auditNote)
|
||||
}
|
||||
|
||||
init(
|
||||
id: Int = 0,
|
||||
code: String = "",
|
||||
staffId: Int = 0,
|
||||
scenicId: Int = 0,
|
||||
scenicName: String = "",
|
||||
scenicImages: String = "",
|
||||
scenicProvince: String = "",
|
||||
scenicCity: String = "",
|
||||
coopType: Int = 0,
|
||||
remark: String? = nil,
|
||||
status: Int = 0,
|
||||
rejectReason: String? = nil,
|
||||
auditedBy: String? = nil,
|
||||
auditedAt: String? = nil,
|
||||
auditNote: String? = nil
|
||||
) {
|
||||
self.id = id
|
||||
self.code = code
|
||||
self.staffId = staffId
|
||||
self.scenicId = scenicId
|
||||
self.scenicName = scenicName
|
||||
self.scenicImages = scenicImages
|
||||
self.scenicProvince = scenicProvince
|
||||
self.scenicCity = scenicCity
|
||||
self.coopType = coopType
|
||||
self.remark = remark
|
||||
self.status = status
|
||||
self.rejectReason = rejectReason
|
||||
self.auditedBy = auditedBy
|
||||
self.auditedAt = auditedAt
|
||||
self.auditNote = auditNote
|
||||
}
|
||||
}
|
||||
|
||||
/// 景区申请待审核列表响应。
|
||||
struct ScenicApplicationPendingsResponse: Decodable, Equatable {
|
||||
let items: [ScenicApplicationPendingResponse]
|
||||
|
||||
init(items: [ScenicApplicationPendingResponse] = []) {
|
||||
self.items = items
|
||||
}
|
||||
}
|
||||
|
||||
/// 景区申请提交请求。
|
||||
struct ScenicApplicationSubmitRequest: Encodable {
|
||||
let scenicName: String?
|
||||
let scenicImages: [String]?
|
||||
let scenicProvince: String
|
||||
let scenicCity: String
|
||||
let coopType: Int
|
||||
let remark: String
|
||||
let scenicId: Int
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case scenicName = "scenic_name"
|
||||
case scenicImages = "scenic_images"
|
||||
case scenicProvince = "scenic_province"
|
||||
case scenicCity = "scenic_city"
|
||||
case coopType = "coop_type"
|
||||
case remark
|
||||
case scenicId = "scenic_id"
|
||||
}
|
||||
}
|
||||
|
||||
/// 单张景区申请图片的上传状态。
|
||||
struct ScenicApplicationImageItem: Equatable, Identifiable {
|
||||
let id: UUID
|
||||
var localData: Data?
|
||||
var fileName: String
|
||||
var remoteURL: String
|
||||
var isUploading: Bool
|
||||
var uploadProgress: Int
|
||||
var errorMessage: String?
|
||||
|
||||
var isUploaded: Bool { !remoteURL.isEmpty }
|
||||
|
||||
static func fromRemoteURL(_ url: String) -> ScenicApplicationImageItem {
|
||||
let trimmed = url.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let name = URL(string: trimmed)?.lastPathComponent ?? "image.jpg"
|
||||
return ScenicApplicationImageItem(
|
||||
id: UUID(),
|
||||
localData: nil,
|
||||
fileName: name,
|
||||
remoteURL: trimmed,
|
||||
isUploading: false,
|
||||
uploadProgress: 100,
|
||||
errorMessage: nil
|
||||
)
|
||||
}
|
||||
|
||||
static func fromLocal(data: Data, fileName: String) -> ScenicApplicationImageItem {
|
||||
ScenicApplicationImageItem(
|
||||
id: UUID(),
|
||||
localData: data,
|
||||
fileName: fileName,
|
||||
remoteURL: "",
|
||||
isUploading: false,
|
||||
uploadProgress: 0,
|
||||
errorMessage: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 图片上传进度弹窗状态。
|
||||
struct ScenicApplicationUploadDialogState: Equatable {
|
||||
let title: String
|
||||
let progress: Int
|
||||
}
|
||||
Reference in New Issue
Block a user