Advance UIKit rewrite with AMap integration and core UI modules.
Integrate高德 SDK with simulator-safe build flags, add map views for operating area and punch points, refactor main tabs and key feature screens to UIKit with Diffable lists, and document Swift concurrency defaults in AGENTS.md. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -31,6 +31,7 @@ struct OperatingAreaItem: Decodable, Equatable, Identifiable {
|
||||
let typeText: String
|
||||
let auditStatusText: String
|
||||
|
||||
/// 枚举,定义相关常量或状态。
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case name
|
||||
@ -40,6 +41,7 @@ struct OperatingAreaItem: Decodable, Equatable, Identifiable {
|
||||
case auditStatusText = "audit_status_text"
|
||||
}
|
||||
|
||||
/// 初始化实例。
|
||||
init(
|
||||
id: Int = 0,
|
||||
name: String = "",
|
||||
@ -56,6 +58,7 @@ struct OperatingAreaItem: Decodable, Equatable, Identifiable {
|
||||
self.auditStatusText = auditStatusText
|
||||
}
|
||||
|
||||
/// 初始化实例。
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try container.operatingDecodeLossyInt(forKey: .id) ?? 0
|
||||
@ -76,6 +79,7 @@ enum OperatingMapArea: Decodable, Equatable {
|
||||
case array([OperatingMapArea])
|
||||
case object([String: OperatingMapArea])
|
||||
|
||||
/// 初始化实例。
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
if container.decodeNil() {
|
||||
@ -106,6 +110,7 @@ enum OperatingMapArea: Decodable, Equatable {
|
||||
return fromJSONObject(raw)
|
||||
}
|
||||
|
||||
/// fromJSONObject相关逻辑。
|
||||
private static func fromJSONObject(_ value: Any) -> OperatingMapArea {
|
||||
switch value {
|
||||
case is NSNull:
|
||||
@ -140,6 +145,7 @@ struct OperatingFenceRing: Identifiable, Equatable {
|
||||
let points: [OperatingGeoPoint]
|
||||
let isCurrentStore: Bool
|
||||
|
||||
/// 初始化实例。
|
||||
init(itemId: Int, regionName: String, points: [OperatingGeoPoint], isCurrentStore: Bool, ringIndex: Int) {
|
||||
self.id = "\(itemId)-\(ringIndex)"
|
||||
self.itemId = itemId
|
||||
@ -184,6 +190,7 @@ enum OperatingAreaParser {
|
||||
return parseElement(area)
|
||||
}
|
||||
|
||||
/// 解析Element数据。
|
||||
private static func parseElement(_ value: OperatingMapArea) -> [[OperatingGeoPoint]] {
|
||||
switch value {
|
||||
case .null, .bool, .number:
|
||||
@ -199,6 +206,7 @@ enum OperatingAreaParser {
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析Object数据。
|
||||
private static func parseObject(_ object: [String: OperatingMapArea]) -> [[OperatingGeoPoint]] {
|
||||
let type: String?
|
||||
if case let .string(rawType)? = object["type"] {
|
||||
@ -231,6 +239,7 @@ enum OperatingAreaParser {
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析ArrayRoot数据。
|
||||
private static func parseArrayRoot(_ array: [OperatingMapArea]) -> [[OperatingGeoPoint]] {
|
||||
guard let first = array.first else { return [] }
|
||||
switch first {
|
||||
@ -257,6 +266,7 @@ enum OperatingAreaParser {
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析ObjectRing数据。
|
||||
private static func parseObjectRing(_ array: [OperatingMapArea]) -> [OperatingGeoPoint]? {
|
||||
let points = array.compactMap { element -> OperatingGeoPoint? in
|
||||
guard case let .object(object) = element else { return nil }
|
||||
@ -265,6 +275,7 @@ enum OperatingAreaParser {
|
||||
return points.count >= 3 ? points : nil
|
||||
}
|
||||
|
||||
/// 解析Ring数据。
|
||||
private static func parseRing(_ array: [OperatingMapArea]) -> [OperatingGeoPoint]? {
|
||||
let points = array.compactMap { element -> OperatingGeoPoint? in
|
||||
switch element {
|
||||
@ -283,6 +294,7 @@ enum OperatingAreaParser {
|
||||
return points.count >= 3 ? points : nil
|
||||
}
|
||||
|
||||
/// point从对象相关逻辑。
|
||||
private static func pointFromObject(_ object: [String: OperatingMapArea]) -> OperatingGeoPoint? {
|
||||
let lat = object["lat"]?.numberValue ?? object["latitude"]?.numberValue
|
||||
let lng = object["lng"]?.numberValue ?? object["lon"]?.numberValue ?? object["longitude"]?.numberValue
|
||||
@ -290,6 +302,7 @@ enum OperatingAreaParser {
|
||||
return OperatingGeoPoint(latitude: lat, longitude: lng)
|
||||
}
|
||||
|
||||
/// 规范化Pair格式。
|
||||
private static func normalizePair(_ a: Double, _ b: Double) -> OperatingGeoPoint {
|
||||
if looksLikeLngLatPair(lng: a, lat: b) {
|
||||
return OperatingGeoPoint(latitude: b, longitude: a)
|
||||
@ -303,24 +316,29 @@ enum OperatingAreaParser {
|
||||
return OperatingGeoPoint(latitude: a, longitude: b)
|
||||
}
|
||||
|
||||
/// looksLikeLngLat坐标对相关逻辑。
|
||||
private static func looksLikeLngLatPair(lng: Double, lat: Double) -> Bool {
|
||||
(-90.0...90.0).contains(lat) && abs(lng) <= 180.0 && abs(lng) > abs(lat)
|
||||
}
|
||||
|
||||
/// looksLikeLatLng坐标对相关逻辑。
|
||||
private static func looksLikeLatLngPair(lat: Double, lng: Double) -> Bool {
|
||||
(-90.0...90.0).contains(lat) && abs(lng) <= 180.0 && abs(lat) <= abs(lng)
|
||||
}
|
||||
}
|
||||
|
||||
/// 结构体,封装数据实体。
|
||||
private struct OperatingDynamicCodingKey: CodingKey {
|
||||
let stringValue: String
|
||||
let intValue: Int?
|
||||
|
||||
/// 初始化实例。
|
||||
init?(stringValue: String) {
|
||||
self.stringValue = stringValue
|
||||
intValue = nil
|
||||
}
|
||||
|
||||
/// 初始化实例。
|
||||
init?(intValue: Int) {
|
||||
stringValue = String(intValue)
|
||||
self.intValue = intValue
|
||||
@ -341,6 +359,7 @@ private extension OperatingMapArea {
|
||||
}
|
||||
|
||||
private extension KeyedDecodingContainer {
|
||||
/// operating解码宽松字符串相关逻辑。
|
||||
func operatingDecodeLossyString(forKey key: Key) throws -> String {
|
||||
if let value = try? decodeIfPresent(String.self, forKey: key) {
|
||||
return value
|
||||
@ -357,6 +376,7 @@ private extension KeyedDecodingContainer {
|
||||
return ""
|
||||
}
|
||||
|
||||
/// operating解码宽松整数相关逻辑。
|
||||
func operatingDecodeLossyInt(forKey key: Key) throws -> Int? {
|
||||
if let value = try? decodeIfPresent(Int.self, forKey: key) {
|
||||
return value
|
||||
|
||||
Reference in New Issue
Block a user