fix: 统一报销付款详情布局与票据展示(09-04-reimbursement-state-gap-finance-view)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-09-11 22:28:06 +08:00
父节点 2b4e3faa0e
当前提交 98eabdde7f
共修改 11 个文件,包含 205 行新增和 31 行删除
@@ -14,6 +14,11 @@ and verification contracts. Do not copy broad aesthetic guidance from
## Convention: Reimbursement Payment Handoff Consistency
- Reimbursement desktop shells and payment detail opt into `detail-workspace-grid--payment`: a 320px aside at lg and above, single column below lg. A shared proportional grid does not guarantee equal asides when parent max-width differs. Verify actual widths on both pages at 1280/1440, not only matching class names; leave unrelated detail grids unchanged.
- `BusinessDetailActionPanel({ inlineActions: true })` puts the primary action followed by the More trigger in a wrapping, content-width row. The default layout stays unchanged. Both detail pages use the existing DropdownMenu; menu items are portalled outside the card, so test via page-level menu roles. Keep disabled states, permission conditions, confirmations and mobile payment actions intact. Do not pass known-empty action components as children: a React element that renders null is still a nonempty slot and otherwise creates a phantom divider.
- Linked reimbursement invoices use a desktop table with number preview, seller, date and right-aligned amount; narrow rows stack without duplicating IDs or preview controls. Keep OCR warnings, unlinked correction cards, attachment delete confirmation and evidence anchors. Test five synthetic invoices, long names/numbers, empty attachments, preview calls, narrow layout and the existing approval/detail consumers.
- A compact payee-account reveal control stays beside the masked value as a 44px Eye button with title and aria-label `查看完整账号`. Preserve role/permission/status/account gates and the reason/audit dialog; icon clicks must not immediately request plaintext. Layout measurements wait for fonts and compare aligned centers; round subpixel box heights to hundredths before checking the 44px minimum (Chromium can return 43.99994 for a CSS 44px target).
- `resolveReimbursementPaymentHandoff({ status, deletedAt, progress })` consumes the server's `payment_batch_created`, `payment_batch_review` and `payment_and_receipt` stages. It is a display projection, not a second payment eligibility or write state machine.
- Only an explicit current creation stage followed by pending review/payment can advertise creation, and the caller still requires `payment.batch.manage`. Missing stages, unknown status or contradictory facts never produce a guessed creation action. Cancelled and failed batches use the existing stage explanation, not automatic recreation.
- Read-only detail states (including reviewing, approved and paid) override global focus caching locally (`staleTime: 0`, refetch on mount and visibility return). Do not enable whole-app focus refetch or overwrite draft/rejected editors for this fix. A query error must not keep a stale actionable payment panel.