feat: add AI retouch task center
This commit is contained in:
@@ -5,25 +5,32 @@ enum PushDestination: Sendable, Equatable {
|
||||
case paymentRecord
|
||||
case paymentDetails
|
||||
case messageCenter
|
||||
case aiRetouchTaskList
|
||||
case aiRetouchTaskDetail(batchId: Int)
|
||||
}
|
||||
|
||||
/// 极光/APNs payload 解析结果,仅提取业务消息类型用于点击路由。
|
||||
struct PushPayload: Sendable, Equatable {
|
||||
private let type: String
|
||||
private let aiRetouchBatchId: Int?
|
||||
|
||||
/// 从系统通知 userInfo 提取顶层或推送包装层中的业务消息类型。
|
||||
nonisolated init(userInfo: [AnyHashable: Any]) {
|
||||
type = Self.extractType(from: userInfo)
|
||||
aiRetouchBatchId = Self.extractBatchId(from: userInfo)
|
||||
}
|
||||
|
||||
/// 从可发送的字符串字典创建 payload,仅保留业务消息类型。
|
||||
nonisolated init(values: [String: String]) {
|
||||
type = Self.normalizedType(values["type"])
|
||||
aiRetouchBatchId = Int(values["ai_retouch_batch_id"] ?? "").flatMap { $0 > 0 ? $0 : nil }
|
||||
}
|
||||
|
||||
/// 可发送的规范化字段快照。
|
||||
nonisolated var normalizedValues: [String: String] {
|
||||
type.isEmpty ? [:] : ["type": type]
|
||||
var values = type.isEmpty ? [:] : ["type": type]
|
||||
if let aiRetouchBatchId { values["ai_retouch_batch_id"] = String(aiRetouchBatchId) }
|
||||
return values
|
||||
}
|
||||
|
||||
/// 仅根据后端业务消息类型解析目标页面。
|
||||
@@ -33,6 +40,11 @@ struct PushPayload: Sendable, Equatable {
|
||||
return .paymentRecord
|
||||
case "6":
|
||||
return .paymentDetails
|
||||
case "14":
|
||||
if let aiRetouchBatchId, aiRetouchBatchId > 0 {
|
||||
return .aiRetouchTaskDetail(batchId: aiRetouchBatchId)
|
||||
}
|
||||
return .aiRetouchTaskList
|
||||
default:
|
||||
return .messageCenter
|
||||
}
|
||||
@@ -80,6 +92,50 @@ struct PushPayload: Sendable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private nonisolated static func extractBatchId(
|
||||
from dictionary: [AnyHashable: Any],
|
||||
depth: Int = 0
|
||||
) -> Int? {
|
||||
guard depth <= 5 else { return nil }
|
||||
if let value = normalizedPositiveInt(dictionary["ai_retouch_batch_id"]) { return value }
|
||||
|
||||
if let data = dictionary["data"] {
|
||||
if let nested = data as? [AnyHashable: Any],
|
||||
let value = extractBatchId(from: nested, depth: depth + 1) { return value }
|
||||
if let text = data as? String,
|
||||
let nested = jsonDictionary(text),
|
||||
let value = extractBatchId(from: nested, depth: depth + 1) { return value }
|
||||
}
|
||||
|
||||
for key in nestedTypeContainerKeys {
|
||||
guard let value = dictionary[key] else { continue }
|
||||
if let nested = value as? [AnyHashable: Any],
|
||||
let batchId = extractBatchId(from: nested, depth: depth + 1) { return batchId }
|
||||
if let text = value as? String,
|
||||
let nested = jsonDictionary(text),
|
||||
let batchId = extractBatchId(from: nested, depth: depth + 1) { return batchId }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private nonisolated static func normalizedPositiveInt(_ value: Any?) -> Int? {
|
||||
let parsed: Int?
|
||||
switch value {
|
||||
case let number as NSNumber: parsed = number.intValue
|
||||
case let string as String: parsed = Int(string.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
default: parsed = nil
|
||||
}
|
||||
return parsed.flatMap { $0 > 0 ? $0 : nil }
|
||||
}
|
||||
|
||||
private nonisolated static func jsonDictionary(_ text: String) -> [AnyHashable: Any]? {
|
||||
guard let data = text.data(using: .utf8),
|
||||
let object = try? JSONSerialization.jsonObject(with: data),
|
||||
let dictionary = object as? [String: Any]
|
||||
else { return nil }
|
||||
return Dictionary(uniqueKeysWithValues: dictionary.map { (AnyHashable($0.key), $0.value) })
|
||||
}
|
||||
|
||||
private nonisolated static let nestedTypeContainerKeys = [
|
||||
"extras", "extra", "JMessageExtra", "n_extras",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user