feat: 成绩明细打印 + SQLite + 每卷独立配置(满分/合格率/免考) + 导航精简
- 成绩明细打印:默认成绩降序,可选按班级/组别分组对比(段首小计) - 修复看板退出全屏无反应(exitFullscreen 挂在 document 而非 documentElement) - 导航栏精简:三页统一为单一主标题,移除 Logo 与副标题 - 优化三端布局:重排断点、竖排隐藏 spacer、触摸设备热区 - 全面启用 SQLite(data/ny.db):配置/名单/每卷配置入库,无 pdo_sqlite 自动降级文件 - 新增独立合格率配置(全局 + 每卷),合格率不再写死 60% - 新增免考配置,仅对当前试卷生效,试卷间隔离 - 试卷独立满分从设置移出,改到主页面「试卷设置」 - 测试:新增 4 条每卷配置隔离断言,全套 113 项通过
This commit is contained in:
+43
-1
@@ -19,10 +19,49 @@ class Roster
|
||||
return class_exists('Db') && Db::pdo() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次启用 SQLite 时,把已有的 data/roster.json 迁进数据库(老数据不丢)。
|
||||
* 只在「DB 名单为空 且 文件有数据」时执行一次,之后由 DB 全权负责。
|
||||
*/
|
||||
private static function migrateFileToDbOnce(): void
|
||||
{
|
||||
if (!self::useDb()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (Db::rosterCount() > 0) {
|
||||
return; // DB 已有数据,不覆盖
|
||||
}
|
||||
$d = ny_read_json(self::file(), null);
|
||||
if (!is_array($d) || empty($d['students']) || !is_array($d['students'])) {
|
||||
return;
|
||||
}
|
||||
$clean = [];
|
||||
foreach ($d['students'] as $s) {
|
||||
if (!is_array($s)) {
|
||||
continue;
|
||||
}
|
||||
$clean[] = [
|
||||
'sid' => trim((string)($s['sid'] ?? '')),
|
||||
'name' => trim((string)($s['name'] ?? '')),
|
||||
'cls' => trim((string)($s['cls'] ?? '')),
|
||||
'grp' => trim((string)($s['grp'] ?? '')),
|
||||
'login' => trim((string)($s['login'] ?? '')),
|
||||
];
|
||||
}
|
||||
if ($clean !== []) {
|
||||
Db::rosterReplace($clean);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
// 迁移失败不影响主流程:仍可退回文件读取
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array<int,array{sid:string,name:string,cls:string}> */
|
||||
public static function all(): array
|
||||
{
|
||||
if (self::useDb()) {
|
||||
self::migrateFileToDbOnce();
|
||||
return Db::rosterAll();
|
||||
}
|
||||
$d = ny_read_json(self::file(), null);
|
||||
@@ -105,7 +144,10 @@ class Roster
|
||||
public static function fingerprint(): string
|
||||
{
|
||||
if (self::useDb()) {
|
||||
return 'db:' . self::count();
|
||||
// 人数 + 内容哈希:名单内容变了指纹才变(只靠人数会在"换人"时误命中缓存)
|
||||
$n = self::count();
|
||||
$hash = md5(json_encode(self::all(), JSON_UNESCAPED_UNICODE));
|
||||
return 'db:' . $n . ':' . $hash;
|
||||
}
|
||||
$f = self::file();
|
||||
$mt = is_file($f) ? (string)filemtime($f) : '0';
|
||||
|
||||
Reference in New Issue
Block a user