# m_react_admin **Repository Path**: sunnyfg/m_react_admin ## Basic Information - **Project Name**: m_react_admin - **Description**: react的管理后台,自用,简单,适合二开 - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-06-04 - **Last Updated**: 2026-09-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # m_react_admin 基于 **React 19 + Ant Design 6 + Vite** 的通用后台管理系统模板。 内置 Mock API(axios-mock-adapter),克隆后 `pnpm dev` 即可跑起来,无需后端;需要对接真实接口时关闭 Mock 开关即可。 ## 🖼 界面预览 | 登录页(角色动画) | 数据概览 | | :---: | :---: | | ![登录页](screenshots/01-login.png) | ![数据概览](screenshots/02-dashboard.png) | | 用户管理 | 菜单管理(RBAC 树) | 暗黑模式 | | :---: | :---: | :---: | | ![用户管理](screenshots/03-users.png) | ![菜单管理](screenshots/06-menus.png) | ![暗黑模式](screenshots/11-dashboard-dark.png) | ## ✨ 特性 - **RBAC 权限管理** — 服务端驱动菜单树 + 按钮权限(`hasPermission`),支持目录 / 菜单 / 按钮三种菜单类型 - **多标签页** — 懒渲染、会话持久化、关闭当前 / 其他 / 全部、刷新 - **多风格登录页** — 注册表模式,内置 `classic`(表单)与 `character`(角色动画)两种风格,可扩展、可切换 - **暗黑模式** — 圆形收缩过渡动画,主题色自适应 - **国际化** — 简中 / 繁中 / 英文三语,零依赖自研,缺 key 编译期报错;菜单名走服务端下发的 i18n key - **Mock API** — 开箱即用,`VITE_USE_MOCK` 一键切换真实后端 - **完整 CRUD 示例** — 用户 / 管理员 / 角色 / 菜单 + 表单校验 + CSV 导出 - **数据概览** — 统计卡片 + 折线图 / 柱状图(@ant-design/charts) - **日志中心** — 操作日志、登录日志,支持多条件筛选 - **测试覆盖** — Vitest + Testing Library,登录核心逻辑含属性测试 ## 🛠 技术栈 | 类别 | 技术 | |------|------| | 框架 | React 19 | | 语言 | TypeScript | | UI 库 | Ant Design 6 | | 路由 | react-router-dom 7 | | HTTP | axios + axios-mock-adapter | | 日期 | dayjs(随语言切换 locale) | | 国际化 | 自研(`src/locales/`,零依赖) | | 构建 | Vite 8 | | 测试 | Vitest + Testing Library | ## 🚀 快速开始 ```bash # 1. 安装依赖 pnpm install # 2. 启动开发服务器(默认启用 Mock) pnpm dev # 3. 打开浏览器 # http://localhost:3000 ``` **演示账号:** `admin` / `admin123`(超管);`editor` / `editor123`(受限账号,用于观察按钮权限收放) ## 📦 常用命令 | 命令 | 说明 | |------|------| | `pnpm dev` | 开发服务器(staging 模式,端口 3000) | | `pnpm check` | **质量门禁**:`导入顺序` + `硬编码色值` + `硬编码中文` + `tsc -b` + `vitest --run` + `eslint .`(改完代码跑这个) | | `pnpm check:imports` | 只查导入顺序(最快,迭代时用) | | `pnpm check:colors` | 只查硬编码色值 | | `pnpm check:i18n` | 只查硬编码中文 UI 文案 | | `pnpm build` | 类型检查 + 生产构建 | | `pnpm build:prod` | 生产构建(关闭 Mock) | | `pnpm lint` | ESLint | | `pnpm test` | 运行测试 | | `pnpm test:watch` | 监听模式测试 | > 类型检查务必用 `tsc -b`(或 `pnpm check`)。根 `tsconfig.json` 是 solution 风格, > 裸 `tsc --noEmit` 不检查任何文件且静默通过。 ## ⚙️ 环境变量 | 变量 | 说明 | 默认 | |------|------|------| | `VITE_API_BASE_URL` | 后端接口地址 | `http://localhost:8000` | | `VITE_USE_MOCK` | 是否启用 Mock 拦截(`true` 开发 / `false` 生产) | 由 `.env.*` 决定 | | `VITE_LOGIN_STYLE` | 构建期默认登录风格(`classic` / `character`) | 后端配置 | | `VITE_DEFAULT_LOCALE` | 构建期默认语言(`zh-CN` / `zh-TW` / `en`,或 `auto` 跟随浏览器) | `zh-CN` | Mock 开关按环境生效:`.env.development` / `.env.staging` 默认 `true`,`.env.production` 默认 `false`。 生产构建不会把 mock 逻辑打进包里,可直接对接真实后端。 ## 🔌 对接真实后端(接口契约) 登录、会话、权限已按「服务端驱动」语义实现,关掉 Mock 后只需后端实现以下接口(响应统一包一层 `{ code, msg, data }`,`code===200` 视为成功,非 200 会弹出 `msg` 并 reject): | 接口 | 方法 | 说明 | |------|------|------| | `/api/login` | POST | 入参 `{ username, password }`,成功返回 `{ token, admin: { id, username, role, created_at } }`;失败返回 `code:400` 与原因。`role` 取值 `super_admin` / `admin` | | `/api/captcha` | GET | 返回 `{ enabled }`;启用时含 `captchaId`、`captchaSvg` | | `/api/captcha/verify` | POST | 入参 `{ captchaId, code }`,返回 `{ valid }` | | `/api/config/login` | GET | 返回 `{ loginStyle }`(`classic` / `character`) | | `/api/profile` | GET | 返回当前登录账号;**token 失效请返回 HTTP 401**(前端据此统一清理会话并跳登录) | | `/api/profile` | PUT | 更新个人资料 `{ nickname?, email?, avatar? }`,返回最新账号 | | `/api/profile/change-password` | POST | 入参 `{ oldPassword, newPassword }`;旧密码错误返回 `code:400` | | `/api/permission/menus` | GET | **按请求头 `Authorization: Bearer ` 识别身份**,返回当前账号可见菜单树(目录/菜单/按钮);401 同 `/api/profile` | | `/api/dashboard/stats`、`/api/dashboard/trend` | GET | 数据概览 | | `/api/users`、`/api/admins`、`/api/roles`、`/api/menus`、`/api/logs`、`/api/login-logs`、`/api/settings` | GET/POST/PUT/DELETE | 各 CRUD(分页入参 `page` / `page_size`,返回 `{ list, total, page, page_size }`) | > 关键语义:菜单权限由**后端按 token** 决定并下发,前端只负责渲染与 `hasPermission('module:action')` 显隐——请不要在后端菜单里下发前端本地身份判断。 ### 语言相关约定 前端已在请求头带 `Accept-Language`(当前为 `zh-CN` / `zh-TW` / `en`)。 | 字段 | 约定 | |------|------| | 菜单 `name` | 可下发 i18n key(如 `menu.dashboard`),前端按当前语言翻译;命中不到则**原样显示**(后端自己本地化)。因此后端新增菜单无需改前端 | | 响应体 `msg` | 服务端消息,前端不翻译。请按 `Accept-Language` 返回对应语言 | | 业务枚举(`users.role`、`logs.module`、`logs.action`、登录日志 `message`) | **下发稳定 code 而非中文**,前端负责展示层本地化。把中文当值会**静默**打断筛选与表单回显 | | 操作日志 `target` / `detail` | 服务端生成的叙述文本,前端不翻译 | ## 🔐 登录风格切换 优先级:**localStorage 手动切换 > `VITE_LOGIN_STYLE` 环境变量 > 后端配置**。 ```js // 控制台手动切换,刷新即生效 localStorage.setItem('login_style', 'character') localStorage.setItem('login_style', 'classic') ``` 新增风格:在 `src/pages/Login//` 创建默认导出组件,并在 [registry.ts](src/pages/Login/registry.ts) 注册即可。 ## 🔑 权限说明 - 菜单与按钮权限由 `/api/permission/menus` 下发(Mock 数据在 `src/mock/data/menus.ts`)。 - 页面按钮通过 `hasPermission('module:action')` 控制显隐,如 `admin:create` / `user:delete`。 - **超级管理员始终拥有全部权限**;普通账号按角色关联的 `menu_ids` 过滤。 > 演示按钮权限收放,用受限账号 `editor` / `editor123` 登录: > 该账号只有「数据概览 + 管理员管理」,且**没有**「新增管理员」权限—— > 管理员管理页的「新增管理员」按钮会被隐藏,「编辑 / 删除」正常显示; > 直接访问无权限的菜单(如 `/users`)会被路由守卫踢到 403。 > 想调整,改 `src/contexts/AuthContext.tsx` 的 `MOCK_ACCOUNTS` 或 > `src/mock/data/roles.ts` 里角色的 `menu_ids` 即可。 ## 📁 目录结构 ```text src/ ├── main.tsx # 入口:按环境加载 Mock > StrictMode > createRoot ├── App.tsx # ThemeProvider > ConfigProvider(按当前语言) > AntdApp > AuthProvider > Router ├── router/index.tsx # 三段式路由定义 ├── contexts/ # AuthContext / PermissionContext / ThemeContext ├── locales/ # 国际化:<语言>/<命名空间>.ts,zh-CN 是 key 的事实来源 ├── hooks/ # useAuth / useTabs / useIsMobile / useTableScrollY ├── components/ # AdminLayout / ListPage / AuthGuard / SearchBar / TableActions │ # TablePagination / ExportDropdown / ErrorBoundary / RouteError │ # Icon / AppFooter ├── pages/ # 页面(每个页面一个目录,登录页为多风格注册表) ├── services/ # request.ts + 各业务 API ├── mock/ # axios-mock-adapter Mock 数据 ├── types/ # 通用类型 + 权限模块类型 ├── utils/ # export / datetime / feedback / session ├── styles/global.css # 全局样式 └── test/setup.ts # 测试初始化 ``` ## 📄 文档 按「Agent 需要知道什么」分层,避免把所有内容堆进一个常驻文件: - [AGENTS.md](./AGENTS.md) — **项目宪法**:边界、硬规则、质量门禁、提交规范(常驻加载) - [CLAUDE.md](./CLAUDE.md) — Claude Code 专属偏好:技能、环境、记忆(顶部导入 AGENTS.md) - [docs/architecture.md](./docs/architecture.md) — 架构机制:路由 / 认证 / 权限 / 多标签 / Mock / 国际化 - [docs/conventions.md](./docs/conventions.md) — 代码规范:命名 / 样式分层 / 导入 / 测试 / 国际化 - [docs/history/ROADMAP.md](./docs/history/ROADMAP.md) — 已归档的历史计划(P0–P2,均已完成) ## 📃 License [MIT](./LICENSE)