diff --git a/console-ui/public/console/index.html b/console-ui/public/console/index.html
index 223c119..f3e0235 100644
--- a/console-ui/public/console/index.html
+++ b/console-ui/public/console/index.html
@@ -445,6 +445,15 @@ window.ARCRUN_API_BASE = (window.ARCRUN_CONFIG && window.ARCRUN_CONFIG.apiBase)
+
系統資訊
@@ -1526,6 +1535,27 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
})
.catch(function (e) { st.innerHTML = '
請求失敗:' + esc(friendlyErr(e)) + ''; });
});
+ // arcrun-rag#25:portal admin 密碼救援——只吃 console owner session(S.token,本頁登入用的
+ // 那把),不吃 portal session,所以就算忘記 portal 密碼、進不去 portal 也走得通。
+ $('st-portal-recover-btn').addEventListener('click', function () {
+ var email = $('st-portal-recover-email').value.trim();
+ var st = $('st-portal-recover-status');
+ if (!email) { st.innerHTML = '
請輸入 Email'; return; }
+ st.textContent = '處理中…';
+ fetch(API_BASE + '/portal/admin/recover-password', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + S.token },
+ body: JSON.stringify({ email: email })
+ })
+ .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })
+ .then(function (x) {
+ if (!x.ok) { st.innerHTML = '
' + esc(x.d.error || '失敗') + ''; return; }
+ st.innerHTML = '
新密碼:' + esc(x.d.password) + '(只顯示這一次,請立刻抄下)';
+ $('st-portal-recover-email').value = '';
+ toast('新密碼已產生,請立刻抄下');
+ })
+ .catch(function (e) { st.innerHTML = '
請求失敗:' + esc(friendlyErr(e)) + ''; });
+ });
// t36:原本這裡綁在那顆假開關上(點了只會 toast 一段 CLI 指示)。開關已移除,
// 這個 handler 也必須一起拿掉——留著會讓 $('st-vec-switch') 回 null、addEventListener
// 當場拋錯,把後面所有綁定(含登出)一起打斷。
diff --git a/console-ui/public/portal/index.html b/console-ui/public/portal/index.html
index 348702a..6f92768 100644
--- a/console-ui/public/portal/index.html
+++ b/console-ui/public/portal/index.html
@@ -220,6 +220,7 @@ if (!window.ARCRUN_API_BASE) {