feat(client): 完成 F34 票据中心增强\n\n- 补齐人工修正/手工归档/解绑/重试 OCR/判重例外等入口\n- 补充 data-testid 并与后端错误码映射保持一致\n- 更新 P5 蓝图 v3 中 F34 状态为 DONE

这个提交包含在:
2026-02-09 18:55:46 +08:00
父节点 00f23678ea
当前提交 c9ac18e2e2
共修改 3 个文件,包含 397 行新增和 6 行删除
@@ -35,7 +35,7 @@ F30,通知触发集成(workflow/pay/auth),"把关键事件写入 notificatio
F31,Delegation Grants API对齐(新增别名/增强响应),"新增 /api/delegation-grants 别名路由并增强现有 delegation API:响应内嵌 principal/delegate 员工摘要;system.users 可代维护 principal;delegate 资格校验:scope=reimbursement_submit 需 expense.proxy_submit(administration);scope=all 需 expense.approve;支持 includeInactive","/api/delegation-grants 与 /api/delegations 兼容;返回包含员工摘要;无权限阻断;代维护审计完整","manual: 启动 server;以 [email protected]/AdminPassword1234 登录拿 accessToken;curl -sS -H 'authorization: Bearer <TOKEN>' 'http://127.0.0.1:3000/api/delegation-grants' | jq;curl -sS -X POST -H 'authorization: Bearer <TOKEN>' -H 'content-type: application/json' 'http://127.0.0.1:3000/api/delegation-grants' -d '{delegateEmployeeId:... scope:... validTo:...}';验证 /api/delegations/mine 与 /api/delegation-grants 返回一致且包含 principal/delegate 摘要",manual,DONE,DONE,DONE,"server/src/routes/delegations.js | server/src/app.js | server/README.md","[""F27""]","不破坏既有 /api/delegations 客户端;新增别名优先"
F32,前端组织与员工最小运营,"补齐前端最小组织能力:部门列表/创建/归档;在用户管理页支持部门选择与直属上级选择(管理员视角)","admin 可完成部门增改归档(含约束提示);可创建员工并选择部门与直属上级;typecheck/build 通过","cd client && npm run typecheck && npm run build",manual,DONE,DONE,DONE,"client/src/pages/DepartmentsPage.tsx | client/src/pages/UserManagementPage.tsx | client/src/api/departments.ts | client/src/api/employees.ts | client/src/router/index.tsx","[""F26"",""F27""]","单机试运行优先;部门树可简化为层级列表"
F33,前端行政代提交/代上传入口,"为 administration 增加 owner 选择入口:报销创建可选 owner;票据上传可选 owner;并基于 delegation-grants 限定可选范围","有授权时可为指定员工创建/提交/上传;无授权时提示并阻断;typecheck/build/e2e 通过","cd client && npm run typecheck && npm run build && npm run test:e2e",manual,DONE,DONE,DONE,"client/src/pages/ReimbursementsPage.tsx | client/src/pages/InvoicePoolPage.tsx | client/src/api/reimbursements.ts | client/src/api/invoicePool.ts | client/src/api/delegations.ts | client/src/api/employees.ts","[""F7"",""F8"",""F31"",""F27""]","为 E2E 增加 data-testid(owner selector / submit/upload)"
F34,前端票据中心增强(编辑/归档/解绑/重试/例外),"补齐票据中心 UI:人工修正/手工归档/解绑重绑/重试 OCR;finance_mgr 判重例外入口;并补 data-testid","上述动作按角色/权限可见;状态与错误码展示清晰;typecheck/build/e2e 通过","cd client && npm run typecheck && npm run build && npm run test:e2e",manual,TODO,TODO,TODO,"client/src/pages/InvoicePoolPage.tsx | client/src/api/invoicePool.ts | client/src/api/errorMessages.ts","[""F28"",""F9"",""F10"",""F11""]","动作按钮必须二次确认并给出不可逆提示(如归档)"
F34,前端票据中心增强(编辑/归档/解绑/重试/例外),"补齐票据中心 UI:人工修正/手工归档/解绑重绑/重试 OCR;finance_mgr 判重例外入口;并补 data-testid","上述动作按角色/权限可见;状态与错误码展示清晰;typecheck/build/e2e 通过","cd client && npm run typecheck && npm run build && npm run test:e2e",manual,DONE,DONE,DONE,"client/src/pages/InvoicePoolPage.tsx | client/src/api/invoicePool.ts | client/src/api/errorMessages.ts","[""F28"",""F9"",""F10"",""F11""]","动作按钮必须二次确认并给出不可逆提示(如归档)"
F35,前端错误码文案补齐(VALID/AUTH/PERM),"补齐新增错误码文案与 details 映射:VALID_004/006/007 等;保证 SYS_001 提示可读且可操作","相关错误在页面/Toast 可读;不暴露敏感字段;typecheck/build 通过","cd client && npm run typecheck && npm run build",manual,DONE,DONE,DONE,"client/src/api/errorMessages.ts | client/src/api/http.ts | client/src/api/ApiError.ts","[""F34""]","错误文案遵循:可行动/可定位(建议带 requestId)"
F36,首次登录强制改密(后端),"落实规格书:首次登录必须修改初始密码;新增 must_change_password 标记与改密接口(校验旧密码+密码策略+tokenVersion 强制下线);管理员重置密码后仍要求首次改密","首次登录返回 mustChangePassword=true;改密成功后 mustChangePassword=false 且旧会话失效;审计包含改密动作","manual: 创建员工使用初始密码登录->提示改密->改密后可进入系统;管理员重置密码后再次触发改密",manual,DONE,DONE,DONE,"server/src/routes/auth.js | server/src/routes/users.js | server/src/utils/passwordPolicy.js | server/prisma/schema.prisma | server/prisma/migrations/* | server/README.md","[""F1""]","默认策略:允许登录但强制前端在改密前禁止访问业务页(路由守卫)"
F37,登录失败锁定与解锁(AUTH_002),"落实规格书:15分钟内失败5次锁定30分钟;返回 AUTH_002(423);system.users 可解锁;所有动作写审计","锁定窗口/次数/时长按配置生效;锁定期间无法登录;解锁后可登录;审计可检索","manual: 连续输错触发锁定->验证423与AUTH_002;管理员解锁->恢复登录",manual,DONE,DONE,DONE,"server/src/routes/auth.js | server/src/routes/users.js | server/src/config.js | server/prisma/schema.prisma | server/prisma/migrations/* | server/README.md","[""F1""]","优先用 DB 字段记录失败窗口与锁定截止时间;避免引入外部缓存"
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
35 F31 Delegation Grants API对齐(新增别名/增强响应) 新增 /api/delegation-grants 别名路由并增强现有 delegation API:响应内嵌 principal/delegate 员工摘要;system.users 可代维护 principal;delegate 资格校验:scope=reimbursement_submit 需 expense.proxy_submit(administration);scope=all 需 expense.approve;支持 includeInactive /api/delegation-grants 与 /api/delegations 兼容;返回包含员工摘要;无权限阻断;代维护审计完整 manual: 启动 server;以 [email protected]/AdminPassword1234 登录拿 accessToken;curl -sS -H 'authorization: Bearer <TOKEN>' 'http://127.0.0.1:3000/api/delegation-grants' | jq;curl -sS -X POST -H 'authorization: Bearer <TOKEN>' -H 'content-type: application/json' 'http://127.0.0.1:3000/api/delegation-grants' -d '{delegateEmployeeId:... scope:... validTo:...}';验证 /api/delegations/mine 与 /api/delegation-grants 返回一致且包含 principal/delegate 摘要 manual DONE DONE DONE server/src/routes/delegations.js | server/src/app.js | server/README.md ["F27"] 不破坏既有 /api/delegations 客户端;新增别名优先
36 F32 前端组织与员工最小运营 补齐前端最小组织能力:部门列表/创建/归档;在用户管理页支持部门选择与直属上级选择(管理员视角) admin 可完成部门增改归档(含约束提示);可创建员工并选择部门与直属上级;typecheck/build 通过 cd client && npm run typecheck && npm run build manual DONE DONE DONE client/src/pages/DepartmentsPage.tsx | client/src/pages/UserManagementPage.tsx | client/src/api/departments.ts | client/src/api/employees.ts | client/src/router/index.tsx ["F26","F27"] 单机试运行优先;部门树可简化为层级列表
37 F33 前端行政代提交/代上传入口 为 administration 增加 owner 选择入口:报销创建可选 owner;票据上传可选 owner;并基于 delegation-grants 限定可选范围 有授权时可为指定员工创建/提交/上传;无授权时提示并阻断;typecheck/build/e2e 通过 cd client && npm run typecheck && npm run build && npm run test:e2e manual DONE DONE DONE client/src/pages/ReimbursementsPage.tsx | client/src/pages/InvoicePoolPage.tsx | client/src/api/reimbursements.ts | client/src/api/invoicePool.ts | client/src/api/delegations.ts | client/src/api/employees.ts ["F7","F8","F31","F27"] 为 E2E 增加 data-testid(owner selector / submit/upload)
38 F34 前端票据中心增强(编辑/归档/解绑/重试/例外) 补齐票据中心 UI:人工修正/手工归档/解绑重绑/重试 OCR;finance_mgr 判重例外入口;并补 data-testid 上述动作按角色/权限可见;状态与错误码展示清晰;typecheck/build/e2e 通过 cd client && npm run typecheck && npm run build && npm run test:e2e manual TODO DONE TODO DONE TODO DONE client/src/pages/InvoicePoolPage.tsx | client/src/api/invoicePool.ts | client/src/api/errorMessages.ts ["F28","F9","F10","F11"] 动作按钮必须二次确认并给出不可逆提示(如归档)
39 F35 前端错误码文案补齐(VALID/AUTH/PERM) 补齐新增错误码文案与 details 映射:VALID_004/006/007 等;保证 SYS_001 提示可读且可操作 相关错误在页面/Toast 可读;不暴露敏感字段;typecheck/build 通过 cd client && npm run typecheck && npm run build manual DONE DONE DONE client/src/api/errorMessages.ts | client/src/api/http.ts | client/src/api/ApiError.ts ["F34"] 错误文案遵循:可行动/可定位(建议带 requestId)
40 F36 首次登录强制改密(后端) 落实规格书:首次登录必须修改初始密码;新增 must_change_password 标记与改密接口(校验旧密码+密码策略+tokenVersion 强制下线);管理员重置密码后仍要求首次改密 首次登录返回 mustChangePassword=true;改密成功后 mustChangePassword=false 且旧会话失效;审计包含改密动作 manual: 创建员工使用初始密码登录->提示改密->改密后可进入系统;管理员重置密码后再次触发改密 manual DONE DONE DONE server/src/routes/auth.js | server/src/routes/users.js | server/src/utils/passwordPolicy.js | server/prisma/schema.prisma | server/prisma/migrations/* | server/README.md ["F1"] 默认策略:允许登录但强制前端在改密前禁止访问业务页(路由守卫)
41 F37 登录失败锁定与解锁(AUTH_002) 落实规格书:15分钟内失败5次锁定30分钟;返回 AUTH_002(423);system.users 可解锁;所有动作写审计 锁定窗口/次数/时长按配置生效;锁定期间无法登录;解锁后可登录;审计可检索 manual: 连续输错触发锁定->验证423与AUTH_002;管理员解锁->恢复登录 manual DONE DONE DONE server/src/routes/auth.js | server/src/routes/users.js | server/src/config.js | server/prisma/schema.prisma | server/prisma/migrations/* | server/README.md ["F1"] 优先用 DB 字段记录失败窗口与锁定截止时间;避免引入外部缓存