refactor: 代码架构重构 - 提取组件、统一状态管理和数据访问层

- 新增布局组件(SidebarBrand、SidebarUser、SidebarNavItem)
- 新增通用UI组件(EmptyState、StatusBadge、TagInput、SearchBar)
- 新增全局状态管理(UserContext)
- 新增自定义Hooks(usePageState、useNavigation)
- 新增统一数据访问层(src/services/api.js)
- 新增常量配置(constants/pages.js、constants/storageKeys.js)
- 样式文件模块化,拆分页面特定样式
- 更新README文档,添加组件和使用说明
- 同步OpenSpec规范到主specs目录
This commit is contained in:
2026-03-20 10:19:31 +08:00
parent f2e0ec047e
commit 56c08a34ff
27 changed files with 1812 additions and 199 deletions

View File

@@ -0,0 +1,49 @@
# Data Service Layer Specification
## Purpose
提供统一的数据访问接口层,将数据访问逻辑与静态数据文件分离,便于后续对接真实 API。
## Requirements
### Requirement: 统一数据访问接口
系统 SHALL 提供 api 服务对象,包含按功能模块划分的数据访问方法,作为所有数据访问的统一入口。
#### Scenario: api.user 模块提供用户信息访问
- **WHEN** 调用 api.user.getInfo()
- **THEN** 系统返回用户信息对象(包含 name、avatar、role 等字段)
#### Scenario: api.skills 模块提供技能数据访问
- **WHEN** 调用 api.skills.list()
- **THEN** 系统返回所有技能列表数组
#### Scenario: api.skills 支持按 ID 查询单个技能
- **WHEN** 调用 api.skills.getById(skillId)
- **THEN** 系统返回对应 ID 的技能对象,若不存在则返回 undefined
#### Scenario: api.conversations 模块提供会话数据访问
- **WHEN** 调用 api.conversations.list()
- **THEN** 系统返回所有会话列表数组
#### Scenario: api.conversations 支持按场景获取聊天内容
- **WHEN** 调用 api.conversations.getScene(sceneName)
- **THEN** 系统返回对应场景的 HTML 内容字符串
#### Scenario: api.logs 模块支持筛选查询
- **WHEN** 调用 api.logs.list(filters)
- **THEN** 系统根据 filters 参数(用户、类型、状态)筛选并返回日志列表
### Requirement: 数据层与静态文件分离
系统 SHALL 将数据访问逻辑与静态数据文件分离,便于后续对接真实 API。
#### Scenario: API 层内部调用静态数据文件
- **WHEN** 调用 api 模块的任何方法
- **THEN** 系统从对应的 data/*.js 文件读取并返回数据
#### Scenario: API 层支持数据转换
- **WHEN** 静态数据结构与页面需求不一致
- **THEN** 系统在 API 层进行数据转换,返回页面所需的格式
#### Scenario: API 层提供一致的返回格式
- **WHEN** 调用 API 层方法
- **THEN** 系统返回符合约定格式的数据(如对象、数组),无论底层存储格式如何

View File

@@ -0,0 +1,52 @@
# Modular Styles Specification
## Purpose
提供模块化的样式文件组织结构,将页面特定样式从全局样式文件中拆分到独立的页面样式文件中,提高代码的可维护性。
## Requirements
### Requirement: 样式文件按页面拆分
系统 SHALL 将页面特定样式从 global.scss 中拆分到独立的页面样式文件中,按功能组织。
#### Scenario: 工作台样式独立文件
- **WHEN** 系统包含 _console.scss 文件
- **THEN** 该文件包含工作台相关的所有样式(聊天、技能市场、日志查询、定时任务、项目管理等)
#### Scenario: 管理台样式独立文件
- **WHEN** 系统包含 _admin.scss 文件
- **THEN** 该文件包含管理台相关的所有样式(总览、部门管理、用户管理、项目管理等)
#### Scenario: 开发台样式独立文件
- **WHEN** 系统包含 _developer.scss 文件
- **THEN** 该文件包含开发台相关的所有样式(我的技能、技能编辑、开发文档等)
#### Scenario: 首页样式独立文件
- **WHEN** 系统包含 _home.scss 文件
- **THEN** 该文件包含首页相关的所有样式
### Requirement: global.scss 作为样式主入口
系统 SHALL 保持 global.scss 作为样式主入口文件,导入所有样式模块。
#### Scenario: global.scss 导入设计系统模块
- **WHEN** global.scss 文件被加载
- **THEN** 系统按顺序导入 _variables.scss、_mixins.scss、_base.scss、_components.scss、_layout.scss
#### Scenario: global.scss 导入页面样式模块
- **WHEN** global.scss 文件被加载
- **THEN** 系统导入 pages/_console.scss、pages/_admin.scss、pages/_developer.scss、pages/_home.scss
#### Scenario: 通用样式保留在主文件中
- **WHEN** 样式属于通用组件(按钮、表单、表格、状态标签等)
- **THEN** 该样式保留在 _components.scss 或 _layout.scss 中,不移动到页面样式文件
### Requirement: 页面样式文件组织结构
系统 SHALL 在 src/styles/pages/ 目录下按页面组织样式文件,每个文件包含对应页面的所有特定样式。
#### Scenario: 页面样式文件命名规范
- **WHEN** 创建页面样式文件
- **THEN** 文件名使用 _<page-name>.scss 格式(如 _console.scss、_admin.scss
#### Scenario: 页面样式文件内容结构
- **WHEN** 查看页面样式文件
- **THEN** 该文件包含页面特定的布局、组件、状态等样式,使用清晰的注释分节

View File

@@ -0,0 +1,41 @@
# Reusable Components Specification
## Purpose
提供可复用的布局组件和通用 UI 组件库,用于在不同页面中保持一致的视觉呈现和交互体验。
## Requirements
### Requirement: 布局组件复用
系统 SHALL 提供可复用的布局组件,包括品牌区域、用户信息区域、导航项组件,用于在不同页面中保持一致的视觉呈现。
#### Scenario: SidebarBrand 组件渲染
- **WHEN** 页面使用 SidebarBrand 组件并传入 subtitle 属性
- **THEN** 系统显示 GrandClaw 品牌 logo 和对应的副标题文本
#### Scenario: SidebarUser 组件显示用户信息
- **WHEN** 页面使用 SidebarUser 组件
- **THEN** 系统从 UserContext 获取用户信息并显示用户头像、姓名和角色
#### Scenario: SidebarNavItem 组件支持状态切换
- **WHEN** 页面使用 SidebarNavItem 组件并传入 active 状态
- **THEN** 系统根据 active 状态应用相应的激活样式
### Requirement: 通用 UI 组件库
系统 SHALL 提供通用 UI 组件库,包括空状态组件、状态标签组件、标签输入组件、搜索栏组件,支持在多个页面中复用。
#### Scenario: EmptyState 组件显示空状态
- **WHEN** 页面使用 EmptyState 组件并传入 icon、message、description 属性
- **THEN** 系统显示居中的空状态提示,包含图标、标题和描述文本
#### Scenario: StatusBadge 组件显示不同状态
- **WHEN** 页面使用 StatusBadge 组件并传入 status 属性(如 running、stopped、warning、error
- **THEN** 系统根据 status 值应用对应的颜色样式和图标
#### Scenario: TagInput 组件支持标签增删
- **WHEN** 用户在 TagInput 组件中输入文本并按回车
- **THEN** 系统将输入内容添加为标签,并显示删除按钮
#### Scenario: SearchBar 组件提供筛选功能
- **WHEN** 页面使用 SearchBar 组件并传入搜索条件配置
- **THEN** 系统渲染对应的筛选输入框,并在用户输入时触发 onChange 回调

View File

@@ -0,0 +1,52 @@
# Unified State Management Specification
## Purpose
提供统一的状态管理方案,包括全局用户信息上下文、页面状态持久化、导航逻辑管理,确保应用状态的一致性和可维护性。
## Requirements
### Requirement: 用户信息全局上下文
系统 SHALL 使用 React Context API 提供全局用户信息上下文,确保用户数据在整个应用中保持一致。
#### Scenario: UserContext 提供用户信息
- **WHEN** 组件使用 useUserContext Hook
- **THEN** 系统返回包含用户 name、avatar、role 的用户信息对象
#### Scenario: 用户信息在多个页面同步显示
- **WHEN** 用户信息在 UserContext 中更新
- **THEN** 所有使用 UserContext 的组件自动更新显示
#### Scenario: UserContext 提供默认值
- **WHEN** 应用启动且没有提供用户信息
- **THEN** 系统使用默认用户信息name: '张三', avatar: '张', role: 'AI 产品部'
### Requirement: 页面状态持久化 Hook
系统 SHALL 提供 usePageState Hook封装页面状态持久化逻辑自动处理 localStorage 同步和主页跳转重置。
#### Scenario: usePageState 初始化从 localStorage 恢复状态
- **WHEN** 页面使用 usePageState Hook 并传入 storageKey 和 defaultPage
- **THEN** 系统从 localStorage 读取之前保存的页面状态,若无则使用 defaultPage
#### Scenario: usePageState 自动同步状态到 localStorage
- **WHEN** 调用 usePageState 返回的 setCurrentPage 函数
- **THEN** 系统更新状态并自动保存到 localStorage
#### Scenario: usePageState 处理主页跳转重置
- **WHEN** 从主页跳转到页面location.state.fromHome 为 true
- **THEN** 系统重置页面状态为默认值,并清除路由 state
#### Scenario: usePageState 提供 getPageTitle 函数
- **WHEN** 调用 usePageState 返回的 getPageTitle 函数
- **THEN** 系统根据当前页面 ID 从配置中查找并返回对应的页面标题
### Requirement: 导航逻辑 Hook
系统 SHALL 提供 useNavigation Hook统一处理页面导航和路由状态管理。
#### Scenario: useNavigation 提供页面切换函数
- **WHEN** 调用 useNavigation 返回的 navigateToPage 函数并传入目标页面 ID
- **THEN** 系统更新当前页面状态并执行相应导航逻辑
#### Scenario: useNavigation 处理带数据的页面切换
- **WHEN** 调用 navigateToPage 并传入目标页面 ID 和附加数据(如 skillId
- **THEN** 系统更新页面状态和附加数据状态