7.2 KiB
「全部功能」页业务逻辑
Android 工程对应文档:zhiflyfollow/docs/home/AllFunctions.md
模块职责
「全部功能」页(HomeMoreFunctionsView)展示当前角色可用的功能入口,分为两个分区:
- 常用应用:已加入首页常用的入口,支持移除(
-) - 更多功能:其余可用入口,支持添加为常用(
+)
常用应用的增删会同步写入本地持久化,并与首页「常用应用」网格共用同一套配置(HomeCommonMenuStore)。
本页数据构建规则与 Android AllFunctionsViewModel 对齐,不复用首页 HomeViewModel 的 flatten + preferredOrder 逻辑。
涉及文件
| 文件 | 职责 |
|---|---|
Views/HomeMoreFunctionsView.swift |
页面 UI、增删常用、触发重建 |
Services/HomeAllFunctionsBuilder.swift |
菜单列表构建与常用/更多拆分 |
Services/HomeCommonMenuStore.swift |
常用 URI 持久化与默认生成 |
Services/HomeAllFunctionsDiagnostics.swift |
Debug 诊断日志 |
App/State/PermissionContext.swift |
提供当前角色顶层权限 |
Routing/HomeMenuRouter.swift |
点击入口后的路由解析 |
数据流
flowchart TD
API[role-permission 接口] --> PC[PermissionContext]
PC --> TLP[topLevelPermissions 顶层节点]
TLP --> BUILDER[HomeAllFunctionsBuilder.build]
CMS[HomeCommonMenuStore.load] --> COMMON[commonURIs]
COMMON --> BUILDER
BUILDER --> ALL[allFunctions]
BUILDER --> CF[commonFunctions]
BUILDER --> MF[moreFunctions]
CF --> UI1[常用应用网格]
MF --> UI2[更多功能网格]
触发重建的时机
HomeMoreFunctionsView.rebuildMenus() 在以下情况执行:
- 页面首次进入(
.task) - 当前角色
roleCode变化 rolePermissions数量变化
用户点击 + / - 时只更新 commonUris 并调用 applySnapshot,不重新走持久化读取(除非权限上下文同时变化)。
第一步:读取顶层权限
数据来源:PermissionContext.topLevelPermissions(for: roleCode)
- 仅取当前匹配角色的
role.permission顶层数组 - 不递归展开
children子节点 - 顺序与 API 返回一致,不做本地重排
- 过滤掉 URI 为空的节点
对应 Android:appStore.getPermission() 中保存的顶层权限列表(MMKV 快照)。
第二步:白名单过滤(可用入口)
由 HomeAllFunctionsBuilder.allMenuItems(from:) 执行:
allFunctions = 顶层权限
.按 API 顺序遍历
.保留 uri ∈ HomeCommonMenuStore.androidHomeMenuURIs 的项
.映射为 HomeMenuItem
androidHomeMenuURIs 与 Android Constants.menuList 登记 URI 一致。已登记且会出现在「全部功能」页的 URI 包括 location_report、photographer_report(举报摄影师)、wallet、message_center 等。
以下典型 URI 不会出现在「全部功能」页,即使接口返回了顶层权限:
basic_info、photographer_stats、photographer_orderslocation_info、scan_qr、payment_qralbum_list、material_upload等未登记 URI
子权限 URI 也不会出现(未 flatten)。
第三步:菜单项字段映射
每个保留的 PermissionItem 转为 HomeMenuItem:
| 字段 | 规则 |
|---|---|
uri |
权限节点原始 URI,精确字符串 |
title |
API name 非空时用 name;否则 HomeMenuRouter.title(for:);再经 HomeMenuRouter.displayTitle 统一部分同义入口文案 |
iconSrc |
API icon_src;为空时 UI 层用 HomeIconCatalog SF Symbol 兜底 |
Android 端标题/icon 来自本地 Constants.menuList drawable;iOS 优先接口字段 + 本地图标兜底。
第四步:读取常用 URI
由 HomeCommonMenuStore.load 提供 commonUris,规则详见 Home.md「常用应用」章节,核心要点:
- 存储 key:
home.common.menu.uris.account.{accountScope}.role.{roleCode}(无 accountScope 时用home.common.menu.uris.role.{roleCode}) - 首次无 saved:按顶层前 4 个 URI 与 menuList 求交生成默认,并落库
- 已有 saved:精确 URI 匹配当前可用顶层权限;全部失效时返回空,不回退默认
- 增删常用:精确 URI 匹配(不使用
menuAliasKey)
第五步:拆分为常用 / 更多
HomeAllFunctionsBuilder.build(topLevelPermissions:commonURIs:):
commonSet = Set(commonURIs)
commonFunctions = allFunctions.filter { commonSet.contains($0.uri) }
moreFunctions = allFunctions.filter { !commonSet.contains($0.uri) }
要点:
- 匹配方式:精确 URI,不做别名归一
- 常用区顺序:跟随
allFunctions列表顺序(API 顺序 ∩ 白名单后的顺序),不是commonUris数组的存储顺序 - 更多区顺序:同样跟随
allFunctions剩余项顺序
与 Android 一致:
val common = functions.filter { it.uri in commonUris }
val more = functions.filter { it.uri !in commonUris }
展示层
布局
- 两节标题:「常用应用」「更多功能」
- 每节 3 列
LazyVGrid,卡片高度 112pt - 卡片右上角:
常用显示红色-,更多显示蓝色+
点击行为
- 点击卡片主体:
HomeMenuRouter.resolve(uri:title:)解析路由- Tab 切换、订单 Tab、Home 子路由、占位页等
more_functionsURI 在页内忽略(防循环)
- 点击
-:HomeCommonMenuStore.remove→applySnapshot - 点击
+:HomeCommonMenuStore.add(校验 URI 在顶层可用白名单内)→applySnapshot
与首页的关系
| 维度 | 首页常用应用网格 | 全部功能页 |
|---|---|---|
| 数据源 | HomeCommonMenuStore + HomeViewModel(展示标题/icon) |
HomeAllFunctionsBuilder |
| 列表范围 | 仅 common URIs + 「更多功能」入口 | 全部可用入口分 common / more |
| 排序 | common 按 store 顺序映射 | common/more 均按 allFunctions API 顺序 |
| 持久化 | 共用 HomeCommonMenuStore |
共用 HomeCommonMenuStore |
与 HomeViewModel 的区别
HomeViewModel(首页等) |
HomeAllFunctionsBuilder(全部功能) |
|
|---|---|---|
| 权限范围 | 递归 flatten 整棵权限树 | 仅顶层 |
| 白名单 | 无 | androidHomeMenuURIs |
| 排序 | preferredOrder 硬编码权重 |
API 顶层顺序 |
| 去重 | menuAliasKey 别名去重 |
无(顶层 URI 精确保留) |
「全部功能」页不应调用 HomeViewModel.buildMenus()。
诊断日志
Debug 构建下可用 Xcode Console 过滤 HomeAllFunctions:
| step | 含义 |
|---|---|
allFunctions |
白名单过滤后的完整 URI 列表 |
commonFunctions |
常用分区 URI |
moreFunctions |
更多分区 URI |
常用应用持久化链路仍使用 HomeCommonMenu tag,见 HomeCommonMenuStore / 首页 HomeView 日志。
测试
单元测试:suixinkanTests/HomeAllFunctionsBuilderTests.swift
覆盖场景:
- menuList 白名单过滤
- API 顶层顺序保留(非 preferredOrder)
- 不展开子权限
- 精确 URI 拆分 common / more
- 常用区顺序跟随
allFunctions - 与 Android 样例账号(27 顶层 → 21 可用 → 3 常用 + 18 更多)一致