feat: 设计菜单权限和员工端登录

This commit is contained in:
湛兮
2026-05-26 12:30:38 +08:00
parent 55b99b5307
commit aa65cb0928
17 changed files with 708 additions and 64 deletions
+74 -19
View File
@@ -17,12 +17,12 @@
## 项目能力
- 门店管理:查询、新增、修改、软删除门店。
- 角色管理:查询服务端固定角色,用于员工权限分配
- 角色管理:管理员可查看角色;超级管理员可新增、修改、删除自定义角色,服务端内置角色不可变更
- 员工管理:分页查询、新增、修改、启用/停用、软删除员工。
- 员工角色:一个员工可以绑定多个角色。
- 登录账号:超级管理员和员工都可以登录。
- 后台权限:超级管理员拥有所有权限;员工只有绑定 `admin` 角色时才能访问后台管理接口
- 固定角色:店长、收银员、后厨、兼职、管理员是服务端固定角色,不提供角色新增、修改、删除接口
- 后台权限:超级管理员拥有所有权限;管理员可管理门店和员工、只读角色;店长只看当前门店员工
- 固定权限:菜单和动作权限由服务端写死,前端只按接口返回结果展示
- JWT 鉴权:登录后签发 token,除健康检查和登录外,接口都需要 Bearer token。
- 数据校验:使用 zod 校验路径参数、查询参数和请求体。
- 数据库迁移:使用 `migrations/*.sql` 管理建表和初始化数据。
@@ -44,7 +44,8 @@
│ ├── 001_initial_schema.sql # 创建基础表结构
│ ├── 002_seed_demo_data.sql # 初始化演示门店和角色
│ ├── 003_create_super_admins.sql # 创建超级管理员表和默认账号
── 004_add_employee_login_fields.sql # 给员工补充登录字段
── 004_add_employee_login_fields.sql # 给员工补充登录字段
│ └── 005_refine_employee_login_and_role_policy.sql # 调整员工默认密码、手机号唯一和系统角色
├── src/
│ ├── app.ts # 创建 Fastify 应用、注册路由、统一错误处理
│ ├── server.ts # 启动 HTTP 服务和优雅停机
@@ -56,7 +57,8 @@
│ ├── modules/
│ │ ├── auth/ # 登录、当前用户和 JWT 鉴权模块
│ │ ├── catalog/ # 门店和角色模块
│ │ ── employees/ # 员工 CRUD 模块
│ │ ── employees/ # 员工 CRUD 模块
│ │ └── permissions/ # 服务端固定菜单和动作权限策略
│ └── shared/ # 通用响应结构和业务错误
├── docker-compose.yml # 本地 MySQL
├── package.json
@@ -81,9 +83,10 @@
| `src/config/env.ts` | 使用 zod 校验 `.env.development` 中的环境变量,避免配置错误拖到请求阶段才暴露。 |
| `src/db/migrate.ts` | 执行 `migrations/*.sql`,并用 `schema_migrations` 记录已执行迁移。 |
| `src/db/pool.ts` | 创建 MySQL 连接池,提供数据库健康检查和关闭连接的方法。 |
| `src/modules/auth/` | 登录鉴权模块,负责超级管理员和员工登录、密码校验、JWT 签发、当前用户查询和后台权限 guard。 |
| `src/modules/auth/` | 登录鉴权模块,负责后台登录、员工登录、密码校验、JWT 签发、当前用户查询和权限 guard。 |
| `src/modules/catalog/` | 门店和角色模块,负责基础资料接口。 |
| `src/modules/employees/` | 员工模块,负责员工分页、详情、新增、修改、状态变更和软删除。 |
| `src/modules/permissions/` | 服务端固定权限策略,返回前端菜单、动作权限和权限策略说明。 |
| `src/shared/` | 跨模块复用的响应结构和业务错误类型。 |
| `docker-compose.yml` | 本地开发用 MySQL 容器配置。 |
| `package.json` | 项目信息、依赖和常用脚本;脚本会读取现有 `.env.development`。 |
@@ -260,7 +263,7 @@ pnpm dev
本项目有两类可登录账号:
- 超级管理员:拥有所有后台管理权限。
- 员工:都可以登录;只有绑定 `admin` 角色的员工才能访问后台管理接口
- 员工:都可以通过员工端接口登录;后台登录只开放给有后台菜单权限的员工,例如 `admin``store_manager`
默认本地超级管理员账号由 [003_create_super_admins.sql](./migrations/003_create_super_admins.sql) 初始化:
@@ -269,26 +272,39 @@ pnpm dev
密码:Admin@123456
```
员工登录字段由 [004_add_employee_login_fields.sql](./migrations/004_add_employee_login_fields.sql) 初始化。已有员工和新建员工默认密码是:
员工登录字段由 [004_add_employee_login_fields.sql](./migrations/004_add_employee_login_fields.sql) 和 [005_refine_employee_login_and_role_policy.sql](./migrations/005_refine_employee_login_and_role_policy.sql) 初始化。已有员工和新建员工默认密码是:
```text
账号:员工手机号
密码:Employee@123456
密码:pw111111
```
登录获取 token
后台登录获取 token。超级管理员、管理员和店长使用这个接口
```bash
curl -X POST http://localhost:3500/api/auth/login \
curl -X POST http://localhost:3500/api/auth/admin/login \
-H 'Content-Type: application/json' \
-d '{
"username": "admin",
"password": "Admin@123456"
}'
```
`POST /api/auth/login` 也保留为后台登录的兼容入口。
员工端登录使用独立接口,给后续 toc 项目使用:
```bash
curl -X POST http://localhost:3500/api/auth/employee/login \
-H 'Content-Type: application/json' \
-d '{
"username": "13812345678",
"password": "pw111111"
}'
```
响应里的 `data.token` 就是后续接口要使用的 JWT。
响应里的 `data.user.canManage` 表示当前账号是否能访问后台管理接口
响应里的 `data.user.permissions` 是服务端计算出的固定权限点;菜单和按钮动作以 `/api/permissions/me` 返回结果为准
为了方便测试,可以先把 token 保存成 shell 变量:
@@ -309,7 +325,30 @@ curl http://localhost:3500/api/auth/me \
-H "Authorization: Bearer $TOKEN"
```
如果员工账号没有 `admin` 角色,可以登录并访问 `/api/auth/me`,但访问门店、角色、员工等后台管理接口会返回 `403 FORBIDDEN`
获取当前账号菜单和动作权限:
```bash
curl http://localhost:3500/api/permissions/me \
-H "Authorization: Bearer $TOKEN"
```
查看服务端固定权限策略:
```bash
curl http://localhost:3500/api/permissions/policies \
-H "Authorization: Bearer $TOKEN"
```
如果员工账号没有后台菜单权限,可以通过员工端登录并访问 `/api/auth/me`,但访问门店、角色、员工等后台管理接口会返回 `403 FORBIDDEN`
### 后台菜单权限
| 菜单 | 超级管理员 | 管理员 `admin` | 店长 `store_manager` | 其他员工 |
| --- | --- | --- | --- | --- |
| 门店管理 | 查看、新增、修改、删除 | 查看、新增、修改、删除 | 不可见 | 不可见 |
| 角色管理 | 查看、新增、修改、删除自定义角色 | 仅查看 | 不可见 | 不可见 |
| 员工管理 | 查看全部、新增、修改、删除 | 查看全部、新增、修改、删除 | 仅查看当前门店员工 | 不可见 |
| 权限管理 | 查看 | 查看 | 不可见 | 不可见 |
## 门店接口示例
@@ -363,7 +402,8 @@ curl -X DELETE http://localhost:3500/api/stores/1 \
## 角色接口示例
角色是服务端固定权限集合,只允许查询,不允许通过接口新增、修改或删除。
角色管理页面只有超级管理员和管理员可见。管理员只能看;超级管理员可以新增、修改、删除自定义角色。服务端内置角色不可修改或删除。
自定义角色默认不绑定后台菜单权限;后台菜单权限仍由服务端固定策略控制。
查询角色:
@@ -372,6 +412,19 @@ curl http://localhost:3500/api/roles \
-H "Authorization: Bearer $TOKEN"
```
新增自定义角色:
```bash
curl -X POST http://localhost:3500/api/roles \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"code": "regional_manager",
"name": "区域经理",
"description": "自定义角色示例"
}'
```
## 员工接口示例
新增员工:
@@ -445,7 +498,7 @@ curl -X DELETE http://localhost:3500/api/employees/1 \
-H "Authorization: Bearer $TOKEN"
```
同一个门店下,未删除员工的手机号不能重复。员工软删除后,可以重新录入相同手机号。
员工手机号就是登录账号,未删除员工的手机号不能重复。员工软删除后,可以重新录入相同手机号。
## 数据库迁移说明
@@ -457,6 +510,7 @@ curl -X DELETE http://localhost:3500/api/employees/1 \
- [002_seed_demo_data.sql](./migrations/002_seed_demo_data.sql):写入一个示例门店和几个常见角色。
- [003_create_super_admins.sql](./migrations/003_create_super_admins.sql):创建超级管理员表,并初始化本地登录账号。
- [004_add_employee_login_fields.sql](./migrations/004_add_employee_login_fields.sql):给员工补充登录密码哈希和最后登录时间。
- [005_refine_employee_login_and_role_policy.sql](./migrations/005_refine_employee_login_and_role_policy.sql):员工默认密码改为 `pw111111`,手机号改为全局唯一,并标记服务端内置角色。
执行 `pnpm db:migrate` 时,脚本会:
@@ -476,12 +530,13 @@ migrations/003_add_employee_email.sql
## 学习重点
- `stores.deleted_at``employees.deleted_at` 用于软删除。
- `employees.active_phone` 是生成列,用来实现“同一门店未删除员工手机号唯一”。
- `employees.password_hash` 让员工也能登录,默认本地密码是 `Employee@123456`
- `employees.active_phone` 是生成列,用来实现“未删除员工手机号全局唯一”。
- `employees.password_hash` 让员工也能登录,默认本地密码是 `pw111111`
- `employee_roles` 是多对多关系表。
- `super_admins` 保存超级管理员账号,密码使用 PBKDF2 哈希,禁止存明文。
- 角色定义由服务端固定,`admin` 角色用于判断员工是否能访问后台管理接口
- JWT 鉴权在 `src/modules/auth/` 中实现,`managementGuard` 统一保护后台管理接口
- 菜单和动作权限由 `src/modules/permissions/` 固定,前端根据 `/api/permissions/me` 渲染
- `admin` 角色可查看角色、管理门店和员工;`store_manager` 只能查看当前门店员工
- JWT 鉴权在 `src/modules/auth/` 中实现,`permissionGuard` 按固定权限点保护接口。
- `repository` 使用参数化查询,避免 SQL 注入。
- `service` 使用事务保证员工信息和角色绑定同时成功或同时失败。
- `app.ts` 统一注册 JWT、业务路由和错误处理,并处理 zod 校验错误、业务错误和数据库唯一索引冲突。