feat: 全面打磨平台交互

- 名单导入容错:rowsToStudents 加去重/跳过统计、表头正则扩充、.0 尾巴清理;importFile 返回精确 count
- 看板:修复 .repeat(0) 空状态坏代码;新增实时点 stale 指示(手动/自动刷新失败变红 + 提示刷新中断);
        手动刷新按钮加刷新中…反馈;记住自动刷新开关与间隔(localStorage + ?interval= 深链)
- 主统计页:后台静默刷新连续失败时连接指示转实时刷新中断告警;记住用户手动调整的刷新间隔
- 设置页:新增 config_test 端点 + 独立测试连接按钮(用弹窗内未保存凭据测连接,不落盘);
        保存按钮加保存中…防重提交;登录失败不清旧 token
- 抽取页:重置结果加二次确认;新增复制名单按钮(两列制表符分隔,可粘到微信/Excel)
- 修复看板预先存在 JS 语法错误(少一个右括号导致整页 JS 失效)
This commit is contained in:
2026-09-09 18:53:00 +08:00
parent c4c3bf7da1
commit 9ee2aec2f0
8 changed files with 247 additions and 31 deletions
+37 -1
View File
@@ -132,6 +132,36 @@ try {
}
ny_ok($res);
// ---------------- 用弹窗内(未保存)的凭据测试连接 ----------------
case 'config_test':
$raw = (string)file_get_contents('php://input');
$in = json_decode($raw, true);
if (!is_array($in)) {
$in = $_POST;
}
// 以已保存配置为基底,仅覆盖弹窗中填写的字段,避免漏填导致误测
$test = ny_load_config();
foreach (['base_url', 'api_prefix', 'username', 'verify_ssl', 'timeout'] as $k) {
if (array_key_exists($k, $in)) {
$test[$k] = is_string($in[$k]) ? trim((string)$in[$k]) : $in[$k];
}
}
if (array_key_exists('password', $in)) {
$pwdIn = (string)$in['password'];
if ($pwdIn !== '' && $pwdIn !== '******') {
$test['password'] = $pwdIn;
}
}
$test['base_url'] = rtrim((string)($test['base_url'] ?? ''), '/');
$test['api_prefix'] = '/' . trim((string)($test['api_prefix'] ?? '/api'), '/');
try {
$client = new SurveyKingClient($test);
$p = $client->ping();
ny_ok(['connected' => true, 'projects' => $p['projects'], 'elapsed' => $p['elapsed']]);
} catch (Throwable $e) {
ny_ok(['connected' => false, 'msg' => $e->getMessage()]);
}
// ---------------- 连接测试 ----------------
case 'ping':
$client = new SurveyKingClient(cfg());
@@ -345,7 +375,13 @@ try {
} else {
Roster::save($res['students']);
}
ny_ok(['students' => Roster::all(), 'meta' => Roster::meta(), 'imported' => $res['count']]);
ny_ok([
'students' => Roster::all(),
'meta' => Roster::meta(),
'imported' => $res['count'],
'skipped' => $res['skipped'] ?? 0,
'duplicates' => $res['duplicates'] ?? 0,
]);
case 'roster_save':
$raw = (string)file_get_contents('php://input');