# 部署指南 > 面向现场操作人员与管理员。本系统完全离线运行,不需要联网,不需要安装任何运行时。 --- ## 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 环境,并能访问依赖源)上执行: ```bat 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 使用安装包 1. 双击 `Scoreboard Console-0.1.0-x64.exe`。 2. 按向导选择安装目录(可自定义)。 3. 安装完成后,桌面会出现名为**「赛事积分榜」**的快捷方式。 4. 双击「赛事积分榜」启动。 > 程序会在自己的安装目录下创建 `data\` 与 `logs\`,请安装到当前用户有写权限的目录;若装到受保护的系统目录,可能因无写入权限而无法建库。 ### 3.2 使用免安装包 1. 把 `Scoreboard Console-0.1.0-x64.zip` 解压到任意目录(建议使用纯英文路径)。 2. 双击目录里的 `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`,无需再开浏览器 | | 运行日志 | **自动滚动** | 日志是否跟随最新一行 | | 运行日志 | **清空** | 清空窗口内显示(不影响日志文件) | | 已连接的大屏实例 | — | 显示在线大屏窗口的数量与各自页面,5 秒刷新;需先在管理面板登录过才能读到 | | 标题栏 | 最小化 / 最大化 / 关闭 | 关闭只是**隐藏到托盘**,服务端继续运行 | ### 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,避免中文编码问题): ```powershell Select-String -Path .\logs\console.log -Pattern '初始密码' ``` ```bat findstr /C:"初始密码" logs\console.log ``` 如果中文匹配不到,改用 ASCII 关键字(服务端还会输出一条 `password=` 的日志): ```bat findstr /C:"password=" logs\console.log ``` 也可以直接在 Console 窗口的**运行日志**里查找「初始密码」或「已创建默认管理员」。 > 如果不用 Console、直接双击 `scoreboard.exe`,密码只会打印在终端窗口里,不会落文件。建议始终通过 Console 启动。 ### 5.4 修改密码 - 首次登录后会自动跳到**「修改密码」**页,必须改密才能继续使用; - 新密码至少 8 位,需输入两次确认; - 修改成功后所有会话作废,需用新密码重新登录; - 管理员也可以在「系统设置 → 用户管理 → 重置密码」为其他用户重置。 ### 5.5 忘记密码 / 没记下初始密码 在 Console 里先**停止服务**,然后在部署目录(`config.yaml` 所在目录)执行: ```bat 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` | | `backup.intervalMinutes` | `5` | 自动备份间隔(分钟),`<=0` 关闭自动备份 | | `backup.keep` | `20` | 每个库滚动保留的备份份数 | | `server.allowedOrigins` | `[]` | 额外放行的 WebSocket Origin 白名单;默认只放行同源与不带 Origin 的客户端 | ### 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` | `5000` | 等待服务端优雅退出的上限 | | `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 修改端口 端口必须**两处一致**: 1. 关闭 Console(托盘 → 退出); 2. 修改 `config.yaml` 的 `server.port`; 3. 修改 `console\config.json` 的 `server.port`(保持一致,否则 Console 健康检查和管理面板地址会失效); 4. 重新启动 Console; 5. 之后管理面板地址变为 `http://<主机IP>:<新端口>/admin`。 --- ## 7. 大屏接线 ### 7.1 主方案:Console 驱动 HDMI 1. 用 HDMI 线连接主机与大屏; 2. 在 Windows「显示设置」里把显示模式设为**扩展**(不要「复制」); 3. 确认分辨率与缩放(推荐 1920×1080 或 3840×2160,缩放按现场效果调整); 4. 启动 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 如何备份 | 方式 | 操作 | 产物 | | --- | --- | --- | | 自动 | 服务端启动后按 `backup.intervalMinutes`(默认 5 分钟) | `system-auto-<时间戳>.db` 与 `event-auto-<时间戳>.db` | | 管理端 | 「系统设置 → 备份 → 立即备份」 | `system-manual-<时间戳>.db` 与 `event-manual-<时间戳>.db` | | 命令行 | 在部署目录执行 `scoreboard.exe backup -config config.yaml` | `system-manual-<时间戳>.db` 与 `event-manual-<时间戳>.db` | | 快捷脚本 | `deploy\backup.bat`(原因记 `manual`)或 `deploy\backup.bat publish`(原因记 `publish`) | 同上(`publish` 时原因为 `publish`) | | 发布前 | 每次发布成绩时自动 | `event-publish-<时间戳>.db` | - 备份使用 SQLite 的 `VACUUM INTO`,服务运行中也能安全执行,不需要停服务,也不依赖外部 `sqlite3.exe`; - 自动、手动、命令行三种方式都按 `backup.keep`(默认 20 份)滚动保留,`system` 库与赛事库各自计算,超出的旧备份自动删除; - 同一时刻只允许一个备份在进行,自动备份与手动、发布前备份不会互相踩; - 现场建议:开幕前、每次发布高峰前、每天结束时各手动备份一次(自动备份只是兜底)。 ### 8.3 如何恢复 服务端目前**没有一键恢复接口**,恢复需停机手工执行: 1. 在 Console 里**停止服务**,避免恢复过程中继续写入; 2. 把当前的 `data\event_projs\<项目名>\event.db` 改名留档,确认恢复失败还能退回; 3. 选一份目标备份复制为 `event.db`(覆盖原文件); 4. 同时删除同目录下的 `event.db-wal` 与 `event.db-shm`; 5. 重新启动服务,核对积分榜与最近一次发布记录。 > `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 端口被占用,服务端起不来 1. 查看占用进程(Windows 命令提示符): ```bat netstat -ano | findstr :19540 ``` 2. 根据最后一列的 PID 结束进程: ```bat taskkill /PID /F ``` 3. 或按第 6.3 节把端口改到其他值(两处同时改)。 > 同一台机器不要启动两个 Console,否则会互相抢占端口和大屏。 ### 9.2 大屏不亮 / 只有桌面 按顺序检查: 1. HDMI 线是否插好,大屏电源是否打开; 2. Windows 显示设置是否为**扩展**模式; 3. Console「大屏窗口」卡片是否显示已打开;点「重新排布」; 4. 确认 `display.selection` 选屏策略是否漏掉了目标屏; 5. 服务端未就绪时大屏最多等 20 秒才打开,稍等即可; 6. 查看 Console 运行日志里的「大屏排布完成」「大屏加载」记录; 7. 单屏窗口化时按 **F11** 可切全屏。 ### 9.3 管理面板打不开 1. 确认 Console 里服务端状态为「运行中」; 2. 本机访问 `http://127.0.0.1:19540/admin`,其他设备访问 `http://<主机IP>:19540/admin`; 3. 确认 `config.yaml` 与 `console\config.json` 的端口一致; 4. 检查 Windows 防火墙是否拦截了该端口; 5. 用托盘菜单的「打开服务端管理面板」直接打开。 ### 9.4 服务反复重启 - 打开 `logs\console.log`,搜索 `[server!]`,这是服务端错误输出; - 检查 `data\` 是否可写、磁盘是否已满; - 检查 `config.yaml` 语法与端口是否合法。 ### 9.5 页面显示「示例数据」 - 表示前端连不上后端或接口未就绪,此时录入、发布等操作**不会写入真实赛事**; - 确认服务端状态为「运行中」、实时连接显示「实时在线」; - 恢复连接后刷新页面即可切换到真实数据。 ### 9.6 大屏时间不对 - 系统没有外网 NTP,**以主机时间为准**; - 修改 Windows 系统时间与时区后,大屏顶部时钟会在下一次刷新时跟随(约 15 秒一次); - 建议在开幕前校准主机时间。 ### 9.7 安卓 TV 备选方案打不开 1. 确认电视与主机在同一局域网,主机 IP 为固定 IP; 2. 电视浏览器地址填 `http://<主机IP>:19540/display`; 3. 确认 `config.yaml` 的 `server.host` 为 `0.0.0.0`; 4. 部分电视浏览器对 CSS 动画、字体支持有限,显示效果以实际设备为准。 ### 9.8 忘记管理员密码 见第 5.5 节,使用 `scoreboard.exe passwd -config config.yaml` 重置。 --- ## 10. 上线检查清单 - [ ] 服务端开机自启、崩溃自动拉起已验证 - [ ] `data\backups\` 可写,已生成至少一份备份 - [ ] 大屏 HDMI 输出定位正确、分辨率正确、字体正常 - [ ] 管理端各角色账号可登录,权限正确 - [ ] 主机 IP 固定,管理端 / 大屏地址已打印或做成二维码贴在操作台 - [ ] 防熄屏、屏保、休眠、系统通知已关闭 - [ ] 主机时间已校准 - [ ] 磁盘剩余空间充足 - [ ] 安卓 TV / 浏览器备选通道实测可打开页面