优化报销审批证据布局(reimbursement-form-shared-component-migration)

这个提交包含在:
2026-09-02 12:55:24 +08:00
父节点 9fc3b76438
当前提交 4b974fd87c
共修改 17 个文件,包含 291 行新增和 243 行删除
@@ -503,6 +503,7 @@ reference, not a copy of Feishu or Ant Design branding.
- Dispatchers: `WorkflowTaskRoutePage` and `MobileWorkflowTaskRoutePage` fetch one authorized `WorkflowTaskDetail`, then select the reimbursement adapter or the generic non-reimbursement detail.
- Pure layout shells: `ReimbursementDesktopWorkspaceShell` and `ReimbursementMobileWorkspaceShell`.
- Shared model/capability types: `ReimbursementWorkspaceModel`, `ReimbursementWorkspaceSlots` and `ReimbursementEvidenceCapabilities`.
- Evidence renderers: desktop expense table, mobile expense cards, independent invoice/attachment groups, and `ReimbursementReturnReferencePicker` inside the expanded return action.
- Structural preflight: `node scripts/qa/check-ui-design-rules.mjs --strict`.
### 3. Contracts
@@ -511,11 +512,14 @@ reference, not a copy of Feishu or Ant Design branding.
- A task dispatcher owns the single task-detail query and passes the same result plus controlled refetch to the selected renderer. The reimbursement adapter may fetch current reimbursement detail but must not fetch the same task detail again.
- Desktop and mobile shells share the same model, section order, `ReimbursementItemEvidenceList` and capability contract. They may use different DOM/layout skeletons: desktop main evidence plus one sticky command panel; mobile focus cards plus a bottom safe-area action surface.
- Shells compose ready data and slots only. They contain no `useQuery`, `useMutation`, API/fetch call, role/permission inference, workflow/reimbursement state-machine decision, `mode === ...` comparison or `isMobile` business branch. `check-ui-design-rules.mjs --strict` enforces this boundary and rejects a dormant reimbursement branch in the generic approval pages.
- The shared evidence component receives a minimal projection. Open/reference/edit/delete/link/unlink behavior exists only through callbacks; the component never infers capabilities from roles. Approval injects view/reference/decision only, read-only injects view only, and edit injects maintenance/submission capabilities.
- The shared evidence component receives a minimal projection. Desktop renders one expense table; mobile renders expense cards from the same item projection. Invoices and supplementary attachments render after expenses as separate material groups rather than nested item cards. The table/card shows only invoice count or short status; current item-to-invoice ownership remains in the projection and server contract.
- Open/edit/link/unlink behavior exists only through callbacks; the component never infers capabilities from roles. Approval and read-only expense rows have zero business-action controls. Edit injects one item-edit entry, with delete inside that edit flow, plus material maintenance/submission capabilities.
- A material file name or file row is the single per-file open control. Do not add adjacent `查看原件` or `查看附件` buttons. Unlinked or blocking invoice recovery remains available in the material group, and an optional `查看完整材料` stays a section-level secondary action.
- Item/invoice return references are not persistent evidence capabilities. Only the expanded return editor mounts `ReimbursementReturnReferencePicker`; abnormal candidates appear first, normal candidates require `展开全部`, and selecting a candidate appends an editable reference to the return comment.
- Submission-time fee-standard and budget facts come from the workflow context snapshot. Current item/invoice grouping, amount evidence and attachments come from the reimbursement detail. Approval pages do not call reimbursement precheck or present current budget data as a submission snapshot.
- Reimbursement approval actions fail closed until workflow snapshot parsing and current reimbursement evidence are ready. Historical missing budget snapshots are explained; malformed snapshots disable all decision paths.
- Mobile workflow caching uses an explicit persisted projection. Reimbursement items, invoices, attachments, amount evidence, material access data, workflow snapshot checks and shared component projections do not enter IndexedDB. Offline reimbursement approve/reject/return/draft is forbidden, while other workflow entity offline behavior remains unchanged.
- The information order is compact header and reason, item with owned invoices, unlinked invoices when present, supporting attachments, real issues/differences when present, then history/progress. Normal state creates no `0 条` check card. Issue copy identifies the object, reason, impact and next step rather than exposing internal counters alone.
- The information order is compact header and reason, expense items, invoices, supplementary attachments, real issues/differences when present, then history/progress. Normal state creates no `0 条` check card. Issue copy identifies the object, reason, impact and next step rather than exposing internal counters alone.
- `MobileStickyActionBar` and `MOBILE_STICKY_ACTION_PAGE_CLASS` are one contract. Add the page class only when `mobileActions` exists; omitting it lets `page-scaffold` transform capture the fixed bar, while adding it without a bar leaves false bottom padding.
- `/reimbursements/:id/print` remains a purpose-built print/PDF view. It is not a fourth interactive workbench and receives no workbench mutation.
@@ -530,16 +534,16 @@ reference, not a copy of Feishu or Ant Design branding.
### 5. Good/Base/Bad Cases
- Good: edit, read-only and approval display the same item/invoice grouping; only the adapter-provided actions differ. The approver reads evidence and acts from one task URL.
- Good: edit, read-only and approval share one item/material projection; desktop uses an expense table, mobile uses cards, and only adapter-provided capabilities differ. The approver reads evidence and acts from one task URL.
- Base: a completed task shows the latest authorized read-only evidence with a clear time-semantics note while history and submission snapshots remain historical.
- Bad: keep a dormant reimbursement branch in `WorkflowTaskDetailPage`/`MobileApprovalsPage`, query task detail in both dispatcher and adapter, or put `if (mode === "approval")` around API calls in a shell.
- Bad: cache evidence/context data offline, show normal `0 条` summaries, render two copies of the reimbursement header, or leave a mobile fixed action captured by an animated ancestor.
- Bad: nest full invoice cards and persistent file/reference buttons under every expense item, cache evidence/context data offline, show normal `0 条` summaries, render two copies of the reimbursement header, or leave a mobile fixed action captured by an animated ancestor.
### 6. Tests Required
- UI strict/self-test proves shell and legacy-branch rules are active and reports zero findings.
- Source/structure tests prove both task dispatchers contain one `fetchWorkflowTaskDetail` call, the approval adapter contains none, and both shells share the model/slots/capability contract and section order.
- PC/mobile E2E covers edit/read-only/approval, no-issue suppression, fail-closed, item-local invoice recovery, submit-confirm failure recovery, task deep links/back behavior and mobile fixed-action geometry.
- PC/mobile E2E covers edit/read-only/approval, desktop table/mobile cards, zero expense-row actions in approval/read-only, single file open controls, return-only progressive references, no-issue suppression, fail-closed, item-local invoice recovery, submit-confirm failure recovery, task deep links/back behavior and mobile fixed-action geometry.
- IndexedDB tests inspect the stored record and reject reimbursement item/invoice/attachment/context/material fields plus synthetic sentinel values. Non-reimbursement mobile offline draft create/sync/conflict remains green.
- Run `cd client && npm run typecheck && npm run build`, focused workflow/reimbursement Playwright, route/flow gates, Trellis governance and `git diff --check`.