- domain/rules: 计分与排名解耦、破纪录按组别、tieBreak 生效、调整分不丢、移除 aggregate 假能力 - realtime: 新建 internal/dto,快照三项契约对齐,/ws 只认会话身份 - httpapi: 流水幂等、standings 整表载荷、广播接线、强制改密、XFF 防伪造、records 写入、审计、赛事包内容、发布前备份、result.points、实例列表 - web: FormData 上传、YAML 解析、快照归一化、大屏解析层、bootstrap 降级、访客判定、主题切换 - console: 优雅关闭握手、中文化、免验证改管理员账号、选屏与日志轮转修复 - docs: 用户文档三份 + README - 主代理: 破纪录加分接线(levels 未加载导致恒 0)
19 KiB
部署指南
面向现场操作人员与管理员。本系统完全离线运行,不需要联网,不需要安装任何运行时。
1. 运行环境要求
| 项目 | 要求 |
|---|---|
| 服务端主机 | Windows 10 / 11,64 位(amd64) |
| 大屏 | 通过 HDMI 接入主机;显示模式设为扩展;推荐 16:9、1920×1080 或 3840×2160 |
| 网络 | 完全离线即可运行。若需要手机/平板/电视访问,用独立交换机或路由器组成局域网 |
| 磁盘 | 建议预留 ≥ 10GB |
| 运行时 | 无需安装 Go / Node / 数据库等任何运行时,前端已内嵌进可执行文件 |
| 权限 | 首次运行会在部署目录下创建 data\、logs\,请确保该目录可写 |
服务端只构建 Windows amd64 一个版本。Linux / 其他平台不在交付范围内。
2. 获取安装包
在构建机(具备 Go、Node.js、pnpm、git 环境,并能访问依赖源)上执行:
deploy\build.bat
脚本依次完成:拉取代码 → 构建前端 → 构建服务端 → 打包桌面宿主。产物落在仓库的 dist\ 目录:
| 产物 | 类型 | 说明 |
|---|---|---|
dist\scoreboard.exe |
服务端 | 前端已通过内嵌方式打进可执行文件,单独运行也能提供全部页面 |
dist\console\Scoreboard Console-0.1.0-x64.exe |
安装包 | NSIS 安装程序,双击按向导安装 |
dist\console\Scoreboard Console-0.1.0-x64.zip |
免安装包 | 解压即用 |
dist\console\win-unpacked\ |
目录 | 未压缩的运行目录,便于现场调试 |
文件名中的
0.1.0来自console\package.json的版本号,会随版本升级变化;以dist\console\下的实际文件名为准。目标机器不需要 Go / Node / pnpm,也不联网;上述工具只用于构建机。
3. 安装与首次启动
3.1 使用安装包
- 双击
Scoreboard Console-0.1.0-x64.exe。 - 按向导选择安装目录(可自定义)。
- 安装完成后,桌面会出现名为**「赛事积分榜」**的快捷方式。
- 双击「赛事积分榜」启动。
程序会在自己的安装目录下创建
data\与logs\,请安装到当前用户有写权限的目录;若装到受保护的系统目录,可能因无写入权限而无法建库。
3.2 使用免安装包
- 把
Scoreboard Console-0.1.0-x64.zip解压到任意目录(建议使用纯英文路径)。 - 双击目录里的
Scoreboard Console.exe启动。
3.3 首次启动会自动完成
- 拉起并守护服务端
scoreboard.exe; - 在
data\下自动建库、建目录; - 打开服务端管理面板窗口;
- 把大屏页面投到扩展屏;
- 启用防熄屏;
- 注册开机自启(仅打包后的 Windows 版本)。
部署目录结构(安装或解压后):
安装目录\
├── Scoreboard Console.exe # 桌面宿主,双击启动
├── resources\app.asar # Console 自身资源
├── config.json # Console 配置(可编辑)
├── scoreboard.exe # Go 服务端
├── config.yaml # 服务端配置
├── scoreboard.png # 应用图标
├── data\ # 首次运行生成:数据库、备份
└── logs\console.log # 首次运行生成:运行日志
data\与二进制分离,升级时替换可执行文件即可保留数据。
4. 服务管理窗口(Scoreboard Console)
启动后首先看到的是「Scoreboard Console · 启动管理」窗口。
4.1 窗口按钮
| 位置 | 按钮 / 项 | 作用 |
|---|---|---|
| 服务端状态 | 启动服务 | 手动拉起服务端 |
| 服务端状态 | 停止服务 | 优雅停止服务端(会先请求服务端关闭,超时后强制结束) |
| 服务端状态 | 重启服务 | 停止后重新启动 |
| 服务端状态 | 状态行 | 已停止 / 启动中 / 运行中 / 停止中 / 异常退出 |
| 服务端状态 | 服务地址、进程 PID、自动重启、防熄屏 | 实时运行信息 |
| 服务端状态 | 服务端程序、配置文件 | 实际使用的可执行文件与配置路径 |
| 大屏窗口 | 重新排布 | 重新枚举显示器并重开大屏窗口 |
| 大屏窗口 | 打开服务端管理面板 | 用内置窗口打开 http://127.0.0.1:<端口>/admin,无需再开浏览器 |
| 运行日志 | 自动滚动 | 日志是否跟随最新一行 |
| 运行日志 | 清空 | 清空窗口内显示(不影响日志文件) |
| 标题栏 | 最小化 / 最大化 / 关闭 | 关闭只是隐藏到托盘,服务端继续运行 |
4.2 托盘用法
- 托盘菜单显示当前服务端状态(如「服务端:运行中 · 就绪」);
- 菜单项:启动服务、停止服务、重启服务、打开管理端、打开服务端管理面板、退出;
- 双击托盘图标 = 打开启动管理窗口;
- 要真正退出程序,必须用托盘菜单的「退出」;直接关窗口不会停服务端。
同一台机器只允许运行一个 Console 实例,重复启动会自动退出,避免抢占端口和大屏。
5. 首次登录
5.1 访问地址
| 用途 | 地址 |
|---|---|
| 本机管理面板 | http://127.0.0.1:19540/admin |
| 局域网管理面板 | http://<主机IP>:19540/admin |
| 大屏 | http://<主机IP>:19540/display |
| 导航页 | http://<主机IP>:19540/ |
端口默认 19540,以
config.yaml为准。
5.2 初始账号
- 用户名:
admin - 初始密码:首次启动时随机生成,只打印一次,数据库里只保存加密后的哈希,无法反查。
5.3 从日志里找初始密码
用 Console 启动时,服务端输出会同时显示在「运行日志」面板并写入 logs\console.log。初始密码所在的行形如:
[server] 初始密码: xxxxxxxxxxxxxxxx
在部署目录下执行以下任一命令即可找到(推荐 PowerShell,避免中文编码问题):
Select-String -Path .\logs\console.log -Pattern '初始密码'
findstr /C:"初始密码" logs\console.log
如果中文匹配不到,改用 ASCII 关键字(服务端还会输出一条 password= 的日志):
findstr /C:"password=" logs\console.log
也可以直接在 Console 窗口的运行日志里查找「初始密码」或「已创建默认管理员」。
如果不用 Console、直接双击
scoreboard.exe,密码只会打印在终端窗口里,不会落文件。建议始终通过 Console 启动。
5.4 修改密码
- 首次登录后会自动跳到**「修改密码」**页,必须改密才能继续使用;
- 新密码至少 8 位,需输入两次确认;
- 修改成功后所有会话作废,需用新密码重新登录;
- 管理员也可以在「系统设置 → 用户管理 → 重置密码」为其他用户重置。
5.5 忘记密码 / 没记下初始密码
在 Console 里先停止服务,然后在部署目录(config.yaml 所在目录)执行:
scoreboard.exe passwd -config config.yaml
该命令会为用户 admin 生成一个新的随机密码并打印出来,同时要求下次登录强制改密。可选参数:
| 参数 | 说明 |
|---|---|
-user <用户名> |
指定要重置的用户,默认 admin |
-password <新密码> |
直接指定新密码;留空则随机生成并打印 |
-new-username <新用户名> |
同时修改用户名 |
6. 端口与配置修改
6.1 服务端 config.yaml
| 项 | 当前默认值 | 说明 |
|---|---|---|
server.host |
0.0.0.0 |
监听地址;0.0.0.0 表示局域网内其他设备也能访问 |
server.port |
19540 |
HTTP 端口 |
dataDir |
data |
数据目录,相对服务端工作目录解析 |
log.level |
info |
日志级别:debug / info / warn / error |
6.2 Console console\config.json
| 项 | 当前默认值 | 说明 |
|---|---|---|
server.exe |
scoreboard.exe |
服务端可执行文件;相对路径会在配置目录、当前目录、上级目录、dist\ 依次查找 |
server.args |
["-config","config.yaml"] |
传给服务端的启动参数 |
server.host / server.port |
127.0.0.1 / 19540 |
健康检查与打开管理面板用的地址;配成 0.0.0.0 时本机探测自动改走回环地址 |
server.autoStart |
true |
Console 启动后是否自动拉起服务端 |
server.healthIntervalMs |
5000 |
健康检查间隔(毫秒) |
server.restartDelayMs |
3000 |
崩溃重启的初始退避,之后逐次翻倍 |
server.maxRestarts |
0 |
0 = 无限重启 |
server.shutdownTimeoutMs |
12000 |
等待服务端优雅退出的上限 |
server.healthyResetMs |
60000 |
连续健康多久后清零崩溃计数 |
display.selection |
all-secondary |
选屏策略,见第 7 节 |
display.displays |
[] |
仅 specified 策略生效,填显示器 id 或 0 起序号 |
display.pages |
["standings","medals","individual","results"] |
多屏时按屏序轮转锁定的页面 |
display.pageParam |
page |
页面 URL 参数名 |
display.kiosk |
true |
多屏时是否 kiosk 全屏(单屏恒为窗口化) |
display.ignoreMouse |
true |
多屏窗口是否忽略鼠标 |
display.reloadEveryHours |
24 |
定时重载兜底,0 = 关闭 |
display.waitForServerMs |
20000 |
服务端未就绪时,最多等这么久也先把大屏开出来 |
display.backgroundColor |
#0b0f1a |
大屏窗口底色,减少加载白闪 |
startup.openAtLogin |
true |
打包后随系统启动 |
admin.width / admin.height |
1040 / 760 |
启动管理窗口初始尺寸 |
log.maxLines |
2000 |
内存中保留的日志行数 |
log.file |
logs/console.log |
日志文件,相对 config.json 所在目录 |
log.maxFileBytes |
4194304 |
单个日志文件上限,超出后轮转为 .1 |
配置缺项会自动使用内置默认值;JSON 语法错误时回落到全默认值,并在窗口顶部提示。
6.3 修改端口
端口必须两处一致:
- 关闭 Console(托盘 → 退出);
- 修改
config.yaml的server.port; - 修改
console\config.json的server.port(保持一致,否则 Console 健康检查和管理面板地址会失效); - 重新启动 Console;
- 之后管理面板地址变为
http://<主机IP>:<新端口>/admin。
7. 大屏接线
7.1 主方案:Console 驱动 HDMI
- 用 HDMI 线连接主机与大屏;
- 在 Windows「显示设置」里把显示模式设为扩展(不要「复制」);
- 确认分辨率与缩放(推荐 1920×1080 或 3840×2160,缩放按现场效果调整);
- 启动 Console,大屏窗口会自动打开。
7.2 选屏策略(display.selection)
| 取值 | 行为 |
|---|---|
all-secondary(默认) |
除内置屏外的每块屏各开一个大屏窗口;若所有屏都报告为非内置屏(纯台式机),退回「排除主屏」 |
all |
所有显示器都开大屏窗口 |
specified |
只对 display.displays 里列出的显示器开窗;可填显示器 id 或 0 起序号 |
7.3 单屏:窗口化 + F11
- 只有一块屏时,大屏以窗口化方式打开(屏幕 80% 大小、居中),并显示自绘标题栏;
- 在窗口内按 F11 切换全屏 / 窗口;
- 单屏模式不跟随显示器变化重排。
7.4 多屏:每屏锁一页
- 除内置屏外的每块屏各开一个 kiosk 全屏窗口;
- 每块屏锁定一个页面,按
display.pages的顺序轮转分配; - 多屏 kiosk 不响应 F11,也不接收鼠标(
ignoreMouse); - 可用的页面值:
standings(总积分榜)、medals(团体奖牌榜)、individual(个人积分奖牌榜)、results(分项成绩)、announcement(公告)。
7.5 大屏窗口的自动行为
| 场景 | 行为 |
|---|---|
| 防熄屏 | Console 启动即生效,前后台都算 |
| 服务端就绪 | 首次健康检查通过后开大屏 |
| 服务端迟迟不就绪 | 等待超过 waitForServerMs(默认 20 秒)也先开,避免只见桌面 |
| 服务端崩溃 | 按退避策略自动重启,恢复后大屏自动重载 |
| 长时间运行 | 每 reloadEveryHours(默认 24 小时)自动重载一次 |
7.6 备选方案:安卓 TV / 设备自带浏览器
如果不用 Console 驱动 HDMI,也可以让大屏设备用自己的浏览器访问:
http://<主机IP>:19540/display
- 需要主机设置固定 IP,且设备与主机在同一局域网;
- 安卓电视一般常亮,无需额外防熄屏;
- 浏览器方案不受 Console 的 kiosk、防熄屏、选屏控制,字体与动画表现以实际设备为准;
- 现场以 Console + HDMI 为主方案,浏览器访问作为备用。
8. 备份与恢复
8.1 备份目录
所有备份都在 data\backups\ 下,文件名为 .db 快照。该目录不进版本库。
8.2 如何备份
| 方式 | 操作 | 产物 |
|---|---|---|
| 管理端 | 「系统设置 → 备份 → 立即备份」 | system-<时间戳>.db 与 event-<时间戳>.db |
| 命令行 | 在部署目录执行 scoreboard.exe backup -config config.yaml |
system-<原因>-<时间戳>.db 与 <项目名>-<原因>-<时间戳>.db |
| 快捷脚本 | deploy\backup.bat(原因记 manual)或 deploy\backup.bat publish(原因记 publish) |
同上 |
- 备份使用 SQLite 的
VACUUM INTO,服务运行中也能安全执行,不需要停服务,也不依赖外部sqlite3.exe; - 命令行方式会按前缀滚动保留最近 20 份(
system与赛事库各自计算),超出的旧备份自动删除; - 管理端「立即备份」按钮生成快照,但当前版本不会自动清理旧文件,请定期检查
data\backups\占用; - 现场建议:开幕前、每次发布高峰前、每天结束时各备份一次。
8.3 如何恢复
服务端目前没有一键恢复接口,恢复需停机手工执行:
- 在 Console 里停止服务,避免恢复过程中继续写入;
- 把当前的
data\event_projs\<项目名>\event.db改名留档,确认恢复失败还能退回; - 选一份目标备份复制为
event.db(覆盖原文件); - 同时删除同目录下的
event.db-wal与event.db-shm; - 重新启动服务,核对积分榜与最近一次发布记录。
data\system.db保存账号与会话信息,一般不需要回退;如需一并回退,替换它的方法与event.db相同(同时删除system.db-wal/system.db-shm)。恢复会丢弃备份时间点之后的所有改动。现场若还有备机,优先切换备机比原地恢复更快。
8.4 整机迁移
把整个部署目录(含 data\)拷贝到另一台同版本 Windows 机器,启动 Console 即可,无需重新配置。
8.5 赛事项目包导出 / 导入
| 操作 | 位置 | 说明 |
|---|---|---|
| 导出 | 「导出 → 赛事项目包 → 导出 zip」 | 包内含 meta.yaml、event.db、uploads/、rules.yaml;整包拷走即可在另一台机器复现 |
| 导入 | 「导出 → 赛事项目包 → 选择 .zip → 导入」 | 仅管理员可操作;可填「重命名」,勾选「覆盖同名项目」会先二次确认 |
- 导入后项目落在
data\event_projs\<项目名>\; - 当前运行的服务端默认使用
default项目。要让新导入的赛事生效,可在 Console 的config.json里把server.args改为["-config","config.yaml","-project","<项目名>"],然后重启 Console;也可以直接用scoreboard.exe -config config.yaml -project <项目名>启动; - 导入期间请勿停止服务端进程。
9. 故障排查
9.1 端口被占用,服务端起不来
-
查看占用进程(Windows 命令提示符):
netstat -ano | findstr :19540 -
根据最后一列的 PID 结束进程:
taskkill /PID <PID> /F -
或按第 6.3 节把端口改到其他值(两处同时改)。
同一台机器不要启动两个 Console,否则会互相抢占端口和大屏。
9.2 大屏不亮 / 只有桌面
按顺序检查:
- HDMI 线是否插好,大屏电源是否打开;
- Windows 显示设置是否为扩展模式;
- Console「大屏窗口」卡片是否显示已打开;点「重新排布」;
- 确认
display.selection选屏策略是否漏掉了目标屏; - 服务端未就绪时大屏最多等 20 秒才打开,稍等即可;
- 查看 Console 运行日志里的「大屏排布完成」「大屏加载」记录;
- 单屏窗口化时按 F11 可切全屏。
9.3 管理面板打不开
- 确认 Console 里服务端状态为「运行中」;
- 本机访问
http://127.0.0.1:19540/admin,其他设备访问http://<主机IP>:19540/admin; - 确认
config.yaml与console\config.json的端口一致; - 检查 Windows 防火墙是否拦截了该端口;
- 用托盘菜单的「打开服务端管理面板」直接打开。
9.4 服务反复重启
- 打开
logs\console.log,搜索[server!],这是服务端错误输出; - 检查
data\是否可写、磁盘是否已满; - 检查
config.yaml语法与端口是否合法。
9.5 页面显示「示例数据」
- 表示前端连不上后端或接口未就绪,此时录入、发布等操作不会写入真实赛事;
- 确认服务端状态为「运行中」、实时连接显示「实时在线」;
- 恢复连接后刷新页面即可切换到真实数据。
9.6 大屏时间不对
- 系统没有外网 NTP,以主机时间为准;
- 修改 Windows 系统时间与时区后,大屏顶部时钟会在下一次刷新时跟随(约 15 秒一次);
- 建议在开幕前校准主机时间。
9.7 安卓 TV 备选方案打不开
- 确认电视与主机在同一局域网,主机 IP 为固定 IP;
- 电视浏览器地址填
http://<主机IP>:19540/display; - 确认
config.yaml的server.host为0.0.0.0; - 部分电视浏览器对 CSS 动画、字体支持有限,显示效果以实际设备为准。
9.8 忘记管理员密码
见第 5.5 节,使用 scoreboard.exe passwd -config config.yaml 重置。
10. 上线检查清单
- 服务端开机自启、崩溃自动拉起已验证
data\backups\可写,已生成至少一份备份- 大屏 HDMI 输出定位正确、分辨率正确、字体正常
- 管理端各角色账号可登录,权限正确
- 主机 IP 固定,管理端 / 大屏地址已打印或做成二维码贴在操作台
- 防熄屏、屏保、休眠、系统通知已关闭
- 主机时间已校准
- 磁盘剩余空间充足
- 安卓 TV / 浏览器备选通道实测可打开页面