From 50b8de6c31de9876576a0f2f169d8207490d5fa0 Mon Sep 17 00:00:00 2001 From: Tevin <tingquanren@163.com> Date: Wed, 08 Apr 2026 15:51:24 +0800 Subject: [PATCH] config: 更新 Claude Code 本地设置 --- openspec/docs/old-refactors/side-menu/spec.md | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 207 insertions(+), 0 deletions(-) diff --git a/openspec/docs/old-refactors/side-menu/spec.md b/openspec/docs/old-refactors/side-menu/spec.md new file mode 100644 index 0000000..28aa707 --- /dev/null +++ b/openspec/docs/old-refactors/side-menu/spec.md @@ -0,0 +1,207 @@ +# 侧栏菜单(Side Menu)— 规格说明 + +## 1. 概述与范围 + +### 1.1 业务职能 + +- 本组件承担**整站(管理后台)的主导航**:在典型布局中**常驻于视口左侧**,是用户从任意业务页跳转到其它功能模块的**一级入口**(与顶栏、中部多标签内容区共同构成「壳」;侧栏负责「去哪」,内容区负责「看什么」)。 +- 菜单项与**可打开的业务页**一一对应(具体路由、嵌入页、权限裁剪由宿主与数据层决定,见 §2、§6)。 +- 窄屏下仍承担同一职能,仅**呈现形态**改为覆盖式抽屉(§3.2),不改变「主导航」定位。 + +### 1.2 职责(能力概要) + +在壳布局中提供**可折叠的纵向导航**:展示多级菜单树,标识当前选中项与已打开页签,在窄屏下以「全宽抽屉式」呈现并支持遮罩关闭。 + +### 1.3 非目标 + +- 不在本组件内实现路由注册、权限过滤、菜单数据请求(由宿主提供树数据)。 +- 不重复阐述 **antd@6** 已提供的通用能力(`Layout.Sider`、`Menu` 内联/深色主题等以官方文档为准)。 + +### 1.4 技术栈 + +实现目标:**React**,**antd@6**(自 v4.3 升级场景);SPEC 仅描述与壳子及自定义逻辑相关的约定。 + +--- + +## 2. 数据模型 + +### 2.1 菜单树(由宿主传入) + +- 顶层为**分组**列表(一级),每项包含子列表 `items`(二级及以下)。 +- 每个节点至少具备: + - **标识**:`id`(优先)或 `key`,在整棵树中用于选中、展开状态;比较时按字符串语义相等即可。 + - **展示名**:`name`。 + - **可选类型**:`type`,用于图标映射;常见取值见 §2.3;未匹配时使用默认图标。 +- **子节点**:若存在非空 `items`,则该节点为**可展开**的父节点;否则为**叶子**(可点击打开页)。 +- **层级**:须支持**至少三级**(一级分组 → 二级可展开节点 → 叶子),以合并逻辑与侧栏子菜单的递归结构为准;§2.3 所述静态配置多为「分组 → 叶子」二级,运行时以合并后的 `tree` 为准。 + +### 2.2 宿主提供的运行态 + +- **当前选中页键**:与某叶子或节点的 `id`/`key` 对应,用于菜单选中高亮及「子树选中」样式。 +- **已打开页签列表**:用于在叶子上显示「已打开」样式(例如某 `pane.key` 与节点 `id` 一致则标记)。 + +### 2.3 静态路径配置(数据结构约定) + +以下描述**静态路径骨架**的常见 JSON 形态,便于对齐字段语义(存放文件名与路径由项目自定)。 + +- 根对象可含 `projectName`(工程标识)、`treePaths`(分组数组)、`hiddenPaths`(**不在侧栏展示**的页面映射,供其它入口按 `pageName` 打开;侧栏可不渲染此项,但应知晓 `id` 可能为负数等特殊键,以免选中/标签逻辑异常)。 +- **`treePaths` 每一项(一级分组)**:`id`、`name`、`items`。 +- **`items` 内叶子(典型)**:`id`、`name`、`pageName`、`path`;可选 `type`(如 `chart`、`setting` 等)。若某节点再含非空嵌套 `items`,则为中间层,须按 §4.2 三级规则处理。 +- 合并后叶子可带业务/权限相关字段(由接口与宿主侧合并逻辑写入,如 `forbid`、`show` 在合并阶段已过滤);**侧栏只消费合并后的 `tree`**,不负责请求。 + +### 2.4 合并与权限(宿主职责,侧栏不实现) + +- 典型流程:接口返回的分组/条目与静态骨架在**宿主或数据层**合并,并按 `forbid`、`show` 等规则剔除不可见项(具体函数名与模块划分由项目自定)。 +- 合并后 `type` 缺省时常规范为 `'normal'`(与图标默认分支一致)。 +- 若沿用「静态配置 + 接口权限」形态,须在**宿主层**复现或等价实现合并;侧栏 SPEC 仍以「输入树已最终可用」为前提。 + +### 2.5 点击叶子时传递给宿主的载荷 + +- 「打开页」回调应传入**完整菜单项对象**(至少包含宿主开页所需字段,如 `id`、`name`、`path`、`pageName`),以便宿主增加标签、拼接构建版本等查询参数等与既有开页逻辑一致。 + +--- + +## 3. 布局与响应式 + +### 3.1 常规(宽屏) + +- 侧栏为固定**内容区宽度**的纵向区域(目标约 210px,含与滚动条占位相关的补偿时可由实现决定,但须避免内容被系统滚动条挤压错位)。 +- 侧栏可处于**展开**或**收起**状态;收起宽度为 0(不占可视内容区),由宿主控制 `collapsed`。 + +### 3.2 断点与「固定」模式 + +- 当视口宽度低于约定断点(与 `lg` 量级一致)时,进入**固定(fixed)**布局模式: + - 侧栏行为接近**覆盖在内容之上的抽屉**:展开时占满可视宽度(或产品约定的全宽表现),并与宿主协作设置 `collapsed`。 + - 宿主在断点变化时应被通知以同步折叠状态(例如 `onSetMenuCollapse(broken)` 语义)。 + +### 3.3 顶区标题 + +- 侧栏顶部展示站点/产品标题(由宿主传入);区域宽度与下方菜单内容区对齐(含滚动条占位策略一致)。 + +--- + +## 4. 交互与状态(逻辑) + +### 4.1 一级分组 + +- 一级分组由 antd `SubMenu` 承载常规展示;若当前选中项落在该分组子树内,该分组须有**可区分的选中子树**样式(例如高亮父级)。 + +### 4.2 展开态(openKeys,受控扩展) + +- **内层 Menu**:在 `onOpenChange` 中实现**同级手风琴**——用户**新展开**某节点时,**同一父级下**已展开的**兄弟**节点须关闭;用户主动收起时以传入的 `openKeys` 为准。(非 antd 默认,须自实现。) +- **自定义子菜单层**(三级等):展开某一 key 时从 `openKeys` 移除其**兄弟** key 再并入当前 key;关闭时仅移除该 key。展开/关闭后须在 DOM/动画稳定后**重新检测**是否需滚动条(允许短延迟,如 ~300–500ms)。 + +### 4.3 点击叶子 + +- **宽屏**:立即调用宿主的「打开页」回调。 +- **固定模式**:先通知宿主**收起**侧栏,再在**短延迟**(约 300ms,与侧栏动画匹配)后调用「打开页」回调,避免动画与导航冲突。 + +### 4.4 滚动与自定义滚动条(逻辑) + +- 当菜单内容高度超过可视区域超过约 10px 时,视为**需要纵向滚动**,并切换「需滚动」状态(供 §5 样式与 §4.5 遮罩联动)。 +- 提供**自定义滚动条轨道与滑块**(非仅依赖系统滚动条):滑块高度与可视比例成正比;拖拽滑块与菜单 `scrollTop` **双向同步**;支持鼠标拖拽与触摸拖拽;拖拽期间由 React 状态标记**滚动拖拽中**(与 §5 动效、§4.5 遮罩一致)。 +- 窗口 **resize** 时须更新滚动条占位宽度及滚动需求检测。 + +### 4.5 遮罩(逻辑) + +- 在**固定模式且侧栏展开**时显示遮罩;点击遮罩应通知宿主收起(若在滚动拖拽中则不应因遮罩点击关闭)。 +- 自定义滚动条拖拽过程中遮罩与 §5.3「滚动拖拽」、§5.2 遮罩层级一致;点击关闭语义以 §4.5 与 §5 联合为准。 + +--- + +## 5. 自定义样式与动效 + +本节描述**自研叠加层**(非 antd 默认 token 可完整表达)的视觉与动效契约;实现可用任意 class 命名,但须复现状态、时长与层级关系。 + +### 5.1 顶区标题条(Logo 区) + +- 固定高度(目标约 50px)、全宽、**主色实底**、白字加粗;过长文案 **ellipsis**。 +- 与下方滚动区纵向衔接,滚动区高度为「剩余视高」(如 `calc(100% - 顶区高度)`)。 + +### 5.2 固定模式与遮罩(非滚动拖拽) + +- **固定定位**:侧栏容器覆盖视口;**全宽展开**时使用独立 class 将宽度拉满。 +- **遮罩层**:默认隐藏;在固定模式且侧栏展开时显示,**半透明深色**(如 rgba 黑 ~0.2),铺满视口,**低于侧栏内容**的 z-index,点击触发收起(逻辑见 §4.5)。 + +### 5.3 自定义滚动条(宽屏,约 ≥992px) + +**出现与布局** + +- **不需要滚动**时:自绘轨道**不可见**(如 `opacity: 0`)且 **`pointer-events: none`**,避免挡操作。 +- **需要滚动**时:菜单内容区增加**右侧内边距**(目标约 20px)为轨道留位;轨道贴侧栏**右缘**固定列宽(目标约 20px),**深底**与侧栏深色主题协调;轨道整体**淡入**可用 `transition`,并带 **delay**(与菜单展开/重排动画衔接,目标约 **0.3s 延迟 + 0.2s 过渡**量级)。 +- 实际滚动仍由内容区 `overflow-y: scroll` 承担;自绘滑块仅**视觉与拖拽**同步 `scrollTop`。 + +**滑块(thumb)** + +- 默认较**细**(目标宽约 6px)、居中偏右、**圆角**条、色值深于轨道;`background` / `width` / `margin` 变化带过渡(目标约 **0.3s**),hover 时**加宽、变色**(目标宽约 12px、更高对比浅色)。 +- **滚动区域 hover**(非必须点在滑块上):thumb 可先进入**中间色**态,再与滑块自身 hover 的**最亮**态区分层次。 + +**拖拽中(与 §4.4 `scrollDraging` 等状态对应)** + +- 容器进入「滚动拖拽」class 时:thumb 保持**展开宽度与高亮主色**,且对 **background(及必要时相关属性)关闭 transition(0s)**,避免跟手时出现颜色/过渡迟滞。 +- 同时 **遮罩**若仍处于显示态:变为**全透明**,仍占位或可点,**提高 z-index**,使拖拽过程中交互意图与固定模式下的实心遮罩区分(与 §4.5 逻辑一致:不阻挡拖拽结束后的常规点击语义由实现统一)。 + +### 5.4 菜单深色主题上的局部覆盖(节选) + +- 一级 `SubMenu` 标题在 active/open/子树选中等态下**背景提亮**(rgba 白低不透明度阶梯)。 +- 叶子项:`hover` / `selected` 背景与右侧 **Caret** 箭头显隐、颜色变化带**短过渡**;**已打开**叶子的箭头常显,未打开则隐藏,逻辑见数据模型,样式与 §4 选中态一致。 + +### 5.5 可访问性与降级 + +- 若产品无要求,可暂不实现 `prefers-reduced-motion`;迁移时建议评估:至少保证**键盘可达性**不与自定义滚动条 `pointer-events` 冲突。 +- 窄于 §5.3 断点时以系统滚动或全宽抽屉为主,自绘轨道可隐藏(与 §3.2 一致)。 + +--- + +## 6. 与宿主应用的契约 + +### 6.1 输入(概念) + +| 概念 | 说明 | +|------|------| +| 菜单树 | 见 §2.1~§2.4 | +| 标题 | 顶区展示文案(常与接口站点名同源;与静态配置里的 `projectName` 可能不同源) | +| 是否收起 | 宿主控制折叠 | +| 当前选中键 | 与节点 `id`/`key` 对齐;常见为**数值型菜单 id**(含 `hiddenPaths` 场景的负数 id) | +| 已打开页列表 | 用于叶子「已打开」样式;项上 `key` 与菜单项 `id` 一致 | + +### 6.2 输出(回调) + +| 回调语义 | 时机 | +|----------|------| +| 设置折叠 | 断点变化、用户点遮罩、叶子点击前(固定模式)等;参数可为 **boolean**(是否与断点「broken」对齐)或**无参**(切换/收起);宿主须兼容:**boolean 时设为对应折叠态,无参时按约定的切换语义处理**。 | +| 打开菜单项 | 用户点击叶子;载荷为 **§2.5** 菜单项对象;固定模式下在收起动画后再触发 | + +### 6.3 壳布局集成(建议 props 映射,命名可改) + +侧栏通常与主区域**兄弟**排列:一侧为侧栏,另一侧为 `Layout`(顶栏、多标签内容区等)。折叠状态应由宿主**单一数据源**驱动,并与顶栏等共享同一套折叠回调。 + +建议输入/输出与下列概念对齐(prop 名可重命名,语义须一致): + +| 侧栏侧(示例名) | 含义 | +|------------------|------| +| `title` | 顶区标题 | +| `tree` | 合并后的分组树 | +| `panesOnShelf` | 已打开页签列表(用于「已打开」样式) | +| `collapsed` | 是否收起 | +| `curActivePaneKey` | 当前选中页键 | +| `onClickMenuItem` | 打开/激活标签页 | +| `onSetMenuCollapse` | 折叠:支持 boolean 与无参(见 §6.2) | + +--- + +## 7. 验收 + +验收标准见 [task.md](./task.md)。 + +--- + +## 8. 修订记录 + +| 日期 | 摘要 | +|------|------| +| 2026-04-07 | 初稿,抽象侧栏菜单行为契约 | +| 2026-04-07 | 目标栈明确为 React + antd@6;验收迁至 task.md | +| 2026-04-07 | 对齐静态路径配置、壳集成与宿主合并/回调语义;去除具体仓库路径 | +| 2026-04-07 | 新增 §5 自定义样式与动效(滚动条/遮罩/Logo);宿主契约顺延为 §6 | +| 2026-04-07 | 新增 §1.1 业务职能(整站主导航与壳布局中的角色) | -- Gitblit v1.9.1