收口报销详情返回与金额展示(07-27-yang-jun-reimbursement-readiness)
这个提交包含在:
@@ -92,6 +92,52 @@ const displayed = value.slice(0, 19).replace("T", " ");
|
||||
const displayed = formatDisplayDateTime(value);
|
||||
```
|
||||
|
||||
## Scenario: Shared RMB Display
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: a reimbursement, invoice, fee-control or payment UI displays a CNY amount received as a string, number or nullable field.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Shared formatter: `formatMoney(value: string | number | null | undefined): string` in `client/src/lib/displayFormat.ts`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Reuse the shared formatter across PC and mobile consumers; do not add page-local `Intl.NumberFormat` helpers for the same amount.
|
||||
- Valid amounts display the CNY symbol, thousands separators and exactly two decimal places. Missing, empty or non-finite values display `-`; they must not become `¥0.00`.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- `1860` / `"1860"` -> `¥1,860.00`.
|
||||
- `"550.5"` -> `¥550.50`.
|
||||
- `null`, `""`, invalid text or a non-finite number -> `-`.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: a PC detail total, mobile detail total and invoice summary all use `formatMoney`.
|
||||
- Base: a real zero amount displays `¥0.00`.
|
||||
- Bad: use string interpolation such as `` `¥${amount}` `` or coerce a missing amount with `Number(value ?? 0)`.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Focused frontend regression covers integer, fractional and thousands-separated amounts on PC and mobile.
|
||||
- Run `cd client && npm run typecheck && npm run build`.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```tsx
|
||||
<span>¥{detail.totalAmount ?? "-"}</span>
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```tsx
|
||||
<span>{formatMoney(detail.totalAmount)}</span>
|
||||
```
|
||||
|
||||
## Convention: Frontend Design Token Sources
|
||||
|
||||
**What**: Runtime visual tokens use the sources that are actually consumed by
|
||||
@@ -235,6 +281,7 @@ reference, not a copy of Feishu or Ant Design branding.
|
||||
- Mobile reimbursement target: `/mobile/reimbursements/:reimbursementId`.
|
||||
- PC reimbursement target: `/reimbursements/:reimbursementId`.
|
||||
- Mobile source state: `<Link state={{ from: currentMobileSource }}>`.
|
||||
- PC source state: `<Link state={{ from: currentPcSource }}>`; `currentPcSource` is the trusted internal `pathname + search` of the current reimbursement list or approval task.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
@@ -242,6 +289,8 @@ reference, not a copy of Feishu or Ant Design branding.
|
||||
- When `WorkflowTaskDetail.reimbursement` exists, the task detail exposes an explicitly named `查看完整报销单` or `查看报销单` link near the reimbursement summary.
|
||||
- Reuse the existing business detail route and its permissions. Do not duplicate reimbursement items, invoice or attachment viewers inside the approval page merely to add reachability.
|
||||
- Mobile navigation passes the current approval task URL through the existing `state.from` convention so the business detail back button returns to that task. This is a one-level source contract, not a new nested return stack.
|
||||
- PC reimbursement list and task-detail exits use the same one-level `state.from` contract. The detail page accepts only `/reimbursements` list URLs and `/workflow/tasks/:id`; absolute/protocol-relative URLs, hashes, other modules and the current page are rejected. A direct open or refresh safely falls back to `/reimbursements`.
|
||||
- PC detail return is a visible text action immediately before the detail hero, uses `replace`, and is not duplicated inside the business primary-action group or `更多`.
|
||||
- Approval actions remain on the approval task page. Opening the business detail does not approve, reject, return or mutate the task.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
@@ -260,7 +309,7 @@ reference, not a copy of Feishu or Ant Design branding.
|
||||
### 6. Tests Required
|
||||
|
||||
- Mobile E2E: task detail -> reimbursement detail -> items/evidence visible -> back to the same task -> approval actions still visible.
|
||||
- PC E2E: task detail link -> existing reimbursement detail route and overview visible.
|
||||
- PC E2E: filtered reimbursement list -> task/detail -> visible source-aware return; the list path retains its query string, task detail returns to the same task, and direct-open detail falls back to the reimbursement list.
|
||||
- Assert non-reimbursement task details do not receive a reimbursement target.
|
||||
- Run `cd client && npm run typecheck && npm run build`.
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户