feat: add wild photographer report mock flow
This commit is contained in:
@ -0,0 +1,349 @@
|
||||
//
|
||||
// WildPhotographerReportModels.swift
|
||||
// suixinkan
|
||||
//
|
||||
|
||||
import CoreLocation
|
||||
import Foundation
|
||||
import MapKit
|
||||
import UIKit
|
||||
|
||||
/// 举报摄影师页面状态,用于演示加载、空态和异常态。
|
||||
enum WildReportPageState: String, CaseIterable, Hashable {
|
||||
case normal
|
||||
case loading
|
||||
case empty
|
||||
case error
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .normal: return "正常"
|
||||
case .loading: return "加载"
|
||||
case .empty: return "空状态"
|
||||
case .error: return "异常"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报附件类型,区分现场图片、视频和支付截图。
|
||||
enum WildReportAttachmentKind: Hashable {
|
||||
case image
|
||||
case video
|
||||
case payment
|
||||
}
|
||||
|
||||
/// 举报类型,用于提交页单选并写入 Mock 举报记录。
|
||||
enum WildReportType: String, CaseIterable, Hashable {
|
||||
case suspectedWild = "疑似打野"
|
||||
case noWorkBadge = "未戴工牌"
|
||||
case other = "其他"
|
||||
|
||||
var iconName: String {
|
||||
switch self {
|
||||
case .suspectedWild: return "person.crop.circle.badge.exclamationmark"
|
||||
case .noWorkBadge: return "lanyardcard"
|
||||
case .other: return "ellipsis.circle"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报附件实体,表示一条演示用的上传项。
|
||||
struct WildReportAttachment: Hashable {
|
||||
let id: UUID
|
||||
let kind: WildReportAttachmentKind
|
||||
let title: String
|
||||
|
||||
init(id: UUID = UUID(), kind: WildReportAttachmentKind, title: String) {
|
||||
self.id = id
|
||||
self.kind = kind
|
||||
self.title = title
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报处理状态。
|
||||
enum WildReportStatus: String, Hashable, CaseIterable {
|
||||
case pending = "待处理"
|
||||
case processing = "处理中"
|
||||
case processed = "已处理"
|
||||
|
||||
var displayColor: UIColor {
|
||||
switch self {
|
||||
case .pending: return AppColor.warning
|
||||
case .processing: return AppColor.primary
|
||||
case .processed: return AppColor.success
|
||||
}
|
||||
}
|
||||
|
||||
var backgroundColor: UIColor {
|
||||
switch self {
|
||||
case .pending: return AppColor.warningBackground
|
||||
case .processing: return AppColor.infoBackground
|
||||
case .processed: return AppColor.successBackground
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 我的举报列表筛选条件。
|
||||
enum WildReportListFilter: String, CaseIterable, Hashable {
|
||||
case all = "全部"
|
||||
case pending = "待处理"
|
||||
case processing = "处理中"
|
||||
case processed = "已处理"
|
||||
}
|
||||
|
||||
/// 补充证据记录实体。
|
||||
struct WildReportSupplementaryEvidence: Hashable {
|
||||
let id: String
|
||||
let submitTime: String
|
||||
let text: String
|
||||
let imageCount: Int
|
||||
let videoCount: Int
|
||||
|
||||
var summaryText: String {
|
||||
var parts: [String] = []
|
||||
if !text.isEmpty { parts.append(text) }
|
||||
if imageCount > 0 { parts.append("\(imageCount)张图片") }
|
||||
if videoCount > 0 { parts.append("\(videoCount)段视频") }
|
||||
return parts.isEmpty ? "补充证据" : parts.joined(separator: " · ")
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报位置解析工具。
|
||||
enum WildReportLocationParser {
|
||||
/// 将「景区 · 详细地址」拆成两段展示文案。
|
||||
static func split(_ location: String) -> (scenic: String, detail: String) {
|
||||
let parts = location
|
||||
.components(separatedBy: " · ")
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
.filter { !$0.isEmpty }
|
||||
if parts.count >= 2 {
|
||||
return (parts[0], parts[1])
|
||||
}
|
||||
return (location, location)
|
||||
}
|
||||
}
|
||||
|
||||
/// 附近风险点实体。
|
||||
struct WildReportRiskPoint: Hashable {
|
||||
let id: Int
|
||||
let title: String
|
||||
let location: String
|
||||
let distance: String
|
||||
let riskLevel: String
|
||||
let evidenceCount: Int
|
||||
let latestTime: String
|
||||
let description: String
|
||||
}
|
||||
|
||||
/// 举报记录实体。
|
||||
struct WildReportRecord: Hashable {
|
||||
let id: String
|
||||
let title: String
|
||||
let reportType: WildReportType
|
||||
let status: WildReportStatus
|
||||
let location: String
|
||||
let submitTime: String
|
||||
let description: String
|
||||
let wechatID: String
|
||||
let phoneNumber: String
|
||||
let imageCount: Int
|
||||
let videoCount: Int
|
||||
let handlerInfo: WildReportHandlerInfo?
|
||||
|
||||
var contactDisplayText: String {
|
||||
switch (wechatID.isEmpty, phoneNumber.isEmpty) {
|
||||
case (true, true): return "未填写"
|
||||
case (false, false): return "\(wechatID) / \(phoneNumber)"
|
||||
case (false, true): return wechatID
|
||||
case (true, false): return phoneNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理完成后的媒体项。
|
||||
struct WildReportCompletionMediaItem: Hashable {
|
||||
enum Kind: Hashable {
|
||||
case image
|
||||
case video
|
||||
}
|
||||
|
||||
let id: String
|
||||
let kind: Kind
|
||||
let coverURL: String
|
||||
let duration: String?
|
||||
}
|
||||
|
||||
/// 举报处理人信息实体。
|
||||
struct WildReportHandlerInfo: Hashable {
|
||||
let handlerName: String
|
||||
let handlerPhone: String
|
||||
let processingAt: String
|
||||
let processedAt: String
|
||||
let processOpinion: String
|
||||
let completionMedia: [WildReportCompletionMediaItem]
|
||||
|
||||
var maskedHandlerPhone: String {
|
||||
guard handlerPhone.count == 11, handlerPhone.allSatisfy(\.isNumber) else { return handlerPhone }
|
||||
return "\(handlerPhone.prefix(3))****\(handlerPhone.suffix(4))"
|
||||
}
|
||||
|
||||
var completionMediaSummary: String {
|
||||
let imageCount = completionMedia.filter { $0.kind == .image }.count
|
||||
let videoCount = completionMedia.filter { $0.kind == .video }.count
|
||||
switch (imageCount, videoCount) {
|
||||
case (0, 0): return "0项"
|
||||
case (_, 0): return "\(imageCount)张"
|
||||
case (0, _): return "\(videoCount)段"
|
||||
default: return "\(imageCount)张 \(videoCount)段"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报进度节点状态。
|
||||
enum WildReportProgressStepState: Hashable {
|
||||
case completed
|
||||
case current
|
||||
case pending
|
||||
}
|
||||
|
||||
/// 举报进度时间轴节点。
|
||||
struct WildReportProgressStep: Hashable {
|
||||
let id: String
|
||||
let title: String
|
||||
let timeText: String
|
||||
let state: WildReportProgressStepState
|
||||
}
|
||||
|
||||
/// 举报人材料预览项。
|
||||
enum WildReportReporterMediaItem: Hashable {
|
||||
case image(index: Int)
|
||||
case video(index: Int)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case .image(let index): return "reporter-image-\(index)"
|
||||
case .video(let index): return "reporter-video-\(index)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报提交结果,用于成功页展示。
|
||||
struct WildReportSubmitResult: Hashable {
|
||||
let record: WildReportRecord
|
||||
let imageCount: Int
|
||||
let videoCount: Int
|
||||
}
|
||||
|
||||
/// 风险地图标记类型。
|
||||
enum WildReportMapMarkerKind: Hashable {
|
||||
case selfLocation
|
||||
case wildPhotographer
|
||||
case processingClue
|
||||
case peerPhotographer
|
||||
|
||||
var color: UIColor {
|
||||
switch self {
|
||||
case .selfLocation: return AppColor.primary
|
||||
case .wildPhotographer: return AppColor.danger
|
||||
case .processingClue: return AppColor.warning
|
||||
case .peerPhotographer: return AppColor.success
|
||||
}
|
||||
}
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .selfLocation: return "我的位置"
|
||||
case .wildPhotographer: return "疑似打野"
|
||||
case .processingClue: return "处理中线索"
|
||||
case .peerPhotographer: return "内部摄影师"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 雷达地图标记颜色类型。
|
||||
enum WildReportRadarMarkerType: String, Hashable {
|
||||
case blue
|
||||
case green
|
||||
case red
|
||||
}
|
||||
|
||||
/// 雷达线索举报内容条目。
|
||||
struct WildReportRadarReportContent: Hashable {
|
||||
let time: String
|
||||
let content: String
|
||||
}
|
||||
|
||||
/// 雷达线索处理记录。
|
||||
struct WildReportRadarProcessRecord: Hashable {
|
||||
let handlerName: String
|
||||
let phone: String
|
||||
let maskedPhone: String
|
||||
let statusText: String
|
||||
let processResult: String
|
||||
let processedAt: String?
|
||||
let processingAt: String?
|
||||
}
|
||||
|
||||
/// 雷达线索处理时间轴节点。
|
||||
struct WildReportRadarProcessingTimelineItem: Hashable {
|
||||
let title: String
|
||||
let time: String
|
||||
let status: String
|
||||
}
|
||||
|
||||
/// 雷达地图活动线索详情。
|
||||
struct WildReportRadarActiveClue: Hashable {
|
||||
let id: String
|
||||
let type: WildReportRadarMarkerType
|
||||
let displayTitle: String
|
||||
let statusText: String
|
||||
let actionText: String
|
||||
let nearestAbnormalText: String?
|
||||
let distance: String?
|
||||
let direction: String?
|
||||
let updatedAt: String?
|
||||
let name: String?
|
||||
let storeName: String?
|
||||
let avatar: String?
|
||||
let summary: String?
|
||||
let detail: String?
|
||||
let distanceText: String?
|
||||
let reporterName: String?
|
||||
let reporterPhone: String?
|
||||
let maskedReporterPhone: String?
|
||||
let reportContents: [WildReportRadarReportContent]
|
||||
let images: [String]
|
||||
let processingStarted: Bool
|
||||
let completed: Bool
|
||||
let record: WildReportRadarProcessRecord?
|
||||
let processingTimeline: [WildReportRadarProcessingTimelineItem]
|
||||
let completionPhoto: String?
|
||||
}
|
||||
|
||||
/// 风险地图标记详情。
|
||||
enum WildReportMapMarkerDetail: Hashable {
|
||||
case activeClue(WildReportRadarActiveClue)
|
||||
}
|
||||
|
||||
/// 风险地图标记实体。
|
||||
struct WildReportMapMarker: Hashable {
|
||||
let id: String
|
||||
let title: String
|
||||
let coordinate: CLLocationCoordinate2D
|
||||
let kind: WildReportMapMarkerKind
|
||||
let detail: WildReportMapMarkerDetail
|
||||
|
||||
static func == (lhs: WildReportMapMarker, rhs: WildReportMapMarker) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(id)
|
||||
}
|
||||
}
|
||||
|
||||
extension CLLocationCoordinate2D: @retroactive Equatable {
|
||||
public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
|
||||
lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user