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。
This commit is contained in:
1 parent
6483acf9ad
commit
005b51b2ec
18 files changed
+626
-64
No files matched your search
+39
-3
@@ -13,6 +13,7 @@ const {
|
||||
} = require('electron')
|
||||
|
||||
const { loadConfig, updateConfig, resolveExecutable } = require('./config')
|
||||
const { resolveDataDir, migrateLegacyData, isInside } = require('./datadir')
|
||||
const { LogBus } = require('./log-bus')
|
||||
const { ServiceSupervisor, healthHost } = require('./service')
|
||||
const { DisplayManager } = require('./displays')
|
||||
@@ -40,6 +41,8 @@ function main() {
|
||||
let quitting = false
|
||||
let shutdownDone = false
|
||||
let exePath = null
|
||||
// 解析后的数据目录信息(见 datadir.js),拉起服务端和 passwd 都用它
|
||||
let dataDirInfo = null
|
||||
// 大屏实例看板只在管理窗口可见时轮询,窗口隐藏即停表
|
||||
let instancesTimer = null
|
||||
let instancesLastReason = null
|
||||
@@ -431,6 +434,11 @@ function main() {
|
||||
return 'config.yaml'
|
||||
}
|
||||
|
||||
// 数据目录同理:不带上同一个 -data,passwd 会改到另一个库里的账号上
|
||||
function passwdDataArg() {
|
||||
return dataDirInfo && dataDirInfo.passToServer ? dataDirInfo.dir : ''
|
||||
}
|
||||
|
||||
// 账号重置走同目录的 scoreboard.exe passwd 子命令:本机进程、不经 HTTP,
|
||||
// 所以不需要任何登录态,这就是面板能「免验证」的原因。
|
||||
async function resetAdminAccount(event, payload) {
|
||||
@@ -454,14 +462,16 @@ function main() {
|
||||
}
|
||||
|
||||
const configArg = passwdConfigArg()
|
||||
const args = buildPasswdArgs({ configArg, currentUsername, newUsername, password })
|
||||
const dataDirArg = passwdDataArg()
|
||||
const args = buildPasswdArgs({ configArg, dataDir: dataDirArg, currentUsername, newUsername, password })
|
||||
const sender = event.sender
|
||||
|
||||
accountBusy = true
|
||||
// 日志里不能带明文密码
|
||||
log.push(
|
||||
'console',
|
||||
`重置管理员账号:${exe} passwd -config ${configArg} -user ${currentUsername}` +
|
||||
`重置管理员账号:${exe} passwd -config ${configArg}` +
|
||||
`${dataDirArg ? ` -data ${dataDirArg}` : ''} -user ${currentUsername}` +
|
||||
`${newUsername ? ` -new-username ${newUsername}` : ''}(密码已隐藏)`
|
||||
)
|
||||
|
||||
@@ -565,10 +575,36 @@ function main() {
|
||||
exePath = resolved.path
|
||||
log.push('console', `服务端程序:${resolved.path}`)
|
||||
|
||||
const installDir = path.dirname(resolved.path)
|
||||
dataDirInfo = resolveDataDir({
|
||||
values: cfg.values,
|
||||
installDir,
|
||||
env: process.env,
|
||||
isPackaged: app.isPackaged
|
||||
})
|
||||
|
||||
// 老版本把数据放在安装目录里,而覆盖安装会先静默跑旧卸载器把安装目录整个删掉,
|
||||
// 所以先做一次性迁移。只在打包态做,开发态不动仓库里的 data/。
|
||||
if (app.isPackaged && dataDirInfo.passToServer) {
|
||||
migrateLegacyData({
|
||||
targetDir: dataDirInfo.dir,
|
||||
legacyDir: path.join(installDir, 'data'),
|
||||
log: (message) => log.push('console', message)
|
||||
})
|
||||
}
|
||||
log.push(
|
||||
'console',
|
||||
`数据目录:${dataDirInfo.dir}${dataDirInfo.passToServer ? '' : '(沿用服务端默认)'}`
|
||||
)
|
||||
if (dataDirInfo.passToServer && isInside(installDir, dataDirInfo.dir)) {
|
||||
log.push('console', `警告:数据目录仍在安装目录内(${dataDirInfo.dir}),覆盖安装时会被删除`)
|
||||
}
|
||||
|
||||
service = new ServiceSupervisor({
|
||||
values: cfg.values,
|
||||
exePath: resolved.path,
|
||||
log
|
||||
log,
|
||||
dataDir: dataDirInfo.passToServer ? dataDirInfo.dir : null
|
||||
})
|
||||
|
||||
displays = new DisplayManager({
|
||||
|
||||
Reference in new issue
Block a user