feat(student): auto-reconnect with backoff + WS-open retry

Replace the manual "Disconnected → Reconnect button" screen with a small
top-banner that retries the WS up to 8 times (500ms → 5s, ~27s budget).
On open, snapshot replay restores the question card and countdown so a
brief network blip is invisible to the student. After the retry budget
exhausts, fall back to a manual "Reload" card.

Same path covers initial WS-open failures (transient TLS hiccups on the
Aliyun edge), since the first connect() and subsequent reconnects share
the schedule. Auth-related closes (1008) still hard-reload immediately
so an invalidated cookie lands on the join form, not in a retry loop.

Submits are now also gated on ws.readyState === OPEN; clicks during a
reconnect are silent no-ops, and the question re-renders fresh once the
server replays state.
This commit is contained in:
ameer
2026-05-03 15:05:41 +08:00
parent 55ecb1b396
commit ec8d83aea8
2 changed files with 109 additions and 12 deletions

View File

@@ -332,6 +332,26 @@ input:focus, textarea:focus, select:focus {
.alert.error { margin: 0; }
.alert.info { border-left-color: var(--primary); color: var(--primary); background: color-mix(in srgb, var(--primary) 5%, transparent); }
/* ---------- Reconnect banner ---------- */
.reconnect-banner {
position: fixed;
top: 12px;
left: 50%;
transform: translateX(-50%);
z-index: 50;
padding: 8px 16px;
border-radius: 999px;
font-size: 0.85rem;
font-weight: 500;
color: var(--warn-text);
background: var(--warn);
box-shadow: var(--shadow);
letter-spacing: 0.01em;
pointer-events: none;
}
.reconnect-banner[hidden] { display: none; }
/* ---------- Admin topbar ---------- */
.admin-body { padding-bottom: 32px; }