Initial commit: suixinkan_ios UIKit rewrite project.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
92
suixinkan_ios/App/State/PermissionContext.swift
Normal file
92
suixinkan_ios/App/State/PermissionContext.swift
Normal file
@ -0,0 +1,92 @@
|
||||
//
|
||||
// PermissionContext.swift
|
||||
// suixinkan
|
||||
//
|
||||
// Created by Codex on 2026/6/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
/// 权限上下文状态中心,保存角色权限、当前角色和扁平化权限 URI。
|
||||
final class PermissionContext {
|
||||
|
||||
var onChange: (() -> Void)?
|
||||
private(set) var rolePermissions: [RolePermissionResponse] = [] { didSet { onChange?() } }
|
||||
private(set) var permissionURIs: Set<String> = [] { didSet { onChange?() } }
|
||||
var currentRole: RoleInfo? { didSet { onChange?() } }
|
||||
|
||||
/// 替换角色权限列表,并尽量按缓存角色 ID 保持当前角色。
|
||||
func replaceRolePermissions(_ rolePermissions: [RolePermissionResponse], currentRoleId: Int? = nil) {
|
||||
self.rolePermissions = rolePermissions
|
||||
currentRole = currentRoleId.flatMap { id in
|
||||
rolePermissions.first { $0.role.id == id }?.role
|
||||
} ?? currentRole.flatMap { role in
|
||||
rolePermissions.first { $0.role.id == role.id }?.role
|
||||
} ?? rolePermissions.first?.role
|
||||
permissionURIs = Set(Self.flattenPermissions(currentRole?.permission ?? []))
|
||||
}
|
||||
|
||||
/// 切换当前角色,并同步账号上下文中的景区和门店选择。
|
||||
func selectRole(id roleId: Int, accountContext: AccountContext) {
|
||||
guard let rolePermission = rolePermissions.first(where: { $0.role.id == roleId }) else { return }
|
||||
currentRole = rolePermission.role
|
||||
permissionURIs = Set(Self.flattenPermissions(rolePermission.role.permission))
|
||||
|
||||
let scenicScopes = Self.uniqueScenicScopes(from: rolePermission.scenic)
|
||||
accountContext.replaceScopes(
|
||||
scenic: scenicScopes,
|
||||
stores: accountContext.storeScopes,
|
||||
currentScenicId: accountContext.currentScenic?.id,
|
||||
currentStoreId: accountContext.currentStore?.id
|
||||
)
|
||||
}
|
||||
|
||||
/// 判断当前角色是否拥有指定 URI 权限。
|
||||
func canAccess(_ uri: String) -> Bool {
|
||||
permissionURIs.contains(uri.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
}
|
||||
|
||||
/// 返回当前角色关联的景区作用域。
|
||||
func currentRoleScenicScopes() -> [BusinessScope] {
|
||||
guard let currentRole else { return [] }
|
||||
guard let rolePermission = rolePermissions.first(where: { $0.role.id == currentRole.id }) else {
|
||||
return []
|
||||
}
|
||||
return Self.uniqueScenicScopes(from: rolePermission.scenic)
|
||||
}
|
||||
|
||||
/// 清空权限上下文,通常在退出登录时调用。
|
||||
func reset() {
|
||||
rolePermissions = []
|
||||
permissionURIs = []
|
||||
currentRole = nil
|
||||
}
|
||||
|
||||
/// 递归提取权限树里的非空 URI。
|
||||
private static func flattenPermissions(_ permissions: [PermissionItem]) -> [String] {
|
||||
permissions.flatMap { item -> [String] in
|
||||
let current = item.uri.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let children = flattenPermissions(item.children)
|
||||
return current.isEmpty ? children : [current] + children
|
||||
}
|
||||
}
|
||||
|
||||
/// 将角色关联景区去重并转换为业务作用域。
|
||||
private static func uniqueScenicScopes(from scenics: [ScenicInfo]) -> [BusinessScope] {
|
||||
var seen = Set<Int>()
|
||||
return scenics.compactMap { scenic in
|
||||
guard seen.insert(scenic.id).inserted else { return nil }
|
||||
return BusinessScope(
|
||||
id: scenic.id,
|
||||
name: scenic.name,
|
||||
kind: .scenic,
|
||||
status: scenic.status,
|
||||
address: scenic.location?.address,
|
||||
latitude: scenic.location?.lat,
|
||||
longitude: scenic.location?.lng,
|
||||
coverURLString: scenic.coverImg
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user