// // HomeMoreFunctionsView.swift // suixinkan // // Created by Codex on 2026/6/22. // import SwiftUI /// 首页全部功能视图,展示常用应用和当前角色拥有的更多功能。 struct HomeMoreFunctionsView: View { @EnvironmentObject private var accountContext: AccountContext @EnvironmentObject private var permissionContext: PermissionContext @EnvironmentObject private var appRouter: AppRouter @EnvironmentObject private var router: RouterPath @State private var snapshot = HomeAllFunctionsSnapshot( allFunctions: [], commonFunctions: [], moreFunctions: [] ) @State private var commonUris: [String] = [] private let commonMenuStore = HomeCommonMenuStore() var body: some View { ScrollView { VStack(alignment: .leading, spacing: 26) { section(title: "常用应用", items: snapshot.commonFunctions, isCommon: true) section(title: "更多功能", items: snapshot.moreFunctions, isCommon: false) } .padding(.horizontal, AppMetrics.Spacing.mediumLarge) .padding(.top, AppMetrics.Spacing.medium) .padding(.bottom, AppMetrics.Spacing.xxLarge) } .background(Color(hex: 0xF5F5F5)) .navigationTitle("全部功能") .navigationBarTitleDisplayMode(.inline) .task { rebuildMenus() } .onChange(of: permissionContext.currentRole?.roleCode) { _ in rebuildMenus() } .onChange(of: permissionContext.rolePermissions.count) { _ in rebuildMenus() } } private func section(title: String, items: [HomeMenuItem], isCommon: Bool) -> some View { VStack(alignment: .leading, spacing: AppMetrics.Spacing.medium) { Text(title) .font(.system(size: AppMetrics.FontSize.title, weight: .bold)) .foregroundStyle(Color(hex: 0x2C2C2C)) appGrid(items: items, isCommon: isCommon) } } private func appGrid(items: [HomeMenuItem], isCommon: Bool) -> some View { LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 14), count: 3), spacing: AppMetrics.Spacing.mediumLarge) { ForEach(items, id: \.uri) { item in ZStack(alignment: .topTrailing) { Button { openMenu(item) } label: { VStack(spacing: AppMetrics.Spacing.mediumLarge + 1) { menuIconView(for: item) .frame(width: 34, height: 34) Text(item.title) .font(.system(size: AppMetrics.FontSize.callout)) .foregroundStyle(Color(hex: 0x252525)) .lineLimit(1) .minimumScaleFactor(0.78) } .frame(maxWidth: .infinity) .frame(height: 112) .background(.white, in: RoundedRectangle(cornerRadius: 8)) } .buttonStyle(.plain) Button { updateCommonUris(isCommon: isCommon, uri: item.uri) } label: { Image(systemName: isCommon ? "minus.circle.fill" : "plus.circle.fill") .font(.system(size: 24, weight: .bold)) .foregroundStyle(isCommon ? Color(hex: 0xFF1111) : AppDesign.primary) .background(Color.white, in: Circle()) } .buttonStyle(.plain) .offset(x: 9, y: -9) } .frame(maxWidth: .infinity) .frame(height: 112) } } } @ViewBuilder private func menuIconView(for item: HomeMenuItem) -> some View { RemoteImage(urlString: item.iconSrc, contentMode: .fit) { fallbackMenuIcon(for: item.uri) } } private func fallbackMenuIcon(for uri: String) -> some View { Image(systemName: HomeIconCatalog.iconName(for: uri)) .resizable() .scaledToFit() .foregroundStyle(AppDesign.primary) .frame(width: 34, height: 34) } private func openMenu(_ item: HomeMenuItem) { switch HomeMenuRouter.resolve(uri: item.uri, title: item.title) { case .tab(let tab): appRouter.select(tab) case .orders(let entry): appRouter.selectOrders(entry: entry) case .orderPush(let route): appRouter.select(.orders) appRouter.router(for: .orders).navigate(to: .orders(route)) case .destination(let route): if route == .moreFunctions { return } router.navigate(to: .home(route)) case .unsupported(let uri, let title, _): router.navigate(to: .home(.modulePlaceholder(uri: uri, title: title))) case .placeholder(let uri, let title): HomeRouteDiagnostics.recordUnknown(uri: uri, title: title) router.navigate(to: .home(.modulePlaceholder(uri: uri, title: title))) } } /// 增删常用应用并刷新分区快照。 private func updateCommonUris(isCommon: Bool, uri: String) { let roleCode = permissionContext.currentAppRole?.rawValue let topLevelURIs = permissionContext.topLevelPermissionURIs(for: roleCode) if isCommon { commonUris = commonMenuStore.remove( uri, current: commonUris, roleCode: roleCode, accountScope: accountContext.accountCachePrefix ) } else { commonUris = commonMenuStore.add( uri, current: commonUris, topLevelPermissionURIs: topLevelURIs, roleCode: roleCode, accountScope: accountContext.accountCachePrefix ) } applySnapshot(commonURIs: commonUris) } private func rebuildMenus() { let roleCode = permissionContext.currentAppRole?.rawValue let legacyRoleId = permissionContext.currentRole?.id let topLevelPermissions = permissionContext.topLevelPermissions(for: roleCode) commonUris = commonMenuStore.load( menuItems: [], roleCode: roleCode, accountScope: accountContext.accountCachePrefix, legacyRoleId: legacyRoleId, topLevelPermissionURIs: topLevelPermissions.map(\.uri) ) applySnapshot(commonURIs: commonUris) } /// 按当前顶层权限与常用 URI 重建全部功能快照。 private func applySnapshot(commonURIs: [String]) { let roleCode = permissionContext.currentAppRole?.rawValue snapshot = HomeAllFunctionsBuilder.build( topLevelPermissions: permissionContext.topLevelPermissions(for: roleCode), commonURIs: commonURIs ) } }