完成批次 L-R:限流移除/白名单驱动/打印增强/全屏/表格对齐/主题变量/滚动闪烁修复

- 移除登录失败限流;fix-config.php 修正 e2e 串味的 127.0.0.1 连接

- 白名单驱动缺/待考名单(DataService + SurveyKingClient::getWhitelist,复用已取 survey)

- 打印成绩明细增强(范围/合格列默认关/去页脚);看板全屏占满;表格 vertical-align:middle;隐藏登陆账号;导入默认追加

- 主题变量收口(:root 新增 brand/primary-2/ok-2 等,替换硬编码渐变);删死规则

- 表头/数据列对齐修复(index 未匹配表、dashboard 成员榜、draw 结果/历史/排除表);看板占位卡片配色一致

- 修复滚动闪烁:row-drop-in 动画经 _dropAnim 门控,仅强制重绘时播放

- 测试:新增 test-whitelist.js;run-all.sh 全绿 132
This commit is contained in:
2026-09-13 10:25:48 +08:00
parent 804b04de60
commit 94ac381579
17 changed files with 856 additions and 301 deletions
+9 -70
View File
@@ -56,17 +56,6 @@ class Db
return self::$err;
}
/** 连接参数(SQLite 固定,保留接口以兼容既有调用) */
public static function params(): array
{
return ['driver' => 'sqlite', 'file' => self::dbFile()];
}
public static function saveParams(array $p): bool
{
return true; // SQLite 无需外部配置
}
/** 建立/复用连接;失败返回 null 而不抛异常(上层要能优雅降级) */
public static function connect(array $p = []): PDO
{
@@ -180,25 +169,6 @@ class Db
// ---------------- 设置 ----------------
public static function settingsAll(): array
{
$pdo = self::pdo();
if (!$pdo) {
return [];
}
try {
$p = self::prefix();
$st = $pdo->query("SELECT k, v FROM {$p}settings");
$out = [];
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) {
$out[(string)$r['k']] = (string)$r['v'];
}
return $out;
} catch (Throwable $e) {
self::$err = $e->getMessage();
return [];
}
}
/** SQLite 用 ON CONFLICT 做 upsert(其它方言见历史版本) */
public static function settingsSet(string $k, string $v): void
@@ -265,12 +235,16 @@ class Db
}
}
/** 全量替换名单(roster_save 语义) */
public static function rosterReplace(array $students): void
/**
* 全量替换名单(roster_save 语义)
* @return bool 成功 true;DB 不可用或事务失败 false(失败原因见 lastError)
*/
public static function rosterReplace(array $students): bool
{
$pdo = self::pdo();
if (!$pdo) {
return;
self::$err = '数据库未连接';
return false;
}
try {
$p = self::prefix();
@@ -296,11 +270,13 @@ class Db
]);
}
$pdo->commit();
return true;
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
self::$err = $e->getMessage();
return false;
}
}
@@ -321,29 +297,6 @@ class Db
// ---------------- 每卷独立配置(满分 / 合格率 / 免考名单) ----------------
/** @return array<string,array> 全部试卷配置 [project_id => cfg] */
public static function projectConfigAll(): array
{
$pdo = self::pdo();
if (!$pdo) {
return [];
}
try {
$p = self::prefix();
$st = $pdo->query("SELECT project_id, config_json FROM {$p}project_config");
$out = [];
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) {
$j = json_decode((string)($r['config_json'] ?? '{}'), true);
if (is_array($j)) {
$out[(string)$r['project_id']] = $j;
}
}
return $out;
} catch (Throwable $e) {
self::$err = $e->getMessage();
return [];
}
}
/** @return array 单卷配置(缺省返回空结构) */
public static function projectConfigGet(string $projectId): array
@@ -394,18 +347,4 @@ class Db
}
}
public static function projectConfigDelete(string $projectId): void
{
$pdo = self::pdo();
if (!$pdo) {
return;
}
try {
$p = self::prefix();
$st = $pdo->prepare("DELETE FROM {$p}project_config WHERE project_id = ?");
$st->execute([$projectId]);
} catch (Throwable $e) {
self::$err = $e->getMessage();
}
}
}