## Context admin2-components 是管理后台组件库,位于 `src/framework/sideMenu/`。组件需要: - 基于 antd@6 Menu 实现三级菜单(antd 原生支持内嵌三级) - 实现全局手风琴展开(最多同时展开一个分支,避免滚动条过长) - 响应式固定模式(窄屏下覆盖式抽屉 + 遮罩,仅移动端生效) - 受控组件模式,菜单数据由外部注入 详细行为规范见 `openspec/docs/old-refactors/side-menu/` 下的 spec.md、adr.md、task.md。 ## Goals / Non-Goals **Goals:** - 实现 P0:基础三级菜单 + 全局手风琴展开 - 实现 P1:响应式固定模式 + 遮罩 **Non-Goals:** - P2 自定义滚动条、P3 动效细节留作后续迭代 - 不实现菜单数据请求(由宿主提供已合并的树结构) - PC 端不启用覆盖模式(固定模式仅移动端生效) ## Decisions ### 1. 三级菜单采用 antd 原生实现 **决定**:利用 antd@6 Menu 的 `items` + `children` 嵌套结构,支持 `key > label > children > key > label > children` 三级结构。 **原因**:antd@6 已原生支持多级菜单展开,自定义第三级增加了不必要的复杂度。 ### 2. 手风琴逻辑为全局互斥 **决定**:在 `onOpenChange` 中实现全局互斥——当用户展开一个新分支时,关闭之前展开的分支。 **原因**:避免多分支同时展开导致滚动条过长,影响导航效率。 **实现**:维护单一 `openKeys` 数组,展开时用新 key 替换数组。 ### 3. 响应式固定模式仅移动端生效,使用样式自定义覆盖 **决定**: - 移动端(断点 `< lg`):侧边栏以 `position: fixed` 悬浮覆盖在内容之上,配合半透明遮罩 - PC 端:侧边栏固定在内容左侧,不覆盖 **原因**:使用 Drawer 组件会增加复杂性,且 PC 端不需要覆盖效果。 **实现**:使用 antd Layout.Sider 的 `breakpoint` 检测断点,配合 CSS 媒体查询控制覆盖样式。 ### 4. 组件 Props 设计 ```typescript interface CSideMenuProps { title: string; // 顶区标题 tree: MenuTree; // 合并后的菜单树 collapsed: boolean; // 是否收起 curActivePaneKey?: string | number; // 当前选中键 panesOnShelf?: Array<{ key: string }>; // 已打开页签列表 onClickMenuItem: (item: MenuItem) => void; onSetMenuCollapse: (collapsed: boolean | void) => void; } ``` ### 5. 统一组件导出入口 **决定**:创建 `src/index.ts` 作为组件库的统一导出入口。 **结构**: ```typescript export { CSideMenu } from './framework/sideMenu/CSideMenu'; // 后续组件陆续添加 ``` ### 6. example 极简结构 **决定**:example 保持极简,仅作为组件演示用途。 **结构**: ``` example/ ├── App.tsx # 组件列表页 ├── main.tsx # 入口 ├── index.css # 全局样式 └── pages/ └── side-menu/ └── SideMenuPage.tsx # 组件示例页 ``` **原因**:极简结构减少维护成本,重点在组件本身,Playwright 测试也依赖此示例。 ### 7. vitest 测试文件放在 test 文件夹 **决定**:组件的 vitest 测试文件放在 `test/unit/` 目录。 **结构**: ``` test/ ├── setup.ts └── unit/ └── CSideMenu.test.tsx ``` ## Risks / Trade-offs | Risk | Mitigation | |------|------------| | 全局手风琴限制了多分支展开的灵活性 | 当前业务场景以导航效率优先,后续可扩展为可配置 | | 移动端覆盖模式可能影响内容区交互 | 遮罩层 `z-index` 正确设置,确保点击遮罩可关闭侧栏 | ## Open Questions 无。所有决策已确认。