feat: 完善员工门店软删除与密码管理
This commit is contained in:
+142
-17
@@ -107,13 +107,13 @@ pw111111
|
||||
| 权限码 | 说明 |
|
||||
| --- | --- |
|
||||
| `*` | 超级管理员,拥有全部权限 |
|
||||
| `store:view` | 查看门店 |
|
||||
| `store:manage` | 新增、修改、删除门店 |
|
||||
| `store:view` | 查看门店和门店下员工 |
|
||||
| `store:manage` | 新增、修改、停用、软删除门店 |
|
||||
| `role:view` | 查看角色 |
|
||||
| `role:manage` | 新增、修改、删除自定义角色 |
|
||||
| `role:manage` | 新增、修改、软删除自定义角色 |
|
||||
| `employee:view:all` | 查看全部门店员工 |
|
||||
| `employee:view:store` | 查看当前门店员工 |
|
||||
| `employee:manage` | 新增、修改、删除员工 |
|
||||
| `employee:manage` | 新增、修改、启停、移除、软删除员工和维护密码 |
|
||||
| `permission:view` | 查看权限策略 |
|
||||
| `permission:manage` | 分配角色权限 |
|
||||
|
||||
@@ -192,14 +192,23 @@ interface Role extends RoleOption {
|
||||
|
||||
```ts
|
||||
type EmployeeStatus = "ACTIVE" | "INACTIVE";
|
||||
type EmployeeStoreStatus = "ACTIVE" | "INACTIVE";
|
||||
|
||||
interface EmployeeStatusTag {
|
||||
code: "EMPLOYEE_ACTIVE" | "EMPLOYEE_INACTIVE" | "STORE_INACTIVE";
|
||||
label: string;
|
||||
variant: "success" | "warning" | "default";
|
||||
}
|
||||
|
||||
interface Employee {
|
||||
id: number;
|
||||
storeId: number;
|
||||
storeName: string;
|
||||
storeStatus: EmployeeStoreStatus;
|
||||
name: string;
|
||||
phone: string;
|
||||
status: EmployeeStatus;
|
||||
statusTags: EmployeeStatusTag[];
|
||||
remark: string | null;
|
||||
roles: Array<{
|
||||
id: number;
|
||||
@@ -238,20 +247,24 @@ interface PermissionMenu {
|
||||
| `PUT` | `/api/permissions/roles/:roleId` | 是 | `permission:manage` | 更新角色权限 |
|
||||
| `GET` | `/api/stores` | 是 | `store:view` | 门店列表或门店下拉选项 |
|
||||
| `GET` | `/api/stores/:id` | 是 | `store:view` | 门店详情 |
|
||||
| `GET` | `/api/stores/:id/employees` | 是 | `store:view` | 门店员工列表 |
|
||||
| `POST` | `/api/stores` | 是 | `store:manage` | 新增门店 |
|
||||
| `PATCH` | `/api/stores/:id` | 是 | `store:manage` | 修改门店 |
|
||||
| `DELETE` | `/api/stores/:id` | 是 | `store:manage` | 删除门店 |
|
||||
| `DELETE` | `/api/stores/:storeId/employees/:employeeId` | 是 | `employee:manage` | 从门店移除员工 |
|
||||
| `DELETE` | `/api/stores/:id` | 是 | `store:manage` | 软删除门店 |
|
||||
| `GET` | `/api/roles` | 是 | `role:view` | 角色列表 |
|
||||
| `GET` | `/api/roles/:id` | 是 | `role:view` | 角色详情 |
|
||||
| `POST` | `/api/roles` | 是 | `role:manage` | 新增自定义角色 |
|
||||
| `PATCH` | `/api/roles/:id` | 是 | `role:manage` | 修改自定义角色 |
|
||||
| `DELETE` | `/api/roles/:id` | 是 | `role:manage` | 删除自定义角色 |
|
||||
| `DELETE` | `/api/roles/:id` | 是 | `role:manage` | 软删除自定义角色 |
|
||||
| `GET` | `/api/employees` | 是 | `employee:view:all` 或 `employee:view:store` | 员工分页列表 |
|
||||
| `GET` | `/api/employees/:id` | 是 | `employee:view:all` 或当前门店 `employee:view:store` | 员工详情 |
|
||||
| `POST` | `/api/employees` | 是 | `employee:manage` | 新增员工 |
|
||||
| `PATCH` | `/api/employees/:id` | 是 | `employee:manage` | 修改员工 |
|
||||
| `PATCH` | `/api/employees/:id/status` | 是 | `employee:manage` | 修改员工状态 |
|
||||
| `DELETE` | `/api/employees/:id` | 是 | `employee:manage` | 删除员工 |
|
||||
| `PATCH` | `/api/employees/:id/password` | 是 | `employee:manage` | 修改员工密码 |
|
||||
| `PATCH` | `/api/employees/:id/password/reset` | 是 | `employee:manage` | 重置员工为初始密码 |
|
||||
| `DELETE` | `/api/employees/:id` | 是 | `employee:manage` | 软删除员工 |
|
||||
|
||||
## 健康检查
|
||||
|
||||
@@ -326,6 +339,8 @@ interface PermissionMenu {
|
||||
|
||||
- 超级管理员使用 `super_admins.username` 登录。
|
||||
- 员工使用手机号登录。
|
||||
- 登录会先校验密码;密码正确但账号停用时返回 `401 UNAUTHORIZED`,消息为 `账号已被禁用`。
|
||||
- 员工所属门店停用时返回 `401 UNAUTHORIZED`,消息为 `所属门店已被禁用`。
|
||||
- 员工必须拥有后台菜单权限,否则返回 `401 UNAUTHORIZED`,消息为 `当前账号没有后台登录权限`。
|
||||
- `cashier`、`kitchen`、`part_time` 默认没有后台登录权限。
|
||||
|
||||
@@ -336,6 +351,7 @@ interface PermissionMenu {
|
||||
### POST /api/auth/employee/login
|
||||
|
||||
员工端登录入口。员工使用手机号和密码登录,不要求后台管理权限。
|
||||
密码正确但员工账号停用时返回 `账号已被禁用`;所属门店停用时返回 `所属门店已被禁用`。
|
||||
|
||||
请求体:
|
||||
|
||||
@@ -555,7 +571,7 @@ Authorization: Bearer <token>
|
||||
|
||||
更新指定角色拥有的权限点。需要 `permission:manage`。
|
||||
|
||||
后端只接受 `GET /api/permissions/definitions` 返回的权限码。保存时会自动补齐依赖权限,例如提交 `permission:manage` 会自动保留 `permission:view`。
|
||||
后端只接受 `GET /api/permissions/definitions` 返回的权限码。保存时会自动补齐依赖权限,例如提交 `permission:manage` 会自动保留 `permission:view`。本次保存中被移除的权限关系会写入 `role_permissions.deleted_at`,不会物理删除关系行。
|
||||
|
||||
请求:
|
||||
|
||||
@@ -694,7 +710,24 @@ Authorization: Bearer <token>
|
||||
| --- | --- | --- |
|
||||
| `id` | `number` | 正整数 |
|
||||
|
||||
响应 `data` 为 `Store`。
|
||||
响应 `data` 为门店详情,结构是在 `Store` 基础上增加 `employees: Employee[]`。
|
||||
|
||||
门店停用后,员工仍保留在该门店下。员工对象会返回:
|
||||
|
||||
- `storeStatus: "INACTIVE"`
|
||||
- `statusTags` 中包含 `{ "code": "STORE_INACTIVE", "label": "门店被禁用", "variant": "warning" }`
|
||||
|
||||
### GET /api/stores/:id/employees
|
||||
|
||||
查询某个门店下的员工。需要 `store:view`。
|
||||
|
||||
路径参数:
|
||||
|
||||
| 参数 | 类型 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| `id` | `number` | 正整数 |
|
||||
|
||||
响应 `data` 为 `Employee[]`。员工对象会包含 `storeStatus` 和 `statusTags`,供前端直接展示员工状态和门店禁用标签。
|
||||
|
||||
### POST /api/stores
|
||||
|
||||
@@ -760,7 +793,33 @@ Authorization: Bearer <token>
|
||||
|
||||
- `404 NOT_FOUND`:门店不存在。
|
||||
- `409 CONFLICT`:门店名称已存在。
|
||||
- `409 CONFLICT`:门店下还有员工,不能停用。
|
||||
|
||||
业务规则:
|
||||
|
||||
- 门店下还有员工时,允许把门店状态改为 `INACTIVE`。
|
||||
- 停用门店后,该门店员工仍可在员工列表和门店详情中查看,并通过 `statusTags` 标识“门店被禁用”。
|
||||
|
||||
### DELETE /api/stores/:storeId/employees/:employeeId
|
||||
|
||||
从门店详情中移除员工。需要 `employee:manage`。
|
||||
|
||||
路径参数:
|
||||
|
||||
| 参数 | 类型 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| `storeId` | `number` | 正整数 |
|
||||
| `employeeId` | `number` | 正整数 |
|
||||
|
||||
成功响应:`204 No Content`。
|
||||
|
||||
业务规则:
|
||||
|
||||
- 只有员工属于该门店时才会移除。
|
||||
- 移除沿用员工软删除规则:员工状态会变为 `INACTIVE`,`deleted_at` 写入删除时间,手机号唯一约束释放。
|
||||
|
||||
可能的业务错误:
|
||||
|
||||
- `404 NOT_FOUND`:门店员工不存在。
|
||||
|
||||
### DELETE /api/stores/:id
|
||||
|
||||
@@ -889,10 +948,17 @@ Authorization: Bearer <token>
|
||||
|
||||
### DELETE /api/roles/:id
|
||||
|
||||
删除自定义角色。需要 `role:manage`。
|
||||
软删除自定义角色。需要 `role:manage`。
|
||||
|
||||
成功响应:`204 No Content`。
|
||||
|
||||
删除后:
|
||||
|
||||
- `roles.deleted_at` 会写入删除时间。
|
||||
- 角色不会再出现在角色列表、角色下拉选项和权限策略中。
|
||||
- 该角色编码的唯一约束会释放,之后可以重新创建同编码角色。
|
||||
- 员工角色关系不会被物理删除,解绑和重新绑定通过 `employee_roles.deleted_at` 记录当前关系状态。
|
||||
|
||||
可能的业务错误:
|
||||
|
||||
- `404 NOT_FOUND`:角色不存在。
|
||||
@@ -938,9 +1004,17 @@ Authorization: Bearer <token>
|
||||
"id": 1,
|
||||
"storeId": 1,
|
||||
"storeName": "示例门店",
|
||||
"storeStatus": "ACTIVE",
|
||||
"name": "张三",
|
||||
"phone": "13800000001",
|
||||
"status": "ACTIVE",
|
||||
"statusTags": [
|
||||
{
|
||||
"code": "EMPLOYEE_ACTIVE",
|
||||
"label": "员工启用",
|
||||
"variant": "success"
|
||||
}
|
||||
],
|
||||
"remark": null,
|
||||
"roles": [
|
||||
{
|
||||
@@ -963,6 +1037,8 @@ Authorization: Bearer <token>
|
||||
}
|
||||
```
|
||||
|
||||
如果员工所属门店已停用,`storeStatus` 会返回 `"INACTIVE"`,且 `statusTags` 会同时包含员工自身状态标签和“门店被禁用”标签。
|
||||
|
||||
### GET /api/employees/:id
|
||||
|
||||
查询员工详情。需要员工查看权限。
|
||||
@@ -1019,13 +1095,13 @@ Authorization: Bearer <token>
|
||||
|
||||
- `storeId` 必须对应启用且未删除门店。
|
||||
- `phone` 在未删除员工范围内全局唯一。
|
||||
- `roleIds` 中的角色必须存在;自定义角色可先通过角色接口创建,再通过权限接口分配权限。
|
||||
- `roleIds` 中的角色必须存在且未软删除;自定义角色可先通过角色接口创建,再通过权限接口分配权限。
|
||||
- 新员工默认密码为 `pw111111`。
|
||||
|
||||
可能的业务错误:
|
||||
|
||||
- `400 BAD_REQUEST`:门店不存在或已停用。
|
||||
- `400 BAD_REQUEST`:提交的角色包含不存在的角色。
|
||||
- `400 BAD_REQUEST`:提交的角色包含不存在或已删除的角色。
|
||||
- `409 CONFLICT`:员工手机号已存在。
|
||||
|
||||
### PATCH /api/employees/:id
|
||||
@@ -1036,12 +1112,12 @@ Authorization: Bearer <token>
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `storeId` | `number` | 正整数 | 新门店必须启用且未删除 |
|
||||
| `storeId` | `number` | 正整数 | 更换门店时,新门店必须启用且未删除 |
|
||||
| `name` | `string` | trim 后 1-50 字符 | 员工姓名 |
|
||||
| `phone` | `string` | 中国大陆手机号,`/^1[3-9]\d{9}$/` | 员工手机号,未删除员工范围内全局唯一 |
|
||||
| `status` | `"ACTIVE" \| "INACTIVE"` | 枚举 | 员工状态 |
|
||||
| `remark` | `string \| null` | trim 后最多 500 字符 | 备注 |
|
||||
| `roleIds` | `number[]` | 正整数数组,最多 20 个 | 不传表示不修改角色,传空数组表示清空角色 |
|
||||
| `roleIds` | `number[]` | 正整数数组,最多 20 个 | 不传表示不修改角色,传空数组表示清空角色;解绑会写入 `employee_roles.deleted_at` |
|
||||
|
||||
请求示例:
|
||||
|
||||
@@ -1057,8 +1133,8 @@ Authorization: Bearer <token>
|
||||
可能的业务错误:
|
||||
|
||||
- `404 NOT_FOUND`:员工不存在。
|
||||
- `400 BAD_REQUEST`:门店不存在或已停用。
|
||||
- `400 BAD_REQUEST`:提交的角色包含不存在的角色。
|
||||
- `400 BAD_REQUEST`:更换后的门店不存在或已停用。
|
||||
- `400 BAD_REQUEST`:提交的角色包含不存在或已删除的角色。
|
||||
- `409 CONFLICT`:员工手机号已存在。
|
||||
|
||||
### PATCH /api/employees/:id/status
|
||||
@@ -1081,6 +1157,55 @@ Authorization: Bearer <token>
|
||||
|
||||
响应 `data` 为 `Employee`。
|
||||
|
||||
### PATCH /api/employees/:id/password
|
||||
|
||||
修改员工密码。需要 `employee:manage`。
|
||||
|
||||
路径参数:
|
||||
|
||||
| 参数 | 类型 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| `id` | `number` | 正整数 |
|
||||
|
||||
请求体:
|
||||
|
||||
| 字段 | 类型 | 必填 | 约束 |
|
||||
| --- | --- | --- | --- |
|
||||
| `oldPassword` | `string` | 是 | 8-128 字符 |
|
||||
| `newPassword` | `string` | 是 | 8-128 字符 |
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"oldPassword": "pw111111",
|
||||
"newPassword": "NewPw111111"
|
||||
}
|
||||
```
|
||||
|
||||
后端会先校验旧密码,旧密码不正确时不会写入新密码。
|
||||
|
||||
响应 `data` 为 `Employee`,不会返回密码或密码哈希。
|
||||
|
||||
可能的业务错误:
|
||||
|
||||
- `404 NOT_FOUND`:员工不存在。
|
||||
- `400 BAD_REQUEST`:旧密码不正确。
|
||||
|
||||
### PATCH /api/employees/:id/password/reset
|
||||
|
||||
重置员工密码为初始密码 `pw111111`。需要 `employee:manage`。
|
||||
|
||||
路径参数:
|
||||
|
||||
| 参数 | 类型 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| `id` | `number` | 正整数 |
|
||||
|
||||
请求体:不需要请求体。
|
||||
|
||||
响应 `data` 为 `Employee`,不会返回密码或密码哈希。
|
||||
|
||||
### DELETE /api/employees/:id
|
||||
|
||||
软删除员工。需要 `employee:manage`。
|
||||
|
||||
Reference in New Issue
Block a user