// // PermissionApplyViewModel.swift // suixinkan // import Foundation /// 权限申请 ViewModel,对齐 Android `PermissionApplyViewModel`。 final class PermissionApplyViewModel { private(set) var availableRoles: [RoleOption] = [] private(set) var selectedRoleId: Int? private(set) var selectedRoleName = "" private(set) var availableScenics: [ScenicOption] = [] private(set) var selectedScenicIds: [Int] = [] private(set) var selectedScenicNames: [String] = [] private(set) var isLoadingScenics = false private(set) var isSubmitting = false private(set) var showRolePicker = false private(set) var showScenicPicker = false var onStateChange: (() -> Void)? var onShowMessage: ((String) -> Void)? var onSubmitSuccess: ((String) -> Void)? private let appStore: AppStore init(appStore: AppStore = .shared) { self.appStore = appStore loadRolesFromLocal() } /// 从待审核数据预填表单(status=3 去编辑)。 func initWithPendingData(_ pending: RoleApplyPendingResponse) { selectedRoleId = pending.roleId selectedRoleName = pending.roleName selectedScenicIds = pending.scenicList.map(\.id) selectedScenicNames = pending.scenicList.map(\.name) availableRoles = availableRoles.map { role in var copy = role copy.isSelected = role.id == pending.roleId return copy } notifyStateChange() } func loadRolesFromLocal() { let rolePermissionList = appStore.rolePermissionList() var seen = Set() availableRoles = rolePermissionList.compactMap { item in guard !seen.contains(item.role.id) else { return nil } seen.insert(item.role.id) return RoleOption( id: item.role.id, name: item.role.name, description: item.role.notes ?? "", isSelected: false ) } notifyStateChange() } func showRolePickerSheet() { showRolePicker = true notifyStateChange() } func hideRolePickerSheet() { showRolePicker = false notifyStateChange() } func selectRole(_ role: RoleOption) { selectedRoleId = role.id selectedRoleName = role.name availableRoles = availableRoles.map { item in var copy = item copy.isSelected = item.id == role.id return copy } selectedScenicIds = [] selectedScenicNames = [] availableScenics = [] showRolePicker = false notifyStateChange() } func showScenicPickerSheet() { guard selectedRoleId != nil else { onShowMessage?("请先选择角色") return } showScenicPicker = true notifyStateChange() } func hideScenicPickerSheet() { showScenicPicker = false notifyStateChange() } func loadAvailableScenics(api: HomeAPI?) async { guard let roleId = selectedRoleId else { return } guard let api else { return } isLoadingScenics = true notifyStateChange() do { let response = try await api.scenicListAll() let existingIds = existingScenicIds(for: roleId) availableScenics = response.list.map { scenic in let isExisting = existingIds.contains(scenic.id) let isPreselected = selectedScenicIds.contains(scenic.id) return ScenicOption( id: scenic.id, name: scenic.name, isSelected: isExisting || isPreselected, isDisabled: isExisting ) } } catch { onShowMessage?("获取景区列表失败") } isLoadingScenics = false notifyStateChange() } func toggleScenic(_ scenic: ScenicOption) { guard !scenic.isDisabled else { return } if selectedScenicIds.contains(scenic.id) { selectedScenicIds.removeAll { $0 == scenic.id } selectedScenicNames.removeAll { $0 == scenic.name } } else { selectedScenicIds.append(scenic.id) selectedScenicNames.append(scenic.name) } availableScenics = availableScenics.map { item in var copy = item if !copy.isDisabled { copy.isSelected = selectedScenicIds.contains(copy.id) } return copy } notifyStateChange() } func removeSelectedScenic(id: Int, name: String) { selectedScenicIds.removeAll { $0 == id } selectedScenicNames.removeAll { $0 == name } availableScenics = availableScenics.map { item in var copy = item if !copy.isDisabled { copy.isSelected = selectedScenicIds.contains(copy.id) } return copy } notifyStateChange() } /// 已有角色下已开通的景区列表。 func existingScenics(for roleId: Int) -> [ScenicInfo] { appStore.rolePermissionList() .filter { $0.role.id == roleId } .flatMap(\.scenic) } func submit(api: HomeAPI) async { guard let roleId = selectedRoleId else { onShowMessage?("请先选择角色") return } let newScenicIds = selectedScenicIds.filter { id in !existingScenicIds(for: roleId).contains(id) } guard !newScenicIds.isEmpty else { onShowMessage?("请至少选择一个景区") return } isSubmitting = true notifyStateChange() do { let result = try await api.submitRoleApply(scenicIds: newScenicIds, roleId: roleId) onShowMessage?("提交成功") onSubmitSuccess?(result.code) } catch { onShowMessage?("提交失败,请稍后重试") } isSubmitting = false notifyStateChange() } private func existingScenicIds(for roleId: Int) -> Set { Set(existingScenics(for: roleId).map(\.id)) } private func notifyStateChange() { onStateChange?() } }