From 9a29eb5af68a25d9f2b89de0efabfd3105a1279d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 10 Aug 2026 13:51:41 +0000 Subject: [PATCH] =?UTF-8?q?fix(portal):=20=E7=80=8F=E8=A6=BD=E5=99=A8?= =?UTF-8?q?=E5=AF=A6=E6=B8=AC=E6=8A=93=E5=88=B0=E7=9A=84=E5=85=A9=E5=80=8B?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E7=BC=BA=E9=99=B7=E2=80=94=E2=80=94=E9=80=A3?= =?UTF-8?q?=E7=B5=90=E8=A2=AB=E8=B7=AF=E7=94=B1=E5=90=83=E6=8E=89=E3=80=81?= =?UTF-8?q?.hide=20=E5=BE=9E=E4=BE=86=E6=B2=92=E6=9C=89=E5=9C=A8=E8=97=8F?= =?UTF-8?q?=E6=9D=B1=E8=A5=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 兩個都是「HTTP 200 看不出來、真的開瀏覽器才會現形」的(規則五點五③)。 ① `#/reset?token=…` 被路由正規化吃掉 route() 的第一行是「raw 不在 VIEWS 就換成 HOME」,而 reset 不是站內的 view ⇒ 使用者點信裡的連結,網址被改寫成 `#/search`、修改密碼畫面根本沒出現, **而且 token 一起被丟掉**——連結一次有效,等於這條連結就這樣廢了。 改:route() 開頭先看有沒有 reset token,有就走 showReset 並 return。 (boot() 那條只顧得到「整頁重新載入」;hash 變動這條路以前沒人守。) ② `.hide` 一直只有三條有 scope 的規則(#tabbar .tab / #sidenav .nav / .modebtn) 沒有通用的 `.hide { display:none }` ⇒ 任何其他元素掛上 class="hide" **完全沒被藏起來**, 看起來有藏、其實沒藏。實測畫面:登入頁還沒按「忘記密碼」就已經露出 email 欄與「寄出連結」; 連結模式下「現有密碼」那一格也照樣顯示(D62 的「差別只有一格」當場破功)。 補通用規則,帶 !important 以蓋過 inline display(#forgot-box 有)。 既有三種用法意圖一致(都是要藏),行為不變。 stage 瀏覽器實測(youlin,playwright):忘記密碼 → 取連結 → 點進去 → 不輸入現有密碼設新密碼 → 自動回登入頁 → 用新密碼登入成功 → 進站 → 設定頁同一份表單(現有密碼那一格回來)改密碼 → **沒有被踢出去、可以繼續操作**。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01R8vF2zS2XpaZjzkC75Fjss --- console-ui/public/portal/index.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/console-ui/public/portal/index.html b/console-ui/public/portal/index.html index e0a6bec..c09c43c 100644 --- a/console-ui/public/portal/index.html +++ b/console-ui/public/portal/index.html @@ -122,6 +122,12 @@ .modebtn { flex: none; padding: 9px 18px; font-size: 14.5px; border-radius: 999px; cursor: pointer; border: 1px solid rgba(var(--ink-rgb),.18); background: none; color: rgba(var(--ink-rgb),.6); } .modebtn.on { border-color: rgba(var(--amber-rgb),.6); background: rgba(var(--amber-rgb),.14); color: var(--amber); font-weight: 600; } .modebtn.hide { display: none; } + /* 🔴 2026-08-10 實測撞到:`.hide` 一直**只有上面那三條有 scope 的規則**(#tabbar .tab / #sidenav .nav / .modebtn), + 所以任何其他元素掛上 class="hide" 都**完全沒有被藏起來**——看起來有藏、其實沒藏。 + D62 的「忘記密碼」欄位與「現有密碼」欄位就是這樣在瀏覽器上原形畢露的。 + 補一條通用規則;帶 !important 是因為要蓋過 inline 的 display(#forgot-box 就有)。 + 既有那三種用法的意圖與本規則一致(都是「藏起來」),加這條不改變它們的行為。 */ + .hide { display: none !important; } .kgrid { display: grid; grid-template-columns: 1fr; gap: 12px; padding-bottom: 8px; } @media (min-width: 700px) { .kgrid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } } .kcard { padding: 18px; border-radius: 13px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); cursor: pointer; display: flex; flex-direction: column; gap: 9px; } @@ -780,6 +786,12 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { } var LOADERS = { card: loadCard, map: loadMap, workflows: loadWorkflows, admin: loadAdmin, settings: loadSettings }; function route() { + // 🔴 D62:`#/reset?token=…` **不是站內的一個 view**,是「還沒登入的人拿著連結進來」。 + // 少了這一段,下面那行正規化會把不認得的 `reset` 換成 HOME ⇒ **連 token 一起丟掉**, + // 使用者點信裡的連結會落在搜尋頁、而且再也回不去(連結一次有效,已經耗掉了)。 + // 實測(2026-08-10 stage,瀏覽器):網址被改寫成 `#/search`、修改密碼畫面根本沒出現。 + var rt = resetTokenFromUrl(); + if (rt) { showReset(rt); return; } var r = currentRoute(); if (r.raw && r.raw !== r.view) { location.hash = '#/' + r.view; return; } if (r.view === 'card' && r.arg) S.cardId = decodeURIComponent(r.arg);