修复"未配置卷王登录账号"导致后台刷新陷入死状态
根因:login.php 仅持久化 username、不持久化 password;token 缓存失效后
自动重登因缺少密码而抛 RuntimeException('未配置卷王登录账号'),前端仅提示
"后台刷新失败,已显示本地缓存"却无法自愈,刷新循环永不恢复。
修复:
- login.php:登录成功时同时持久化 username 与 password,token 失效时平台
可凭凭据自动重新登录卷王,避免死状态。
- api.php:全局 catch 对鉴权类错误(未配置账号/登录失败)打标 extra.auth=true。
- assets/app.js、dashboard.php:api() 透传 auth 标记;刷新失败若为鉴权错误,
自动跳转 login.php 重新登录,不再停留在本地缓存死状态。
验证:本地 mock 卷王端到端复现 CASE1(空账号精确复现报错)与 CASE2
(凭据齐备自动重登成功),HTTP 接口确认返回 extra.auth:true 与 ok:true。
This commit is contained in:
@@ -502,7 +502,13 @@ try {
|
|||||||
ny_fail('未知操作:' . $action);
|
ny_fail('未知操作:' . $action);
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) {
|
} 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,
|
'trace' => defined('NY_DEBUG') && NY_DEBUG ? $e->getTraceAsString() : null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -70,7 +70,12 @@
|
|||||||
try { json = JSON.parse(text); } catch (e) {
|
try { json = JSON.parse(text); } catch (e) {
|
||||||
throw new Error('服务端返回异常(可能 PHP 报错):' + text.slice(0, 300));
|
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;
|
return json.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +249,12 @@
|
|||||||
// 名单缓存一份(便于刷新前/失败时仍能渲染班级/组别下拉)
|
// 名单缓存一份(便于刷新前/失败时仍能渲染班级/组别下拉)
|
||||||
LS.set(LS_ROSTER, { ts: Date.now(), students: d.roster || [] });
|
LS.set(LS_ROSTER, { ts: Date.now(), students: d.roster || [] });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e.auth) {
|
||||||
|
// 卷王账号未配置或登录已失效:引导重新登录,避免卡在"已显示本地缓存"的死状态
|
||||||
|
showAlert('卷王账号未配置或登录已失效,正在跳转登录页…', 'error');
|
||||||
|
setTimeout(() => { location.href = 'login.php'; }, 900);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!cached) {
|
if (!cached) {
|
||||||
if (!silent) setConn('conn-err', '数据获取失败');
|
if (!silent) setConn('conn-err', '数据获取失败');
|
||||||
showAlert(e.message);
|
showAlert(e.message);
|
||||||
|
|||||||
+9
-1
@@ -129,7 +129,9 @@ async function api(action, params){
|
|||||||
const res = await fetch(url, { headers: { 'Accept': 'application/json' } });
|
const res = await fetch(url, { headers: { 'Accept': 'application/json' } });
|
||||||
const j = await res.json();
|
const j = await res.json();
|
||||||
if (j && j.ok) return j.data;
|
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();
|
renderBoard();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e.auth) {
|
||||||
|
// 卷王账号未配置或登录失效:跳转登录页自愈
|
||||||
|
$('#boardBody').innerHTML = '<div class="empty">卷王账号未配置或登录已失效,<a href="login.php">点击重新登录</a></div>';
|
||||||
|
setTimeout(() => { location.href = 'login.php'; }, 1200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
sel.innerHTML = '<option value="">加载失败</option>';
|
sel.innerHTML = '<option value="">加载失败</option>';
|
||||||
sel.disabled = true;
|
sel.disabled = true;
|
||||||
$('#boardBody').innerHTML = '<div class="empty">加载失败:' + esc(e.message) + '</div>';
|
$('#boardBody').innerHTML = '<div class="empty">加载失败:' + esc(e.message) + '</div>';
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
try {
|
try {
|
||||||
$client = new SurveyKingClient($test);
|
$client = new SurveyKingClient($test);
|
||||||
$client->getToken(true);
|
$client->getToken(true);
|
||||||
// 登录成功:把账号写回配置(如需),并建立会话
|
// 登录成功:把账号与密码写回配置(本地单用户工具,持久化密码以便 token
|
||||||
|
// 失效时平台能自动重新登录卷王,避免后台刷新陷入"未配置账号"的死状态)
|
||||||
$cfg['username'] = $user;
|
$cfg['username'] = $user;
|
||||||
|
$cfg['password'] = $pwd;
|
||||||
ny_save_config($cfg);
|
ny_save_config($cfg);
|
||||||
ny_login();
|
ny_login();
|
||||||
$ok = true;
|
$ok = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user