增加企微旧包刷新护栏(07-27-yang-jun-reimbursement-readiness)
这个提交包含在:
@@ -1764,6 +1764,90 @@ onNeedRefresh() {
|
||||
}
|
||||
```
|
||||
|
||||
## Scenario: Live WebView Build Freshness
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: a production browser, PWA or Enterprise WeChat WebView can remain
|
||||
alive across deployment and continue running an old SPA bundle even though
|
||||
public `index.html`, service worker and immutable chunks are current.
|
||||
- A public bundle containing new copy proves deployment, not that every live
|
||||
WebView has loaded that bundle.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Client build: `document.documentElement.dataset.buildSha`, sourced from
|
||||
`VITE_BUILD_SHA` and normalized to 12 hexadecimal characters.
|
||||
- Server check: `GET /ready` -> `{ data: { ok: true, buildSha: string } }`.
|
||||
- Resume event: document `visibilitychange` with `visibilityState="visible"`.
|
||||
- Prompt event: `hyb-oa:pwa-update-ready` with `{ applyUpdate }`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Check only when a loaded page returns to the foreground; do not add a timer
|
||||
or poll continuously.
|
||||
- Request `/ready` with `cache: "no-store"`; compare only valid hexadecimal
|
||||
build identifiers and never display the identifiers to ordinary users.
|
||||
- A mismatch dispatches the existing update-ready event once per page
|
||||
lifecycle. The logged-in shell shows `发现新版本` with an explicit
|
||||
`点击刷新`; it must not auto-reload an approval, form or auth input.
|
||||
- The refresh handler clears known PWA runtime/precache caches and then reloads
|
||||
the current URL. Existing auth-page update protection remains in force.
|
||||
- This monitor does not replace deployment build checks or real-device
|
||||
verification; it closes the live-client freshness gap after deployment.
|
||||
- The first deployment of this monitor cannot notify a WebView that is still
|
||||
executing an older bundle without the monitor. That rollout still requires
|
||||
an explicit manual refresh instruction; later deployments gain the guard.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Client and server builds match -> no prompt.
|
||||
- Valid builds differ -> show one prompt.
|
||||
- `/ready` is unavailable, non-2xx, malformed or missing `buildSha` -> stay
|
||||
silent and preserve the current page.
|
||||
- Client build is `development`, `unknown`, empty or malformed -> stay silent.
|
||||
- Repeated foreground events after a mismatch -> no duplicate request or
|
||||
prompt in the same page lifecycle.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: a manager returns to an old approval WebView, sees one refresh prompt,
|
||||
chooses refresh and then receives the deployed approval-detail bundle.
|
||||
- Base: the deployed and client builds match, so returning to the app adds no
|
||||
UI or network loop beyond the single readiness check.
|
||||
- Bad: infer that a missing button is a permission problem when adjacent UI
|
||||
from the same unconditional JSX block proves an old bundle is running.
|
||||
- Bad: force-refresh every foreground event or build a general update center.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Focused Playwright with synthetic builds covers mismatch, match and failed
|
||||
`/ready` responses.
|
||||
- Mismatch coverage asserts one prompt, no duplicate check in the same page,
|
||||
user-triggered reload, a 44px refresh target and no horizontal overflow at
|
||||
375px portrait and phone landscape widths.
|
||||
- Run the full affected login/portal UX file, frontend typecheck and build.
|
||||
- Production acceptance still requires the representative Enterprise WeChat
|
||||
WebView to refresh and visibly receive the new business entry.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```ts
|
||||
setInterval(() => window.location.reload(), 60_000);
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```ts
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (document.visibilityState === "visible") {
|
||||
void checkBuildFreshness();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Scenario: Auth Page Layout And Login Entry Hierarchy
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
在新工单中引用
屏蔽一个用户