feat: 重构前端为企业 Admin 后台布局,引入 React Router 路由
- 引入 React Router v7 (Declarative mode) 实现 SPA 路由 - 重构 Layout 为 Header + 侧边栏 + 内容区的企业 Admin 布局 - 新增侧边栏菜单组件,支持折叠/展开,状态持久化到 localStorage - 新增示例页面:仪表盘、用户管理、系统设置、404 - 菜单配置与路由统一为单一数据源 (menu.tsx) - Vite code splitting 新增 vendor-router 组 - 更新 DEVELOPMENT.md 和 README.md 文档
This commit is contained in:
2
openspec/changes/refactor-frontend-layout/.openspec.yaml
Normal file
2
openspec/changes/refactor-frontend-layout/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-20
|
||||
95
openspec/changes/refactor-frontend-layout/design.md
Normal file
95
openspec/changes/refactor-frontend-layout/design.md
Normal file
@@ -0,0 +1,95 @@
|
||||
## Context
|
||||
|
||||
当前前端为单页面应用,`app.tsx` 直接渲染 Header + Content,无路由、无侧边栏。技术栈为 React 19 + TDesign React + TanStack Query + Vite。后端使用 Bun.serve,已支持 SPA fallback(无扩展名路径返回 index.html)。
|
||||
|
||||
目标:重构为经典企业 Admin 后台布局,引入路由,支持多页面导航。
|
||||
|
||||
约束:
|
||||
- 前端样式开发优先使用 TDesign 组件和 CSS tokens,禁止内联 style、硬编码色值
|
||||
- 新增代码需编写完善测试
|
||||
- 后端无需改动
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 引入 React Router v7 (Declarative mode) 实现 SPA 路由
|
||||
- 实现企业 Admin 后台布局:Header + 侧边栏 + 内容区
|
||||
- 侧边栏支持折叠/展开,状态持久化到 localStorage
|
||||
- 路由定义与菜单配置统一为单一数据源
|
||||
- 提供示例页面(仪表盘、用户管理、系统设置、404)
|
||||
|
||||
**Non-Goals:**
|
||||
- 不实现路由守卫/权限控制(预留接口但不启用)
|
||||
- 不实现懒加载(页面少,暂不需要)
|
||||
- 不实现面包屑导航
|
||||
- 不实现用户认证
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 路由方案:React Router v7 Declarative mode
|
||||
|
||||
**选择**:`react-router` v7,使用 Declarative mode(`BrowserRouter` + `Routes` + `Route`)
|
||||
|
||||
**理由**:
|
||||
- v7 统一了 `react-router` 和 `react-router-dom`,单包导入
|
||||
- Declarative mode 满足当前需求,无需 framework mode 的文件系统路由
|
||||
- 社区成熟,文档完善
|
||||
|
||||
**替代方案**:
|
||||
- TanStack Router:类型安全强,但较新、API 变动风险
|
||||
- 自实现:零依赖但功能有限,扩展成本高
|
||||
|
||||
### 2. Routes 定义位置:独立文件
|
||||
|
||||
**选择**:抽离为 `src/web/routes.tsx`,`app.tsx` 引用
|
||||
|
||||
**理由**:
|
||||
- 路由增删时改动范围小,不污染 app.tsx
|
||||
- 便于后续扩展路由守卫、懒加载
|
||||
|
||||
### 3. 侧边栏折叠按钮位置:Header 左侧
|
||||
|
||||
**选择**:折叠按钮放在 Header 左侧,Sidebar 不使用 Menu 的 operations prop
|
||||
|
||||
**理由**:
|
||||
- Sidebar 折叠变窄后,底部按钮变小且易被忽略
|
||||
- Header 上的按钮始终可见且易触达
|
||||
- 符合 Ant Design Pro 等主流企业后台习惯
|
||||
|
||||
### 4. 页面标题来源:复用 menu label
|
||||
|
||||
**选择**:Header 页面标题直接使用 `menu.tsx` 中的 `label` 字段
|
||||
|
||||
**理由**:
|
||||
- 简单直接,侧边栏标签即页面标题
|
||||
- 如需差异化,后续加 `title` 字段即可
|
||||
|
||||
### 5. Layout 嵌套:保留嵌套结构
|
||||
|
||||
**选择**:`Layout > (Header + Layout > (Aside + Content))`
|
||||
|
||||
**理由**:
|
||||
- 为 Footer 预留位置,将来加 Footer 无需重构
|
||||
- 符合 TDesign 官方组合导航布局示例
|
||||
|
||||
### 6. Vite code splitting:react-router 单独分组
|
||||
|
||||
**选择**:新增 `vendor-router` 组,包含 `react-router`
|
||||
|
||||
**理由**:
|
||||
- 路由库独立于 React 核心,更新节奏不同
|
||||
- 便于缓存隔离
|
||||
|
||||
### 7. 菜单与路由数据源:menu.tsx
|
||||
|
||||
**选择**:`src/web/menu.tsx` 定义菜单项配置,Sidebar 和 Routes 共同引用
|
||||
|
||||
**理由**:
|
||||
- 单一数据源,保证菜单项和路由同步
|
||||
- 便于类型安全(`as const`)
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **路由与菜单配置一致性**:需人工保证 `menu.tsx` 与 `routes.tsx` 中 Route 定义一致 → 测试覆盖路由跳转和菜单点击
|
||||
- **CSS 类名迁移影响**:`.dashboard-*` → `.app-*` 可能影响测试选择器 → 全局搜索确认影响范围,更新测试
|
||||
- **React Router v7 新版本风险**:v7 较新,可能存在未发现的 bug → 使用成熟 API(BrowserRouter/Routes/Route),避免实验性特性
|
||||
36
openspec/changes/refactor-frontend-layout/proposal.md
Normal file
36
openspec/changes/refactor-frontend-layout/proposal.md
Normal file
@@ -0,0 +1,36 @@
|
||||
## Why
|
||||
|
||||
当前前端为单页面应用,仅有 Header + Content 的简单布局,无路由、无侧边栏,页面结构单一,无法支撑企业级 Admin 后台的多页面导航需求。作为 Bun 全栈应用模板,需要提供更完善的前端布局范例,便于使用者在此基础上扩展业务页面。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 引入 React Router v7 (Declarative mode) 实现前端 SPA 路由
|
||||
- 重构 Layout 为经典企业 Admin 后台布局:Header + 侧边栏 + 内容区
|
||||
- 新增侧边栏菜单组件,支持折叠/展开,折叠状态持久化到 localStorage
|
||||
- 新增多个示例页面(仪表盘、用户管理、系统设置、404)
|
||||
- 将路由定义与菜单配置统一为单一数据源,保证两者同步
|
||||
- 新增 `react-router` 依赖,Vite code splitting 单独分组
|
||||
|
||||
**BREAKING**: 原 `app.tsx` 的 Content 内容迁移至 Dashboard 页面;CSS 类名 `.dashboard-*` 变更为 `.app-*`
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `frontend-routing`: 前端 SPA 路由能力,基于 React Router v7,支持多页面导航、路由匹配、404 处理
|
||||
- `admin-layout`: 企业 Admin 后台布局能力,Header + 侧边栏 + 内容区,侧边栏可折叠
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `app-constants`: 新增 localStorage key `"sidebar.collapsed"` 用于持久化侧边栏折叠状态
|
||||
|
||||
## Impact
|
||||
|
||||
- 新增依赖:`react-router`
|
||||
- 新增目录:`src/web/pages/`、`src/web/components/Sidebar/`
|
||||
- 新增文件:`src/web/routes.tsx`、`src/web/menu.tsx`、`src/web/hooks/use-sidebar-collapsed.ts`
|
||||
- 修改文件:`src/web/app.tsx`(重构 Layout)、`src/web/main.tsx`(+ BrowserRouter)、`src/web/styles.css`(布局样式重写)
|
||||
- 修改配置:`vite.config.ts`(code splitting 新增 vendor-router 组)
|
||||
- 更新文档:`DEVELOPMENT.md`、`README.md`
|
||||
- 新增测试:Sidebar 组件测试、各页面测试、test-utils 增强
|
||||
- 后端无需改动(SPA fallback 已支持)
|
||||
@@ -0,0 +1,138 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 企业 Admin 后台布局
|
||||
|
||||
系统 SHALL 实现 Header + 侧边栏 + 内容区的企业 Admin 后台布局,使用 TDesign Layout 组件。
|
||||
|
||||
#### Scenario: 布局结构
|
||||
|
||||
- **WHEN** 用户访问应用
|
||||
- **THEN** 系统 SHALL 渲染包含 Header、Aside、Content 的 Layout 结构
|
||||
|
||||
#### Scenario: Layout 嵌套结构
|
||||
|
||||
- **WHEN** 布局渲染
|
||||
- **THEN** 系统 SHALL 使用嵌套 Layout 结构:`Layout > (Header + Layout > (Aside + Content))`
|
||||
|
||||
### Requirement: Header 布局
|
||||
|
||||
Header SHALL 包含折叠按钮、页面标题、主题切换控件。
|
||||
|
||||
#### Scenario: Header 左侧折叠按钮
|
||||
|
||||
- **WHEN** Header 渲染
|
||||
- **THEN** 系统 SHALL 在左侧显示侧边栏折叠/展开按钮
|
||||
|
||||
#### Scenario: Header 页面标题
|
||||
|
||||
- **WHEN** Header 渲染
|
||||
- **THEN** 系统 SHALL 显示当前路由对应的页面标题(从 menu 获取)
|
||||
|
||||
#### Scenario: Header 右侧主题切换
|
||||
|
||||
- **WHEN** Header 渲染
|
||||
- **THEN** 系统 SHALL 在右侧显示主题切换 RadioGroup(系统/明亮/黑暗)
|
||||
|
||||
### Requirement: 侧边栏菜单
|
||||
|
||||
系统 SHALL 提供侧边栏菜单组件(Sidebar),使用 TDesign Menu 组件,支持折叠/展开。
|
||||
|
||||
#### Scenario: 侧边栏渲染菜单项
|
||||
|
||||
- **WHEN** 侧边栏渲染
|
||||
- **THEN** 系统 SHALL 根据 `menu.tsx` 渲染所有菜单项
|
||||
|
||||
#### Scenario: 菜单项点击导航
|
||||
|
||||
- **WHEN** 用户点击菜单项
|
||||
- **THEN** 系统 SHALL 使用 React Router 的 `navigate` 跳转到对应路径
|
||||
|
||||
#### Scenario: 菜单项激活状态
|
||||
|
||||
- **WHEN** 当前路由与菜单项路径匹配
|
||||
- **THEN** 系统 SHALL 高亮显示该菜单项
|
||||
|
||||
### Requirement: 侧边栏折叠
|
||||
|
||||
侧边栏 SHALL 支持折叠/展开,折叠状态持久化到 localStorage。
|
||||
|
||||
#### Scenario: 侧边栏折叠交互
|
||||
|
||||
- **WHEN** 用户点击 Header 左侧的折叠按钮
|
||||
- **THEN** 系统 SHALL 切换侧边栏折叠状态
|
||||
|
||||
#### Scenario: 侧边栏折叠宽度
|
||||
|
||||
- **WHEN** 侧边栏折叠
|
||||
- **THEN** Aside 宽度 SHALL 变为 80px,Menu 仅显示图标
|
||||
|
||||
#### Scenario: 侧边栏展开宽度
|
||||
|
||||
- **WHEN** 侧边栏展开
|
||||
- **THEN** Aside 宽度 SHALL 变为 232px,Menu 显示图标和文字
|
||||
|
||||
#### Scenario: 折叠状态持久化
|
||||
|
||||
- **WHEN** 用户切换侧边栏折叠状态
|
||||
- **THEN** 系统 SHALL 将状态存储到 localStorage key `"sidebar.collapsed"`
|
||||
|
||||
#### Scenario: 折叠状态恢复
|
||||
|
||||
- **WHEN** 应用初始化
|
||||
- **THEN** 系统 SHALL 从 localStorage 读取 `"sidebar.collapsed"` 并恢复折叠状态
|
||||
|
||||
### Requirement: 侧边栏主题跟随全局
|
||||
|
||||
侧边栏 Menu 的主题 SHALL 跟随全局主题设置,不单独设置 `theme` prop。
|
||||
|
||||
#### Scenario: 侧边栏跟随全局主题
|
||||
|
||||
- **WHEN** 全局主题切换为 dark
|
||||
- **THEN** 侧边栏 SHALL 自动应用 dark 主题样式
|
||||
|
||||
### Requirement: 菜单配置单一数据源
|
||||
|
||||
系统 SHALL 在 `src/web/menu.tsx` 定义菜单项配置,包含 `value`、`label`、`path`、`icon` 字段。
|
||||
|
||||
#### Scenario: 菜单配置类型安全
|
||||
|
||||
- **WHEN** 定义菜单配置
|
||||
- **THEN** 系统 SHALL 使用 `as const` 保证字面量类型推断
|
||||
|
||||
#### Scenario: Sidebar 引用菜单配置
|
||||
|
||||
- **WHEN** Sidebar 渲染
|
||||
- **THEN** 系统 SHALL 遍历 `MENU_ITEMS` 渲染 MenuItem
|
||||
|
||||
### Requirement: 示例页面
|
||||
|
||||
系统 SHALL 提供示例页面组件:Dashboard、Users、Settings、NotFound。
|
||||
|
||||
#### Scenario: Dashboard 页面
|
||||
|
||||
- **WHEN** 用户访问 `/`
|
||||
- **THEN** 系统 SHALL 渲染 Dashboard 页面(包含原 app.tsx 的欢迎语和 /health 展示)
|
||||
|
||||
#### Scenario: Users 页面占位
|
||||
|
||||
- **WHEN** 用户访问 `/users`
|
||||
- **THEN** 系统 SHALL 渲染用户管理占位页面
|
||||
|
||||
#### Scenario: Settings 页面占位
|
||||
|
||||
- **WHEN** 用户访问 `/settings`
|
||||
- **THEN** 系统 SHALL 渲染系统设置占位页面
|
||||
|
||||
#### Scenario: NotFound 页面
|
||||
|
||||
- **WHEN** 用户访问未定义路径
|
||||
- **THEN** 系统 SHALL 渲染 404 页面,提供返回首页按钮
|
||||
|
||||
### Requirement: CSS 类名迁移
|
||||
|
||||
原 `.dashboard-*` CSS 类名 SHALL 变更为 `.app-*`。
|
||||
|
||||
#### Scenario: 布局类名
|
||||
|
||||
- **WHEN** 样式应用
|
||||
- **THEN** 系统 SHALL 使用 `.app-layout`、`.app-header`、`.app-content`、`.app-sidebar` 类名
|
||||
@@ -0,0 +1,15 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 侧边栏折叠状态 localStorage key
|
||||
|
||||
侧边栏折叠状态存储 key SHALL 为 `"sidebar.collapsed"`,不包含应用名前缀。
|
||||
|
||||
#### Scenario: 折叠状态持久化
|
||||
|
||||
- **WHEN** 用户切换侧边栏折叠状态
|
||||
- **THEN** 系统 SHALL 将状态存储到 localStorage key `"sidebar.collapsed"`
|
||||
|
||||
#### Scenario: 折叠状态读取
|
||||
|
||||
- **WHEN** 应用初始化时读取侧边栏折叠状态
|
||||
- **THEN** 系统 SHALL 从 localStorage key `"sidebar.collapsed"` 读取
|
||||
@@ -0,0 +1,57 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 前端 SPA 路由
|
||||
|
||||
系统 SHALL 使用 React Router v7 (Declarative mode) 实现前端 SPA 路由,支持多页面导航。
|
||||
|
||||
#### Scenario: 应用启动时初始化路由
|
||||
|
||||
- **WHEN** 应用启动
|
||||
- **THEN** 系统 SHALL 在 `main.tsx` 中使用 `BrowserRouter` 包裹根组件
|
||||
|
||||
#### Scenario: 路由匹配渲染对应页面
|
||||
|
||||
- **WHEN** 用户访问路径 `/`
|
||||
- **THEN** 系统 SHALL 渲染 Dashboard 页面
|
||||
|
||||
#### Scenario: 用户管理页面路由
|
||||
|
||||
- **WHEN** 用户访问路径 `/users`
|
||||
- **THEN** 系统 SHALL 渲染用户管理页面
|
||||
|
||||
#### Scenario: 系统设置页面路由
|
||||
|
||||
- **WHEN** 用户访问路径 `/settings`
|
||||
- **THEN** 系统 SHALL 渲染系统设置页面
|
||||
|
||||
#### Scenario: 未知路径返回 404 页面
|
||||
|
||||
- **WHEN** 用户访问未定义的路径(如 `/unknown`)
|
||||
- **THEN** 系统 SHALL 渲染 NotFound 页面
|
||||
|
||||
### Requirement: 路由定义独立文件
|
||||
|
||||
路由定义 SHALL 抽离为独立文件 `src/web/routes.tsx`,`app.tsx` 引用该文件。
|
||||
|
||||
#### Scenario: 路由配置集中管理
|
||||
|
||||
- **WHEN** 开发者需要新增或修改路由
|
||||
- **THEN** 系统 SHALL 在 `routes.tsx` 中统一管理所有 `<Route>` 定义
|
||||
|
||||
### Requirement: 路由守卫预留
|
||||
|
||||
系统 SHALL 预留路由守卫接口(`ProtectedRoute` 组件),但暂不实现认证逻辑。
|
||||
|
||||
#### Scenario: 路由守卫组件存在
|
||||
|
||||
- **WHEN** 需要实现认证保护
|
||||
- **THEN** 系统 SHALL 提供 `ProtectedRoute` wrapper 组件供 Routes 使用
|
||||
|
||||
### Requirement: Vite code splitting 包含路由库
|
||||
|
||||
`vite.config.ts` 的 code splitting 配置 SHALL 新增 `vendor-router` 组,包含 `react-router`。
|
||||
|
||||
#### Scenario: 路由库独立分包
|
||||
|
||||
- **WHEN** 执行生产构建
|
||||
- **THEN** `react-router` SHALL 被打包到独立的 `vendor-router` chunk 中
|
||||
56
openspec/changes/refactor-frontend-layout/tasks.md
Normal file
56
openspec/changes/refactor-frontend-layout/tasks.md
Normal file
@@ -0,0 +1,56 @@
|
||||
## 1. 依赖与配置
|
||||
|
||||
- [x] 1.1 安装 react-router 依赖
|
||||
- [x] 1.2 更新 vite.config.ts code splitting 配置,新增 vendor-router 组
|
||||
|
||||
## 2. 工具与 Hook
|
||||
|
||||
- [x] 2.1 创建 src/web/menu.tsx,定义菜单项配置
|
||||
- [x] 2.2 创建 src/web/hooks/use-sidebar-collapsed.ts,实现侧边栏折叠状态 hook
|
||||
|
||||
## 3. 页面组件
|
||||
|
||||
- [x] 3.1 创建 src/web/pages/dashboard/index.tsx,迁移原 app.tsx 内容区逻辑
|
||||
- [x] 3.2 创建 src/web/pages/users/index.tsx,实现用户管理占位页面
|
||||
- [x] 3.3 创建 src/web/pages/settings/index.tsx,实现系统设置占位页面
|
||||
- [x] 3.4 创建 src/web/pages/404/index.tsx,实现 404 页面
|
||||
|
||||
## 4. 侧边栏组件
|
||||
|
||||
- [x] 4.1 创建 src/web/components/Sidebar/index.tsx,实现侧边栏菜单组件
|
||||
|
||||
## 5. 路由配置
|
||||
|
||||
- [x] 5.1 创建 src/web/routes.tsx,定义所有路由
|
||||
|
||||
## 6. 根组件重构
|
||||
|
||||
- [x] 6.1 重构 src/web/app.tsx,实现 Header + Aside + Content 布局
|
||||
- [x] 6.2 修改 src/web/main.tsx,添加 BrowserRouter 包裹
|
||||
|
||||
## 7. 样式更新
|
||||
|
||||
- [x] 7.1 更新 src/web/styles.css,迁移 .dashboard-* 为 .app-*,新增布局样式
|
||||
|
||||
## 8. 测试工具增强
|
||||
|
||||
- [x] 8.1 增强 tests/web/test-utils.tsx,提供 renderWithProviders 函数
|
||||
|
||||
## 9. 组件测试
|
||||
|
||||
- [x] 9.1 创建 tests/web/components/Sidebar/index.test.tsx
|
||||
- [x] 9.2 创建 tests/web/routes/dashboard.test.tsx
|
||||
- [x] 9.3 创建 tests/web/routes/users.test.tsx
|
||||
- [x] 9.4 创建 tests/web/routes/settings.test.tsx
|
||||
- [x] 9.5 创建 tests/web/routes/404.test.tsx
|
||||
- [x] 9.6 更新 tests/web/App.test.tsx 适配 BrowserRouter
|
||||
|
||||
## 10. 文档更新
|
||||
|
||||
- [x] 10.1 更新 DEVELOPMENT.md,更新技术栈表格、组件树、目录结构说明
|
||||
- [x] 10.2 更新 README.md,更新技术栈表格、项目结构说明
|
||||
|
||||
## 11. 质量保障
|
||||
|
||||
- [x] 11.1 运行 bun run check 确保类型检查、lint、测试通过
|
||||
- [x] 11.2 运行 bun run build 验证构建成功
|
||||
Reference in New Issue
Block a user