// // LocationModels.swift // suixinkan // import Foundation /// 位置上报详情,对齐 Android `LocationDetailResponse`。 struct LocationDetailResponse: Decodable, Sendable { let status: Int let needReport: Bool let expireTime: Int64 enum CodingKeys: String, CodingKey { case status case needReport = "need_report" case expireTime = "expire_time" } init(status: Int = 0, needReport: Bool = true, expireTime: Int64 = 0) { self.status = status self.needReport = needReport self.expireTime = expireTime } } /// 位置上报结果,对齐 Android `LocationReportResponse`。 struct LocationReportResponse: Decodable, Sendable { let staffId: String let expired: Int64 let status: Int enum CodingKeys: String, CodingKey { case staffId = "staff_id" case expired case status case storeUserId = "store_user_id" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) staffId = Self.decodeFlexibleString(from: container, forKey: .staffId) expired = try container.decodeIfPresent(Int64.self, forKey: .expired) ?? 0 status = try container.decodeIfPresent(Int.self, forKey: .status) ?? 0 } init(staffId: String = "", expired: Int64 = 0, status: Int = 0) { self.staffId = staffId self.expired = expired self.status = status } private static func decodeFlexibleString( from container: KeyedDecodingContainer, forKey key: CodingKeys, defaultValue: String = "" ) -> String { if let string = try? container.decode(String.self, forKey: key) { return string } if let intValue = try? container.decode(Int.self, forKey: key) { return String(intValue) } if let int64Value = try? container.decode(Int64.self, forKey: key) { return String(int64Value) } return defaultValue } } /// 历史上报类型筛选,对齐 Android `LocationReportFilterType`。 enum LocationReportFilterType: CaseIterable, Equatable { case all case immediate case marked case offline var displayName: String { switch self { case .all: "全部" case .immediate: "立即上报" case .marked: "标记上报" case .offline: "离线上报" } } var typeCode: Int { switch self { case .all: 0 case .immediate: 1 case .marked: 2 case .offline: 3 } } var tagColorHex: UInt { switch self { case .all, .immediate: 0x0073FF case .marked: 0x22C55E case .offline: 0x999999 } } static func from(typeCode: Int) -> LocationReportFilterType { switch typeCode { case 1: .immediate case 2: .marked case 3: .offline default: .all } } static func fromReportType(_ type: Int) -> LocationReportFilterType { switch type { case 1: .immediate case 2: .marked case 3: .offline default: .all } } } /// 历史上报单条记录,对齐 Android `LocationReportHistoryItem`。 struct LocationReportHistoryItem: Decodable, Equatable, Identifiable { let id: Int64 let staffId: Int64 let type: Int let latitude: String let longitude: String let address: String let ip: String? let remark: String let createdAt: String enum CodingKeys: String, CodingKey { case id case staffId = "staff_id" case type case latitude case longitude case address case ip case remark case createdAt = "created_at" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decodeIfPresent(Int64.self, forKey: .id) ?? 0 staffId = try container.decodeIfPresent(Int64.self, forKey: .staffId) ?? 0 type = try container.decodeIfPresent(Int.self, forKey: .type) ?? 0 latitude = try container.decodeIfPresent(String.self, forKey: .latitude) ?? "" longitude = try container.decodeIfPresent(String.self, forKey: .longitude) ?? "" address = try container.decodeIfPresent(String.self, forKey: .address) ?? "" ip = try container.decodeIfPresent(String.self, forKey: .ip) remark = try container.decodeIfPresent(String.self, forKey: .remark) ?? "" createdAt = try container.decodeIfPresent(String.self, forKey: .createdAt) ?? "" } init( id: Int64 = 0, staffId: Int64 = 0, type: Int = 0, latitude: String = "", longitude: String = "", address: String = "", ip: String? = nil, remark: String = "", createdAt: String = "" ) { self.id = id self.staffId = staffId self.type = type self.latitude = latitude self.longitude = longitude self.address = address self.ip = ip self.remark = remark self.createdAt = createdAt } var filterType: LocationReportFilterType { LocationReportFilterType.fromReportType(type) } } /// 历史上报列表响应。 struct LocationReportHistoryListResponse: Decodable, Equatable { let list: [LocationReportHistoryItem] let total: Int init(list: [LocationReportHistoryItem] = [], total: Int = 0) { self.list = list self.total = total } }