feat: 初始化 ChatOne 管理后台前端
基于 React + Vite + Ant Design Pro 搭建登录、动态菜单、布局主题与数据总览,并补充按菜单整理的 UI 设计稿。 Co-authored-by: Cursor <cursoragent@cursor.com>
110
docs/ui/README.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# ChatOne Admin UI 图目录
|
||||
|
||||
按侧栏菜单结构组织。路径相对于 `docs/ui/`。
|
||||
|
||||
## 目录树
|
||||
|
||||
```text
|
||||
docs/ui/
|
||||
├── README.md # 本索引
|
||||
├── layout/ # 全局布局参考
|
||||
├── login/ # 登录
|
||||
├── dashboard/ # 总览
|
||||
│ ├── overview/ # 数据概览
|
||||
│ └── modules/ # 模块示意 / 地图
|
||||
├── llm/ # 大模型管理
|
||||
│ ├── list/ # 模型列表(含用量抽屉)
|
||||
│ ├── form/ # 新增 / 编辑模型
|
||||
│ ├── provider/ # 供应商管理
|
||||
│ ├── usage/ # 用量统计
|
||||
│ ├── usage-detail/ # 用量明细
|
||||
│ └── quota/ # 限流与配额
|
||||
└── system/ # 系统管理(待补图)
|
||||
├── user/
|
||||
├── role/
|
||||
└── permission/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 菜单 ↔ 路由 ↔ UI 图
|
||||
|
||||
| 菜单 | 建议路由 | UI 图 |
|
||||
| --- | --- | --- |
|
||||
| (布局) | — | [layout/chatone-admin-layout-ui.png](./layout/chatone-admin-layout-ui.png) |
|
||||
| 登录 | `/login` | [login/chatone-login-ui.png](./login/chatone-login-ui.png) |
|
||||
| **总览** | `/dashboard` | [dashboard/overview/…](./dashboard/overview/) |
|
||||
| └ 模块示意 | — | [dashboard/modules/…](./dashboard/modules/) |
|
||||
| **大模型管理** | `/llm` | — |
|
||||
| ├ 模型列表 | `/llm/models` | [llm/list/chatone-llm-list-ui.png](./llm/list/chatone-llm-list-ui.png) |
|
||||
| │ └ 用量抽屉 | (列表内 Drawer) | [llm/list/chatone-llm-usage-drawer-ui.png](./llm/list/chatone-llm-usage-drawer-ui.png) |
|
||||
| ├ 新增/编辑模型 | `/llm/models/create` · `/llm/models/:id/edit` | [llm/form/chatone-llm-form-ui.png](./llm/form/chatone-llm-form-ui.png) |
|
||||
| ├ 供应商管理 | `/llm/providers` | [llm/provider/chatone-llm-provider-ui.png](./llm/provider/chatone-llm-provider-ui.png) |
|
||||
| ├ 用量统计 | `/llm/usage` | [llm/usage/chatone-llm-usage-ui.png](./llm/usage/chatone-llm-usage-ui.png) |
|
||||
| ├ 用量明细 | `/llm/usage/details` | [llm/usage-detail/chatone-llm-usage-detail-ui.png](./llm/usage-detail/chatone-llm-usage-detail-ui.png) |
|
||||
| └ 限流配额 | `/llm/quota` | [llm/quota/chatone-llm-quota-ui.png](./llm/quota/chatone-llm-quota-ui.png) |
|
||||
| **系统管理** | `/system` | 待补 |
|
||||
| ├ 用户管理 | `/system/user` | `system/user/` |
|
||||
| ├ 角色管理 | `/system/role` | `system/role/` |
|
||||
| └ 权限配置 | `/system/permission` | `system/permission/` |
|
||||
|
||||
---
|
||||
|
||||
## 大模型管理:功能清单
|
||||
|
||||
### 模型列表 `/llm/models`(你点名的能力)
|
||||
|
||||
- 新增模型
|
||||
- 编辑 / 删除(含批量删除)
|
||||
- 启用 / 禁用(Switch)
|
||||
- 拖拽或排序号调整顺序
|
||||
- 筛选:供应商、状态、关键词
|
||||
- 行内查看今日 Token;入口打开用量抽屉或跳转明细
|
||||
|
||||
### 新增 / 编辑模型(子页)
|
||||
|
||||
- 基础:名称、供应商、Model ID、类型(对话 / 嵌入 / 多模态)
|
||||
- 接入:Base URL、API Key、超时、重试
|
||||
- 计费:输入/输出单价
|
||||
- 能力:上下文长度、最大输出 Token
|
||||
- 运维:排序权重、启用状态、备注
|
||||
|
||||
### 供应商管理(主流补充)
|
||||
|
||||
- 管理 OpenAI / Anthropic / 通义 / Gemini / DeepSeek / 自定义
|
||||
- 凭证配置、连通性测试、关联模型数、启停
|
||||
|
||||
### 用量统计(主流补充)
|
||||
|
||||
- KPI:今日 / 本月 Token、调用次数、预估费用
|
||||
- 趋势图、模型占比、用量排行
|
||||
|
||||
### 用量明细(你点名的明细)
|
||||
|
||||
- 按时间 / 模型 / 用户过滤
|
||||
- 输入/输出/合计 Token、耗时、状态、费用
|
||||
- 导出;可下钻单次请求详情
|
||||
|
||||
### 限流与配额(主流补充)
|
||||
|
||||
- 按模型 / 用户 / 全局:RPM、TPM、日/月 Token 配额
|
||||
- 用量进度、超额策略(拒绝 / 降级 / 告警)
|
||||
|
||||
---
|
||||
|
||||
## 建议的菜单 Mock 结构
|
||||
|
||||
```ts
|
||||
{
|
||||
name: '大模型管理',
|
||||
path: '/llm',
|
||||
icon: 'BlockOutlined',
|
||||
children: [
|
||||
{ name: '模型列表', path: '/llm/models' },
|
||||
{ name: '供应商管理', path: '/llm/providers' },
|
||||
{ name: '用量统计', path: '/llm/usage' },
|
||||
{ name: '用量明细', path: '/llm/usage/details' },
|
||||
{ name: '限流配额', path: '/llm/quota' },
|
||||
],
|
||||
}
|
||||
```
|
||||
|
After Width: | Height: | Size: 1.3 MiB |
BIN
docs/ui/dashboard/modules/chatone-dashboard-modules-map.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/ui/dashboard/overview/chatone-dashboard-overview-ui.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/ui/layout/chatone-admin-layout-ui.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
docs/ui/llm/form/chatone-llm-form-ui.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/ui/llm/list/chatone-llm-list-ui.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/ui/llm/list/chatone-llm-usage-drawer-ui.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
docs/ui/llm/provider/chatone-llm-provider-ui.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/ui/llm/quota/chatone-llm-quota-ui.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/ui/llm/usage-detail/chatone-llm-usage-detail-ui.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/ui/llm/usage/chatone-llm-usage-ui.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/ui/login/chatone-login-ui.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
718
docs/后台管理前端设计方案.md
Normal file
@@ -0,0 +1,718 @@
|
||||
# ChatOne 后台管理前端 — 设计方案
|
||||
|
||||
> 版本:v1.1
|
||||
> 适用范围:中小型后台管理系统(10~30 个业务模块,5~15 人前端团队)
|
||||
> 更新日期:2026-06-04
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计目标
|
||||
|
||||
| 维度 | 目标 |
|
||||
| ------------ | ------------------------------------------ |
|
||||
| **开发效率** | 脚手架开箱即用,CRUD 页面可快速复制模板 |
|
||||
| **可维护性** | 分层清晰、类型安全、模块边界明确 |
|
||||
| **可扩展性** | 权限、路由、菜单由后端驱动,新增模块成本低 |
|
||||
| **用户体验** | 统一布局、响应式、加载/错误状态一致 |
|
||||
| **工程质量** | 自动化 lint/test/CI,代码风格统一 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 技术选型(2026 主流方案)
|
||||
|
||||
### 2.1 推荐主栈:React 生态
|
||||
|
||||
在国内中小型后台项目中,**React 18 + Vite + TypeScript + Ant Design 5 + Zustand** 是团队规模扩大后最主流、招聘与协作成本最低的组合,参考项目包括 [Ant Design Pro](https://pro.ant.design/)、[Umi Max](https://umijs.org/)。
|
||||
|
||||
| 类别 | 选型 | 说明 |
|
||||
| ---------------- | ---------------------------------------------------- | -------------------------------------- |
|
||||
| 框架 | **React 18+** | 函数组件 + Hooks 为默认写法 |
|
||||
| 构建 | **Vite 6** | 极速 HMR,原生 ESM,Rollup 生产构建 |
|
||||
| 语言 | **TypeScript 5.x** | 严格模式,接口类型与后端对齐 |
|
||||
| 路由 | **React Router 6** | 支持动态路由、Loader/Guard 模式 |
|
||||
| 状态 | **Zustand** | 轻量、TS 友好,无样板代码 |
|
||||
| 服务端状态 | **TanStack Query (React Query)** | 请求缓存、重试、失效刷新(可选但推荐) |
|
||||
| UI 库 | **Ant Design 5** | 表格/表单/弹窗等后台组件完备 |
|
||||
| 高级组件 | **@ant-design/pro-components** | ProTable、ProForm、ProLayout 开箱即用 |
|
||||
| HTTP | **Axios** | 拦截器统一处理 Token、错误、重试 |
|
||||
| CSS | **CSS Modules + Ant Design Token** | 组件库主题 Token + 局部样式隔离 |
|
||||
| 样式方案(可选) | **Tailwind CSS** | 与 Ant Design 共存,用于布局/间距 |
|
||||
| 图标 | **@ant-design/icons** + **Iconify** | 内置图标 + 按需扩展 |
|
||||
| 工具库 | **ahooks**、**dayjs**、**lodash-es** | Hooks 工具、日期、数据处理 |
|
||||
| 表单校验 | **Ant Design Form**(内置 rules) | 声明式校验规则 |
|
||||
| 图表 | **@ant-design/charts** 或 **ECharts 5** | 与 Ant Design 风格一致 |
|
||||
| 包管理 | **pnpm** | 磁盘占用小、依赖隔离好 |
|
||||
| 代码规范 | **ESLint 9 (flat config) + Prettier + Stylelint** | 统一风格 |
|
||||
| Git 钩子 | **Husky + lint-staged + commitlint** | 提交前自动检查 |
|
||||
| 单元测试 | **Vitest + React Testing Library** | 与 Vite 同源配置 |
|
||||
| E2E 测试 | **Playwright** | 覆盖登录、核心流程 |
|
||||
| API 类型 | **openapi-typescript** 或 **swagger-typescript-api** | 由 OpenAPI 自动生成 TS 类型 |
|
||||
|
||||
### 2.2 备选栈:Vue 生态
|
||||
|
||||
若团队 Vue 经验更丰富,可选用 **Vue 3 + Vite + TypeScript + Element Plus + Pinia**,参考 [Vben Admin](https://github.com/vbenjs/vue-vben-admin)。两套方案在架构层面等价,本文以 React 主栈展开。
|
||||
|
||||
### 2.3 不推荐的选型(中小型场景)
|
||||
|
||||
| 方案 | 原因 |
|
||||
| ------------------------- | -------------------------------------------------- |
|
||||
| Next.js SSR | 后台以 SPA 为主,SSR 收益低、复杂度上升 |
|
||||
| 微前端(qiankun 等) | 模块量 < 30 时过度设计,联调与部署成本高 |
|
||||
| 自研 UI 组件库 | 投入大,Ant Design / ProComponents 已足够 |
|
||||
| Redux Toolkit(单独使用) | 中小型项目 Zustand 更轻量,除非团队已有 Redux 规范 |
|
||||
| JavaScript(无 TS) | 中大型项目维护成本显著上升 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 整体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Browser (SPA) │
|
||||
├──────────────┬──────────────────────────────────────────┤
|
||||
│ Pages │ 页面组件(列表 / 表单 / 详情 / 仪表盘) │
|
||||
├──────────────┼──────────────────────────────────────────┤
|
||||
│ Components │ 业务组件 + 通用组件(Access、PageContainer)│
|
||||
├──────────────┼──────────────────────────────────────────┤
|
||||
│ Hooks │ 可复用逻辑(useTable、useAuth、usePermission)│
|
||||
├──────────────┼──────────────────────────────────────────┤
|
||||
│ Stores │ Zustand(user / permission / app / dict)│
|
||||
├──────────────┼──────────────────────────────────────────┤
|
||||
│ Router │ 静态路由 + 动态路由(权限驱动) │
|
||||
├──────────────┼──────────────────────────────────────────┤
|
||||
│ API Layer │ 按模块划分的 API + 统一 Request 封装 │
|
||||
├──────────────┼──────────────────────────────────────────┤
|
||||
│ Utils │ 工具函数、常量、枚举、类型定义 │
|
||||
└──────────────┴──────────────────────────────────────────┘
|
||||
│
|
||||
▼ HTTP / WebSocket
|
||||
┌──────────────────┐
|
||||
│ Backend API │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
### 3.1 核心设计原则
|
||||
|
||||
1. **单向数据流**:View → Action → Store/API → View,避免组件间隐式耦合。
|
||||
2. **权限后置**:路由与按钮权限均来自后端,前端只做渲染控制。
|
||||
3. **页面薄、逻辑厚**:页面组件负责组装,业务逻辑下沉到 Hooks 和 Stores。
|
||||
4. **约定优于配置**:CRUD 页面遵循 ProComponents 模板,减少决策成本。
|
||||
|
||||
---
|
||||
|
||||
## 4. 目录结构
|
||||
|
||||
```
|
||||
chat-one-admin-web/
|
||||
├── public/ # 静态资源(favicon、静态 JSON)
|
||||
├── src/
|
||||
│ ├── api/ # API 接口(按业务模块划分)
|
||||
│ │ ├── auth.ts
|
||||
│ │ ├── user.ts
|
||||
│ │ └── types/ # 接口请求/响应类型
|
||||
│ ├── assets/ # 图片、字体等
|
||||
│ ├── components/ # 全局通用组件
|
||||
│ │ ├── Access/ # 权限控制组件
|
||||
│ │ ├── Icon/ # 图标封装
|
||||
│ │ └── ...
|
||||
│ ├── hooks/ # 自定义 Hooks
|
||||
│ │ ├── useTable.ts
|
||||
│ │ ├── useAuth.ts
|
||||
│ │ └── usePermission.ts
|
||||
│ ├── layouts/ # 布局
|
||||
│ │ ├── BasicLayout/ # 侧边栏 + 顶栏 + 内容区(ProLayout)
|
||||
│ │ │ └── index.tsx
|
||||
│ │ └── BlankLayout/ # 登录页等无框架页面
|
||||
│ │ └── index.tsx
|
||||
│ ├── pages/ # 页面(按业务模块划分,约定式路由)
|
||||
│ │ ├── login/
|
||||
│ │ │ └── index.tsx
|
||||
│ │ ├── dashboard/
|
||||
│ │ │ └── index.tsx
|
||||
│ │ ├── system/
|
||||
│ │ │ └── user/
|
||||
│ │ │ ├── index.tsx # 列表页
|
||||
│ │ │ └── components/
|
||||
│ │ │ └── UserForm.tsx
|
||||
│ │ └── exception/
|
||||
│ │ ├── 403.tsx
|
||||
│ │ └── 404.tsx
|
||||
│ ├── router/
|
||||
│ │ ├── index.tsx # 路由入口(createBrowserRouter)
|
||||
│ │ ├── routes.tsx # 静态路由(登录、404)
|
||||
│ │ ├── AuthGuard.tsx # 路由守卫(鉴权、动态路由加载)
|
||||
│ │ └── utils.ts # 菜单 → 路由转换工具
|
||||
│ ├── stores/
|
||||
│ │ ├── user.ts # 用户信息、Token
|
||||
│ │ ├── permission.ts # 动态路由、菜单
|
||||
│ │ ├── app.ts # 侧边栏折叠、主题、语言
|
||||
│ │ └── dict.ts # 数据字典缓存
|
||||
│ ├── styles/
|
||||
│ │ ├── global.css # 全局样式入口
|
||||
│ │ └── theme.ts # Ant Design 主题 Token 配置
|
||||
│ ├── utils/
|
||||
│ │ ├── request.ts # Axios 封装
|
||||
│ │ ├── auth.ts # Token 存取
|
||||
│ │ ├── storage.ts # localStorage 封装
|
||||
│ │ └── index.ts
|
||||
│ ├── App.tsx
|
||||
│ ├── main.tsx
|
||||
│ └── vite-env.d.ts
|
||||
├── .env # 公共环境变量
|
||||
├── .env.development
|
||||
├── .env.production
|
||||
├── vite.config.ts
|
||||
├── tsconfig.json
|
||||
├── eslint.config.js
|
||||
├── package.json
|
||||
└── docs/ # 项目文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 核心模块设计
|
||||
|
||||
### 5.1 认证与鉴权
|
||||
|
||||
```
|
||||
登录流程:
|
||||
用户输入账号密码
|
||||
↓
|
||||
POST /api/auth/login → 返回 accessToken + refreshToken
|
||||
↓
|
||||
存储 Token(内存 + localStorage,refreshToken 建议 httpOnly Cookie 由后端设置)
|
||||
↓
|
||||
GET /api/auth/userInfo → 用户信息 + 角色 + 权限码
|
||||
↓
|
||||
GET /api/auth/menus → 动态菜单/路由配置
|
||||
↓
|
||||
生成动态路由并注入 Router → 跳转首页
|
||||
```
|
||||
|
||||
**Token 策略(推荐):**
|
||||
|
||||
| 项目 | 方案 |
|
||||
| ------------- | ----------------------------------------------- |
|
||||
| Access Token | 短期(15~30 min),放 Authorization Header |
|
||||
| Refresh Token | 长期,httpOnly Cookie 或安全存储 |
|
||||
| 过期处理 | 401 拦截 → 尝试 refresh → 失败则跳转登录 |
|
||||
| 多 Tab | 通过 `storage` 事件或 BroadcastChannel 同步登出 |
|
||||
|
||||
**权限模型:RBAC(角色 → 权限 → 资源)**
|
||||
|
||||
- **路由级**:后端返回菜单树,前端转换为 `RouteObject[]` 动态注册。
|
||||
- **按钮级**:权限码字符串(如 `user:create`),通过 `<Access />` 组件或 `usePermission` Hook 控制。
|
||||
- **数据级**:由后端接口过滤,前端不做数据权限逻辑。
|
||||
|
||||
### 5.2 路由设计
|
||||
|
||||
```typescript
|
||||
// 静态路由(无需权限)
|
||||
const staticRoutes: RouteObject[] = [
|
||||
{ path: '/login', element: <LoginPage />, handle: { hidden: true } },
|
||||
{ path: '/404', element: <NotFoundPage />, handle: { hidden: true } },
|
||||
]
|
||||
|
||||
// 动态路由(后端驱动,示例结构)
|
||||
interface MenuRoute {
|
||||
path: string
|
||||
name: string
|
||||
component: string // 组件路径,如 'system/user/index'
|
||||
meta: {
|
||||
title: string
|
||||
icon?: string
|
||||
permissions?: string[] // 页面级权限码
|
||||
keepAlive?: boolean
|
||||
}
|
||||
children?: MenuRoute[]
|
||||
}
|
||||
```
|
||||
|
||||
**路由守卫(AuthGuard)职责:**
|
||||
|
||||
1. 未登录 → 重定向 `/login?redirect=原路径`
|
||||
2. 已登录但未加载动态路由 → 拉取菜单 → 生成路由 → 渲染 `<Outlet />`
|
||||
3. 无权限 → 403 页面
|
||||
4. 切换路由 → NProgress 进度条
|
||||
|
||||
```tsx
|
||||
// router/AuthGuard.tsx 示意
|
||||
function AuthGuard() {
|
||||
const { token } = useUserStore();
|
||||
const { routesLoaded, loadRoutes } = usePermissionStore();
|
||||
const location = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
if (token && !routesLoaded) loadRoutes();
|
||||
}, [token, routesLoaded]);
|
||||
|
||||
if (!token) return <Navigate to={`/login?redirect=${location.pathname}`} replace />;
|
||||
if (!routesLoaded) return <PageLoading />;
|
||||
|
||||
return <Outlet />;
|
||||
}
|
||||
```
|
||||
|
||||
**动态路由注入:**
|
||||
|
||||
```tsx
|
||||
// 后端 component 字段 → React.lazy 懒加载
|
||||
const modules = import.meta.glob('../pages/**/index.tsx');
|
||||
|
||||
function resolveComponent(path: string) {
|
||||
const key = `../pages/${path}/index.tsx`;
|
||||
return lazy(modules[key] as () => Promise<{ default: ComponentType }>);
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 状态管理(Zustand)
|
||||
|
||||
| Store | 职责 | 持久化 |
|
||||
| -------------------- | -------------------------------- | -------------------------------------- |
|
||||
| `useUserStore` | Token、用户信息、登录/登出 | Token → localStorage(persist 中间件) |
|
||||
| `usePermissionStore` | 动态路由、菜单树、权限码集合 | 否(每次登录重新拉取) |
|
||||
| `useAppStore` | 侧边栏状态、主题、语言、设备类型 | 部分 → localStorage |
|
||||
| `useDictStore` | 数据字典(状态枚举等) | 会话级缓存 |
|
||||
|
||||
```typescript
|
||||
// stores/user.ts 示意
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
interface UserState {
|
||||
token: string | null;
|
||||
userInfo: UserInfo | null;
|
||||
setToken: (token: string) => void;
|
||||
logout: () => void;
|
||||
}
|
||||
|
||||
export const useUserStore = create<UserState>()(
|
||||
persist(
|
||||
set => ({
|
||||
token: null,
|
||||
userInfo: null,
|
||||
setToken: token => set({ token }),
|
||||
logout: () => set({ token: null, userInfo: null }),
|
||||
}),
|
||||
{ name: 'user-store', partialize: s => ({ token: s.token }) },
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
**原则:** 只有跨页面共享的状态才进 Store;页面私有状态用 `useState`/`useReducer` 即可。服务端列表数据优先用 TanStack Query 管理。
|
||||
|
||||
### 5.4 API 层
|
||||
|
||||
```typescript
|
||||
// utils/request.ts 核心能力
|
||||
const service = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 15000 });
|
||||
|
||||
// 请求拦截:注入 Token
|
||||
// 响应拦截:统一错误码处理、Token 刷新、message 提示
|
||||
// 取消重复请求(可选,AbortController)
|
||||
// 下载文件(blob)特殊处理
|
||||
```
|
||||
|
||||
**接口组织规范:**
|
||||
|
||||
```typescript
|
||||
// api/user.ts
|
||||
export function getUserList(params: UserQuery) {
|
||||
return request.get<PageResult<UserVO>>('/users', { params });
|
||||
}
|
||||
export function createUser(data: UserCreateDTO) {
|
||||
return request.post<UserVO>('/users', data);
|
||||
}
|
||||
```
|
||||
|
||||
**与后端协作:**
|
||||
|
||||
- 统一响应格式:`{ code: number, data: T, message: string }`
|
||||
- 业务成功码约定(如 `code === 0` 或 `200`)
|
||||
- 提供 OpenAPI/Swagger 文档,前端用工具自动生成 TS 类型
|
||||
|
||||
### 5.5 布局系统
|
||||
|
||||
推荐使用 **ProLayout**(`@ant-design/pro-components`)作为基础布局:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ Logo 面包屑 / 标签页(Tabs) 用户头像 ▼ │ ← Header
|
||||
├────────┬─────────────────────────────────────────────┤
|
||||
│ │ │
|
||||
│ 侧 │ Main Content │
|
||||
│ 边 │ (Outlet + 页面缓存) │
|
||||
│ 栏 │ │
|
||||
│ │ │
|
||||
├────────┴─────────────────────────────────────────────┤
|
||||
│ 折叠按钮 │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**主流交互特性:**
|
||||
|
||||
- 侧边栏可折叠,移动端自动切换为 Drawer
|
||||
- **多标签页(Tabs)**:缓存已访问页面,支持关闭/刷新(`react-activation` 或自研 Tab + 条件渲染)
|
||||
- 面包屑导航(ProLayout 内置)
|
||||
- 全屏、主题切换(亮/暗)、国际化入口(可选)
|
||||
|
||||
```tsx
|
||||
// layouts/BasicLayout/index.tsx 示意
|
||||
<ProLayout
|
||||
title="ChatOne"
|
||||
logo="/logo.svg"
|
||||
route={{ routes: menuRoutes }}
|
||||
location={{ pathname: location.pathname }}
|
||||
menuItemRender={(item, dom) => <Link to={item.path!}>{dom}</Link>}
|
||||
>
|
||||
<TabLayout>
|
||||
<Outlet />
|
||||
</TabLayout>
|
||||
</ProLayout>
|
||||
```
|
||||
|
||||
### 5.6 通用业务组件
|
||||
|
||||
中小型项目的效率关键 — 优先使用 ProComponents,必要时二次封装:
|
||||
|
||||
#### ProTable(表格页模板)
|
||||
|
||||
```
|
||||
┌─ 搜索区(可折叠)──────────────────────────┐
|
||||
│ [关键词] [状态 ▼] [日期范围] [搜索] [重置] │
|
||||
├─ 工具栏 ────────────────────────────────────┤
|
||||
│ [+ 新增] [导出] [批量删除] │
|
||||
├─ 数据表格 ──────────────────────────────────┤
|
||||
│ ☐ 姓名 状态 创建时间 操作 │
|
||||
│ ☐ 张三 启用 2026-01-01 编辑 删除 │
|
||||
├─ 分页 ──────────────────────────────────────┤
|
||||
│ < 1 2 3 ... 10 > │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
配置驱动:`columns`、`request`(返回 `{ data, total, success }`)两个核心 props。
|
||||
|
||||
```tsx
|
||||
// pages/system/user/index.tsx 示意
|
||||
<ProTable<UserVO>
|
||||
columns={columns}
|
||||
request={async params => {
|
||||
const res = await getUserList(params);
|
||||
return { data: res.data.list, total: res.data.total, success: true };
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Access key="create" permission="user:create">
|
||||
<Button type="primary" onClick={handleCreate}>
|
||||
新增
|
||||
</Button>
|
||||
</Access>,
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
#### ProForm(表单弹窗/抽屉)
|
||||
|
||||
- 支持 `ModalForm` / `DrawerForm` 两种模式
|
||||
- Schema 驱动字段渲染(`ProFormText`、`ProFormSelect` 等)
|
||||
- 内置新增/编辑模式切换
|
||||
|
||||
#### Access(权限组件)
|
||||
|
||||
```tsx
|
||||
// components/Access/index.tsx
|
||||
interface AccessProps {
|
||||
permission: string | string[];
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function Access({ permission, children }: AccessProps) {
|
||||
const { hasPermission } = usePermission();
|
||||
if (!hasPermission(permission)) return null;
|
||||
return <>{children}</>;
|
||||
}
|
||||
```
|
||||
|
||||
### 5.7 典型 CRUD 页面模式
|
||||
|
||||
每个业务模块的标准文件:
|
||||
|
||||
```
|
||||
pages/system/user/
|
||||
├── index.tsx # 列表页(ProTable)
|
||||
├── components/
|
||||
│ └── UserForm.tsx # 新增/编辑表单(ModalForm / DrawerForm)
|
||||
└── types.ts # 页面级类型(可选)
|
||||
```
|
||||
|
||||
**列表页职责:** 组装 ProTable 配置,处理新增/编辑/删除事件。
|
||||
**表单组件职责:** 接收 `record` prop,提交成功后回调 `onSuccess`。
|
||||
|
||||
---
|
||||
|
||||
## 6. 横切关注点
|
||||
|
||||
### 6.1 错误处理
|
||||
|
||||
| 场景 | 处理方式 |
|
||||
| -------------- | ----------------------------------- |
|
||||
| 网络错误 | `message.error` 提示 + 可选重试 |
|
||||
| 401 未授权 | 刷新 Token 或跳转登录 |
|
||||
| 403 无权限 | 提示 + 停留当前页 |
|
||||
| 404 接口不存在 | 开发环境 console 详细日志 |
|
||||
| 500 服务端错误 | 友好提示,上报 Sentry(可选) |
|
||||
| 表单校验失败 | Ant Design Form 字段级红色提示 |
|
||||
| React 渲染错误 | `<ErrorBoundary>` 捕获并展示降级 UI |
|
||||
|
||||
### 6.2 加载状态
|
||||
|
||||
- **全局**:路由切换 NProgress 细条
|
||||
- **页面级**:`<Spin>`、`<Skeleton>`(首屏)
|
||||
- **按钮级**:`<Button loading={submitting}>`
|
||||
- **表格级**:ProTable 内置 `loading` 状态
|
||||
|
||||
### 6.3 国际化(可选)
|
||||
|
||||
- 使用 `react-i18next`,语言包按模块拆分
|
||||
- Ant Design `ConfigProvider` 同步切换 locale
|
||||
- 中小型项目若仅中文,可暂不引入,预留 `meta.title` 的 i18n key
|
||||
|
||||
### 6.4 主题
|
||||
|
||||
- 基于 Ant Design 5 **Design Token** + `ConfigProvider` 实现亮/暗主题
|
||||
- 主色、圆角、字体大小通过 `theme.ts` 统一管理
|
||||
- 暗色模式:`algorithm: theme.darkAlgorithm`
|
||||
|
||||
```tsx
|
||||
// App.tsx 示意
|
||||
<ConfigProvider
|
||||
locale={zhCN}
|
||||
theme={{
|
||||
algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm,
|
||||
token: { colorPrimary: '#1677ff', borderRadius: 6 },
|
||||
}}
|
||||
>
|
||||
<App />
|
||||
</ConfigProvider>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 开发规范
|
||||
|
||||
### 7.1 命名约定
|
||||
|
||||
| 类型 | 规范 | 示例 |
|
||||
| ----------- | ------------------- | ----------------------------- |
|
||||
| 组件文件 | PascalCase | `UserForm.tsx` |
|
||||
| 页面入口 | `index.tsx` | `pages/system/user/index.tsx` |
|
||||
| 自定义 Hook | camelCase,use 前缀 | `useTable.ts` |
|
||||
| API 函数 | camelCase,动词开头 | `getUserList` |
|
||||
| 常量 | UPPER_SNAKE_CASE | `TOKEN_KEY` |
|
||||
| 路由 path | kebab-case | `/system/user-list` |
|
||||
|
||||
### 7.2 组件编写规范
|
||||
|
||||
- 默认使用函数组件 + TypeScript
|
||||
- Props 使用 `interface` 或 `type` 显式声明
|
||||
- 单文件组件不超过 300 行,超出则拆分
|
||||
- 样式优先 Ant Design Token;局部样式用 CSS Modules
|
||||
- 列表渲染必须提供稳定的 `rowKey`
|
||||
- 避免在 render 中创建内联对象/函数(或使用 `useMemo`/`useCallback`)
|
||||
|
||||
### 7.3 Git 提交规范(Conventional Commits)
|
||||
|
||||
```
|
||||
feat: 新增用户管理页面
|
||||
fix: 修复 Token 刷新后路由丢失
|
||||
refactor: 重构 ProTable 搜索逻辑
|
||||
docs: 更新设计方案文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 环境配置
|
||||
|
||||
```bash
|
||||
# .env.development
|
||||
VITE_APP_TITLE=ChatOne 管理后台
|
||||
VITE_API_BASE_URL=/api
|
||||
VITE_MOCK=false
|
||||
|
||||
# .env.production
|
||||
VITE_APP_TITLE=ChatOne 管理后台
|
||||
VITE_API_BASE_URL=https://api.example.com
|
||||
```
|
||||
|
||||
**Vite 代理(开发环境):**
|
||||
|
||||
```typescript
|
||||
// vite.config.ts
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 构建与部署
|
||||
|
||||
### 9.1 构建命令
|
||||
|
||||
```bash
|
||||
pnpm dev # 本地开发
|
||||
pnpm build # 生产构建 → dist/
|
||||
pnpm preview # 预览构建产物
|
||||
pnpm lint # 代码检查
|
||||
pnpm test # 单元测试
|
||||
```
|
||||
|
||||
### 9.2 构建优化
|
||||
|
||||
| 策略 | 手段 |
|
||||
| ---------- | ------------------------------------------------------ |
|
||||
| 分包 | `manualChunks` 分离 react、antd、echarts |
|
||||
| 按需引入 | Ant Design 5 默认 Tree Shaking;ProComponents 按需导入 |
|
||||
| 路由懒加载 | `React.lazy` + `import.meta.glob` |
|
||||
| 压缩 | gzip / brotli(Nginx 层) |
|
||||
| 缓存 | 文件名带 content hash |
|
||||
| 图片 | 小图 inline,大图 CDN |
|
||||
|
||||
### 9.3 部署架构
|
||||
|
||||
```
|
||||
用户 → CDN/Nginx → 静态文件 (dist/)
|
||||
→ /api 反向代理 → 后端服务
|
||||
```
|
||||
|
||||
- SPA 需要 Nginx `try_files $uri /index.html` 配置
|
||||
- 推荐 Docker 多阶段构建,产物仅含 dist + Nginx
|
||||
|
||||
### 9.4 CI/CD 流水线
|
||||
|
||||
```
|
||||
Push/PR → ESLint + TypeCheck → Vitest → Build → Deploy (staging/prod)
|
||||
```
|
||||
|
||||
推荐 GitHub Actions 或 GitLab CI,PR 必须通过 lint 和 build。
|
||||
|
||||
---
|
||||
|
||||
## 10. 安全要点
|
||||
|
||||
| 项 | 措施 |
|
||||
| -------- | --------------------------------------------------------------- |
|
||||
| XSS | React 默认转义;`dangerouslySetInnerHTML` 必须消毒(DOMPurify) |
|
||||
| CSRF | Cookie 方案启用 CSRF Token;Token Header 方案风险较低 |
|
||||
| 敏感信息 | `.env` 不入库;生产环境变量由 CI 注入 |
|
||||
| 权限 | 前端权限仅为 UX 优化,**后端必须独立校验** |
|
||||
| 依赖安全 | 定期 `pnpm audit`,Dependabot 自动 PR |
|
||||
|
||||
---
|
||||
|
||||
## 11. 可选增强(按阶段引入)
|
||||
|
||||
| 阶段 | 能力 | 工具 |
|
||||
| ---- | ------------------ | ------------------------------- |
|
||||
| MVP | Mock 数据 | MSW (Mock Service Worker) |
|
||||
| V1.1 | 操作日志、消息通知 | WebSocket / SSE |
|
||||
| V1.2 | 错误监控 | Sentry |
|
||||
| V1.2 | 页面缓存 | react-activation |
|
||||
| V2.0 | 低代码表单 | ProForm Schema + 自研表单设计器 |
|
||||
| V2.0 | 数据大屏 | ECharts + 自适应方案 |
|
||||
|
||||
---
|
||||
|
||||
## 12. 实施路线图
|
||||
|
||||
### Phase 1 — 基础脚手架(1~2 周)
|
||||
|
||||
- [ ] 初始化 Vite + React 18 + TS 项目
|
||||
- [ ] 集成 Ant Design 5、ProComponents、Zustand、React Router
|
||||
- [ ] 实现 ProLayout 布局(侧边栏 + 顶栏 + 内容区)
|
||||
- [ ] 实现登录页 + Token 认证流程
|
||||
- [ ] Axios 封装 + 环境变量配置
|
||||
- [ ] ESLint + Prettier + Husky 配置
|
||||
|
||||
### Phase 2 — 权限与通用组件(1~2 周)
|
||||
|
||||
- [ ] 动态路由 + 菜单渲染
|
||||
- [ ] Access 权限组件 + usePermission Hook
|
||||
- [ ] 基于 ProTable / ProForm 封装业务模板
|
||||
- [ ] 多标签页(Tabs)+ 页面缓存
|
||||
- [ ] 数据字典 Store
|
||||
|
||||
### Phase 3 — 业务模块开发(持续)
|
||||
|
||||
- [ ] 按后端模块迭代 CRUD 页面
|
||||
- [ ] Dashboard 仪表盘
|
||||
- [ ] 完善错误处理与边界场景
|
||||
|
||||
### Phase 4 — 质量与上线(1 周)
|
||||
|
||||
- [ ] 核心流程 E2E 测试
|
||||
- [ ] 构建优化 + CI/CD
|
||||
- [ ] 部署文档 + 运维手册
|
||||
|
||||
---
|
||||
|
||||
## 13. 参考资源
|
||||
|
||||
| 资源 | 链接 |
|
||||
| -------------- | -------------------------------- |
|
||||
| React 官方文档 | https://react.dev |
|
||||
| Vite 官方文档 | https://vite.dev |
|
||||
| Ant Design 5 | https://ant.design |
|
||||
| Ant Design Pro | https://pro.ant.design |
|
||||
| ProComponents | https://procomponents.ant.design |
|
||||
| Zustand | https://zustand.docs.pmnd.rs |
|
||||
| ahooks | https://ahooks.js.org |
|
||||
| TanStack Query | https://tanstack.com/query |
|
||||
|
||||
---
|
||||
|
||||
## 附录 A:Vue 技术栈映射表
|
||||
|
||||
| React 主栈 | Vue 等价 |
|
||||
| ----------------- | ----------------------- |
|
||||
| React 18 | Vue 3 |
|
||||
| Zustand | Pinia |
|
||||
| React Router 6 | Vue Router 4 |
|
||||
| Ant Design 5 | Element Plus |
|
||||
| ProComponents | 自研 ProTable / ProForm |
|
||||
| ahooks | VueUse |
|
||||
| 函数组件 + Hooks | `<script setup>` |
|
||||
| `<Access />` 组件 | `v-permission` 指令 |
|
||||
|
||||
---
|
||||
|
||||
## 附录 B:关键依赖版本参考
|
||||
|
||||
```json
|
||||
{
|
||||
"react": "^18.3",
|
||||
"react-dom": "^18.3",
|
||||
"react-router-dom": "^6.28",
|
||||
"antd": "^5.22",
|
||||
"@ant-design/pro-components": "^2.8",
|
||||
"@ant-design/icons": "^5.5",
|
||||
"zustand": "^5.0",
|
||||
"@tanstack/react-query": "^5.62",
|
||||
"axios": "^1.7",
|
||||
"ahooks": "^3.8",
|
||||
"dayjs": "^1.11",
|
||||
"vite": "^6.0",
|
||||
"typescript": "^5.7",
|
||||
"vitest": "^3.0",
|
||||
"@testing-library/react": "^16.0",
|
||||
"eslint": "^9.0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_本文档将随项目演进持续更新。_
|
||||