diff --git a/api.php b/api.php index 1fb2d9d..355e40d 100644 --- a/api.php +++ b/api.php @@ -502,7 +502,13 @@ try { ny_fail('未知操作:' . $action); } } catch (Throwable $e) { - ny_fail($e->getMessage(), [ + $msg = $e->getMessage(); + // 鉴权类错误(账号未配置 / 登录卷王失败)打标,前端据此跳登录页自愈 + $isAuth = str_contains($msg, '未配置卷王登录账号') + || str_contains($msg, '登录卷王失败') + || str_contains($msg, '登录失败'); + ny_fail($msg, [ + 'auth' => $isAuth, 'trace' => defined('NY_DEBUG') && NY_DEBUG ? $e->getTraceAsString() : null, ]); } diff --git a/assets/app.js b/assets/app.js index 95373f4..2ad6cf2 100644 --- a/assets/app.js +++ b/assets/app.js @@ -70,7 +70,12 @@ try { json = JSON.parse(text); } catch (e) { throw new Error('服务端返回异常(可能 PHP 报错):' + text.slice(0, 300)); } - if (!json.ok) throw new Error(json.msg || '请求失败'); + if (!json.ok) { + const err = new Error(json.msg || '请求失败'); + err.auth = !!(json.extra && json.extra.auth); + err.extra = json.extra || null; + throw err; + } return json.data; } @@ -244,6 +249,12 @@ // 名单缓存一份(便于刷新前/失败时仍能渲染班级/组别下拉) LS.set(LS_ROSTER, { ts: Date.now(), students: d.roster || [] }); } catch (e) { + if (e.auth) { + // 卷王账号未配置或登录已失效:引导重新登录,避免卡在"已显示本地缓存"的死状态 + showAlert('卷王账号未配置或登录已失效,正在跳转登录页…', 'error'); + setTimeout(() => { location.href = 'login.php'; }, 900); + return; + } if (!cached) { if (!silent) setConn('conn-err', '数据获取失败'); showAlert(e.message); diff --git a/dashboard.php b/dashboard.php index 001dc4b..ba59ee5 100644 --- a/dashboard.php +++ b/dashboard.php @@ -129,7 +129,9 @@ async function api(action, params){ const res = await fetch(url, { headers: { 'Accept': 'application/json' } }); const j = await res.json(); if (j && j.ok) return j.data; - throw new Error((j && (j.msg || j.error)) || '请求失败'); + const err = new Error((j && (j.msg || j.error)) || '请求失败'); + err.auth = !!(j && j.extra && j.extra.auth); + throw err; } /* ---------- 问卷列表(双策略文件夹识别 + 缓存) ---------- */ @@ -212,6 +214,12 @@ async function refreshClassSel(){ } renderBoard(); } catch (e) { + if (e.auth) { + // 卷王账号未配置或登录失效:跳转登录页自愈 + $('#boardBody').innerHTML = '
卷王账号未配置或登录已失效,点击重新登录
'; + setTimeout(() => { location.href = 'login.php'; }, 1200); + return; + } sel.innerHTML = ''; sel.disabled = true; $('#boardBody').innerHTML = '
加载失败:' + esc(e.message) + '
'; diff --git a/login.php b/login.php index 6ca9580..1654c24 100644 --- a/login.php +++ b/login.php @@ -30,8 +30,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { $client = new SurveyKingClient($test); $client->getToken(true); - // 登录成功:把账号写回配置(如需),并建立会话 + // 登录成功:把账号与密码写回配置(本地单用户工具,持久化密码以便 token + // 失效时平台能自动重新登录卷王,避免后台刷新陷入"未配置账号"的死状态) $cfg['username'] = $user; + $cfg['password'] = $pwd; ny_save_config($cfg); ny_login(); $ok = true;