Files
Scoreboard/docs/部署指南.md
T
AskaEth 005b51b2ec fix: 数据目录移出安装目录,修掉「覆盖安装/卸载即丢数据」
根因:数据目录是 <安装目录>\data(config.yaml 的 dataDir 相对服务端工作目录),
而 electron-builder 的卸载器结尾执行 RMDir /r $INSTDIR,且覆盖安装会先跑旧卸载器
(installSection.nsh:52 的 uninstallOldVersion)→ 赛事库/规则/用户/审计/上传图片
连同安装目录被整个删除,再装新版。卸载一次同样如此。

- 服务端新增 -data <dir>(主命令、backup、passwd 三处),非空时覆盖 config.yaml 的
  dataDir;不传时行为完全不变(兼容便携/手工运行)
- Console 把数据指到当前用户目录 %LOCALAPPDATA%\ScoreboardConsole\data(卸载器不会碰
  这里;没有用 app.getPath('userData'),因为 %APPDATA%\<AppName> 正是被删的那个)
- 一次性迁移:目标为空且 <安装目录>\data 有数据时整体改名过去;两边都有数据时不动作
  只记警告;任何失败都保留原地数据、绝不删除
- passwd 也带 -data(否则重置的是安装目录下那个空库里的账号)
- deploy/backup.bat 指向同一数据目录
- 文档:部署指南新增「数据放在哪里(升级/卸载都不会删)」+ 备份/恢复/迁移路径改写,
  上线检查清单与使用手册同步

自检:服务端 12 包全绿;console 语法 14 文件 + datadir 单测 11/11;backup.bat 保持纯 ASCII。
2026-09-10 09:17:56 +08:00

