docs(plan): 回写 A1 部门管理补强
ci / 质量门禁 (push) Canceled after 0s

背景:
- 部门管理已实现(独立页面 /system/departments、只停用不删除、
  有成员/启用子部门禁止停用),需要同步计划、规范与实施报告。

改动:
- 开发计划:新增 WBS A1-BE-05(部门接口)与 A1-FE-04(部门管理页),
  A1 进度更新为 10/10、测试计数与「补强」说明;附录 C 增加
  /system/departments,§7.1 页面/接口清单更新;版本记录增补。
- A1 实施报告:范围表、契约/后端/前端交付物、测试计数与验证表补充
  部门管理;新增 §2.5 部门管理补强(口径、规则、覆盖范围)与遗留项。
- 11-前端路由与目录规范:管理中心模块表补 /system/departments
  (pages/system/departments/),版本 V1.1。

影响面:
- 仅文档;与已提交的代码行为一致,不改变其它批次范围。

回滚方式:
- 回滚本提交即恢复文档原状;不影响代码。

验证证据:
- pnpm format:check 通过;
- 文档中的测试计数、接口与页面路径与 feat(identity) 提交一致。
This commit is contained in:
Stev_Wang committed 2026-11-03 15:02:14 +08:00
1 parent 6661c42e84
commit 981757b76c
3 files changed
+31 -12

No files matched your search

