# much-admin
**Repository Path**: chenhang0612/much-admin
## Basic Information
- **Project Name**: much-admin
- **Description**: 基于 Vue 3 + TypeScript + Vite 的后台管理前端,对接网关下的 认证(/auth)、系统(/system)、会员(/member) 等接口
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-04-01
- **Last Updated**: 2026-05-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Much Admin
基于 **Vue 3 + TypeScript + Vite** 的后台管理前端,对接网关下的 **认证(`/auth`)**、**系统(`/system`)** 等服务。菜单与路由由后端权限树动态生成,配套布局 Tab、可折叠侧栏、主题切换与 Element Plus 图标选择等能力。
默认配套后端:**much-system-service**(经网关,如 `http://localhost:8080`)。
---
## 技术栈
| 类别 | 技术 |
|------|------|
| 框架 | Vue 3、Vue Router 4、Vuex 4 |
| UI | Element Plus、`@element-plus/icons-vue` |
| 构建 | Vite 6、Sass(全局注入 `variables.scss`) |
| HTTP | Axios(`src/utils/request.ts`) |
| 其它 | NProgress、TypeScript、ESLint、Prettier |
---
## 功能概览
- **SSO 登录**:`/auth/sso/login`,Token 写入本地并在请求头携带 `token`
- **动态路由 / 侧栏**:`getUserPermissionList` 拉取权限树 → 适配为路由 → 注册到 Layout 子路由
- **权限码**:`collectPermissionCodes` 收集按钮权限,供 `v-perm` 指令使用
- **布局 Tab**:访问页面自动开 Tab,可关闭;数量上限由 `VITE_LAYOUT_TAB_MAX` 控制(硬顶 8)
- **侧栏折叠**:展开时仅在侧栏 Logo 行显示收起;折叠后侧栏完全隐藏,顶栏显示 **Expand** 展开按钮
- **菜单管理**:类型 **1-项目 / 2-菜单 / 9-按钮**;Element Plus 官方图标选择器;表格预览图标
- **系统模块页面**:用户、角色、菜单、部门、字典、日志、设置、工作台等(见下方页面列表)
---
## 环境要求
- **Node.js**:建议 18+ / LTS(与 Vite 6、当前依赖兼容)
- **后端网关**:开发环境默认代理到 `http://localhost:8080`(见 `vite.config.ts`)
---
## 快速开始
```bash
# 安装依赖
npm install
# 开发
npm run dev
# 生产构建
npm run build
# 预览构建产物
npm run preview
# 构建并复制到 monorepo 发布目录(见 release.sh)
npm run build:release
# 代码检查 / 格式化
npm run lint
npm run prettier
```
浏览器访问开发地址(以终端输出为准,常见为 `http://localhost:5173`)。
---
## 环境变量
文件:`.env.development`、`.env.production`。
| 变量 | 说明 |
|------|------|
| `VITE_APP_BASE_URL` | 接口根路径。开发建议 **`/api`**,由 Vite 代理到网关;生产填网关完整地址(如 `http://localhost:8080`)。 |
| `VITE_PERMISSION_ROOT_ID` | `getUserPermissionList` 请求体中的菜单树根节点 **id**,默认 `1`。 |
| `VITE_LAYOUT_TAB_MAX` | 布局 Tab 最大数量,默认 `8`(代码硬顶 8)。 |
---
## 开发代理
`vite.config.ts` 将 **`/api`** 转发到网关,并去掉前缀:
```text
浏览器请求 /api/system/user/list
↓
网关收到 /system/user/list
```
这样前端路由(如 `/system/user`)刷新时不会被误代理到后端。修改网关地址请改 `server.proxy['/api'].target`。
---
## 鉴权与请求
- **Token**:登录成功后缓存;Axios 拦截器在请求头附加 **`token`**
- **响应约定**:兼容 `code` / `message`(或 `msg`)/ `data` 等常见 `Result` 结构;未登录等场景可触发 `redirect` 跳转登录
- **登录接口**:`POST /auth/sso/login`(`src/api/user.ts`)
- **用户信息**:`GET /auth/sso/getUserInfo`
- **权限树**:`POST /system/permission/getUserPermissionList`(body:`userId`、`id` 树根)
---
## 路由与菜单
### 静态路由(`src/router/index.ts`)
| 路径 | 说明 |
|------|------|
| `/` | Layout,默认重定向 `/workbench` |
| `/workbench` | 工作台 |
| `/login` | 登录页 |
| `/500` | 服务异常页 |
| `/:pathMatch(.*)*` | 404(挂在 Layout 子级,避免抢动态路由) |
### 动态路由流程
1. `src/permission.ts` 路由守卫:有 Token 时拉取用户信息与权限树
2. `permissionAdapter.ts`:后端 **PermissionDto**(`sonList`)→ 前端菜单行结构
3. `filterAsyncRoutes` + `createRouteRecord`(`src/core/lib/router.ts`)生成 `RouteRecordRaw`
4. `addDynamicRoutes` 挂到主 Layout(`indexName`)下
### 菜单类型(与后端 `Permission.type` 对齐)
| type | 含义 | 侧栏 | 路由 |
|------|------|------|------|
| `1` | 项目(目录) | 展示 | `RouterView` 容器 |
| `2` | 菜单(页面) | 展示 | 按 `component` 加载 `src/views/**/*.vue` |
| `9` | 按钮 | **不展示** | 仅权限码,供 `v-perm` |
| `0` | 历史目录 | 按项目兼容 | 适配层映射为项目 |
侧栏另过滤 `type` 为 `12`、`99` 等非导航节点(见 `PERM_TYPES_HIDDEN_IN_SIDEBAR`)。
### 页面组件解析
- 菜单字段 **`component`** 应对应 `src/views` 下路径,如 `system/user/index` → `src/views/system/user/index.vue`
- `import.meta.glob('../../views/**/*.vue')` 动态匹配;未命中时使用 **`src/views/system/common/dynamic-placeholder.vue`**
---
## 内置页面(`src/views`)
| 路径 | 页面 |
|------|------|
| `workbench/index.vue` | 工作台 |
| `account/login.vue` | 登录 |
| `system/user/index.vue` | 用户管理 |
| `system/role/index.vue` | 角色管理 |
| `system/menu/index.vue` | 菜单管理 |
| `system/dept/index.vue` | 部门管理 |
| `system/dict/index.vue` | 字典管理 |
| `system/log/index.vue` | 日志 |
| `system/setting/index.vue` | 系统设置 |
| `system/common/dynamic-placeholder.vue` | 动态路由占位 |
| `error/404.vue`、`error/500.vue` | 错误页 |
实际可见菜单以后台配置为准。
---
## 主要接口模块(`src/api`)
| 文件 | 职责 |
|------|------|
| `user.ts` | 登录、登出、用户信息、权限树 |
| `auth.ts` | 用户/角色/菜单 CRUD、角色授权、菜单树 |
| `organize.ts` | 部门树、分页、增删改查 |
| `dict.ts` | 字典类型与字典数据 |
| `log.ts` | 登录日志、操作日志 |
### 部分接口约定(与 much-system 对齐)
- 用户列表:`POST /system/user/list`
- 用户注册:`POST /system/user/register`
- 用户更新:`POST /system/user/update`
- 用户删除:`POST /system/user/delete?id=`(Query 参数)
- 权限树:`POST /system/permission/getPermissionTree`
- 菜单创建/更新:`POST /system/permission/create`、`/update`
---
## 目录结构
```text
much-admin/
├── public/ # 静态资源(favicon 等)
├── src/
│ ├── api/ # 接口封装
│ ├── assets/ # 图片、iconfont
│ ├── components/ # 通用组件(admin-page、pagination、icon-picker、menu-icon…)
│ ├── config/ # 应用配置、权限树根、主题、布局 Tab 上限
│ ├── core/
│ │ ├── directives/ # 自定义指令(v-perm、v-copy)
│ │ ├── hooks/ # useAdmin、分页 hooks
│ │ └── lib/ # 路由生成、权限适配、Tab、菜单图标
│ ├── layout/ # 布局、侧栏、顶栏、Tab 栏、主内容区
│ ├── plugins/ # Element Plus 注册
│ ├── router/ # 静态路由、动态路由注册
│ ├── store/ # Vuex(user、permission、app、tabs)
│ ├── styles/ # 全局样式、SCSS 变量
│ ├── utils/ # 请求、缓存、主题、校验
│ ├── views/ # 业务页面
│ ├── App.vue
│ ├── main.ts
│ └── permission.ts # 全局路由守卫
├── .env.development
├── .env.production
├── vite.config.ts
├── tsconfig.json
└── release.sh # 构建产物复制到 ../frontend/public/admin
```
---
## 布局与主题
- **布局**:左侧菜单 + 顶栏(面包屑、主题、用户)+ Tab 栏 + 主内容
- **侧栏折叠**:状态存 `localStorage`(`much_admin_sidebar_collapse`)
- **主题**:顶栏切换多套主色,写入 CSS 变量与 `localStorage`(`much-admin-theme`),启动时 `initTheme()` 恢复
布局相关变量见 `src/styles/variables.scss`(侧栏宽 200px,收起为 0)。
---
## 自定义指令
```html
编辑
```
`getUserPermissionList`:**仅 type=9 为按钮权限**,出现在接口结果树中即表示用户具备该权限,写入 `store.getters.permission`;未出现的 `Perm.*` 对应按钮不展示。支持通配符(如 `system:dict:type:*`)。`userType === 1` 超级管理员默认放行。
---
## 生产部署
```bash
npm run build
```
产物在 `dist/`。若需并入 monorepo 前端静态目录:
```bash
npm run build:release
# 默认复制到 ../frontend/public/admin
```
生产环境请将 `VITE_APP_BASE_URL` 设为网关对外地址,或由 Nginx 将 `/api` 反代到网关(与开发代理策略一致即可)。
---
## 与后端对齐检查清单
- [ ] 网关地址与 `vite.config.ts` 代理、`VITE_APP_BASE_URL` 一致
- [ ] `VITE_PERMISSION_ROOT_ID` 与库中菜单树根 **id** 一致
- [ ] 菜单 **path / component** 与 `src/views` 文件路径一致
- [ ] 菜单 **type** 使用 `1 / 2 / 9`,按钮不进侧栏
- [ ] 用户删除接口为 **POST + Query `id`**,勿用 JSON Body
- [ ] 登录响应包含 **token** 字段
---
## 常见问题
**登录成功但白屏或 404**
- 检查动态路由是否注册成功,URL 是否与菜单 **path** 一致
- 检查 **component** 能否解析到 `src/views` 下对应 `.vue`
**接口跨域**
- 开发环境使用 `VITE_APP_BASE_URL=/api` + Vite 代理
- 若直连网关,需在网关配置 CORS
**侧栏无菜单**
- 确认 `getUserPermissionList` 返回非空 `sonList`
- 确认节点未被标为按钮(`type=9`)或隐藏类型
**菜单管理类型显示不对**
- 列表展示以后端 **type** 为准(1/2/9),见 `permissionAdapter.normalizeBackendMenuType`
**动态页显示「功能页面待接入」**
- 表示 `component` 路径未匹配到视图文件,请补全 `src/views` 或修正后台配置
---
## 许可证
以项目仓库或组织约定为准;若需开源协议请补充根目录 `LICENSE` 文件。