文件
hyb-oa/.trellis/tasks/archive/2026-10/08-28-reimbursement-detail-material-preview-fixes/prd.md
T
wangsli和Claude Opus 5.5 b85ff6a9bf 归档 11 个已上线 Trellis 任务并补收口记录(09-17-company-loan-principal-repayment 任务整理)
- 报销一页式审批工作台父任务及 B-2a/B-2b/只读一致性子任务(AC11 依用户 2026-09-27 确认)
- 报销详情材料预览修复及其部署子任务(由候选 59dc5f6 发布覆盖,原步骤未执行,记录保留)
- 资产事前批准纠偏、Trellis 流程对齐、ERP 遗留精简、预算池并发、采购提交超时
- 各任务 prd 顶部新增收口记录,实现均包含于生产 4a5cd8f2;原未勾清单保留不补勾
- B 组与有真实待办的任务保持进行中

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 10:19:21 +08:00

8.8 KiB

报销详情权限与材料预览缺陷修复

2026-10-11 收口归档

撤回展示与 EXIF 尺寸修复 46bfa7e0(回填 174cb7ac)随候选 59dc5f6 上线,现包含于当前生产 4a5cd8f2;部署子任务由该发布覆盖。BX-20260828-0017 首图未显示在只读复现中未重现,按原记录保留。原未勾选清单为当时规划记录,保留原样、不补勾。经用户 2026-10-11 明确授权归档。

Goal

修复报销只读查看者误看到“撤回报销”操作,以及带 EXIF 方向信息的图片进入材料合并预览后页面尺寸错误的问题;同时对 BX-20260828-0017 的首张图片未正常显示现象做受控、脱敏、只读诊断,让财务只看到职责内动作,并让图片材料在合并 PDF 中保持正确方向和比例。

Background

  • PC 报销详情已经计算 isReimbursementParticipant,但调用 ReimbursementActions 时未传 showWithdrawAction;该组件默认允许在 reviewing 状态显示撤回,因此具备全量查看权限的财务人员也会看到撤回入口。
  • 服务端撤回接口仍按 owner/submitter 做对象资格校验,非参与人会被拒绝;当前问题是前端动作资格投影错误,不是服务端越权或数据损坏。
  • 移动报销详情当前没有撤回操作,本轮只修复存在缺陷的 PC 入口,不增加移动操作。
  • 材料合并服务先对图片执行 Sharp rotate() 自动应用 EXIF 方向,但页面尺寸读取自旋转前 metadata。方向为 6/8 的手机图片会出现“输出像素已转向、PDF 页面仍按原宽高”的不一致。
  • 现有合并预览按发票在前、补充附件在后排序;BX-20260828-0017 有两张 PDF 发票和两张 JPG 补充附件。此前只读核查已确认 JPG 实际为发票图片,但未打开或持久化原件,尚不能仅凭附件列表断定“首张图片未显示”的最终技术原因。
  • 现行业务规则要求:只读审批人不得看到编辑、解绑、删除等数据变更动作;图片各占合并 PDF 一页,合并失败时保留逐份原件查看路径。

Scope

  • 修复 PC 报销详情中 owner/submitter 与财务只读查看者的撤回动作可见性。
  • 修复服务端材料合并时 EXIF 自动旋转后仍沿用输入尺寸的问题,并更新合并器版本。
  • 使用合成数据覆盖前后端回归;对 BX-20260828-0017 仅执行受控、脱敏、生产只读诊断。
  • 保持服务端授权、审批状态机、材料顺序、原件查看与失败降级合同不变。

Requirements

R1 PC 撤回动作资格投影

  • PC 报销详情仅在当前用户是报销单 owner 或 submitter 且状态为 reviewing 时显示“撤回报销”。
  • 财务、审批人、管理员等因 expense.view_all 或当前审批职责获得只读详情访问时,不得看到撤回输入框或按钮。
  • owner/submitter 在 reviewing 状态下继续看到并可使用现有撤回入口;草稿、驳回、已通过、已支付等既有状态行为不变。
  • ReimbursementActions.showWithdrawAction 必须改为无默认值的必填 prop,让遗漏资格投影在 TypeScript 编译期失败,不保留 fail-open 默认行为。
  • 服务端撤回资格校验、权限矩阵、审批状态机和审计合同保持不变,前端不能把隐藏按钮当作安全边界。

R2 EXIF 图片合并尺寸修复

  • 图片经 Sharp 自动旋转、扁平化和 JPEG 规范化后,必须使用实际输出的宽高创建 PDF 页面和绘制图片,不得使用旋转前 metadata。
  • 方向为 6/8 的合成 JPEG 应在输出 PDF 中保持正确的纵横方向和比例;无 EXIF 或无需旋转的 PNG/JPG/WebP 行为保持不变。
  • 继续执行现有图片像素、页数、输出大小、确定性字节、整包失败和逐份原件降级合同;不引入新依赖、不把合并件当作原件。
  • 合并算法的可见输出发生变化后应更新 merger version,避免新旧算法产物共用同一集合缓存身份。

