修复报销详情时区并按 KISS 收敛页面(07-27-yang-jun-reimbursement-readiness)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-07-31 16:44:31 +08:00
父节点 35b44749a5
当前提交 39c3e808a3
共修改 10 个文件,包含 223 行新增和 227 行删除
@@ -36,6 +36,62 @@ and verification contracts. Do not copy broad aesthetic guidance from
with `AUTH_005`.
- Run `cd client && npm run typecheck && npm run build` for frontend changes.
## Scenario: UTC Date-Time Display In The Company Time Zone
### 1. Scope / Trigger
- Trigger: a frontend page displays an API timestamp such as attachment upload,
approval action, payment or audit time. API timestamps remain ISO 8601 UTC;
the company-facing OA displays date-times in `Asia/Shanghai`.
### 2. Signatures
- Shared formatter: `formatDisplayDateTime(value: string | null | undefined): string`.
- Date-only values continue to use `formatDisplayDate`; do not turn business
dates such as reimbursement or invoice dates into timezone-shifted instants.
### 3. Contracts
- Date-time pages reuse `client/src/lib/displayFormat.ts`; do not add a
page-local formatter for the same contract.
- `Intl.DateTimeFormat` must set `timeZone: "Asia/Shanghai"` explicitly so the
result does not depend on the browser, workstation or CI timezone.
- Database storage and API ISO strings remain unchanged.
### 4. Validation & Error Matrix
- Missing value -> `-`.
- Invalid date-time -> the shared display fallback; never throw during render.
- Valid UTC value -> Shanghai calendar date and clock time.
- Browser outside China -> the same Shanghai result as a browser in China.
### 5. Good/Base/Bad Cases
- Good: `2026-05-27T09:10:00.000Z` displays as `2026年5月27日 17:10`.
- Base: a null attachment or approval time displays `-`.
- Bad: `value.slice(0, 19).replace("T", " ")`, which presents UTC clock
fields as if they were local time.
### 6. Tests Required
- Focused Playwright uses synthetic UTC data and a browser `timezoneId` outside
Shanghai, then asserts the exact Shanghai attachment/approval time.
- Run `cd client && npm run typecheck && npm run build`.
### 7. Wrong vs Correct
#### Wrong
```ts
const displayed = value.slice(0, 19).replace("T", " ");
```
#### Correct
```ts
const displayed = formatDisplayDateTime(value);
```
## Convention: Frontend Design Token Sources
**What**: Runtime visual tokens use the sources that are actually consumed by