feat: 完善/优化/新增大批次 + 安全加固 + 性能优化
- 修复再次提交不置顶(排序键改用 last_submit_ts) - 后端结果缓存 + 并发锁(DataCache / ny_build_data / Roster 指纹失效) - 导出 xlsx 多表:按最新成绩 / 按班级分表 / 可选列 - 名单管理:新增改弹窗、删除多选+二次确认、登陆账号列 - 安全:CSRF token + 登录失败限流(5次锁10分钟) - 未匹配答卷一键加入名单(unmatched_map) - 缺考名单增强:复制学号/姓名、按班统计、打印 - 成绩快照 + 跨卷趋势(Snapshot) - 异常检测线索(短时长高分/高频重考/雷同成绩) - 前端性能:虚拟滚动、搜索防抖、后台暂停、失败退避 - 测试沉淀:test-new-features.php + run-all.sh
This commit is contained in:
@@ -98,6 +98,23 @@ class Roster
|
||||
return count(self::all());
|
||||
}
|
||||
|
||||
/**
|
||||
* 名单指纹:名单内容一变就变,用于数据缓存 key。
|
||||
* 只取「人数 + 文件修改时间 + 内容的轻量哈希」,避免每次全量序列化。
|
||||
*/
|
||||
public static function fingerprint(): string
|
||||
{
|
||||
if (self::useDb()) {
|
||||
return 'db:' . self::count();
|
||||
}
|
||||
$f = self::file();
|
||||
$mt = is_file($f) ? (string)filemtime($f) : '0';
|
||||
$sz = is_file($f) ? (string)filesize($f) : '0';
|
||||
$d = ny_read_json($f, null);
|
||||
$hash = is_array($d) ? md5(json_encode($d['students'] ?? [], JSON_UNESCAPED_UNICODE)) : '0';
|
||||
return $mt . ':' . $sz . ':' . $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次使用时,若名单为空且存在 导入模板.xlsx,自动导入
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user