- DEFAULTS.startup.openAtLogin 与随包 config.json 默认改为 false;
applyOpenAtLogin 只有显式 true 才注册登录项(缺省/null/false 都不注册)
- config.js 新增 updateConfig():只写回文件里已有的键 + 目标键,不把 DEFAULTS 落盘
- 主进程 setOpenAtLogin():改内存 → 写回 config.json → setLoginItemSettings,
任一失败都回滚,返回 {ok, openAtLogin};状态快照新增 openAtLogin / openAtLoginSupported
- 渲染层:服务端状态卡片新增「开机自启」滑块(纯 CSS,无依赖),
切换即时生效并有本地意图守卫,避免被随后到达的陈旧快照冲掉
- 文档:console/README.md 与 docs/部署指南.md 同步
注意:旧包 config.json 里已显式写 true 的用户升级后仍会自启(不悄悄改既有行为),
在窗口里关一次即可;全新安装默认不注册。
10 KiB
10 KiB
Scoreboard Console
赛事积分榜系统的桌面宿主(Electron)。它只做六件事:
- 拉起并守护同目录(或配置指定)的
scoreboard.exe,把它的 stdout/stderr 接管到管理窗口与日志文件; - 用
screen.getAllDisplays()枚举显示器,把大屏页面投到扩展屏; powerSaveBlocker.start('prevent-display-sleep')防熄屏;- 提供启动/停止/状态/日志的管理 GUI 和托盘菜单;
- 默认不随系统启动,可在服务管理窗口的「开机自启」开关里开启;
- 在服务管理窗口展示服务端在线的大屏实例(
GET /api/display/instances)。
规范来源:devdocs/06-大屏端设计.md 第 6 节、devdocs/10-部署与现场方案.md 第 4 节。
目录结构
console/
├── package.json # main 指向 main/index.js;electron-builder 配置
├── config.json # 运行配置(端口 / exe 路径 / 选屏策略)
├── main/
│ ├── index.js # 应用入口:窗口 / 托盘 / IPC / 生命周期
│ ├── config.js # 配置加载与合并、exe 路径解析
│ ├── service.js # 服务端子进程守护:spawn / 日志转发 / 健康检查 / 自动重启
│ ├── instances.js # 已连接大屏实例看板:复用管理面板登录态读 /api/display/instances
│ ├── account.js # 管理员账号重置:参数校验 + 调 scoreboard.exe passwd
│ ├── displays.js # 大屏窗口管理:选屏、kiosk、排布、24h 重载
│ ├── log-bus.js # 日志环形缓冲 + 落文件 + 广播
│ └── tray-icon.js # 托盘图标(base64 内嵌,无外部资源文件)
├── scripts/
│ └── check-syntax.js # pnpm check:跨平台递归 node --check
├── extra/ # 打包前由 deploy/build.bat 暂存 使用说明.txt(extraFiles 指向它)
└── renderer/
├── index.html # 管理窗口(含自绘标题栏)
├── styles.css
├── app.js
├── preload.js # 管理窗口的 contextBridge 白名单
└── shell-preload.js # 服务端管理面板窗口的 window.desktopShell 白名单
运行方式
cd console
pnpm install # 首次需要下载 Electron
pnpm start # 等价于 electron .
开发时把 scoreboard.exe 放在以下任一位置都能被找到(config.json 里的相对路径会按顺序探测):
console/- 当前工作目录
- 仓库根目录
dist/
现场(部署包)形态:
scoreboard-windows-amd64/
├── Scoreboard Console.exe
├── resources/app.asar # 内含 main/ renderer/ config.json
├── config.json # exe 旁边的可编辑配置
├── scoreboard.exe
├── config.yaml
├── rules/
├── data/
└── logs/console.log # 运行时生成
打包后 config.json 读取顺序:SCOREBOARD_CONSOLE_CONFIG 环境变量 → exe 同目录的 config.json。
行为说明
| 场景 | 行为 |
|---|---|
| 只有一块屏 | 窗口化(屏幕 80% 大小、居中),不做多屏编排,不挂 display-metrics-changed 等监听(行为冻结);F11 手动切换全屏 |
| 多块屏 | 除内置屏外的每块屏一个 kiosk 窗口,按 display.bounds(DIP)定位,窗口 setIgnoreMouseEvents(true),光标由页面 CSS 隐藏 |
| 选屏 | 运行时枚举,不写死坐标;selection 可选 all-secondary(默认,用 display.internal 排除内置屏)/ all / specified |
| 页面锁定 | 每块屏各锁一页,URL 形如 http://127.0.0.1:19540/display?page=standings&lock=1&screen=<id>&instance=<host>-<id>,页序按 display.pages 轮转 |
| 防熄屏 | Console 启动即生效,退出时释放;前台后台都算 |
| 服务端就绪 | 首次 /api/health 通过后开大屏窗口;等待超过 display.waitForServerMs 也先开,避免现场只见桌面 |
| 服务端崩溃 | 按 restartDelayMs 递增退避自动重启(maxRestarts=0 为无限);持续健康 healthyResetMs 后崩溃计数清零;恢复健康后自动重载大屏 |
| 停止服务 | 先 POST server.shutdownPath 并带 X-Shutdown-Token(启动时用 crypto.randomBytes(32) 生成,经环境变量 SCOREBOARD_SHUTDOWN_TOKEN 只交给该子进程)请求服务端优雅关闭;受理后最多等 shutdownTimeoutMs,超时或接口不可用(404/连接失败)再强杀 |
| 已连接大屏实例 | 管理窗口打开时每 5 秒读一次服务端 GET /api/display/instances(复用管理面板的 scoreboard_session Cookie,需记录员及以上),显示实例数、页面名与在线状态;窗口隐藏即停表,未登录/服务未启动时显示占位文案 |
| 关管理窗口 | 只隐藏到托盘,服务端继续运行;退出必须走托盘「退出」 |
| 开机自启 | 默认关闭;在服务管理窗口的「开机自启」开关里控制(startup.openAtLogin),仅打包后的 Windows/macOS 生效,开发态不注册 |
| 窗口外观 | 管理窗口与服务端管理面板窗口都是 frame: false 无边框,标题栏与最小化/最大化/关闭三键由页面自绘(拖拽区 -webkit-app-region: drag,按钮 no-drag,双击标题栏切最大化,关闭键 hover 变红) |
| 服务端管理面板 | 用独立无边框 Electron 窗口加载 http://127.0.0.1:<port>/admin(shell-preload.js 暴露 window.desktopShell),不再调系统浏览器;面板页在浏览器里直接打开时标题栏自动不渲染 |
| 管理员账号 | 主进程 spawn 同目录 scoreboard.exe passwd -config <同一份配置> -user <当前用户名> -new-username <新用户名> -password <新密码>(留空 = 不改 / 随机生成)。本机进程、不经 HTTP,因此免登录验证;用户名/密码含空格、制表符或换行会被主进程拒绝,密码不进日志。passwd 会作废该用户全部会话,UI 提交前二次确认并提示 |
| 日志 | 内存环形缓冲(log.maxLines)+ 文件 logs/console.log(超 maxFileBytes 轮转一份 .1,轮转前会删掉旧 .1 以兼容 Windows) |
配置项(config.json)
| 键 | 默认值 | 说明 |
|---|---|---|
server.exe |
scoreboard.exe |
相对路径按上文顺序探测,也可写绝对路径 |
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 |
重启基础退避,每次翻倍,最多 5 倍 |
server.maxRestarts |
0 |
0 = 无限重启 |
server.shutdownPath |
/api/shutdown |
优雅关闭握手接口(需服务端实现并校验 X-Shutdown-Token),不可用时回退强杀 |
server.shutdownTimeoutMs |
5000 |
服务端受理关闭请求后等待其自行退出的上限,超过则强杀 |
server.healthyResetMs |
60000 |
连续健康多久后清零崩溃计数 |
display.selection |
all-secondary |
all-secondary / all / specified |
display.displays |
[] |
specified 时生效,填 display 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 |
1040 / 760 |
管理窗口初始尺寸(服务端管理面板窗口按 width 不小于 1100 取用) |
log.maxLines / log.file / log.maxFileBytes |
2000 / logs/console.log / 4194304 |
日志缓冲与文件 |
配置缺项自动用内置默认值,文件不存在或 JSON 语法错误时回落到全默认值,并在管理窗口顶部给出提示。
打包(electron-builder)
package.json 里已写好 build 段:
cd console
pnpm install
pnpm check # 跨平台语法检查(scripts/check-syntax.js)
pnpm dist # electron-builder --win --x64 → ../dist/console/
pnpm pack # 只出目录,不生成安装包,便于现场调试
- 产物:NSIS 安装包 + zip(
Scoreboard Console-0.1.0-x64.*)。 extraFiles会把../dist/scoreboard.exe、../config.yaml、config.json(exe 旁的可编辑配置,缺失时 Console 会回落到内置默认值)与../rules拷到安装目录,最终形成第 4 节里的部署包形态。使用说明.txt是可选的:deploy/build.bat在打包前依次找docs/使用说明.txt、docs/使用手册.md,命中就暂存到console/extra/使用说明.txt(extraFiles会把该目录内容平铺到部署包根目录),都没有就跳过并在构建日志里注明。- 图标在
resources/icon.ico(package.json的win.icon指向它)。 - 已在 Windows 构建机上通过
deploy\build.bat实跑(含pnpm dist,产出 NSIS 安装包 + zip);Linux 开发机未安装 Electron/electron-builder。
尚未实机验证
以下内容只做了静态语法检查,需要在 Windows + 真实多显示器环境跑一遍:
- 多屏 kiosk 定位与
display-metrics-changed重排(改分辨率 / 缩放 / 插拔 HDMI)。 powerSaveBlocker在长时间后台下的实际效果。- 托盘图标在 Windows 任务栏的显示效果(16px 缩放)。
scoreboard.exe真实拉起、日志转发、健康检查与崩溃重启的端到端链路。- electron-builder 打包已通过
deploy\build.bat实跑;NSIS 安装包在真机上的安装 / 卸载流程尚未验证。