新增门店订单与核销管理列表,对齐 Android 订单能力并完善账号级缓存。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-29 14:46:10 +08:00
parent c4de3d17d0
commit 08492df6ce
51 changed files with 3668 additions and 102 deletions

View File

@ -10,6 +10,37 @@ import Foundation
/// URI
struct HomeCommonMenuStore {
static let storageKeyPrefix = "home.common.menu.uris.role."
static let accountScopedStorageKeyPrefix = "home.common.menu.uris.account."
/// Android `Constants.menuList` URI
static let androidHomeMenuURIs: Set<String> = [
"space_settings",
"wallet",
"cloud_management",
"asset_management",
"task_management",
"schedule_management",
"system_settings",
"message_center",
"checkin_points",
"sample_management",
"live_stream_management",
"verification_order",
"live_album",
"pm",
"location_report",
"registration_invitation",
"store",
"fly",
"pilot_cert",
"task_management_editor",
"pm_manager",
"pilot_controller",
"/scenic-queue",
"operating-area",
"/scenic-order-manage",
"cooperation_order"
]
private let defaults: UserDefaults
@ -27,7 +58,7 @@ struct HomeCommonMenuStore {
let trimmed = uri.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return nil }
let canonical = HomeMenuRouter.canonicalURI(for: trimmed, availableURIs: availableURIs)
return availableURIs.contains(canonical) ? canonical : nil
return Self.isAndroidHomeMenuURI(canonical) && availableURIs.contains(canonical) ? canonical : nil
}
let deduplicated = unique(resolved)
if deduplicated.count > 4 {
@ -40,23 +71,24 @@ struct HomeCommonMenuStore {
func load(
menuItems: [HomeMenuItem],
roleCode: String?,
accountScope: String? = nil,
legacyRoleId: Int? = nil,
topLevelPermissionURIs: [String]
) -> [String] {
guard let roleCode, !roleCode.isEmpty else { return [] }
migrateLegacyStorageIfNeeded(roleCode: roleCode, legacyRoleId: legacyRoleId)
migrateLegacyStorageIfNeeded(roleCode: roleCode, accountScope: accountScope, legacyRoleId: legacyRoleId)
let availableURIs = Set(menuItems.map(\.uri))
let key = storageKey(for: roleCode)
let key = Self.storageKey(roleCode: roleCode, accountScope: accountScope)
let saved = defaults.stringArray(forKey: key)
if let saved, !saved.isEmpty {
let filtered = Self.unique(saved.compactMap { uri -> String? in
let resolved = HomeMenuRouter.canonicalURI(for: uri, availableURIs: availableURIs)
return availableURIs.contains(resolved) ? resolved : nil
return Self.isAndroidHomeMenuURI(resolved) && availableURIs.contains(resolved) ? resolved : nil
})
if !filtered.isEmpty {
save(filtered, roleCode: roleCode)
save(filtered, roleCode: roleCode, accountScope: accountScope)
return filtered
}
}
@ -65,54 +97,63 @@ struct HomeCommonMenuStore {
orderedTopLevelURIs: topLevelPermissionURIs,
availableURIs: availableURIs
)
save(defaultURIs, roleCode: roleCode)
save(defaultURIs, roleCode: roleCode, accountScope: accountScope)
return defaultURIs
}
/// URI
func add(_ uri: String, current: [String], menuItems: [HomeMenuItem], roleCode: String?) -> [String] {
func add(_ uri: String, current: [String], menuItems: [HomeMenuItem], roleCode: String?, accountScope: String? = nil) -> [String] {
guard let roleCode, !roleCode.isEmpty else { return current }
let availableURIs = Set(menuItems.map(\.uri))
let resolved = HomeMenuRouter.canonicalURI(for: uri, availableURIs: availableURIs)
guard availableURIs.contains(resolved) else { return current }
guard Self.isAndroidHomeMenuURI(resolved), availableURIs.contains(resolved) else { return current }
guard !current.contains(where: { HomeMenuRouter.menuAliasKey(for: $0) == HomeMenuRouter.menuAliasKey(for: resolved) }) else {
return current
}
let next = current + [resolved]
save(next, roleCode: roleCode)
save(next, roleCode: roleCode, accountScope: accountScope)
return next
}
/// URI URI
func remove(_ uri: String, current: [String], roleCode: String?) -> [String] {
func remove(_ uri: String, current: [String], roleCode: String?, accountScope: String? = nil) -> [String] {
guard let roleCode, !roleCode.isEmpty else { return current }
let aliasKey = HomeMenuRouter.menuAliasKey(for: uri)
let next = current.filter { HomeMenuRouter.menuAliasKey(for: $0) != aliasKey }
save(next, roleCode: roleCode)
save(next, roleCode: roleCode, accountScope: accountScope)
return next
}
/// URI
func save(_ uris: [String], roleCode: String) {
defaults.set(Self.unique(uris), forKey: storageKey(for: roleCode))
func save(_ uris: [String], roleCode: String, accountScope: String? = nil) {
defaults.set(Self.unique(uris), forKey: Self.storageKey(roleCode: roleCode, accountScope: accountScope))
}
/// key legacy role id key
func migrateLegacyStorageIfNeeded(roleCode: String, legacyRoleId: Int?) {
let newKey = storageKey(for: roleCode)
guard defaults.stringArray(forKey: newKey) == nil,
let legacyRoleId,
let legacyData = defaults.stringArray(forKey: legacyStorageKey(for: legacyRoleId)),
!legacyData.isEmpty else {
/// key roleCode legacy role id key
func migrateLegacyStorageIfNeeded(roleCode: String, accountScope: String? = nil, legacyRoleId: Int?) {
let newKey = Self.storageKey(roleCode: roleCode, accountScope: accountScope)
guard defaults.stringArray(forKey: newKey) == nil else { return }
let legacyKeys = [
legacyStorageKey(for: roleCode),
legacyRoleId.map { legacyStorageKey(for: $0) }
].compactMap { $0 }
for legacyKey in legacyKeys {
guard let legacyData = defaults.stringArray(forKey: legacyKey), !legacyData.isEmpty else { continue }
defaults.set(legacyData, forKey: newKey)
defaults.removeObject(forKey: legacyKey)
return
}
defaults.set(legacyData, forKey: newKey)
defaults.removeObject(forKey: legacyStorageKey(for: legacyRoleId))
}
/// role_code UserDefaults key
private func storageKey(for roleCode: String) -> String {
Self.storageKeyPrefix + roleCode
/// role_code UserDefaults key
static func storageKey(roleCode: String, accountScope: String?) -> String {
let normalizedScope = accountScope?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if normalizedScope.isEmpty {
return storageKeyPrefix + roleCode
}
return accountScopedStorageKeyPrefix + normalizedScope + ".role." + roleCode
}
/// numeric role id key
@ -120,6 +161,16 @@ struct HomeCommonMenuStore {
Self.storageKeyPrefix + String(roleId)
}
/// role_code key
private func legacyStorageKey(for roleCode: String) -> String {
Self.storageKeyPrefix + roleCode
}
/// URI Android
private static func isAndroidHomeMenuURI(_ uri: String) -> Bool {
androidHomeMenuURIs.contains(uri)
}
/// URI URI
private static func unique(_ uris: [String]) -> [String] {
var seen = Set<String>()