接入举报摄影师正式接口
This commit is contained in:
@ -32,31 +32,81 @@ enum WildReportAttachmentKind: Hashable {
|
||||
case payment
|
||||
}
|
||||
|
||||
/// 举报类型,用于提交页单选并写入 Mock 举报记录。
|
||||
enum WildReportType: String, CaseIterable, Hashable {
|
||||
case suspectedWild = "疑似打野"
|
||||
case noWorkBadge = "未戴工牌"
|
||||
case other = "其他"
|
||||
/// 举报类型接口返回的单项数据,由后端动态配置。
|
||||
struct WildReportType: Decodable, Hashable {
|
||||
let value: Int
|
||||
let label: String
|
||||
|
||||
var iconName: String {
|
||||
switch self {
|
||||
case .suspectedWild: return "person.crop.circle.badge.exclamationmark"
|
||||
case .noWorkBadge: return "lanyardcard"
|
||||
case .other: return "ellipsis.circle"
|
||||
}
|
||||
static let defaultSelected = WildReportType(value: 2, label: "疑似打野")
|
||||
|
||||
static let fallbackOptions = [
|
||||
WildReportType(value: 1, label: "私下收款"),
|
||||
WildReportType(value: 2, label: "疑似打野"),
|
||||
WildReportType(value: 3, label: "未戴工牌"),
|
||||
WildReportType(value: 4, label: "其他")
|
||||
]
|
||||
}
|
||||
|
||||
/// 举报类型接口返回的列表包裹。
|
||||
struct WildReportTypeListResponse: Decodable, Hashable {
|
||||
let list: [WildReportType]
|
||||
|
||||
init(list: [WildReportType]) {
|
||||
self.list = list
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报附件实体,表示一条演示用的上传项。
|
||||
/// 举报附件实体,表示一条本地待上传或演示用的上传项。
|
||||
struct WildReportAttachment: Hashable {
|
||||
let id: UUID
|
||||
let kind: WildReportAttachmentKind
|
||||
let title: String
|
||||
let localFileURL: URL?
|
||||
let fileName: String
|
||||
let fileType: Int
|
||||
let uploadedURL: String?
|
||||
|
||||
init(id: UUID = UUID(), kind: WildReportAttachmentKind, title: String) {
|
||||
init(
|
||||
id: UUID = UUID(),
|
||||
kind: WildReportAttachmentKind,
|
||||
title: String,
|
||||
localFileURL: URL? = nil,
|
||||
fileName: String? = nil,
|
||||
uploadedURL: String? = nil
|
||||
) {
|
||||
self.id = id
|
||||
self.kind = kind
|
||||
self.title = title
|
||||
self.localFileURL = localFileURL
|
||||
self.fileName = fileName ?? "\(title).\(kind.defaultFileExtension)"
|
||||
self.fileType = kind.reportFileType
|
||||
self.uploadedURL = uploadedURL
|
||||
}
|
||||
}
|
||||
|
||||
extension WildReportAttachment {
|
||||
/// 读取待上传附件的本地文件数据。
|
||||
func uploadData() throws -> Data {
|
||||
guard let localFileURL else { throw OSSUploadError.emptyFile }
|
||||
return try Data(contentsOf: localFileURL)
|
||||
}
|
||||
}
|
||||
|
||||
extension WildReportAttachmentKind {
|
||||
/// 提交举报接口的文件类型:1 图片,2 视频。
|
||||
var reportFileType: Int {
|
||||
switch self {
|
||||
case .image, .payment: return 1
|
||||
case .video: return 2
|
||||
}
|
||||
}
|
||||
|
||||
/// 本地附件默认扩展名。
|
||||
var defaultFileExtension: String {
|
||||
switch self {
|
||||
case .image, .payment: return "jpg"
|
||||
case .video: return "mp4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,6 +133,29 @@ enum WildReportStatus: String, Hashable, CaseIterable {
|
||||
}
|
||||
}
|
||||
|
||||
extension WildReportStatus {
|
||||
/// 后端举报处理状态码:0 待处理、1 处理中、2 已处理。
|
||||
init(handleStatus: Int, fallbackText: String = "") {
|
||||
switch handleStatus {
|
||||
case 0:
|
||||
self = .pending
|
||||
case 1:
|
||||
self = .processing
|
||||
case 2:
|
||||
self = .processed
|
||||
default:
|
||||
switch fallbackText {
|
||||
case WildReportStatus.processing.rawValue:
|
||||
self = .processing
|
||||
case WildReportStatus.processed.rawValue:
|
||||
self = .processed
|
||||
default:
|
||||
self = .pending
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 我的举报列表筛选条件。
|
||||
enum WildReportListFilter: String, CaseIterable, Hashable {
|
||||
case all = "全部"
|
||||
@ -91,6 +164,187 @@ enum WildReportListFilter: String, CaseIterable, Hashable {
|
||||
case processed = "已处理"
|
||||
}
|
||||
|
||||
extension WildReportListFilter {
|
||||
/// 后端列表筛选状态码:全部不传,0 待处理、1 处理中、2 已处理。
|
||||
var handleStatusValue: Int? {
|
||||
switch self {
|
||||
case .all: return nil
|
||||
case .pending: return 0
|
||||
case .processing: return 1
|
||||
case .processed: return 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 我的举报列表接口请求参数。
|
||||
struct WildReportListRequest: Equatable {
|
||||
let scenicId: Int?
|
||||
let handleStatus: Int?
|
||||
let page: Int
|
||||
let pageSize: Int
|
||||
|
||||
init(
|
||||
scenicId: Int?,
|
||||
handleStatus: Int?,
|
||||
page: Int = 1,
|
||||
pageSize: Int = 10
|
||||
) {
|
||||
self.scenicId = scenicId
|
||||
self.handleStatus = handleStatus
|
||||
self.page = page
|
||||
self.pageSize = pageSize
|
||||
}
|
||||
|
||||
var queryItems: [URLQueryItem] {
|
||||
var items: [URLQueryItem] = []
|
||||
if let scenicId, scenicId > 0 {
|
||||
items.append(URLQueryItem(name: "scenic_id", value: String(scenicId)))
|
||||
}
|
||||
if let handleStatus {
|
||||
items.append(URLQueryItem(name: "handle_status", value: String(handleStatus)))
|
||||
}
|
||||
items.append(URLQueryItem(name: "page", value: String(max(1, page))))
|
||||
items.append(URLQueryItem(name: "page_size", value: String(min(max(1, pageSize), 50))))
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/// 我的举报列表接口响应体。
|
||||
struct WildReportListResponse: Decodable, Equatable {
|
||||
let list: [WildReportListItem]
|
||||
let total: Int
|
||||
let page: Int
|
||||
let pageSize: Int
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case list
|
||||
case total
|
||||
case page
|
||||
case pageSize = "page_size"
|
||||
}
|
||||
|
||||
init(list: [WildReportListItem], total: Int, page: Int, pageSize: Int) {
|
||||
self.list = list
|
||||
self.total = total
|
||||
self.page = page
|
||||
self.pageSize = pageSize
|
||||
}
|
||||
}
|
||||
|
||||
/// 我的举报列表接口单条举报数据。
|
||||
struct WildReportListItem: Decodable, Equatable, Hashable {
|
||||
let id: Int
|
||||
let complaintNo: String
|
||||
let title: String
|
||||
let reportType: Int
|
||||
let reportTypeText: String
|
||||
let desc: String
|
||||
let scenicId: Int
|
||||
let scenicName: String
|
||||
let locationName: String
|
||||
let latitude: String
|
||||
let longitude: String
|
||||
let handleStatus: Int
|
||||
let handleStatusText: String
|
||||
let createdAt: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case complaintNo = "complaint_no"
|
||||
case title
|
||||
case reportType = "report_type"
|
||||
case reportTypeText = "report_type_text"
|
||||
case desc
|
||||
case scenicId = "scenic_id"
|
||||
case scenicName = "scenic_name"
|
||||
case locationName = "location_name"
|
||||
case latitude
|
||||
case longitude
|
||||
case handleStatus = "handle_status"
|
||||
case handleStatusText = "handle_status_text"
|
||||
case createdAt = "created_at"
|
||||
}
|
||||
|
||||
init(
|
||||
id: Int,
|
||||
complaintNo: String,
|
||||
title: String,
|
||||
reportType: Int,
|
||||
reportTypeText: String,
|
||||
desc: String,
|
||||
scenicId: Int,
|
||||
scenicName: String,
|
||||
locationName: String,
|
||||
latitude: String,
|
||||
longitude: String,
|
||||
handleStatus: Int,
|
||||
handleStatusText: String,
|
||||
createdAt: String
|
||||
) {
|
||||
self.id = id
|
||||
self.complaintNo = complaintNo
|
||||
self.title = title
|
||||
self.reportType = reportType
|
||||
self.reportTypeText = reportTypeText
|
||||
self.desc = desc
|
||||
self.scenicId = scenicId
|
||||
self.scenicName = scenicName
|
||||
self.locationName = locationName
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
self.handleStatus = handleStatus
|
||||
self.handleStatusText = handleStatusText
|
||||
self.createdAt = createdAt
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0
|
||||
complaintNo = try container.decodeIfPresent(String.self, forKey: .complaintNo) ?? ""
|
||||
title = try container.decodeIfPresent(String.self, forKey: .title) ?? ""
|
||||
reportType = try container.decodeIfPresent(Int.self, forKey: .reportType) ?? 0
|
||||
reportTypeText = try container.decodeIfPresent(String.self, forKey: .reportTypeText) ?? ""
|
||||
desc = try container.decodeIfPresent(String.self, forKey: .desc) ?? ""
|
||||
scenicId = try container.decodeIfPresent(Int.self, forKey: .scenicId) ?? 0
|
||||
scenicName = try container.decodeIfPresent(String.self, forKey: .scenicName) ?? ""
|
||||
locationName = try container.decodeIfPresent(String.self, forKey: .locationName) ?? ""
|
||||
latitude = try container.decodeIfPresent(String.self, forKey: .latitude) ?? ""
|
||||
longitude = try container.decodeIfPresent(String.self, forKey: .longitude) ?? ""
|
||||
handleStatus = try container.decodeIfPresent(Int.self, forKey: .handleStatus) ?? 0
|
||||
handleStatusText = try container.decodeIfPresent(String.self, forKey: .handleStatusText) ?? ""
|
||||
createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt) ?? ""
|
||||
}
|
||||
|
||||
/// 转换为当前 UIKit 列表和详情页复用的举报记录实体。
|
||||
func toRecord() -> WildReportRecord {
|
||||
let scenic = scenicName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let location = locationName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let displayLocation: String
|
||||
if !scenic.isEmpty, !location.isEmpty, scenic != location {
|
||||
displayLocation = "\(scenic) · \(location)"
|
||||
} else if !location.isEmpty {
|
||||
displayLocation = location
|
||||
} else {
|
||||
displayLocation = scenic
|
||||
}
|
||||
|
||||
return WildReportRecord(
|
||||
id: complaintNo,
|
||||
title: title.isEmpty ? "\(reportTypeText)举报" : title,
|
||||
reportType: WildReportType(value: reportType, label: reportTypeText.isEmpty ? "其他" : reportTypeText),
|
||||
status: WildReportStatus(handleStatus: handleStatus, fallbackText: handleStatusText),
|
||||
location: displayLocation,
|
||||
submitTime: createdAt,
|
||||
description: desc,
|
||||
wechatID: "",
|
||||
phoneNumber: "",
|
||||
imageCount: 0,
|
||||
videoCount: 0,
|
||||
handlerInfo: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 补充证据记录实体。
|
||||
struct WildReportSupplementaryEvidence: Hashable {
|
||||
let id: String
|
||||
|
||||
Reference in New Issue
Block a user