diff --git a/README.md b/README.md index 029af3e..b6687aa 100644 --- a/README.md +++ b/README.md @@ -1,1004 +1,428 @@ # GrandClaw 原型项目 -## 项目概述 +企业级AI智能助手平台前端原型,展示主要页面布局、交互流程和视觉设计。 -GrandClaw 是一个企业级AI智能助手平台的前端原型项目,主要用于展示平台的主要页面布局、交互流程和视觉设计。项目采用现代化的前端技术栈,实现了四大核心模块: +--- -- **首页**:平台入口,包含登录功能 -- **工作台**:用户与AI助手交互的主要界面,包含聊天、技能市场、日志查询、定时任务等功能 -- **管理台**:运营管理界面,包含总览、部门管理、用户管理、项目管理 -- **开发台**:技能开发界面,包含我的技能、技能编辑、开发文档等 +## ⚠️ 核心约束(必读) -## 技术栈 +> 以下约束必须严格遵守,不得违反 -### 核心框架 -- **React 19.2.4**:UI组件库 -- **React Router 7.13.1**:路由管理(使用HashRouter) -- **Vite 8.0.1**:构建工具和开发服务器 +### 项目性质 -### UI与样式 -- **react-icons 5.5.0**:图标库(Feather + FontAwesome图标集) -- **Sass 1.98.0**:CSS预处理器 -- **五层分层架构**:tokens → core → layouts → components → pages -- **BEM 命名规范**:所有组件类名遵循 `.block__element--modifier` 格式 +- **纯前端展示原型**:无后端交互,供内部开发人员参考UI界面 +- **目标**:展示页面布局、样式和组件能力 +- **交互限制**:允许轻量级交互展示(表单验证、弹框),重叠/覆盖类状态(弹框、下拉)允许简单交互切换 -### 构建优化 -- **vite-plugin-singlefile 2.3.2**:单文件打包,解决CORS问题 -- **相对路径配置**:支持直接打开HTML文件运行 -- **注意**:构建时会显示弃用警告 `WARN inlineDynamicImports option is deprecated, please use codeSplitting: false instead.`,这是由 `vite-plugin-singlefile` 插件内部使用弃用选项导致的,不影响功能,可以忽略。 +### 语言规范 -### 包管理 -- **pnpm**:高效的包管理器 - -## 项目结构 - -``` -grandclaw-archtype/ -├── dist/ # 构建输出目录(单个index.html) -├── public/ # 静态资源 -├── src/ # 源代码 -│ ├── App.jsx # 主路由配置 -│ ├── main.jsx # 应用入口 -│ ├── components/ # 组件 -│ │ ├── layout/ # 布局组件(SidebarBrand、SidebarUser、SidebarNavItem) -│ │ ├── common/ # 通用UI组件(EmptyState、StatusBadge、TagInput、SearchBar) -│ │ ├── Layout.jsx # 通用布局组件(侧边栏+主内容) -│ │ └── ListSelector.jsx # 列表选择器组件(支持单选/多选) -│ ├── contexts/ # 全局状态管理 -│ │ └── UserContext.jsx # 用户信息上下文 -│ ├── hooks/ # 自定义Hook -│ │ ├── useLocalStorage.js # localStorage状态管理Hook -│ │ ├── usePageState.js # 页面状态持久化Hook -│ │ └── useNavigation.js # 导航逻辑Hook -│ ├── constants/ # 常量定义 -│ │ ├── pages.js # 页面配置(路由、标题、图标) -│ │ └── storageKeys.js # localStorage键名常量 -│ ├── services/ # 数据访问层 -│ │ └── api.js # 统一数据访问接口 -│ ├── data/ # 模拟数据 -│ │ ├── conversations.js # 聊天场景数据 -│ │ ├── developerData.js # 开发台数据 -│ │ ├── logs.js # 日志数据 -│ │ ├── members.js # 成员数据 -│ │ ├── skills.js # 技能数据 -│ │ ├── tasks.js # 定时任务数据 -│ │ ├── adminData.js # 管理台数据(部门/用户/项目/总览/日志/模型配置) -│ │ └── configTypes.js # 模型配置类型注册表 -│ ├── pages/ # 页面组件 -│ │ ├── HomePage.jsx # 首页 -│ │ ├── LoginPage.jsx # 登录页面 -│ │ ├── ConsolePage.jsx # 工作台主页面 -│ │ ├── AdminPage.jsx # 管理台主页面 -│ │ ├── DeveloperPage.jsx # 开发台主页面 -│ │ ├── console/ # 工作台子页面 -│ │ ├── admin/ # 管理台子页面 -│ │ └── developer/ # 开发台子页面 -│ └── styles/ # SCSS样式系统(分层架构) -│ ├── tokens/ # 第1层:设计令牌 -│ │ ├── _colors.scss # 品牌色、功能色、中性色 -│ │ ├── _spacing.scss # 间距系统(4px基数) -│ │ ├── _shadows.scss # 阴影层级 -│ │ ├── _radius.scss # 圆角系统 -│ │ ├── _typography.scss # 字体、字号、字重 -│ │ ├── _z-index.scss # 层级系统 -│ │ ├── _transitions.scss # 过渡动画参数 -│ │ ├── _breakpoints.scss # 响应式断点 -│ │ ├── _mixins.scss # 可复用混入 -│ │ └── _index.scss # 统一导出 -│ ├── core/ # 第2层:核心样式 -│ │ ├── _reset.scss # CSS重置 -│ │ ├── _css-variables.scss # :root CSS变量 -│ │ ├── _base.scss # body全局样式 -│ │ └── _index.scss -│ ├── layouts/ # 第3层:布局系统 -│ │ ├── _app-shell.scss # 主框架(sidebar+header+main) -│ │ ├── _chat-layout.scss # 聊天页面布局 -│ │ ├── _admin-layout.scss # 管理台布局 -│ │ └── _index.scss -│ ├── components/ # 第4层:组件库 -│ │ ├── button/ # 按钮(.btn, .btn--primary, .btn--ghost) -│ │ ├── card/ # 卡片(.card, .card__header, .card__body) -│ │ ├── table/ # 表格(.table, .table-actions, .col-actions) -│ │ ├── form/ # 表单(.form-group, .form__input, .form__label) -│ │ ├── tag/ # 标签(.tag--running, .tag--admin) -│ │ ├── modal/ # 弹窗(.modal, .modal__overlay) -│ │ ├── toast/ # 提示(.toast--success, .toast--error) -│ │ ├── pagination/ # 分页 -│ │ ├── empty-state/ # 空状态 -│ │ ├── switch/ # 开关 -│ │ ├── skill-card/ # 技能卡片 -│ │ ├── nav/ # 导航项 -│ │ ├── detail/ # 详情页组件 -│ │ ├── password-input/ # 密码输入框 -│ │ ├── search-bar/ # 搜索栏 -│ │ ├── stat-card/ # 统计卡片 -│ │ └── _index.scss # 统一导出 -│ ├── pages/ # 第5层:页面特有样式 -│ │ ├── _console.scss # 工作台特有组件 -│ │ ├── _admin.scss # 管理台特有组件 -│ │ ├── _developer.scss # 开发台特有组件 -│ │ ├── _home.scss # 首页特有组件 -│ │ └── _index.scss -│ └── global.scss # 主入口文件(仅 @use,无直接样式) -├── index.html # HTML入口文件 -├── package.json # 项目配置和依赖 -├── vite.config.js # Vite配置 -└── pnpm-lock.yaml # 依赖锁定文件 -``` - -## 开发指南 - -### 环境要求 -- Node.js 18+ -- pnpm(推荐)或 npm - -### 安装依赖 -```bash -pnpm install -``` - -### 开发模式 -```bash -pnpm dev -# 访问 http://localhost:5173 -``` - -### 构建生产版本 -```bash -pnpm build -# 生成 dist/index.html(单个HTML文件) -``` - -### 预览生产构建 -直接双击 `dist/index.html` 文件,或在浏览器中打开。 - -## 核心功能 - -### 1. 首页 -- 平台品牌展示 -- 导航入口(工作台、开发台、管理台) -- 登录入口 - -### 2. 登录页面 -- 用户名/邮箱登录 -- 密码输入 -- 验证码(防爆破) -- 记住我功能 -- 忘记密码链接 - -### 3. 工作台(Console) -- **聊天界面**:支持多种聊天场景(欢迎页、普通对话、技能调用、文件上传) -- **技能市场**:浏览已上架技能、订阅技能(仅展示已上架技能) -- **我的技能**:管理已订阅技能,支持启用/禁用、配置变量、取消订阅(NEW) -- **技能配置**:为已订阅技能配置 key-value 变量(NEW) -- **日志查询**:支持按用户、类型、状态筛选 -- **定时任务**:管理定时任务,支持启用/禁用,查看任务详情 -- **项目管理**:成员列表,增加成员 -- **账号管理**:个人信息和密码修改 - -### 4. 管理台(Admin) -- **运营总览**:平台运营指标卡片(用户总数、部门数量、项目数量、今日调用)、异常/待办事项提醒、最近操作日志 -- **审核管理**:版本审核列表与详情、下架审核列表与详情 -- **部门管理**:部门列表,支持搜索筛选、新增、编辑、启用/禁用、删除确认 -- **用户管理**:用户列表,支持搜索筛选(关键词/部门/状态)、新增、编辑、启用/禁用、删除确认,角色区分(管理员/开发者/成员) -- **项目管理**:项目列表,支持搜索筛选、新增、编辑、启用/禁用、删除确认 -- **模型配置**:管理平台的默认模型接入配置,支持多组配置(OpenAI兼容接口、智算管理平台等类型),可切换生效配置,生效中配置不可编辑/删除,配置类型创建后不可修改 -- **日志查询**:全局系统日志查询,支持多维度筛选(关键词、用户、部门、类型、状态、时间范围) - -### 5. 开发台(Developer) -- **总览**:开发者指标卡片(我的技能总数、已上架、开发中、待审核)、待审核项目列表、最近动态 -- **我的技能**:技能列表,支持关键词搜索(内部名称/内部描述)、状态筛选(开发中/已上架/下架审核中/已下架)、分页,支持下架(需要先撤回审核中的版本)、删除(已上架需要先下架),仅展示开发者内部信息 -- **技能详情**:四段式布局 - 1) 概览卡片(内部信息:内部名称、状态、编辑按钮);2) 当前生效版本卡片(商店展示效果预览,分类作为第一个标签显示);3) 版本历史卡片(普通卡片布局,展示版本号、状态、日期、版本说明、发布信息预览、操作按钮,无下载按钮);4) 管理操作卡片 -- **创建技能**:简化表单 - 仅内部技能名称、内部技能描述(明确标注仅供开发者管理使用) -- **编辑内部信息**:独立页面编辑内部技能名称/内部技能描述(明确标注不影响商店展示) -- **上传新版本**:增强表单 - 版本说明区域 + 发布信息区域(技能发布名称、技能发布描述、分类、标签、图标),非首版本默认继承当前生效版本的值 -- **开发文档**:技能开发相关文档 -- **开发者设置**:开发者账号信息 - -#### 重要数据结构变更说明 -- **开发者内部信息**:内部名称、内部描述 - 仅供开发者管理,与商店展示完全无关,可随时修改无需审核 -- **版本发布信息**:发布名称、发布描述、分类、标签、图标 - 存储在版本中,随版本审核通过后生效,修改必须发布新版本 -- **技能商店展示**:完全从当前生效版本取发布信息,确保任何商店内容变更都经过版本审核 -- **分类与标签展示**:分类始终作为第一个标签显示,与普通标签一起展示 - -#### 按钮禁用规则 -基于 `hasPendingReview` 标志和技能状态控制操作按钮可用性: -- **上传新版本按钮**:`status === 'unlisting' || status === 'unlisted' || hasPendingReview === true` 时禁用 -- **下架技能按钮**:`hasPendingReview === true` 时禁用 -- **删除技能按钮**:`status === 'published' || status === 'unlisting' || hasPendingReview === true` 时禁用 - -#### 撤回审核按钮样式 -- **按钮类型**:警告按钮(橙色) -- **按钮类名**:`btn btn-warning btn-sm` -- **按钮图标**:逆时针旋转图标(FiRotateCcw) -- **按钮文案**:"撤回审核" -- **展示位置**:版本历史卡片中审核中版本的操作区域 - -## 路由结构 - -项目使用 **HashRouter**,所有路由基于哈希路径,支持直接打开HTML文件运行。 - -### 主要路由 -``` -/ # 首页 -/login # 登录页面 -/console # 工作台 -/admin # 管理台 -/developer # 开发台 -``` - -### 路由配置(App.jsx) -```jsx -import { HashRouter as Router, Routes, Route } from 'react-router-dom'; - - - - } /> - } /> - } /> - } /> - } /> - - -``` - -## 通用组件 - -### 布局组件 - -#### SidebarBrand 品牌区域 -侧边栏顶部的品牌展示组件。 - -```jsx -import { SidebarBrand } from '../components/layout/SidebarBrand.jsx'; - - -``` - -#### SidebarUser 用户信息 -侧边栏底部的用户信息展示组件,使用全局用户上下文。 - -```jsx -import { SidebarUser } from '../components/layout/SidebarUser.jsx'; - - navigate('/account')} - wrapperClassName="sidebar-user" - infoClassName="sidebar-user-info" - nameClassName="sidebar-user-name" - roleClassName="sidebar-user-role" -/> -``` - -#### SidebarNavItem 导航项 -侧边栏导航菜单项组件。 - -```jsx -import { SidebarNavItem } from '../components/layout/SidebarNavItem.jsx'; - -} - label="智能助手" - active={currentPage === 'chat'} - onClick={() => setCurrentPage('chat')} - itemClassName="sidebar-nav-item" - iconClassName="sidebar-nav-icon" - textClassName="sidebar-nav-text" -/> -``` - -### 通用UI组件 - -#### EmptyState 空状态 -用于展示空列表或无数据状态的组件。 - -```jsx -import EmptyState from '../components/common/EmptyState.jsx'; - -} - title="暂无数据" - description="当前没有可显示的内容" -/> -``` - -#### Modal 弹窗 -用于展示确认操作的弹窗组件,支持自定义标题和内容。 - -```jsx -import Modal from '../components/common/Modal.jsx'; - - - 确定要删除这个任务吗? - -``` - -#### Toast 消息提示 -用于展示操作结果的消息提示组件,支持成功、错误、警告、信息四种类型。 - -```jsx -import Toast from '../components/common/Toast.jsx'; - - setShowToast(false)} -/> -``` - -**支持的类型:** -- `success` - 成功(绿色) -- `error` - 错误(红色) -- `warning` - 警告(黄色) -- `info` - 信息(蓝色) - -#### StatusBadge 状态标签 -用于显示状态(成功、失败、警告等)的标签组件。 - -```jsx -import StatusBadge from '../components/common/StatusBadge.jsx'; - - - - - -``` - -#### TagInput 标签输入 -支持输入标签的输入框组件。 - -```jsx -import TagInput from '../components/common/TagInput.jsx'; - - -``` - -#### SearchBar 搜索框 -通用的搜索输入框组件。 - -```jsx -import SearchBar from '../components/common/SearchBar.jsx'; - - -``` - -### 列表组件 - -#### ListSelector 列表选择器 -通用的列表选择器组件,支持单选和多选模式。 - -```jsx -import ListSelector from '../components/ListSelector.jsx'; - - {}} // 清除已选回调 -/> -``` - -## 状态管理 - -### 全局状态 - -#### UserContext 用户信息上下文 -全局用户信息状态,通过 `UserProvider` 提供给整个应用。 - -```jsx -import { UserProvider, useUserContext } from '../contexts/UserContext.jsx'; - -// 在 App.jsx 中包裹 - - - - -// 在组件中使用 -function Component() { - const { user } = useUserContext(); - return
{user.name}
; -} -``` - -### 自定义 Hooks - -#### usePageState 页面状态持久化 -处理页面切换状态的 Hook,支持 localStorage 持久化和主页跳转重置。 - -```javascript -import { usePageState } from '../hooks/usePageState.js'; -import { CONSOLE_PAGES } from '../constants/pages.js'; -import { CONSOLE_KEYS } from '../constants/storageKeys.js'; - -const { currentPage, setCurrentPage } = usePageState({ - storageKey: CONSOLE_KEYS.CURRENT_PAGE, - defaultPage: 'chat', - pageTitles: CONSOLE_PAGES, -}); -``` - -#### useNavigation 导航逻辑 -封装页面导航逻辑的 Hook,支持携带额外数据。 - -```javascript -import { useNavigation } from '../hooks/useNavigation.js'; - -const { navigateToPage, extraData } = useNavigation(setCurrentPage); - -// 导航到指定页面 -navigateToPage('skills', { skillId: '1' }); - -// 获取导航传递的数据 -const skillId = extraData.skillId; -``` - -#### useLocalStorage localStorage 状态管理 -同步组件状态到 localStorage 的 Hook。 - -```javascript -import { useLocalStorage } from '../hooks/useLocalStorage.js'; - -const [value, setValue] = useLocalStorage('myKey', 'defaultValue'); -setValue('newValue'); // 自动同步到 localStorage -``` - -### 导航状态持久化策略 -每个主要页面(工作台、管理台、开发台)都有独立的`localStorage`键: - -```javascript -// 工作台 -localStorage.setItem('console_currentPage', 'chat'); -localStorage.setItem('console_currentScene', 'welcome'); - -// 管理台 -localStorage.setItem('admin_currentPage', 'overview'); - -// 开发台 -localStorage.setItem('developer_currentPage', 'overview'); -localStorage.setItem('developer_currentSkillId', '1'); -``` - -### 主页跳转 vs 刷新浏览器 -通过`location.state.fromHome`区分两种导航来源: - -```javascript -// 从主页跳转:显示默认页面 -useEffect(() => { - if (location.state?.fromHome) { - setCurrentPage('chat'); // 默认页面 - navigate('.', { replace: true, state: {} }); // 清除state - } -}, [location.state]); - -// 刷新浏览器:从localStorage恢复 -const [currentPage, setCurrentPage] = useState(() => { - return localStorage.getItem('console_currentPage') || 'chat'; -}); -``` - -## 样式系统 - -### 分层架构 - -样式采用五层架构,依赖方向自上而下:`tokens → core → layouts → components → pages` - -``` -┌─────────────────────────────────────────┐ -│ pages/ 页面特有组件,仅覆盖模式 │ ← 最上层 -├─────────────────────────────────────────┤ -│ components/ 可复用UI组件库,BEM命名 │ -├─────────────────────────────────────────┤ -│ layouts/ 布局系统(shell/chat/admin) │ -├─────────────────────────────────────────┤ -│ core/ 重置、CSS变量、body样式 │ -├─────────────────────────────────────────┤ -│ tokens/ 设计令牌(颜色/间距/阴影...) │ ← 最底层 -└─────────────────────────────────────────┘ -``` - -### 第1层:Tokens(设计令牌) - -所有设计决策集中定义,禁止在组件或页面中硬编码值。 - -```scss -// src/styles/tokens/_colors.scss -$primary: #3B82F6; -$primary-dark: #2563EB; -$success: #10B981; -$danger: #EF4444; -$text-1: #1E293B; -$text-3: #94A3B8; - -// src/styles/tokens/_spacing.scss -$spacing-1: 4px; -$spacing-2: 8px; -$spacing-4: 16px; - -// src/styles/tokens/_typography.scss -$font-size-base: 14px; -$font-weight-semibold: 600; -``` - -**使用方式:** 通过 `@use` 引入,直接使用变量名。 - -```scss -@use '../../tokens' as *; - -.my-component { - color: $text-1; - padding: $spacing-4; - font-weight: $font-weight-semibold; -} -``` - -**同时提供 CSS 变量**(core 层定义),供运行时和 JSX 内联场景使用: - -```scss -// core/_css-variables.scss 自动从 tokens 生成 :root 变量 -:root { - --color-primary: #{$primary}; - --color-text-1: #{$text-1}; -} - -// JSX 中可通过 style 使用 -
-``` - -### 第2层:Core(核心样式) - -包含 CSS 重置、`:root` CSS 变量定义、body 全局样式。无业务逻辑。 - -``` -core/ -├── _reset.scss # * { margin:0; padding:0; box-sizing:border-box; } -├── _css-variables.scss # :root { --color-primary: ...; } -├── _base.scss # body { font-family, color, background } -└── _index.scss # @forward 所有 core 模块 -``` - -### 第3层:Layouts(布局系统) - -页面骨架布局,不包含具体UI组件样式。 - -| 文件 | 职责 | +| 场景 | 语言 | |------|------| -| `_app-shell.scss` | 主框架:sidebar + header + main-content + 响应式 | -| `_chat-layout.scss` | 聊天页:chat-sidebar + chat-content + conversation-list | -| `_admin-layout.scss` | 管理台:admin-sidebar + admin-nav + member-selection | +| 交流、文档、注释、提交信息 | **中文** | +| 代码命名(变量、函数、类、文件) | **英文** | -**关键类名:** -- `.layout` / `.app-shell` — 主布局容器 -- `.sidebar` — 侧边栏 -- `.main-content` — 主内容区 -- `.header` — 顶部栏 -- `.page-content` — 页面内容区 +### 技术约束 -### 第4层:Components(组件库) +| 约束项 | 规则 | +|--------|------| +| UI库 | **禁止引入**,使用当前SCSS样式方案 | +| TypeScript | **禁止引入**,使用JavaScript | +| ESLint | **禁止引入** | +| 包管理器 | **pnpm**(不允许npm、yarn) | +| 测试 | **不构建**,使用`pnpm build`验证打包即可 | +| 性能优化 | **不做**,保持vite-plugin-singlefile单文件打包 | +| 安全防御 | **不做**,eval/dangerouslySetInnerHTML按需使用 | -每个组件一个目录,内部 `_index.scss` 包含该组件的完整样式。 +### 复用优先原则 ``` -components/ -├── button/_index.scss -├── card/_index.scss -├── table/_index.scss -├── form/_index.scss -├── tag/_index.scss -├── modal/_index.scss -├── toast/_index.scss -└── _index.scss # @forward 所有组件 +新增代码时优先级: +1. 复用已有样式(src/styles) +2. 复用已有组件(src/components) +3. 复用已有页面布局模式 +4. 最后才创建新代码 ``` -**组件目录创建规则:** -``` -components/ -└── {component-name}/ - └── _index.scss # 必须存在,包含组件全部样式 -``` - -### 第5层:Pages(页面特有样式) - -仅包含**页面独有的组件样式**,不放可复用组件。 +### Git提交规范 ``` -pages/ -├── _console.scss # 聊天消息、欢迎区、输入框等 -├── _admin.scss # 总览统计、异常列表等 -├── _developer.scss # 技能概览卡片、版本历史卡片等 -├── _home.scss # 首页英雄区、特性卡片等 -└── _index.scss -``` +格式: 类型: 简短描述 -### 主入口文件 +类型可选: +- feat: 新功能 +- fix: 修复 +- refactor: 重构 +- docs: 文档 +- style: 格式 +- test: 测试 +- chore: 构建/工具 -`global.scss` 是纯入口文件,**仅包含 `@use` 语句**,无任何直接样式定义: +多行描述: 空行后加详细说明 -```scss -// src/styles/global.scss -@use 'tokens' as *; -@use 'core' as *; -@use 'layouts' as *; -@use 'components' as *; -@use 'pages/console' as *; -@use 'pages/admin' as *; -@use 'pages/developer' as *; -@use 'pages/home' as *; +示例: +feat: 添加技能详情页面 + +- 新增技能详情布局 +- 集成版本历史展示 ``` --- -## 样式开发规范 +## 快速开始 -### BEM 命名规范 - -所有组件类名必须遵循 BEM 格式:`.block__element--modifier` - -```scss -// Block — 组件根节点 -.card { } - -// Element — 组件内部元素,用双下划线连接 -.card__header { } -.card__body { } -.card__footer { } - -// Modifier — 变体/状态,用双连字符连接 -.card--flat { } -.card--elevated { } -.btn--primary { } -.btn--danger { } -.tag--running { } -.tag--admin { } +```bash +pnpm install # 安装依赖 +pnpm build # 验证打包(不运行pnpm dev,会挂起流程) ``` -**JSX 对应写法:** -```jsx -
-
- 标题 -
-
- 内容 -
-
+--- +## 技术栈 + +| 技术 | 版本 | 用途 | +|------|------|------| +| React | 19.2.4 | UI框架 | +| React Router (HashRouter) | 7.13.1 | 路由管理 | +| Vite | 8.0.1 | 构建工具 | +| react-icons | 5.5.0 | 图标库 | +| Sass | 1.98.0 | 样式预处理 | +| vite-plugin-singlefile | 2.3.2 | 单文件打包 | + +--- + +## 项目结构 + +``` +src/ +├── components/ # 组件库 +│ ├── common/ # 通用组件 (Modal, Toast, EmptyState等) +│ ├── layout/ # 布局组件 (SidebarBrand, SidebarUser等) +│ ├── Layout.jsx # 主布局组件 +│ └── ListSelector.jsx # 列表选择器 +│ +├── contexts/ # 全局状态 (UserContext) +├── hooks/ # 自定义Hook (usePageState, useNavigation) +├── constants/ # 常量配置 (pages, storageKeys) +├── services/ # 数据访问层 (api.js) +├── data/ # 模拟数据 +│ +├── pages/ # 页面组件 +│ ├── console/ # 工作台子页面 +│ ├── admin/ # 管理台子页面 +│ └── developer/ # 开发台子页面 +│ +├── styles/ # 样式系统(五层架构) +│ ├── tokens/ # 设计令牌(颜色、间距等) +│ ├── core/ # 核心样式(重置、CSS变量) +│ ├── layouts/ # 布局系统 +│ ├── components/ # 组件样式 +│ ├── pages/ # 页面样式 +│ └── global.scss # 主入口 +│ +├── App.jsx # 路由配置 +└── main.jsx # 应用入口 +``` + +--- + +## 核心模块 + +| 模块 | 路由 | 功能 | +|------|------|------| +| 首页 | `/` | 品牌展示、登录入口 | +| 工作台 | `/console` | 聊天、技能市场、定时任务、项目管理 | +| 管理台 | `/admin` | 部门/用户/项目管理、模型配置 | +| 开发台 | `/developer` | 技能开发、版本管理 | + +--- + +## 样式规范 + +### 五层架构 + +``` +tokens → core → layouts → components → pages +``` + +| 层级 | 职责 | 规则 | +|------|------|------| +| tokens/ | 设计令牌 | **禁止硬编码**颜色、间距、字号 | +| core/ | 核心样式 | CSS重置、全局变量 | +| layouts/ | 布局系统 | 页面骨架,不含具体组件 | +| components/ | 组件样式 | 可复用,**BEM命名** | +| pages/ | 页面样式 | 页面独有,不放置可复用样式 | + +### BEM命名规范 + +```scss +// 格式: .block__element--modifier +.card { } +.card__header { } +.card__body { } +.btn--primary { } +.tag--running { } +``` + +```jsx +// JSX对应 +
+
标题
+
- 运行中 ``` -### 组件文件内部结构 - -每个组件的 `_index.scss` 按以下顺序组织: +### 引用规则 ```scss -// 1. 依赖引入 -@use '../../tokens' as *; +// tokens层:无依赖 +@use 'colors' as *; -// 2. Block — 组件根节点 -.btn { } - -// 3. Elements — 内部元素 -.btn__icon { } - -// 4. Modifiers — 变体(按语义分组) -// 颜色变体 -.btn--primary { } -.btn--danger { } - -// 尺寸变体 -.btn--sm { } -.btn--lg { } - -// 状态变体 -.btn--loading { } - -// 5. Legacy 兼容别名(过渡期) -.text-btn { @extend .btn--ghost; } +// 其他层:依赖tokens +@use '../tokens' as *; // core、layouts +@use '../../tokens' as *; // components +@use '../tokens' as *; // pages ``` -### 新增组件开发流程 +**禁止跨层引用**(如components引用pages) -1. **确认组件层级**:属于 tokens/core/layouts/components/pages 哪一层 -2. **创建目录**:`src/styles/components/{name}/` -3. **创建 `_index.scss`**:按 BEM 结构编写样式 -4. **引入 tokens**:`@use '../../tokens' as *;` 使用设计令牌 -5. **在 `_index.scss` 中注册**:`components/_index.scss` 添加 `@forward '{name}';` -6. **在 JSX 中使用**:`className="block__element--modifier"` -7. **验证构建**:`pnpm build` +### 按钮规范 -### 新增页面样式开发流程 - -1. **优先复用组件库**:先检查 `components/` 是否已有可用组件 -2. **页面特有组件**:在 `pages/_{page}.scss` 中定义 -3. **仅放页面独有的样式**:可复用的应提取到 `components/` -4. **不硬编码值**:使用 tokens 中的变量或 CSS 变量 - -### 内联样式规则 - -**禁止使用内联 style 的场景:** -- 可复用的组件样式(按钮、卡片、表格操作列等) -- 使用 tokens 中已有变量的值 -- 多个页面/组件中重复出现的模式 - -**允许使用内联 style 的场景:** -- 各表特有的内容列宽(如 `style={{ width: '180px' }}`) -- 动态计算值(如进度条宽度 `width: 65%`) -- 聊天消息内容中的排版(通过 `dangerouslySetInnerHTML` 渲染) +| 场景 | 类名 | +|------|------| +| 主操作 | `btn btn--primary` | +| 次要操作 | `btn` | +| 表格内编辑 | `text-btn text-btn-primary` | +| 表格内删除 | `text-btn text-btn-danger` | +| 危险确认 | `btn btn--danger` | +| 警告操作 | `btn btn--warning` | ### 表格操作列规范 -表格操作列统一使用以下类名,禁止写内联样式: - ```jsx -// 表头 — 操作列宽度 -操作 // 200px -操作 // 120px -操作 // 80px +// 表头 +操作 // 200px +操作 // 120px -// 单元格 — 操作按钮容器 +// 单元格
- -// 可点击行 - ``` -### 按钮使用规范 - -| 场景 | 类名 | 颜色 | -|------|------|------| -| 主操作(确认、提交) | `btn btn--primary` | 蓝色实心 | -| 次要操作(取消、重置) | `btn` | 灰色边框 | -| 表格内编辑 | `text-btn text-btn-primary` | 蓝色文字 | -| 表格内删除/禁用 | `text-btn text-btn-danger` | 红色文字 | -| 危险操作确认 | `btn btn--danger` | 红色实心 | -| 警告操作 | `btn btn--warning` | 橙色实心 | - -### 状态标签规范 - -```jsx -// 运行状态 -运行中 -已停止 -失败 -警告 - -// 用户角色 -管理员 -成员 -开发者 -``` - -### 引用 Tokens 的方式 - -```scss -// 在组件或页面文件中 -@use '../../tokens' as *; - -// 直接使用 SCSS 变量 -.my-class { - color: $primary; - padding: $spacing-4; - border-radius: $radius-md; - font-weight: $font-weight-semibold; - box-shadow: $shadow-card; -} - -// 使用 CSS 变量(适合需要运行时切换的场景) -.my-class { - color: var(--color-primary); - background: var(--color-bg-1); -} -``` - -### 样式文件引用规则 - -```scss -// tokens 层:无依赖 -@use 'colors' as *; - -// core 层:依赖 tokens -@use '../tokens' as *; - -// layouts 层:依赖 tokens -@use '../tokens' as *; - -// components 层:依赖 tokens -@use '../../tokens' as *; - -// pages 层:依赖 tokens -@use '../tokens' as *; -``` - -**禁止**:跨层引用(如 components 直接引用 pages) - -### 响应式开发 - -使用 tokens 中定义的断点,通过 mixins 调用: - -```scss -@use '../../tokens' as *; - -@include mobile { - // <= 768px - .my-component { - flex-direction: column; - } -} - -@include tablet { - // 769px ~ 1024px -} - -@include desktop { - // >= 1025px -} -``` - -## 数据访问层 - -项目使用统一的数据访问接口 `src/services/api.js`,所有数据获取都通过 API 层进行,便于未来对接后端服务。 - -### API 使用示例 - -```javascript -import { api } from '../services/api.js'; - -// 获取技能列表 -const skills = api.skills.list(); - -// 获取单个技能详情 -const skill = api.skills.getById('1'); - -// 获取日志列表 -const logs = api.logs.list(); - -// 按条件筛选日志 -const filteredLogs = api.logs.filter({ user, type, status }); - -// 获取开发者技能 -const mySkills = api.developer.getMySkills(); - -// 获取成员列表 -const members = api.members.list(); -``` - -### API 模块结构 -- `api.user` - 用户信息 -- `api.skills` - 技能市场(列表、详情、文件、版本、图标) -- `api.conversations` - 聊天场景和对话历史 -- `api.logs` - 操作日志(列表、筛选) -- `api.developer` - 开发台数据(总览、技能、分类、文档) -- `api.members` - 项目成员 -- `api.tasks` - 定时任务 -- `api.admin` - 管理台(总览、部门、用户、项目、模型配置、全局日志) - -## 数据模拟 - -所有数据都存储在 `src/data/` 目录下的JavaScript文件中,作为静态模拟数据。API 服务层统一从这些文件读取数据。 - -### 数据文件说明 -- `conversations.js`:聊天场景和对话历史 -- `skills.js`:技能市场数据,包含技能详情(含状态:dev/published/unlisting/unlisted)、文件列表、版本历史(含状态:reviewing/approved/rejected/withdrawn、拒绝理由)、审核列表(pendingVersionReviews、pendingUnlistReviews) -- `developerData.js`:开发台数据,包含我的技能(含图标、版本审核状态、hasPendingReview标识)、技能分类、开发者总览、开发文档 -- `logs.js`:操作日志数据(成功/失败/警告状态) -- `tasks.js`:定时任务数据(包含任务配置和执行日志) -- `adminData.js`:管理台数据(部门列表、用户列表、项目列表、模型配置列表、总览指标、全局日志、可选项数据) -- `configTypes.js`:模型配置类型注册表(OpenAI兼容接口、智算管理平台等类型定义) -- `members.js`:项目成员数据 - -## 构建和部署 - -### 构建配置(vite.config.js) -```javascript -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; -import { viteSingleFile } from 'vite-plugin-singlefile'; - -export default defineConfig({ - base: './', // 相对路径,支持直接打开HTML文件 - plugins: [ - react(), - viteSingleFile() // 单文件打包 - ], -}); -``` - -### 构建产物 -运行 `pnpm build` 后生成: -- `dist/index.html`:包含所有JavaScript和CSS的单个HTML文件 -- 支持直接双击打开,无需服务器 -- 使用HashRouter,路由正常工作 - -### 部署方式 -1. **本地运行**:直接双击 `dist/index.html` -2. **静态服务器**:将 `dist/` 目录部署到任何静态文件服务器 -3. **CDN部署**:上传单个HTML文件到CDN即可 - -## 已知问题和注意事项 - -### 1. 聊天场景渲染 -- 聊天内容使用 `dangerouslySetInnerHTML` 渲染HTML字符串 -- 深度思考区域支持点击展开/折叠 -- 聊天输入框仅为展示,无实际功能 - -### 2. 浏览器兼容性 -- 需要现代浏览器(Chrome、Firefox、Safari、Edge) -- 不支持IE -- file://协议下可能存在某些限制 - -### 3. 状态持久化 -- 使用localStorage存储子页面状态 -- 清除浏览器数据会丢失导航状态 -- 不同浏览器标签页共享localStorage - -### 4. 性能考虑 -- 单个HTML文件较大,首次加载可能稍慢 -- 所有图标已通过react-icons优化,按需加载 -- SCSS样式已编译为CSS,无运行时开销 - -### 5. 构建警告 -- 构建时会显示弃用警告:`WARN inlineDynamicImports option is deprecated, please use codeSplitting: false instead.` -- 这个警告来自 `vite-plugin-singlefile` 插件内部,无法通过配置消除 -- 警告不影响功能,可以安全忽略 - -## 开发建议 - -### 添加新页面 -1. 在 `src/pages/` 目录下创建页面组件 -2. 在父页面组件(如 ConsolePage、AdminPage)中添加路由逻辑 -3. 如果需要持久化状态,添加 localStorage 逻辑 -4. 页面特有样式添加到 `src/styles/pages/_{module}.scss`(优先复用组件库) - -### 添加新组件 -1. 在 `src/components/` 目录下创建组件 -2. 在 `src/styles/components/{name}/` 下创建 `_index.scss` -3. 使用 `@use '../../tokens' as *;` 引入设计令牌 -4. 使用 BEM 命名:`.block__element--modifier` -5. 在 `src/styles/components/_index.scss` 中添加 `@forward '{name}';` - -### 修改样式 -1. **全局调整**:修改 `src/styles/tokens/` 中的令牌变量 -2. **组件调整**:修改 `src/styles/components/{name}/_index.scss` -3. **页面调整**:修改 `src/styles/pages/_{module}.scss` -4. 禁止直接修改 `global.scss`(它是纯入口文件) - -### 样式验证清单 -- [ ] 类名是否遵循 BEM 规范 -- [ ] 颜色/间距/字号是否使用 tokens 变量 -- [ ] 是否存在重复定义的样式 -- [ ] 可复用样式是否放在 `components/` 而非 `pages/` -- [ ] 表格操作列是否使用 `.col-actions` + `.table-actions` -- [ ] `pnpm build` 是否通过 +**禁止内联样式定义操作列** --- -## 更多文档 +## 组件规范 -审核审批流程的详细说明请查看:[docs/审核流程.md](docs/审核流程.md) +### 新增组件流程 + +1. 创建 `src/components/{category}/ComponentName.jsx` +2. 创建 `src/styles/components/{name}/_index.scss` +3. 使用 `@use '../../tokens' as *;` +4. 遵循BEM命名 +5. 在 `components/_index.scss` 添加 `@forward '{name}';` + +### 组件模板 + +```jsx +// components/common/Example.jsx +function Example({ title, children }) { + return ( +
+
{title}
+
{children}
+
+ ); +} +export default Example; +``` + +```scss +// styles/components/example/_index.scss +@use '../../tokens' as *; + +.example { + padding: $spacing-4; + + &__header { + font-weight: $font-weight-semibold; + color: $text-1; + } + + &__body { + color: $text-2; + } +} +``` + +### 可复用组件 + +| 组件 | 路径 | 用途 | +|------|------|------| +| Layout | `components/Layout.jsx` | 主布局(sidebar+header+main) | +| Modal | `components/common/Modal.jsx` | 确认弹窗 | +| Toast | `components/common/Toast.jsx` | 消息提示 | +| EmptyState | `components/common/EmptyState.jsx` | 空状态展示 | +| SearchBar | `components/common/SearchBar.jsx` | 搜索框 | +| StatusBadge | `components/common/StatusBadge.jsx` | 状态标签 | +| SidebarBrand | `components/layout/SidebarBrand.jsx` | 侧边栏品牌 | +| SidebarUser | `components/layout/SidebarUser.jsx` | 侧边栏用户信息 | +| SidebarNavItem | `components/layout/SidebarNavItem.jsx` | 侧边栏导航项 | + +--- + +## 路由规范 + +### 顶层路由 + +```jsx +// App.jsx + + + } /> + } /> + } /> + } /> + + +``` + +### 子页面路由 + +每个主页面内部管理子页面: + +```jsx +// ConsolePage.jsx示例 +const [currentPage, setCurrentPage] = useState('chat'); + +const renderPage = () => { + switch (currentPage) { + case 'chat': return ; + case 'skills': return ; + // ... + } +}; +``` + +### 页面配置 + +```javascript +// constants/pages.js +export const CONSOLE_PAGES = { + chat: { title: '智能助手', icon: 'FiMessageSquare' }, + skills: { title: '技能市场', icon: 'FaPuzzlePiece' }, + // ... +}; +``` + +### 新增页面流程 + +1. 在 `constants/pages.js` 添加页面配置 +2. 在父页面组件导入新页面 +3. 在 `renderPage()` 添加case分支 +4. 添加导航项(如需要) + +--- + +## 状态管理 + +### 全局状态:UserContext + +```jsx +// 使用 +import { useUserContext } from '../contexts/UserContext.jsx'; + +function Component() { + const { user } = useUserContext(); + return
{user.name}
; +} +``` + +### 页面状态持久化 + +| 模块 | localStorage键 | 默认值 | +|------|---------------|--------| +| 工作台 | `console_currentPage` | `'chat'` | +| 管理台 | `admin_currentPage` | `'overview'` | +| 开发台 | `developer_currentPage` | `'overview'` | + +### 自定义Hook + +```javascript +// usePageState - 页面状态持久化 +const { currentPage, setCurrentPage } = usePageState({ + storageKey: CONSOLE_KEYS.CURRENT_PAGE, + defaultPage: 'chat', + pageTitles: CONSOLE_PAGES, +}); + +// useNavigation - 导航逻辑 +const { navigateToPage, extraData } = useNavigation(setCurrentPage); +navigateToPage('skillDetail', { skillId: '1' }); +``` + +--- + +## 数据访问 + +所有数据通过 `src/services/api.js` 访问: + +```javascript +import api from '../services/api.js'; + +// 用户 +api.user.getInfo(); + +// 技能 +api.skills.list(); +api.skills.getById(id); + +// 开发台 +api.developer.getMySkills(); +api.developer.getOverview(); + +// 管理台 +api.admin.departments.list(); +api.admin.users.list(); +api.admin.modelConfigs.create(data); + +// 日志筛选 +api.logs.filter({ user, type, status }); +``` + +--- + +## 开发清单 + +### 新增功能前检查 + +- [ ] 是否可复用已有样式? +- [ ] 是否可复用已有组件? +- [ ] 是否可复用已有页面布局模式? + +### 代码提交前检查 + +- [ ] 类名是否遵循BEM? +- [ ] 颜色/间距是否使用tokens变量? +- [ ] 表格操作列是否使用规范类名? +- [ ] `pnpm build` 是否通过? +- [ ] 文档注释是否使用中文? +- [ ] 变量/函数命名是否使用英文? + +--- + +## 已知问题 + +| 问题 | 说明 | 处理 | +|------|------|------| +| 构建警告 | `inlineDynamicImports is deprecated` | 来自vite-plugin-singlefile,可忽略 | +| 浏览器兼容 | 不支持IE | 使用现代浏览器 | + +--- *最后更新:2026-03-26*