# 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`),通过 `` 组件或 `usePermission` Hook 控制。 - **数据级**:由后端接口过滤,前端不做数据权限逻辑。 ### 5.2 路由设计 ```typescript // 静态路由(无需权限) const staticRoutes: RouteObject[] = [ { path: '/login', element: , handle: { hidden: true } }, { path: '/404', element: , 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. 已登录但未加载动态路由 → 拉取菜单 → 生成路由 → 渲染 `` 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 ; if (!routesLoaded) return ; return ; } ``` **动态路由注入:** ```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()( 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>('/users', { params }); } export function createUser(data: UserCreateDTO) { return request.post('/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 示意 {dom}} > ``` ### 5.6 通用业务组件 中小型项目的效率关键 — 优先使用 ProComponents,必要时二次封装: #### ProTable(表格页模板) ``` ┌─ 搜索区(可折叠)──────────────────────────┐ │ [关键词] [状态 ▼] [日期范围] [搜索] [重置] │ ├─ 工具栏 ────────────────────────────────────┤ │ [+ 新增] [导出] [批量删除] │ ├─ 数据表格 ──────────────────────────────────┤ │ ☐ 姓名 状态 创建时间 操作 │ │ ☐ 张三 启用 2026-01-01 编辑 删除 │ ├─ 分页 ──────────────────────────────────────┤ │ < 1 2 3 ... 10 > │ └─────────────────────────────────────────────┘ ``` 配置驱动:`columns`、`request`(返回 `{ data, total, success }`)两个核心 props。 ```tsx // pages/system/user/index.tsx 示意 columns={columns} request={async params => { const res = await getUserList(params); return { data: res.data.list, total: res.data.total, success: true }; }} toolBarRender={() => [ , ]} /> ``` #### 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 渲染错误 | `` 捕获并展示降级 UI | ### 6.2 加载状态 - **全局**:路由切换 NProgress 细条 - **页面级**:``、``(首屏) - **按钮级**:`