feat: 完善员工门店软删除与密码管理
This commit is contained in:
@@ -16,9 +16,9 @@
|
||||
|
||||
## 项目能力
|
||||
|
||||
- 门店管理:查询、新增、修改、软删除门店。
|
||||
- 角色管理:拥有 `role:manage` 的账号可新增、修改、删除自定义角色,服务端内置角色不可变更。
|
||||
- 员工管理:分页查询、新增、修改、启用/停用、软删除员工。
|
||||
- 门店管理:查询、新增、修改、停用、软删除门店,门店详情可查看员工。
|
||||
- 角色管理:拥有 `role:manage` 的账号可新增、修改、软删除自定义角色,服务端内置角色不可变更。
|
||||
- 员工管理:分页查询、新增、修改、启用/停用、修改密码、重置初始密码、移除和软删除员工。
|
||||
- 员工角色:一个员工可以绑定多个角色。
|
||||
- 登录账号:超级管理员和员工都可以登录。
|
||||
- 后台权限:超级管理员拥有所有权限;角色权限由 `role_permissions` 动态分配。
|
||||
@@ -48,7 +48,8 @@
|
||||
│ ├── 003_create_super_admins.sql # 创建超级管理员表和默认账号
|
||||
│ ├── 004_add_employee_login_fields.sql # 给员工补充登录字段
|
||||
│ ├── 005_refine_employee_login_and_role_policy.sql # 调整员工默认密码、手机号唯一和系统角色
|
||||
│ └── 006_create_role_permissions.sql # 创建角色权限关系表并初始化默认权限
|
||||
│ ├── 006_create_role_permissions.sql # 创建角色权限关系表并初始化默认权限
|
||||
│ └── 007_add_soft_delete_to_roles_and_relations.sql # 给角色和关系表补充逻辑删除字段并移除级联删除
|
||||
├── src/
|
||||
│ ├── app.ts # 创建 Fastify 应用、注册路由、统一错误处理
|
||||
│ ├── server.ts # 启动 HTTP 服务和优雅停机
|
||||
@@ -88,8 +89,8 @@
|
||||
| `src/db/migrate.ts` | 执行 `migrations/*.sql`,并用 `schema_migrations` 记录已执行迁移。 |
|
||||
| `src/db/pool.ts` | 创建 MySQL 连接池,提供数据库健康检查和关闭连接的方法。 |
|
||||
| `src/modules/auth/` | 登录鉴权模块,负责后台登录、员工端登录、密码校验、JWT 签发、当前用户查询和权限 guard。 |
|
||||
| `src/modules/catalog/` | 门店和角色模块,负责基础资料接口。 |
|
||||
| `src/modules/employees/` | 员工模块,负责员工分页、详情、新增、修改、状态变更和软删除。 |
|
||||
| `src/modules/catalog/` | 门店和角色模块,负责基础资料接口、门店详情员工列表和门店移除员工入口。 |
|
||||
| `src/modules/employees/` | 员工模块,负责员工分页、详情、新增、修改、状态变更、密码维护和软删除。 |
|
||||
| `src/modules/permissions/` | 权限模块,维护权限点定义、角色权限分配、当前用户菜单动作权限和权限策略说明。 |
|
||||
| `src/shared/` | 跨模块复用的响应结构和业务错误类型。 |
|
||||
| `docker-compose.yml` | 本地开发用 MySQL 容器配置。 |
|
||||
@@ -314,6 +315,7 @@ curl -X POST http://localhost:3500/api/auth/employee/login \
|
||||
|
||||
响应里的 `data.token` 就是后续接口要使用的 JWT。
|
||||
响应里的 `data.user.permissions` 是服务端按角色动态计算出的权限点;菜单和按钮动作以 `/api/permissions/me` 返回结果为准。
|
||||
登录时会先校验账号和密码;如果密码正确但账号已停用,会返回“账号已被禁用”;如果所属门店已停用,会返回“所属门店已被禁用”。
|
||||
|
||||
为了方便测试,可以先把 token 保存成 shell 变量:
|
||||
|
||||
@@ -371,7 +373,7 @@ curl -X PUT http://localhost:3500/api/permissions/roles/5 \
|
||||
| 菜单 | 超级管理员 | 默认管理员 `admin` | 默认店长 `store_manager` | 其他角色 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 门店管理 | 查看、新增、修改、删除 | 查看、新增、修改、删除 | 不可见 | 不可见 |
|
||||
| 角色管理 | 查看、新增、修改、删除自定义角色 | 查看、新增、修改、删除自定义角色 | 不可见 | 按角色权限决定 |
|
||||
| 角色管理 | 查看、新增、修改、软删除自定义角色 | 查看、新增、修改、软删除自定义角色 | 不可见 | 按角色权限决定 |
|
||||
| 员工管理 | 查看全部、新增、修改、删除 | 查看全部、新增、修改、删除 | 仅查看当前门店员工 | 不可见 |
|
||||
| 权限管理 | 查看、分配 | 查看、分配 | 不可见 | 按角色权限决定 |
|
||||
|
||||
@@ -391,6 +393,13 @@ curl 'http://localhost:3500/api/stores?includeInactive=true' \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
查询门店详情和门店员工:
|
||||
|
||||
```bash
|
||||
curl http://localhost:3500/api/stores/1 \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
新增门店:
|
||||
|
||||
```bash
|
||||
@@ -423,7 +432,14 @@ curl -X DELETE http://localhost:3500/api/stores/1 \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
门店下还有员工时,不能停用或删除门店。
|
||||
从门店详情中移除员工:
|
||||
|
||||
```bash
|
||||
curl -X DELETE http://localhost:3500/api/stores/1/employees/2 \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
门店下还有员工时,可以停用门店;该门店员工会返回 `storeStatus: "INACTIVE"` 和“门店被禁用”状态标签。门店下还有员工时,仍不能删除门店。
|
||||
|
||||
## 角色接口示例
|
||||
|
||||
@@ -516,6 +532,22 @@ curl -X PATCH http://localhost:3500/api/employees/1/status \
|
||||
-d '{"status": "INACTIVE"}'
|
||||
```
|
||||
|
||||
修改员工密码:
|
||||
|
||||
```bash
|
||||
curl -X PATCH http://localhost:3500/api/employees/1/password \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"oldPassword": "pw111111", "newPassword": "NewPw111111"}'
|
||||
```
|
||||
|
||||
重置员工为初始密码:
|
||||
|
||||
```bash
|
||||
curl -X PATCH http://localhost:3500/api/employees/1/password/reset \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
软删除员工:
|
||||
|
||||
```bash
|
||||
@@ -523,7 +555,7 @@ curl -X DELETE http://localhost:3500/api/employees/1 \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
员工手机号就是登录账号,未删除员工的手机号不能重复。员工软删除后,可以重新录入相同手机号。
|
||||
员工手机号就是登录账号,未删除员工的手机号不能重复。员工软删除后,可以重新录入相同手机号。员工返回结构包含 `statusTags`;所属门店停用时会额外包含“门店被禁用”标签。
|
||||
|
||||
## 数据库迁移说明
|
||||
|
||||
@@ -537,6 +569,7 @@ curl -X DELETE http://localhost:3500/api/employees/1 \
|
||||
- [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`,手机号改为全局唯一,并标记服务端内置角色。
|
||||
- [006_create_role_permissions.sql](./migrations/006_create_role_permissions.sql):创建角色权限关系表,并初始化 `admin` 和 `store_manager` 的默认权限。
|
||||
- [007_add_soft_delete_to_roles_and_relations.sql](./migrations/007_add_soft_delete_to_roles_and_relations.sql):给角色、员工角色关系和角色权限关系补充逻辑删除字段,移除关系表旧的 `ON DELETE CASCADE` 级联删除语义。
|
||||
|
||||
执行 `pnpm db:migrate` 时,脚本会:
|
||||
|
||||
@@ -555,11 +588,12 @@ migrations/003_add_employee_email.sql
|
||||
|
||||
## 学习重点
|
||||
|
||||
- `stores.deleted_at` 和 `employees.deleted_at` 用于软删除。
|
||||
- `stores.deleted_at`、`employees.deleted_at`、`roles.deleted_at` 用于软删除。
|
||||
- `employees.active_phone` 是生成列,用来实现“未删除员工手机号全局唯一”。
|
||||
- `roles.active_code` 是生成列,用来实现“未删除角色编码唯一”。
|
||||
- `employees.password_hash` 让员工也能登录,默认本地密码是 `pw111111`。
|
||||
- `employee_roles` 是多对多关系表。
|
||||
- `role_permissions` 保存角色和权限点的多对多关系,权限分配保存后会在接口鉴权时实时生效。
|
||||
- `employee_roles` 是员工和角色的多对多关系表,解绑时写入 `deleted_at`。
|
||||
- `role_permissions` 保存角色和权限点的多对多关系,权限解绑时写入 `deleted_at`,权限分配保存后会在接口鉴权时实时生效。
|
||||
- `super_admins` 保存超级管理员账号,密码使用 PBKDF2 哈希,禁止存明文。
|
||||
- 权限点定义由 `src/modules/permissions/` 固定,角色拥有的权限点由 `role_permissions` 动态决定。
|
||||
- 前端根据 `/api/permissions/me` 渲染菜单和按钮,根据 `/api/permissions/definitions` 渲染可分配权限点。
|
||||
@@ -604,9 +638,9 @@ docker compose ps
|
||||
|
||||
`src/db/migrate.ts` 会把执行过的文件名写入 `schema_migrations`。再次运行时,如果文件名已存在,就会跳过,避免重复建表或重复插入数据。
|
||||
|
||||
### 删除员工后,为什么数据库里还有记录
|
||||
### 删除员工或角色后,为什么数据库里还有记录
|
||||
|
||||
这是软删除。删除接口会把 `deleted_at` 设置为当前时间,并把状态改成 `INACTIVE`。这样可以保留历史数据,同时普通查询会过滤掉已删除记录。
|
||||
这是软删除。员工和门店删除接口会把 `deleted_at` 设置为当前时间,并把状态改成 `INACTIVE`;角色删除接口会写入 `roles.deleted_at`。员工角色关系、角色权限关系的解绑也会写入各自的 `deleted_at`,迁移也会移除旧关系表上的级联物理删除约束。这样可以保留历史数据,同时普通查询会过滤掉已删除记录。
|
||||
|
||||
### 为什么不使用 ORM
|
||||
|
||||
|
||||
Reference in New Issue
Block a user