# Main 模块业务逻辑 ## 模块职责 Main 模块负责登录后的主界面 Tab 容器,以及当前尚未迁移页面的占位入口。 主界面由 `MainTabsView` 承载: - 使用系统 `TabView` 展示登录后的底部导航。 - 底部按顺序展示首页、订单、扫码、数据、我的五个入口。 - 扫码入口只负责打开扫码页,不属于 `AppTab`,也不持有独立业务导航栈。 - 每个 Tab 内部都包裹独立的 `NavigationStack`,并通过 `TabNavigationStackHost` 复用同一套导航构建逻辑。 - 每个 Tab 的导航路径由 `AppRouter` 单独保存。 - 订单 Tab 角标由 `MainTabBadgeViewModel` 提供,数量为 0 或获取失败时不显示。 ## Tab 结构 当前 Tab 来自 `AppTab`: - `home`:首页 - `orders`:订单 - `statistics`:数据 - `profile`:我的 `HomeRootView` 已接入真实的 `HomeView`,`OrdersRootView` 已按角色接入 `StoreOrderListView` 或 `StoreAdminOrderListView`,`StatisticsRootView` 已接入真实的 `StatisticsView`,`ProfileRootView` 已接入真实的 `ProfileView`。 ## 导航流程 1. `MainTabsView` 从 Environment 读取 `AppRouter`。 2. `TabView` 使用内部 `MainTabSelection` 作为选择值,普通 Tab 映射到 `AppTab`,扫码映射到 `.scanner`。 3. 普通 Tab 切换时调用 `AppRouter.select(_:)` 更新当前业务 Tab。 4. 每个普通 Tab 通过 `TabNavigationStackHost` 创建自己的 `NavigationStack(path:)`。 5. 导航栈宿主直接观察当前 Tab 对应的 `RouterPath`,并把 `$router.path` 绑定给 `NavigationStack`。 6. Tab 内页面需要进入子页面时,通过当前 Tab 注入的 `RouterPath` push 对应 `AppRoute`。 7. `navigationDestination` 根据 `AppRoute` 展示详情页。 8. 子页面展示时读取 `AppRoute.hidesTabBarWhenPushed`,默认隐藏底部 TabBar。 ## 扫码入口 扫码入口是系统 `TabView` 中的中间入口,只显示 `qrcode.viewfinder` 图标,并通过无障碍标签标记为“扫码核销”。 点击扫码入口时,`MainTabsView` 拦截 `.scanner` 选择并展示订单模块已有的 `OrderScannerPage`,不会修改 `AppRouter.selectedTab`。因此用户关闭扫码页后,仍停留在打开扫码前的 Tab。 扫码成功后调用 `AppRouter.routeToOrderVerification(scannedCode:)`,订单页再通过 `consumePendingOrderScanCode()` 一次性消费结果。扫码失败时关闭扫码页并展示错误提示。 ## 后续迁移规则 迁移新页面时: - 优先替换对应 Tab 的 RootView。 - 保持每个 Tab 自己的 `NavigationStack`。 - 跨 Tab 跳转通过 `AppRouter.select` 切换 Tab。 - 需要从首页或全局入口进入订单核销时,优先使用 `AppRouter.selectOrders(entry:)` 或 `AppRouter.routeToOrderVerification(scannedCode:)`。 - Tab 内跳转通过当前 Tab 的 `RouterPath.navigate` 或扩展后的 `AppRoute` 处理。 - 普通业务子页面默认隐藏 TabBar;只有确有产品需求时,才在 `AppRoute` 策略中单独放开。 - 不要把扫码入口加入 `AppTab`;它不是业务 Tab,只是主界面的全局动作入口。 - 真实业务页面接入后,应同步补充该模块文档和单元测试。