@@ -19,8 +19,10 @@
| A1-BE-03 | Jwt → Permission → SpecialPermission → Scope 守卫链、`@Audit` 与请求上下文 | ✅(Scope 骨架) |
| A1-BE-04 | `/me` 用户 / 角色 / 权限 / 数据范围 / 可见客户;权限即时生效 | ✅(dataScope 仅 all / 本部门及下级,六类留 A2) |
| A1-FE-01 | 登录页、token 存储刷新、登出、过期跳转、路由回跳 | ✅ |
| A1-FE-02 | 用户列表(游标分页 / 筛选 / 排序)、新建 / 编辑、停用确认、部门树、角色多选、客户转交入口 | ✅ |
| A1-FE-02 | 用户列表(游标分页 / 筛选 / 排序)、新建 / 编辑、停用确认、部门筛选、角色多选、客户转交入口 | ✅ |
| A1-FE-03 | `/me` 缓存、`usePermission` / `<Can>`、路由与按钮级控制、403 页 | ✅ |
| A1-BE-05 | 部门管理补强:树(含停用)、新建 / 改名 / 负责人 / 排序、停用 / 启用、停用拦截 | ✅(2026-11-03 补强) |
| A1-FE-04 | 部门管理页 `/system/departments`:两级树 + 详情/编辑 + 停用启用确认 | ✅(2026-11-03 补强) |
| A1-QA-01 | 登录 / 刷新 / 登出 / 停用 / 角色变更 / 越权 6 类用例 | ✅(接口 int + 浏览器 e2e) |
口径确认(用户拍板):初始密码由管理员设定、首次登录强制修改;手机号列表掩码、详情全号仅 `user:manage` 可见;路由按开发计划附录 C 使用 `/system/users`(2026-11-03 路由规范调整后)。
@@ -31,7 +33,7 @@
### 2.1 契约(`packages/shared`)
- 新增 `src/schemas/identity.ts`(+ spec):`UserSummary`(`phoneMasked`,永不含全号)、`UserDetail`(`phone?` 仅授权时返回)、`UserListQuery`(`cursor/limit/keyword/department_id/role_id/status/sort/order`)、`CreateUserInput`、`UpdateUserInput`、`DisableUserInput`、`TransferCustomersInput`、`LoginInput`、`RefreshInput`、`LoginResponse = tokenPair + me`、`MeResponse`、`DepartmentNode`、`RoleSummary`。
- 新增 `src/schemas/identity.ts`(+ spec):`UserSummary`(`phoneMasked`,永不含全号)、`UserDetail`(`phone?` 仅授权时返回)、`UserListQuery`(`cursor/limit/keyword/department_id/role_id/status/sort/order`)、`CreateUserInput`、`UpdateUserInput`、`DisableUserInput`、`TransferCustomersInput`、`LoginInput`、`RefreshInput`、`LoginResponse = tokenPair + me`、`MeResponse`、`DepartmentNode`(`status / sortOrder / memberCount / directMemberCount`)、`CreateDepartmentInput`、`UpdateDepartmentInput`、`DepartmentTreeQuery`、`RoleSummary`。
- `permissions.ts` 新增 `USER_VIEW = 'user:view'`;保留 `USER_MANAGE`。
- 写 body camelCase、query snake_case;写接口 `.strict()`;错误码沿用 A0 统一表。
@@ -41,7 +43,8 @@
- 迁移:`prisma/migrations/20261102143519_a1_identity`(expand):`departments`、`users`、`roles`、`user_roles`、`role_permissions`、`refresh_tokens`。
- 种子(幂等):8 角色 + 角色权限映射、3 个一级部门 + 6 个小组、11 个用户(`admin` 超管 + 10 位示例成员),统一初始密码 `lingxi2026`、`must_change_password=true`。
- identity 模块(`apps/api/src/modules/identity`):
- `POST /auth/login|refresh|logout|change-password`、`GET /me`、`GET/POST /users`、`GET/PATCH /users/{id}`、`POST /users/{id}/disable|enable|transfer-customers`、`GET /departments/tree`、`POST/PATCH /departments`、`GET /roles`。
- `POST /auth/login|refresh|logout|change-password`、`GET /me`、`GET/POST /users`、`GET/PATCH /users/{id}`、`POST /users/{id}/disable|enable|transfer-customers`、`GET /departments/tree?include_disabled=`、`POST/PATCH /departments`、`POST /departments/{id}/disable|enable`、`GET /roles`。
- 部门:两级组织树;新建 / 改名 / 负责人 / 排序;只停用不删除;有在职成员、启用中的下级小组或下级在职成员时禁止停用(42201 带数量);启用时上级必须启用;负责人必须是启用用户。
- refresh token 旋转:jti + token_hash + family,旧 token 原子吊销;重放整族吊销。
- 登录失败 Redis 计数,达阈值锁定 15 分钟(42901)。
- 权限每请求从 DB 解析,角色变更下一次请求生效。
@@ -57,6 +60,7 @@
- 登录:方案 B 左右分屏(左 560 品牌 + 能力 + CSS 规格缩略,右表单卡);真实 `POST /auth/login`;错误 / loading / 锁定态;首次登录强改在登录页内完成,成功后清会话要求用新密码重登。
- 用户列表 / 详情:左 400 列表 + 右 760 详情(基本资料 / 角色权限 / 负责客户 / 登录与安全 / 操作记录);搜索、部门、角色、状态、排序、游标分页;停用 / 启用 / 客户转交 / 调整角色 / 超管授予均「对象卡 → 后果 → 勾选」二次确认;编辑资料弹窗;空 / 加载 / 错误三态;1024 / 1280 适配。
- 新建用户:单栏三段(账号信息 / 组织与角色 / 初始设置),Semi Form + 共享 Zod 同源校验,部门两级联动、角色多选、超管二次确认。
- 部门管理(补强):`/system/departments`,左两级组织树(人数 / 负责人 / 状态、显示已停用、`?id=` 选中)+ 右详情/内联编辑(名称、上级只读、负责人、排序、直属/含下级人数、下级小组);新建部门/小组、停用/启用二次确认;无 `user:manage` 只读;树/表单/接口封装均有单测。
- 样式:`--lx-*` token + Semi 组件 + `styles/users.css`;未引入其他组件库/图标库。
### 2.4 测试(`e2e`)
@@ -64,6 +68,13 @@
- `e2e/a1-identity.spec.ts`:6 条浏览器端到端用例(`A1_E2E=1` 门控,CI 无依赖时 skip),真实 API + 真实 PG/Redis;测试数据自建自清。
- `e2e/README.md`:运行前置、环境变量、CORS 说明。
### 2.5 A1 补强:部门管理(2026-11-03)
- **口径**:独立页面 `/system/departments`;只停用不删除;有在职成员 / 启用中的下级小组 / 下级在职成员时禁止停用;负责人/排序可改;上级关系创建后不可移动;权限复用 `user:view` / `user:manage`,不新增权限点。
- **后端**:`GET /departments/tree?include_disabled`、`POST/PATCH /departments`、`POST /departments/{id}/disable|enable`;无 DELETE;`@Audit` 覆盖写操作;成员统计只算在职。
- **前端**:管理中心新增「部门管理」;两级树 + 详情/编辑 + 新建/停用启用确认;停用前本地预判 + 服务端文案兜底。
- **测试**:shared 契约(节点字段/新建/更新 strict);api 单测 + int 覆盖两级/重名/负责人/三类停用拦截/启用联动/DELETE 404;web 单测覆盖树、约束、表单、接口封装;真实账号 + 真实 API 手工联调通过(新建部门/小组、改名、停用空小组、重名提示、截图 `70-departments.png`)。
---
## 3 验证结果
@@ -73,10 +84,11 @@
| 格式 | `pnpm format:check` | ✅ |
| Lint | `pnpm lint` | ✅ 0 warning |
| 类型 | `pnpm typecheck` | ✅ 10/10 tasks |
| 单测 | `pnpm test` | ✅ shared 95 / api 60 / web 55,共 210 |
| 集成 | `pnpm test:int` | ✅ 2 files / 7 tests(真实 PG + Redis) |
| OpenAPI | `pnpm openapi:export` | ✅ 新增 14 条 identity 路径,`apps/web/src/api/generated/openapi.d.ts` 已更新 |
| 单测 | `pnpm test` | ✅ shared 121 / api 90 / web 120,共 331 |
| 集成 | `pnpm test:int` | ✅ 4 files / 33 tests(真实 PG + Redis,含部门 6 例) |
| OpenAPI | `pnpm openapi:export` | ✅ identity 路径(含部门 5 条)导出,`apps/web/src/api/generated/openapi.d.ts` 已更新 |
| 浏览器 e2e | `A1_E2E=1 pnpm exec playwright test e2e/a1-identity.spec.ts` | ✅ 6/6(登录+强改、刷新旋转、登出、停用、角色变更、越权 403) |
| 部门管理联调 | 真实 API + 浏览器(jiang.lan) | ✅ 新建一级/小组、改名、停用空小组、重名 40903、树/详情/停用确认均正常 |
联调截图:`design/a1-ui-v1/shots/impl/`(登录、强改、用户列表、详情、角色 Tab、停用弹窗、命中真实接口);e2e 截图:`design/a1-ui-v1/shots/impl/e2e/`。
@@ -111,6 +123,8 @@ pnpm dev # API :3000 + Web :5173(日常启动不需要任何 DB
| 8 | CORS / e2e | API `WEB_ORIGIN` 仅允许 `http://127.0.0.1:5173`;e2e 跑在 dev 5173。若改用 preview 4173,需把该 origin 加进 `WEB_ORIGIN`。 |
| 9 | 本地账号状态 | 联调过程中曾修改本地 admin/jiang.lan 口令并触发锁定;交付前已 `pnpm db:reset` 恢复种子(`lingxi2026`)。 |
| 10 | 客户转交必填 | PRD 要求离职停用前必须转交名下客户;当前因 A3 未落地,停用弹窗的转交为可选项,A3 之后应收紧为有客户时必填。 |
| 11 | 部门管理 e2e | 部门管理暂无独立浏览器 e2e,由 api int(6 例)+ web 单测 + 真实账号手工联调覆盖;后续补 e2e 时建议覆盖「有成员禁止停用」与「停用后不可再选」。 |
| 12 | 部门删除 | 按口径不提供删除,仅停用;如后续确需删除空部门,需先补 PRD/接口口径。 |
---