493 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 部署指南
> 面向现场操作人员与管理员。本系统完全离线运行,不需要联网,不需要安装任何运行时。
---
## 1. 运行环境要求
| 项目 | 要求 |
| --- | --- |
| 服务端主机 | Windows 10 / 11,64 位(amd64) |
| 大屏 | 通过 HDMI 接入主机;显示模式设为**扩展**;推荐 16:9、1920×1080 或 3840×2160 |
| 网络 | 完全离线即可运行。若需要手机/平板/电视访问,用独立交换机或路由器组成局域网 |
| 磁盘 | 建议预留 ≥ 10GB |
| 运行时 | 无需安装 Go / Node / 数据库等任何运行时,前端已内嵌进可执行文件 |
| 权限 | 首次运行会在 `%LOCALAPPDATA%\ScoreboardConsole\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. 双击「赛事积分榜」启动。
> 赛事数据存放在 `%LOCALAPPDATA%\ScoreboardConsole\data`(不随安装目录走,见第 8.1 节),日志写在安装目录的 `logs\` 下;安装目录本身只要当前用户可写即可。
### 3.2 使用免安装包
1. 把 `Scoreboard Console-0.1.0-x64.zip` 解压到任意目录(建议使用纯英文路径)。
2. 双击目录里的 `Scoreboard_Console.exe` 启动。
### 3.3 首次启动会自动完成
- 拉起并守护服务端 `scoreboard.exe`;
- 在数据目录(默认 `%LOCALAPPDATA%\ScoreboardConsole\data`)下自动建库、建目录;
- 打开服务端管理面板窗口;
- 把大屏页面投到扩展屏;
- 启用防熄屏;
- 注册开机自启登录项但**不启用**(任务管理器「启动」里可见、状态为「已禁用」);需要随系统启动时,在服务管理窗口的「开机自启」开关里打开(仅打包后的 Windows 版本生效)。
部署目录结构(安装或解压后):
```
安装目录\
├── Scoreboard_Console.exe # 桌面宿主,双击启动
├── resources\app.asar # Console 自身资源
├── config.json # Console 配置(可编辑)
├── scoreboard.exe # Go 服务端
├── config.yaml # 服务端配置
├── scoreboard.png # 应用图标
└── logs\console.log # 首次运行生成:运行日志
```
数据目录不在安装目录里,是独立的一处(详见 3.4):
```
%LOCALAPPDATA%\ScoreboardConsole\data\ # 数据库、备份、上传的图片
```
### 3.4 数据放在哪里(升级/卸载都不会删)
覆盖安装时安装程序会**先静默运行旧版卸载器**,而卸载器会把整个安装目录删掉,所以数据库、规则、用户、上传的图片都不能放在安装目录里。现在的规则:
| 场景 | 数据目录 |
| --- | --- |
| 默认(`console\config.json` 的 `server.dataDir` 留空) | `%LOCALAPPDATA%\ScoreboardConsole\data`,即 `C:\Users\<用户名>\AppData\Local\ScoreboardConsole\data` |
| 想放到别处,例如 D 盘 | 在 `console\config.json` 里把 `server.dataDir` 改成 `"D:\\scoreboard-data"`(绝对路径),或相对安装目录的路径 |
| 直接双击 `scoreboard.exe`(不经 Console) | 服务端默认行为不变:用工作目录下的 `data\`,**这种用法在覆盖安装时仍会丢数据** |
- Console 启动时会把这个目录用 `-data` 参数交给服务端,界面上方「运行日志」里能看到 `数据目录:...` 这一行;
- **一次性迁移**:如果新数据目录还是空的,而旧的 `<安装目录>\data` 里有数据,Console 会在启动时把旧目录**整体改名**过去(同盘很快),日志里会写「已把旧数据从 X 迁移到 Y」。任何失败(跨盘、权限不足等)都只记日志,旧数据原地保留,不会被删;
- 如果两个目录里**都有数据**,Console 不做任何动作,只写一条警告日志,由现场人工决定保留哪一份;
- 迁移只在安装包版本(打包后)执行一次,`pnpm start` 之类的开发运行不会碰仓库里的 `data\`;
- 迁移的**旧目录只认 `<安装目录>\data`**。如果你已经把数据迁到默认位置、之后又想改成 D 盘等其他目录,Console **不会**自动搬运:请先停服务,把 `%LOCALAPPDATA%\ScoreboardConsole\data` 整个目录复制到新路径,再改 `server.dataDir` 并重启 Console。
> 升级到本版本后第一次启动,请打开 Console 的「运行日志」确认是否有迁移记录,并核对管理端里的赛事/账号数据是否完整。
---
## 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
[server] 首次登录后请立即修改密码
[server] === INITIAL ADMIN CREATED (password above) ===
```
在部署目录下执行以下命令即可找到(搜索纯 ASCII 标记行,中文 `findstr` 在 chcp 936/65001 下不可靠):
```bat
findstr /C:"INITIAL ADMIN CREATED" logs\console.log
```
搜到这一行后,初始密码就在它上面几行(形如 `初始密码: xxxxxxxx`)。也可以直接打开 Console 的「运行日志」面板往上翻。
> 如果不用 Console、直接双击 `scoreboard.exe`,密码只会打印在终端窗口里,不会落文件。建议始终通过 Console 启动。
### 5.4 修改密码
- 首次登录后会自动跳到**「修改密码」**页,必须改密才能继续使用;
- 新密码至少 8 位,需输入两次确认;
- 修改成功后所有会话作废,需用新密码重新登录;
- 管理员也可以在「系统设置 → 用户管理 → 重置密码」为其他用户重置。
### 5.5 忘记密码 / 没记下初始密码
在 Console 里先**停止服务**,然后在部署目录(`config.yaml` 所在目录)执行:
```bat
scoreboard.exe passwd -config config.yaml -data "%LOCALAPPDATA%\ScoreboardConsole\data"
```
> **`-data` 不能省**:不加它服务端会去用工作目录下的 `data\`,改的是另一个库里的账号(那个库是空的,看起来像「密码重置成功但登录不上」)。数据目录改过配置的,把这里换成 `console\config.json` 里 `server.dataDir` 实际生效的那个路径;实在不确定,可以先看 `logs\console.log` 里 `数据目录:` 那一行。
该命令会为用户 `admin` 生成一个新的随机密码并打印出来,同时要求下次登录强制改密。可选参数:
| 参数 | 说明 |
| --- | --- |
| `-user <用户名>` | 指定要重置的用户,默认 `admin` |
| `-password <新密码>` | 直接指定新密码;留空则随机生成并打印 |
| `-new-username <新用户名>` | 同时修改用户名 |
| `-data <数据目录>` | 数据目录;通过 Console 启动时必须带上同一个值(见第 3.4 节) |
---
## 6. 端口与配置修改
### 6.1 服务端 `config.yaml`
| 项 | 当前默认值 | 说明 |
| --- | --- | --- |
| `server.host` | `0.0.0.0` | 监听地址;`0.0.0.0` 表示局域网内其他设备也能访问 |
| `server.port` | `19540` | HTTP 端口 |
| `dataDir` | `data` | 数据目录,相对服务端工作目录解析;**Console 启动时会用 `-data <绝对路径>` 覆盖它**,配置项本身只对直接运行 `scoreboard.exe` 时生效 |
| `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.dataDir` | `""` | 数据目录;留空 = 用默认位置 `%LOCALAPPDATA%\ScoreboardConsole\data`。填了就按它来:绝对路径直接用,相对路径以安装目录为基准。Console 会把它作为 `-data <绝对路径>` 追加到启动参数后(见第 3.4 节) |
| `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` | `false` | 默认注册但不启用(任务管理器可见、已禁用);在服务管理窗口「开机自启」开关里控制 |
| `admin.width` / `admin.height` | `1280` / `860` | 启动管理窗口初始尺寸(服务管理窗口与服务端管理面板共用) |
| `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 备份目录
所有备份都在**数据目录**下的 `backups\` 里,文件名为 `.db` 快照。默认数据目录是 `%LOCALAPPDATA%\ScoreboardConsole\data`,所以备份在:
```
%LOCALAPPDATA%\ScoreboardConsole\data\backups\
```
数据目录改过 `server.dataDir` 的,按改后的路径找(同目录下的 `backups\`)。该目录不进版本库。
### 8.2 如何备份
| 方式 | 操作 | 产物 |
| --- | --- | --- |
| 自动 | 服务端启动后按 `backup.intervalMinutes`(默认 5 分钟) | `system-auto-<时间戳>.db` 与 `event-auto-<时间戳>.db` |
| 管理端 | 「系统设置 → 备份 → 立即备份」 | `system-manual-<时间戳>.db` 与 `event-manual-<时间戳>.db` |
| 命令行 | 在部署目录执行 `scoreboard.exe backup -config config.yaml -data "%LOCALAPPDATA%\ScoreboardConsole\data"` | `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` 库与赛事库各自计算,超出的旧备份自动删除;
- 同一时刻只允许一个备份在进行,自动备份与手动、发布前备份不会互相踩;
- `deploy\backup.bat` 会自动用和 Console 相同的数据目录(优先 `%LOCALAPPDATA%\ScoreboardConsole\data`,该目录还不存在时回退到脚本上级目录的 `data`),并把该目录作为 `-data` 传给服务端,所以从哪里运行都不会备份到别的库;
- 现场建议:开幕前、每次发布高峰前、每天结束时各手动备份一次(自动备份只是兜底)。
### 8.3 如何恢复
服务端目前**没有一键恢复接口**,恢复需停机手工执行:
1. 在 Console 里**停止服务**,避免恢复过程中继续写入;
2. 把当前的 `<数据目录>\event_projs\<项目名>\event.db` 改名留档,确认恢复失败还能退回;
3. 选一份目标备份复制为 `event.db`(覆盖原文件);
4. 同时删除同目录下的 `event.db-wal` 与 `event.db-shm`;
5. 重新启动服务,核对积分榜与最近一次发布记录。
> `<数据目录>\system.db` 保存账号与会话信息,一般不需要回退;如需一并回退,替换它的方法与 `event.db` 相同(同时删除 `system.db-wal` / `system.db-shm`)。
>
> 恢复会丢弃备份时间点之后的所有改动。现场若还有备机,优先切换备机比原地恢复更快。
### 8.4 整机迁移
把 **安装目录**(`Scoreboard_Console.exe`、`config.json`、`config.yaml`、`rules\` 等)与**数据目录** `%LOCALAPPDATA%\ScoreboardConsole\data` 一起拷到另一台同版本 Windows 机器:
- 安装目录:按同样路径放好,或直接用新机器上的安装包装一遍;
- 数据目录:拷到新机器的 `%LOCALAPPDATA%\ScoreboardConsole\data`(同一用户名下路径一致,最省事);
- 启动 Console 即可,无需重新配置;若数据目录放到了别处,记得同步改 `console\config.json` 的 `server.dataDir`。
### 8.5 赛事项目包导出 / 导入
| 操作 | 位置 | 说明 |
| --- | --- | --- |
| 导出 | 「导出 → 赛事项目包 → 导出 zip」 | 包内含 `meta.yaml`、`event.db`、`uploads/`、`rules.yaml`;整包拷走即可在另一台机器复现 |
| 导入 | 「导出 → 赛事项目包 → 选择 .zip → 导入」 | **仅管理员**可操作;可填「重命名」,勾选「覆盖同名项目」会先二次确认 |
- 导入后项目落在 `<数据目录>\event_projs\<项目名>\`;
- 当前运行的服务端默认使用 `default` 项目。要让新导入的赛事生效,可在 Console 的 `config.json` 里把 `server.args` 改为 `["-config","config.yaml","-project","<项目名>"]`,然后重启 Console;也可以直接用 `scoreboard.exe -config config.yaml -project <项目名> -data "%LOCALAPPDATA%\ScoreboardConsole\data"` 启动;
- 导入期间请勿停止服务端进程。
### 8.6 手工备份 / 迁移整个数据目录
快照备份之外,数据库文件、上传的图片、备份都可以整体拷走:
1. 在 Console 里**停止服务**(托盘 → 停止服务),避免拷贝过程中继续写入;
2. 把整个数据目录 `%LOCALAPPDATA%\ScoreboardConsole\data` 复制到 U 盘或其他盘(里面含 `system.db`、`event_projs\`(数据库 + `uploads\` 图片)、`backups\`);
3. 恢复时把整个目录拷回去,然后:
- 拷回**原路径**:直接启动 Console 即可;
- 拷到**别的路径**:先建好目标目录并放入数据,再在 `console\config.json` 里把 `server.dataDir` 指向它,重启 Console;
4. 恢复完成后在管理端核对赛事、账号、上传图片是否齐全。
> 只拷 `backups\` 里的 `.db` 快照也能救回成绩数据,但上传的背景图/会标在 `event_projs\<项目名>\uploads\` 里,不拷这个目录会丢图片。
---
## 9. 故障排查
### 9.1 端口被占用,服务端起不来
1. 查看占用进程(Windows 命令提示符):
```bat
netstat -ano | findstr :19540
```
2. 根据最后一列的 PID 结束进程:
```bat
taskkill /PID <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!]`,这是服务端错误输出;
- 检查数据目录 `%LOCALAPPDATA%\ScoreboardConsole\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 -data "%LOCALAPPDATA%\ScoreboardConsole\data"` 重置。
### 9.9 升级后数据不见了 / 日志里有迁移警告
覆盖安装时安装程序会先跑旧卸载器删掉安装目录,所以本版本起数据默认放在 `%LOCALAPPDATA%\ScoreboardConsole\data`。首次启动后先看 Console「运行日志」或 `logs\console.log`:
| 日志 | 含义 |
| --- | --- |
| `数据目录:<路径>` | 本次实际使用的数据目录,先确认它是不是你期望那个 |
| `已把旧数据从 X 迁移到 Y` | 旧数据已整体搬过去,属正常 |
| `警告:...都有数据...` | 两个目录都有数据,Console 没有动任何一边;请人工把要保留的那份拷到 `数据目录:` 指向的位置 |
| `警告:迁移旧数据失败...` | 跨盘或权限问题;旧数据仍在日志里写的 `X`,手工拷过去再重启即可 |
| `警告:数据目录仍在安装目录内` | `server.dataDir` 配置成了安装目录里的路径,覆盖安装会丢数据,请改到安装目录之外 |
若安装目录里的 `data\` 已被删掉,优先用 `backups\` 里最新的 `.db` 快照按第 8.3 节恢复。
---
## 10. 上线检查清单
- [ ] 服务端开机自启、崩溃自动拉起已验证
- [ ] 「运行日志」里的 `数据目录:` 指向 `%LOCALAPPDATA%\ScoreboardConsole\data`(不是安装目录),且没有迁移警告
- [ ] 数据目录的 `backups\` 可写,已生成至少一份备份
- [ ] 已把数据目录整个拷一份到 U 盘(含 `event_projs\<项目名>\uploads\` 里的图片)
- [ ] 大屏 HDMI 输出定位正确、分辨率正确、字体正常
- [ ] 管理端各角色账号可登录,权限正确
- [ ] 主机 IP 固定,管理端 / 大屏地址已打印或做成二维码贴在操作台
- [ ] 防熄屏、屏保、休眠、系统通知已关闭
- [ ] 主机时间已校准
- [ ] 磁盘剩余空间充足
- [ ] 安卓 TV / 浏览器备选通道实测可打开页面