--- comet_change: weapp-capsule-safearea role: technical-design canonical_spec: openspec archived-with: 2026-06-24-weapp-capsule-safearea status: final --- # 微信小程序胶囊安全区适配设计 ## 背景 清道夫微信小程序所有页面均使用 `navigationStyle: custom` 自定义导航栏。微信小程序右上角存在系统胶囊按钮(菜单 + 关闭),在真机上会遮挡页面右上角的操作按钮(通知铃铛、新增/发布、今天、新增排班等)。 本次 change 引入全局统一的胶囊安全区组件,让 `TopBar` 右侧操作区自动避让胶囊。 ## 目标 - 提供可在任何页面/组件复用的胶囊安全区方案。 - 改造 `TopBar.vue`,使其右侧插槽内容自动避让胶囊。 - 修复首页、任务页、排班页的胶囊遮挡问题。 - 保持 H5/App 等非微信环境下的正常显示(graceful fallback)。 ## 非目标 - 不调整底部 tabBar 结构。 - 不改页面整体布局风格。 - 不处理胶囊以外的系统 UI(如灵动岛、底部横条)。 - 不做横屏/旋转后的实时安全区重算(后续可单独优化)。 ## 组件设计 ### `CapsuleSafeArea.vue` 新增 `src/components/common/CapsuleSafeArea.vue`。 #### 职责 计算微信小程序胶囊按钮所需的最小右侧安全宽度,并以 wrapper 形式给默认 slot 内容添加左侧间距。 #### 算法 ``` safeWidth = screenWidth - menuButton.left + 8px ``` - `screenWidth` 来自 `uni.getSystemInfoSync().screenWidth` - `menuButton.left` 来自 `uni.getMenuButtonBoundingClientRect().left` - `8px` 为额外缓冲,避免按钮紧贴胶囊 #### 平台回退 - 微信小程序:使用上述动态计算值。 - H5 / App / 其他平台:返回 `0`,布局保持不变。 - API 调用失败:使用基于 `screenWidth` 的保守估算值兜底(约为屏幕宽度的 28%,覆盖常见 iPhone/Android 胶囊宽度)。 #### API ```vue ``` 组件仅提供默认 slot,不暴露 props。内部使用 `:style="{ marginLeft: `${safeWidth}px` }"` 作用在包裹层上。 ### `TopBar.vue` 改造 修改 `src/components/common/TopBar.vue`: - 右侧 `` 外层自动包裹 ``。 - 页面只需正常填充 `