R3 BX-20260828-0017 首图只读诊断

  • 在实施获批后,使用既有受控生产只读访问,确认材料实际顺序、MIME、字节/像素元数据、EXIF 方向、合并页数和对应页尺寸;现有事实已将用户所称“第一张图”锁定为合并 PDF 第 3 页,诊断从该页开始,仅在必要时生成短生命周期的本地临时派生预览。
  • 诊断不得写生产数据库、报销、审批、付款、对象存储或企业微信;不得把原始票据、图片、完整票号、存储位置、签名 URL、原始 payload 或凭据写入仓库、任务文档或聊天。
  • 临时原件或渲染页若确有必要,只能放在明确的安全临时目录,诊断完成即删除;交付只记录脱敏元数据和结论。
  • 若证据确认问题由 EXIF 尺寸错误造成,使用 R2 修复覆盖;若属于 PDF AcroForm、可选内容组、损坏源文件或其他超出当前图片合并边界的原因,只形成证据并返回规划,不临时替换 PDF 引擎或扩大任务。

Acceptance Criteria

  • 复用现有 adminMe + ownerId=employee-other-r102 + status=reviewing + scope=all 合成场景;管理员作为非参与只读查看者打开报销详情时,页面不存在 reimbursement-withdraw 和撤回意见输入框。
  • 同一状态下,合成 owner/submitter 仍能看到现有撤回入口;其他状态的既有动作投影不变。
  • 服务端非 owner/submitter 撤回拒绝合同保持通过,未修改权限矩阵、状态机、工作流或数据库结构。
  • 带 EXIF orientation 6 和 8 的合成图片合并后,PDF 页面宽高与规范化输出一致,方向和比例正确;普通横图、普通竖图和 PNG/WebP 回归通过。
  • 相同有序材料在同一 merger version 内重复生成时字节完全一致;跨 merger version 允许因修复产生不同字节。材料顺序、页数上限、整包失败和原件降级合同不变。
  • merger version 随算法修复更新,新的集合缓存身份不会复用旧算法产物。
  • BX-20260828-0017 首图形成一份不含原件和敏感字段的只读诊断结论,明确材料顺序、问题类别、是否由 EXIF 修复覆盖,以及未覆盖时的下一步。
  • 前端 typecheck/build、后端聚焦 Vitest/语法检查、相关 Playwright、Trellis 治理和 git diff --check 通过。
  • 未经另行批准不部署公网;部署与公网检查完成前不告知用户线上可测试。

Out of Scope

  • 财务审批页一页式重构、按钮“处理”的改名或待办信息结构调整。
  • 费用类型、会计科目、发票—明细关联、票面金额差异门禁、多票拆分、图片发票上传提示或附件用途治理;这些属于 Task B。
  • 修改、撤回、退回、审批或付款任何真实报销;重分类或重新上传 BX-20260828-0017 的图片附件。
  • 修改服务端撤回授权、角色/权限矩阵、审批规则、状态机、schema、迁移或生产配置。
  • 引入 PDF.js、Poppler、新 PDF 引擎,或在未重新规划时处理 PDF 表单域/可选内容组兼容。
  • 修改 ReimbursementActions 现有撤回默认说明文案“申请撤回并补充说明后重提”。
  • 对 BX-20260828-0017 执行真实单据处置,包括退回、例外接受、重传 PDF、重分类附件或修正票面合计;该单据应按现行规则另行作出业务处理决定。
  • 公网部署、生产写入、企微写入和真实付款。

Risks and Constraints

  • 隐藏动作只能改善正确性和体验,安全仍由服务端对象资格校验负责。
  • EXIF 修复可以解决旋转后尺寸不一致,但不能预先证明 BX-20260828-0017 的首图问题只有一个原因。
  • 真实材料含敏感信息,诊断必须最小读取、只保留脱敏摘要,并对临时文件 fail closed。
  • 现有视觉回归夹具中 owner 视角明确期待撤回按钮可见,修复不能简单删除该操作;需要新增非参与高权限查看者断言。

Test Plan

  • 后端聚焦:cd server && npx vitest run tests/unit/services/reimbursementMaterialPreview.test.js tests/unit/routes/reimbursements.attachments.test.js。
  • 后端基础:cd server && node --check src/services/reimbursementMaterialPdf.js && node --check src/services/reimbursementMaterialPreview.js && npm run prisma:validate。
  • 前端:cd client && npm run typecheck && npm run build。
  • Playwright:复用 r102-reimbursement-main-flow.spec.ts 的 admin 非参与人全范围夹具增加撤回不可见断言,并保留现有 owner 可见断言;route mock 场景继续阻断 Service Worker。
  • 只读诊断:以脱敏元数据核对 BX-20260828-0017 材料顺序、EXIF/像素和合并页尺寸,不保留真实材料证据。
  • 治理:node scripts/qa/check-process-contract.mjs --baseline --json、node scripts/qa/audit-docs.mjs --check-registry、node scripts/qa/check-trellis-governance.mjs、git diff --check。