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:
1 parent
2d207fd654
commit
407abec3b0
15 files changed
+759
-81
No files matched your search
@@ -0,0 +1,199 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const os = require('node:os')
|
||||
const path = require('node:path')
|
||||
const test = require('node:test')
|
||||
|
||||
const {
|
||||
resolveUserRoot,
|
||||
planUserPaths,
|
||||
prepareUserPaths,
|
||||
withConfigArg
|
||||
} = require('./userpaths')
|
||||
|
||||
// 用绝对路径字符串拼测试目录,避免依赖运行平台的盘符写法
|
||||
const INSTALL = path.resolve('/scoreboard-install')
|
||||
const LOCAL = path.resolve('/localappdata')
|
||||
const USER_ROOT = path.join(LOCAL, 'ScoreboardConsole')
|
||||
|
||||
function makeRoot(t) {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'scoreboard-userpaths-'))
|
||||
t.after(() => fs.rmSync(root, { recursive: true, force: true }))
|
||||
return root
|
||||
}
|
||||
|
||||
function writeFile(file, text) {
|
||||
fs.mkdirSync(path.dirname(file), { recursive: true })
|
||||
fs.writeFileSync(file, text)
|
||||
}
|
||||
|
||||
function readFile(file) {
|
||||
return fs.readFileSync(file, 'utf8')
|
||||
}
|
||||
|
||||
// 打包态 + 有 %LOCALAPPDATA% 是「接管」的唯一组合
|
||||
function planFor({ installDir = INSTALL, env = { LOCALAPPDATA: LOCAL }, isPackaged = true } = {}) {
|
||||
return planUserPaths({ installDir, userRoot: resolveUserRoot(env), isPackaged })
|
||||
}
|
||||
|
||||
test('打包态三项都落到用户根下,与数据目录同一基座', () => {
|
||||
const plan = planFor()
|
||||
assert.equal(plan.mode, 'user')
|
||||
assert.equal(plan.root, USER_ROOT)
|
||||
assert.equal(plan.items.consoleConfig.target, path.join(USER_ROOT, 'console', 'config.json'))
|
||||
assert.equal(plan.items.serverConfig.target, path.join(USER_ROOT, 'config.yaml'))
|
||||
assert.equal(plan.items.rulesDir.target, path.join(USER_ROOT, 'rules'))
|
||||
})
|
||||
|
||||
test('开发态不接管,三项都指向安装目录里随包的那份', () => {
|
||||
const plan = planFor({ isPackaged: false })
|
||||
assert.equal(plan.mode, 'install')
|
||||
assert.equal(plan.reason, 'dev')
|
||||
assert.equal(plan.items.consoleConfig.target, path.join(INSTALL, 'config.json'))
|
||||
assert.equal(plan.items.serverConfig.target, path.join(INSTALL, 'config.yaml'))
|
||||
assert.equal(plan.items.rulesDir.target, path.join(INSTALL, 'rules'))
|
||||
})
|
||||
|
||||
test('拿不到 %LOCALAPPDATA% 时回落安装目录并记日志', () => {
|
||||
const plan = planFor({ env: {} })
|
||||
assert.equal(plan.mode, 'install')
|
||||
assert.equal(plan.reason, 'no-localappdata')
|
||||
|
||||
const lines = []
|
||||
const paths = prepareUserPaths({ plan, log: (line) => lines.push(line) })
|
||||
assert.equal(paths.consoleConfig, path.join(INSTALL, 'config.json'))
|
||||
assert.equal(paths.rulesDir, path.join(INSTALL, 'rules'))
|
||||
assert.equal(paths.serverConfig, null)
|
||||
assert.match(lines.join('\n'), /拿不到 %LOCALAPPDATA%/)
|
||||
})
|
||||
|
||||
test('首次运行把随包的三项复制过去,安装目录那份留作模板', (t) => {
|
||||
const root = makeRoot(t)
|
||||
const installDir = path.join(root, 'install')
|
||||
const userRoot = path.join(root, 'localappdata', 'ScoreboardConsole')
|
||||
writeFile(path.join(installDir, 'config.json'), '{"server":{"port":19541}}')
|
||||
writeFile(path.join(installDir, 'config.yaml'), 'server:\n port: 19541\n')
|
||||
writeFile(path.join(installDir, 'rules', 'cup.yaml'), 'format: scoreboard-rules\n')
|
||||
writeFile(path.join(installDir, 'rules', 'README.md'), '说明\n')
|
||||
|
||||
const lines = []
|
||||
const paths = prepareUserPaths({
|
||||
plan: planUserPaths({ installDir, userRoot, isPackaged: true }),
|
||||
log: (line) => lines.push(line)
|
||||
})
|
||||
|
||||
assert.equal(paths.consoleConfig, path.join(userRoot, 'console', 'config.json'))
|
||||
assert.equal(paths.serverConfig, path.join(userRoot, 'config.yaml'))
|
||||
assert.equal(paths.rulesDir, path.join(userRoot, 'rules'))
|
||||
assert.equal(readFile(paths.consoleConfig), '{"server":{"port":19541}}')
|
||||
assert.equal(readFile(paths.serverConfig), 'server:\n port: 19541\n')
|
||||
assert.equal(readFile(path.join(userRoot, 'rules', 'cup.yaml')), 'format: scoreboard-rules\n')
|
||||
assert.equal(readFile(path.join(userRoot, 'rules', 'README.md')), '说明\n')
|
||||
// 复制不是移动:安装目录那三份必须原样留着当模板
|
||||
assert.equal(readFile(path.join(installDir, 'config.json')), '{"server":{"port":19541}}')
|
||||
assert.equal(readFile(path.join(installDir, 'config.yaml')), 'server:\n port: 19541\n')
|
||||
assert.equal(fs.existsSync(path.join(installDir, 'rules', 'cup.yaml')), true)
|
||||
assert.equal(lines.filter((line) => line.startsWith('已把 ')).length, 3)
|
||||
})
|
||||
|
||||
test('用户目录已有那份就一律用它,不覆盖也不重拷', (t) => {
|
||||
const root = makeRoot(t)
|
||||
const installDir = path.join(root, 'install')
|
||||
const userRoot = path.join(root, 'localappdata', 'ScoreboardConsole')
|
||||
writeFile(path.join(installDir, 'config.json'), '{"server":{"port":1111}}')
|
||||
writeFile(path.join(installDir, 'config.yaml'), 'server:\n port: 1111\n')
|
||||
writeFile(path.join(installDir, 'rules', 'cup.yaml'), 'template\n')
|
||||
writeFile(path.join(userRoot, 'console', 'config.json'), '{"server":{"port":2222}}')
|
||||
writeFile(path.join(userRoot, 'config.yaml'), 'server:\n port: 2222\n')
|
||||
writeFile(path.join(userRoot, 'rules', 'mine.yaml'), 'mine\n')
|
||||
|
||||
const lines = []
|
||||
const paths = prepareUserPaths({
|
||||
plan: planUserPaths({ installDir, userRoot, isPackaged: true }),
|
||||
log: (line) => lines.push(line)
|
||||
})
|
||||
|
||||
assert.equal(readFile(paths.consoleConfig), '{"server":{"port":2222}}')
|
||||
assert.equal(readFile(paths.serverConfig), 'server:\n port: 2222\n')
|
||||
assert.equal(readFile(path.join(userRoot, 'rules', 'mine.yaml')), 'mine\n')
|
||||
// 用户目录里的 rules\ 已存在(哪怕内容和模板不同)→ 不补拷模板里的 cup.yaml
|
||||
assert.equal(fs.existsSync(path.join(userRoot, 'rules', 'cup.yaml')), false)
|
||||
assert.equal(lines.filter((line) => line.startsWith('已把 ')).length, 0)
|
||||
})
|
||||
|
||||
test('用户目录写不进去时记日志并回落到安装目录,不抛异常', (t) => {
|
||||
const root = makeRoot(t)
|
||||
const installDir = path.join(root, 'install')
|
||||
writeFile(path.join(installDir, 'config.json'), '{}')
|
||||
writeFile(path.join(installDir, 'config.yaml'), 'server: {}\n')
|
||||
writeFile(path.join(installDir, 'rules', 'cup.yaml'), 'template\n')
|
||||
// 用户根的位置被一个文件占着:mkdir/rename 必然失败(ENOTDIR)
|
||||
const userRoot = path.join(root, 'blocker')
|
||||
writeFile(userRoot, 'not a dir')
|
||||
|
||||
const lines = []
|
||||
const paths = prepareUserPaths({
|
||||
plan: planUserPaths({ installDir, userRoot, isPackaged: true }),
|
||||
log: (line) => lines.push(line)
|
||||
})
|
||||
|
||||
assert.equal(paths.consoleConfig, path.join(installDir, 'config.json'))
|
||||
assert.equal(paths.serverConfig, null)
|
||||
assert.equal(paths.rulesDir, path.join(installDir, 'rules'))
|
||||
assert.equal(readFile(paths.consoleConfig), '{}')
|
||||
assert.equal(readFile(path.join(installDir, 'rules', 'cup.yaml')), 'template\n')
|
||||
assert.equal(lines.filter((line) => line.includes('继续用安装目录里的')).length, 3)
|
||||
})
|
||||
|
||||
test('两边都没有的那一份跳过复制,路径仍指向用户目录', (t) => {
|
||||
const root = makeRoot(t)
|
||||
const installDir = path.join(root, 'install')
|
||||
const userRoot = path.join(root, 'localappdata', 'ScoreboardConsole')
|
||||
fs.mkdirSync(installDir, { recursive: true })
|
||||
|
||||
const lines = []
|
||||
const paths = prepareUserPaths({
|
||||
plan: planUserPaths({ installDir, userRoot, isPackaged: true }),
|
||||
log: (line) => lines.push(line)
|
||||
})
|
||||
|
||||
// 不接管就没人去读用户目录,服务端会按 config.Load 的默认值跑
|
||||
assert.equal(paths.serverConfig, path.join(userRoot, 'config.yaml'))
|
||||
assert.equal(fs.existsSync(paths.serverConfig), false)
|
||||
assert.equal(lines.filter((line) => line.includes('本次跳过复制')).length, 3)
|
||||
})
|
||||
|
||||
test('规则目录拷贝到位后不留临时目录,重复运行不重做', (t) => {
|
||||
const root = makeRoot(t)
|
||||
const installDir = path.join(root, 'install')
|
||||
const userRoot = path.join(root, 'localappdata', 'ScoreboardConsole')
|
||||
writeFile(path.join(installDir, 'config.json'), '{}\n')
|
||||
writeFile(path.join(installDir, 'config.yaml'), 'server: {}\n')
|
||||
writeFile(path.join(installDir, 'rules', 'cup.yaml'), 'template\n')
|
||||
const plan = planUserPaths({ installDir, userRoot, isPackaged: true })
|
||||
|
||||
const first = prepareUserPaths({ plan, log: () => {} })
|
||||
assert.deepEqual(fs.readdirSync(userRoot).sort(), ['config.yaml', 'console', 'rules'])
|
||||
assert.deepEqual(fs.readdirSync(first.rulesDir), ['cup.yaml'])
|
||||
|
||||
// 第二次启动:目标都在了,不再复制(用户改过的内容不会被模板顶掉)
|
||||
writeFile(path.join(userRoot, 'config.yaml'), 'server:\n port: 3333\n')
|
||||
const second = prepareUserPaths({ plan, log: () => {} })
|
||||
assert.deepEqual(second, first)
|
||||
assert.equal(readFile(path.join(userRoot, 'config.yaml')), 'server:\n port: 3333\n')
|
||||
})
|
||||
|
||||
test('-config 的值换成解析出的绝对路径,其余参数原样保留', () => {
|
||||
assert.deepEqual(withConfigArg(['-config', 'config.yaml'], '/u/config.yaml'), ['-config', '/u/config.yaml'])
|
||||
assert.deepEqual(
|
||||
withConfigArg(['-config', 'config.yaml', '-project', 'cup'], '/u/config.yaml'),
|
||||
['-config', '/u/config.yaml', '-project', 'cup']
|
||||
)
|
||||
// 参数里没写 -config 就补一条,否则用户目录里那份永远不会被读到
|
||||
assert.deepEqual(withConfigArg(['-project', 'cup'], '/u/config.yaml'), ['-project', 'cup', '-config', '/u/config.yaml'])
|
||||
// 不接管(开发态)原样返回
|
||||
assert.deepEqual(withConfigArg(['-config', 'config.yaml'], null), ['-config', 'config.yaml'])
|
||||
assert.deepEqual(withConfigArg(null, '/u/config.yaml'), ['-config', '/u/config.yaml'])
|
||||
})
|
||||
Reference in new issue
Block a user