fix: 审查修复波次(P0x4 + P1x30+)

- domain/rules: 计分与排名解耦、破纪录按组别、tieBreak 生效、调整分不丢、移除 aggregate 假能力
- realtime: 新建 internal/dto,快照三项契约对齐,/ws 只认会话身份
- httpapi: 流水幂等、standings 整表载荷、广播接线、强制改密、XFF 防伪造、records 写入、审计、赛事包内容、发布前备份、result.points、实例列表
- web: FormData 上传、YAML 解析、快照归一化、大屏解析层、bootstrap 降级、访客判定、主题切换
- console: 优雅关闭握手、中文化、免验证改管理员账号、选屏与日志轮转修复
- docs: 用户文档三份 + README
- 主代理: 破纪录加分接线(levels 未加载导致恒 0)
This commit is contained in:
AskaEth committed 2026-09-09 21:06:40 +08:00
1 parent 8dae63ee70
commit 7f9701c465
61 files changed
+3844 -333

No files matched your search

+31 -70
View File
@@ -2,11 +2,11 @@
REM ============================================================================
REM Scoreboard 一键备份(Windows)
REM
REM 用 sqlite3.exe 的 VACUUM INTO 生成一致性快照,服务运行中也能安全执行,
REM 不需要停服务、不需要重启。产物落在 data\backups\,滚动保留最近 20 份。
REM
REM 依赖:sqlite3.exe(放到本脚本同目录、项目根目录,或加入 PATH 均可)。
REM 下载地址 https://www.sqlite.org/download.html 的 sqlite-tools-win-x64。
REM 调用 scoreboard.exe 的 backup 子命令(内置 VACUUM INTO),服务运行中也能
REM 安全执行,不需要停服务、不依赖外部 sqlite3.exe。
REM 产物落在 data\backups\,服务端按库(system / 各赛事)各自滚动保留 20 份。
REM 注意:只快照 .db,不含 event_projs\<项目>\uploads\ 里的背景图/会标等资源;
REM 需要连资源一起留档时,请另行拷贝 data\event_projs\<项目>\uploads\。
REM
REM 用法:deploy\backup.bat 手动备份(原因记 manual)
REM deploy\backup.bat publish 发布前备份(原因记 publish)
@@ -17,8 +17,6 @@ chcp 65001 >nul 2>&1
cd /d "%~dp0.."
set "ROOT=%CD%"
set "DATA=%ROOT%\data"
set "OUT=%DATA%\backups"
set "KEEP=20"
set "REASON=manual"
if not "%~1"=="" set "REASON=%~1"
@@ -33,57 +31,51 @@ if not exist "%DATA%" (
exit /b 1
)
REM ---- 定位 sqlite3.exe -------------------------------------------------------
set "SQLITE="
if exist "%~dp0sqlite3.exe" set "SQLITE=%~dp0sqlite3.exe"
if not defined SQLITE if exist "%ROOT%\sqlite3.exe" set "SQLITE=%ROOT%\sqlite3.exe"
if not defined SQLITE for %%I in (sqlite3.exe) do if exist "%%~$PATH:I" set "SQLITE=%%~$PATH:I"
if not defined SQLITE (
echo [错误] 找不到 sqlite3.exe。
echo 请把它放到 deploy\ 目录或加入 PATH 后重试。
REM ---- 定位 scoreboard.exe ----------------------------------------------------
set "EXE="
if exist "%~dp0..\dist\scoreboard.exe" set "EXE=%~dp0..\dist\scoreboard.exe"
if not defined EXE if exist "%ROOT%\scoreboard.exe" set "EXE=%ROOT%\scoreboard.exe"
if not defined EXE if exist "%~dp0scoreboard.exe" set "EXE=%~dp0scoreboard.exe"
if not defined EXE for %%I in (scoreboard.exe) do if exist "%%~$PATH:I" set "EXE=%%~$PATH:I"
if not defined EXE (
echo [错误] 找不到 scoreboard.exe。
echo 请先执行 deploy\build.bat,或把它放到项目根目录 / 加入 PATH。
exit /b 1
)
REM ---- 时间戳:优先 PowerShell,避免受区域设置影响 -----------------------------
set "TS="
for /f "usebackq delims=" %%I in (`powershell -NoProfile -Command "Get-Date -Format yyyyMMdd-HHmmss" 2^>nul`) do set "TS=%%I"
if not defined TS call :fallback_ts
if not defined TS (
echo [错误] 无法生成时间戳。
REM dataDir 是相对路径,服务端按当前工作目录解析,所以必须在项目根目录调用
if not exist "%ROOT%\config.yaml" (
echo [错误] 找不到 %ROOT%\config.yaml,无法定位 dataDir。
exit /b 1
)
if not exist "%OUT%" mkdir "%OUT%"
echo === Scoreboard 备份 ===
echo 数据目录:%DATA%
echo 备份目录:%OUT%
echo 时间戳 :%TS%
echo 服务端 :%EXE%
echo 原因 :%REASON%
echo.
set /a OK=0
set /a FAIL=0
if exist "%DATA%\system.db" call :backup "system" "%DATA%\system.db"
REM 服务端一次只备份一个赛事库(system.db 每次都会一并快照),按目录逐个调用;
REM 部署形态通常只有一个 default 项目,这里就只跑一次。
set "FOUND="
for /d %%D in ("%DATA%\event_projs\*") do (
if exist "%%~fD\event.db" call :backup "%%~nxD" "%%~fD\event.db"
set "FOUND=1"
echo 备份赛事 %%~nxD
"%EXE%" backup -config config.yaml -project "%%~nxD" -reason "%REASON%"
if errorlevel 1 (set /a FAIL+=1) else (set /a OK+=1)
)
echo.
echo === 滚动清理(保留最近 %KEEP% 份)===
set /a N=0
for /f "delims=" %%F in ('dir /b /o-d /a-d "%OUT%\*.db" 2^>nul') do (
set /a N+=1
if !N! GTR %KEEP% (
echo 删除 %%F
del /f /q "%OUT%\%%F" >nul 2>&1
)
if not defined FOUND (
echo 备份默认赛事
"%EXE%" backup -config config.yaml -reason "%REASON%"
if errorlevel 1 (set /a FAIL+=1) else (set /a OK+=1)
)
echo.
echo === 备份完成:成功 !OK! 个,失败 !FAIL! 个 ===
dir /b "%OUT%\*.db" 2>nul
dir /b "%DATA%\backups\*.db" 2>nul
if !FAIL! GTR 0 (
endlocal
@@ -91,34 +83,3 @@ if !FAIL! GTR 0 (
)
endlocal
exit /b 0
REM ---- 备份单个库:%1 文件名前缀,%2 数据库路径 -------------------------------
:backup
set "PREFIX=%~1"
set "DBFILE=%~2"
set "TARGET=%OUT%\%PREFIX%-%REASON%-%TS%.db"
if exist "%TARGET%" set "TARGET=%OUT%\%PREFIX%-%REASON%-%TS%-%RANDOM%.db"
echo 备份 %DBFILE%
echo -^> %TARGET%
"%SQLITE%" "%DBFILE%" "VACUUM INTO '%TARGET%'"
if errorlevel 1 (
echo [失败] sqlite3 返回错误
set /a FAIL+=1
) else (
set /a OK+=1
)
exit /b 0
REM ---- %DATE%/%TIME% 兜底:只保证名字不重复 -----------------------------------
:fallback_ts
set "D=%DATE%"
set "T=%TIME%"
set "D=%D:/=%"
set "D=%D:-=%"
set "D=%D:.=%"
set "T=%T::=%"
set "T=%T:.=%"
set "T=%T: =0%"
set "TS=%D%-%T%"
exit /b 0