Commit b9c7da30f6ffa1d900050987543144bee1c9a5fd
1 parent
f7becddb
docs(review:FE-04:r1): request-changes
Showing
1 changed file
with
51 additions
and
0 deletions
docs/superpowers/reviews/2026-06-01-FE-04.md
0 → 100644
| 1 | +# FE-04 用户信息单据 — AI 代码评审报告(第 1 轮) | |
| 2 | + | |
| 3 | +- 规格:`docs/superpowers/specs/2026-06-01-FE-04.md` | |
| 4 | +- 阶段:前端(frontend) | |
| 5 | +- 关联 REQ:REQ-USR-001(增加用户)/ REQ-USR-002(修改用户) | |
| 6 | +- 关联原型:`prototype/erp.html` `<section id="screen-userdetail">` | |
| 7 | +- 裁决:**request-changes** | |
| 8 | + | |
| 9 | +--- | |
| 10 | + | |
| 11 | +## 一、作用域核查(通过) | |
| 12 | + | |
| 13 | +本轮 diff 实现文件全部落在 `frontend/` 下(`src/api/`、`src/pages/usr/UserDetail/`、`src/router/index.tsx`、`tests/`),未触碰 `backend/` / `sql/` / `scripts/`,符合前端阶段路径作用域硬约束。 | |
| 14 | + | |
| 15 | +## 二、阻断项(must-fix) | |
| 16 | + | |
| 17 | +### B1. edit 态预填按主键查「用户号」字段,正常导航流必然取不到记录(blocker) | |
| 18 | + | |
| 19 | +- 位置:`frontend/src/pages/usr/UserDetail/useUserDetail.ts:124`(`getUserDetail({ queryField: '用户号', queryValue: String(userId) })`);连带 `frontend/src/pages/usr/UserDetail/index.tsx:43`(`userId = Number(params.id)`)。 | |
| 20 | +- 事实依据: | |
| 21 | + - 路由 `/usr/users/:id` 的 `:id` 是**用户主键**——docs/05 § REQ-USR-002「路径参数 `id`(用户主键)」,且 FE-03 双击行入口为 `frontend/src/pages/usr/UserList/index.tsx:36` `navigate('/usr/users/' + row.id)`(`row.id` 即 `UserVO.id` 主键),**未**经 router state 传 `presetUser`。 | |
| 22 | + - 因此 edit 态 `presetUser` 恒为 `null`,必走 `getUserDetail` 分支;该分支把主键值当作「用户号」去 `GET /api/usr/users?queryField=用户号&matchType=等于&queryValue=<主键>`。 | |
| 23 | + - 主键 `id` 与业务字段「用户号」`sUserNo` 是不同字段,正常情况下二者取值不相等 → 列表精确匹配返回空 `records` → `getUserDetail` 返回 `null` → 进入 `notFound`(40401)分支,页面显示「该用户不存在或已被删除」。 | |
| 24 | + - 真实后端下,REQ-USR-002 验收「编辑预填该用户原值(基本字段 + 已授权权限回勾)」/ spec BR17 将无法满足。 | |
| 25 | +- 附加事实:docs/05 § REQ-USR-003 列表端点的 `queryField` 合法取值为 `用户名/员工名/用户号/部门/用户类型/作废/登录日期/制单人`,**不含主键**,因此无法用列表端点按 `:id` 主键定位单条。这是 spec D4「复用列表端点按 :id 定位」未消解的跨阶段数据流缺口;当前用「用户号=主键值」的实现并未解决该缺口,反而引入了确定性错误。 | |
| 26 | +- 修复方向(任选其一,实现期定): | |
| 27 | + 1. FE-03 双击进入时经 `navigate('/usr/users/' + row.id, { state: { user: row } })` 携带行数据,使 edit 态走 `presetUser` 分支(spec D4 备注已给此先例),避免二次取数;并相应为 `/new` 之外的 edit 直链场景兜底;或 | |
| 28 | + 2. 与后端对齐补「单用户详情」读端点 / 列表端点按主键定位的能力(跨阶段对齐项,记入 decisions),不要把主键塞进「用户号」查询字段。 | |
| 29 | + | |
| 30 | +> 该项单独成立即触发 request-changes。 | |
| 31 | + | |
| 32 | +## 三、建议项(非 must-fix,可在本轮或后续消化) | |
| 33 | + | |
| 34 | +- S1. `frontend/tests/e2e/userdetail.spec.ts:103-110` 的 GET 存根对**任意** `/api/usr/users**` 请求都返回 `makeUser(7,'zhangsan')`,与请求 query 参数无关,因而掩盖了 B1(存根没有校验 `queryField/queryValue` 是否真的命中目标用户)。建议在 edit 预填用例里断言实际发出的 query 参数,避免再次掩盖此类数据流缺陷。 | |
| 35 | +- S2. `frontend/src/pages/usr/UserDetail/UserDetail.module.css:25/29/34` 工具栏按钮与齿轮用硬编码 `#ffffff`。tokens.css 无「深色条上的白色前景」语义 token;该白色前景与 `.toolbar` 的 `#2c2f36` 深色装饰底强绑定,属 spec § 7 D10 已豁免的「工具条局部装饰」同一范畴,故不作 must-fix。若希望严格收敛,可在 tokens.css 登记一个工具条前景/底色 token 一并替换。 | |
| 36 | +- S3. `frontend/src/pages/usr/UserDetail/useUserDetail.ts:150` catch 分支用于错误文案选择的 `permissions.length` 读取的是闭包旧值(`runLoad` 的 `eslint-disable exhaustive-deps`),仅影响 loadError 文案精度,不影响功能;可改读 `permissionsRef` 或不区分文案。 | |
| 37 | + | |
| 38 | +## 四、对照确认(通过项,留痕) | |
| 39 | + | |
| 40 | +- 原型一致性:工具栏(保存/取消/新增 + 5 占位按钮 + 齿轮)、3 列 `form-grid`(创建时间/制单人只读 + 员工名/用户名/类型/语言/用户号 + 单据修改权限复选框)、`tabs-row`(权限组 active + 5 占位页签 disabled)、`perm-list`(表头全选 indeterminate + 逐行复选框)结构与 `#screen-userdetail` 一致;主操作「保存」置于工具栏左侧主按钮,无结构性偏移。 | |
| 41 | +- Design Tokens:表单/权限区语义色均走 `var(--color-*)`;工具栏深色底 `#2c2f36` 为 D10 豁免装饰;未发现语义色硬编码(白色前景见 S2)。 | |
| 42 | +- 业务校验前端复刻:用户名必填 + 3-20 位字母数字下划线正则(BR3)、用户号必填(BR4)、类型/语言必填枚举(BR6/BR7)、单据修改权限默认否(BR8)、员工名联动带出(BR5)、密码不采集(BR9)、权限全量覆盖语义(BR11)均已实现;错误码 40001/40901/40401/40301 文案与就近高亮(用户名冲突 `form.setFields`)对齐 spec § 4。 | |
| 43 | +- API 调用一致性:`createUser`(POST `/usr/users`)、`updateUser`(PUT `/usr/users/{id}`)、`listEmployees`/`listPermissions`/`getUserDetail` 全部经 `frontend/src/api/request.ts` 统一实例,无裸 `fetch`/`axios`;请求体字段(`sUserName/sUserNo/iEmployeeId/sUserType/sLanguage/iCanModifyBill/permissionIds`、PUT 含 `iIsVoid` 不含 `sUserName`)对齐 docs/05 § REQ-USR-001/002。 | |
| 44 | +- 状态机覆盖:loading(`initialLoading` + `Spin`)/ empty(权限空态 `perm-empty`)/ error(`loadError` 重试入口 + `notFound` 返回列表)/ 正常(editing)/ 提交中(`submitting` 置 `loading`+`disabled` 防重)五态齐备。 | |
| 45 | +- a11y(客观项):表单控件均经 AntD `Form.Item label` 关联;危险/导航类「取消」有未保存改动二次确认(`Modal.confirm`)。颜色对比度/响应式为 best-effort,未见明显失败,不单独触发 request-changes。 | |
| 46 | + | |
| 47 | +--- | |
| 48 | + | |
| 49 | +## 五、裁决 | |
| 50 | + | |
| 51 | +存在 1 项 blocker(B1:edit 预填数据流错误,正常导航流必然 40401),故本轮裁决 **request-changes**。其余为通过项与建议项。 | ... | ... |