fix: 大屏背景图被兜底渐变盖住 + 配置/规则也搬到用户数据目录

1) 大屏背景图不生效:App.vue 里 .bg 与 .bg-fallback 都是 absolute inset:0,
   而兜底渐变是不透明的且在图片之后绘制 → 配了背景图也只看得到渐变。
   改成 v-if/v-else 互斥(用无头 Chromium 真渲染对照验证:修复后取到图片像素,
   回退版本只剩渐变)。新增 background-layer.test.ts 锁住层次关系。

2) 规则/config 仍在安装目录,覆盖安装/卸载会连配置一起删:现在三样都落在
   %LOCALAPPDATA%\ScoreboardConsole\(与数据目录同一基座):
   - console\config.json(Console 读写都用这份)
   - config.yaml(Console 用绝对路径 -config 传给服务端与 passwd)
   - rules\(首次从安装目录复制过去,之后只认用户目录那份)
   首次运行复制迁移、已存在不覆盖、不可写则回落安装目录并记日志(不影响启动);
   开发态行为不变。备份脚本与文档同步。
   注意 resolveExecutable 必须显式传部署包根目录,否则会去用户目录找 scoreboard.exe。

自检:服务端 11 包全绿;console 语法 16 文件 + node:test 20/20;
前端 vue-tsc + build、node --test 69/69。
This commit is contained in:
AskaEth committed 2026-09-10 10:06:21 +08:00
1 parent 2d207fd654
commit 407abec3b0
15 files changed
+759 -81

No files matched your search

+41 -10
View File
@@ -14,6 +14,7 @@ const {
const { loadConfig, updateConfig, resolveExecutable } = require('./config')
const { resolveDataDir, migrateLegacyData, isInside } = require('./datadir')
const { resolveUserRoot, planUserPaths, prepareUserPaths } = require('./userpaths')
const { LogBus } = require('./log-bus')
const { ServiceSupervisor, healthHost } = require('./service')
const { DisplayManager } = require('./displays')
@@ -43,21 +44,29 @@ function main() {
let exePath = null
// 解析后的数据目录信息(见 datadir.js),拉起服务端和 passwd 都用它
let dataDirInfo = null
// 解析后的用户配置/规则路径(见 userpaths.js):console\config.json、config.yaml、rules\
let userPaths = null
// 大屏实例看板只在管理窗口可见时轮询,窗口隐藏即停表
let instancesTimer = null
let instancesLastReason = null
// passwd 子进程同一时刻只允许一个:并发写同一个 sqlite 库没有意义,也会让输出互相串
let accountBusy = false
// 部署包根目录:打包后 = exe 所在目录(安装目录),开发态 = 仓库的 console\。
// 注意别和下面数据目录用的 installDir 混用:那个取的是**服务端 exe** 所在目录,
// 开发态两者可能不是同一个地方。
function appDir() {
return app.isPackaged ? path.dirname(app.getPath('exe')) : path.join(__dirname, '..')
}
// Console 自己的 config.json:打包后在 <用户根>\console\config.json(配置/规则已经搬出安装
// 目录,覆盖安装不会丢),开发态仍是仓库里的 console\config.json。
// SCOREBOARD_CONSOLE_CONFIG 优先级最高,方便本机临时换一份配置跑。
function resolveConfigPath() {
if (process.env.SCOREBOARD_CONSOLE_CONFIG) {
return path.resolve(process.env.SCOREBOARD_CONSOLE_CONFIG)
}
// 打包后 config.json 放在 exe 旁边,方便现场直接改,不藏在 asar 里
if (app.isPackaged) {
return path.join(path.dirname(app.getPath('exe')), 'config.json')
}
return path.join(__dirname, '..', 'config.json')
return userPaths ? userPaths.consoleConfig : path.join(__dirname, '..', 'config.json')
}
// 开关显示以系统实际状态为准:打包后的 Windows 读登录项 enabled,其余回落配置值。
@@ -424,8 +433,10 @@ function main() {
return { ok: true, openAtLogin: wanted }
}
// 服务端用什么配置文件,passwd 就得用同一份,否则改的是另一个 data/ 下的账号
// 服务端用什么配置文件,passwd 就得用同一份,否则改的是另一个 data/ 下的账号;
// 打包态这份在用户数据目录里,Console 已经解析好了绝对路径(见 userpaths.js)
function passwdConfigArg() {
if (userPaths && userPaths.serverConfig) return userPaths.serverConfig
const args = Array.isArray(cfg.values.server.args) ? cfg.values.server.args : []
const index = args.indexOf('-config')
if (index !== -1 && typeof args[index + 1] === 'string' && args[index + 1]) {
@@ -456,7 +467,7 @@ function main() {
validateAccountField(password, '新密码', false)
if (invalid) return { ok: false, error: invalid }
const exe = exePath || resolveExecutable(cfg.values.server.exe, cfg.path).path
const exe = exePath || resolveExecutable(cfg.values.server.exe, cfg.path, appDir()).path
if (!exe || !fs.existsSync(exe)) {
return { ok: false, error: `未找到服务端程序:${exe || cfg.values.server.exe}` }
}
@@ -561,17 +572,36 @@ function main() {
}
app.whenReady().then(() => {
const bundleDir = appDir()
// 配置与规则跟数据目录一样搬出安装目录(见 userpaths.js)。这一步在加载配置之前做:
// Console 自己的 config.json 也要先落到用户目录。失败只记日志,攒着等日志器建好再写。
const setupNotes = []
userPaths = prepareUserPaths({
plan: planUserPaths({
installDir: bundleDir,
userRoot: resolveUserRoot(process.env),
isPackaged: app.isPackaged
}),
log: (message) => setupNotes.push(message)
})
cfg = loadConfig(resolveConfigPath())
log = new LogBus({
maxLines: cfg.values.log.maxLines,
file: path.resolve(path.dirname(cfg.path), cfg.values.log.file || 'logs/console.log'),
// 日志固定在部署包根目录的 logs\ 下(log.file 相对它解析):配置文件搬走了,
// 但日志是易失的排查材料,位置保持原样,现场习惯和文档都不用改
file: path.resolve(bundleDir, cfg.values.log.file || 'logs/console.log'),
maxFileBytes: cfg.values.log.maxFileBytes
})
log.push('console', `Scoreboard Console v${app.getVersion()} 启动(配置:${cfg.path})`)
for (const note of setupNotes) log.push('console', note)
if (userPaths.mode === 'user') {
log.push('console', `用户数据目录:${userPaths.root}(Console 配置、服务端 config.yaml、rules 都在这里,覆盖安装不会丢)`)
}
if (cfg.warning) log.push('console', cfg.warning)
const resolved = resolveExecutable(cfg.values.server.exe, cfg.path)
const resolved = resolveExecutable(cfg.values.server.exe, cfg.path, bundleDir)
exePath = resolved.path
log.push('console', `服务端程序:${resolved.path}`)
@@ -604,7 +634,8 @@ function main() {
values: cfg.values,
exePath: resolved.path,
log,
dataDir: dataDirInfo.passToServer ? dataDirInfo.dir : null
dataDir: dataDirInfo.passToServer ? dataDirInfo.dir : null,
configPath: userPaths.serverConfig
})
displays = new DisplayManager({