feat(web,backend,lua,installer): 新增Lua脚本版本管理功能及相关优化

- 升级售票机、检票机内置Lua脚本版本至v1.5.8
- 新增后端配置的lua_versions字段,统一管理售票机、检票机的Lua脚本版本
- 前端新增版本管理配置页面,支持版本号配置和一键补丁升级
- 为售票机、检票机添加远程版本检测功能,屏幕显示版本匹配状态标记
- 简化installer配置交互流程,优化站点代码输入方式
- 重构后端配置规范化处理逻辑,统一配置初始化与存储流程
- 优化售票机外设检测、支付检测逻辑,修复部分已知问题
This commit is contained in:
2026-06-28 16:30:17 +08:00
parent 81debd3b55
commit 07e4200c17
9 changed files with 480 additions and 136 deletions
+12 -4
View File
@@ -148,14 +148,16 @@ const resolveCurrentStationCode = (body, resolveStation) => {
// Config
router.get('/config', (req, res) => {
const cfg = DataService.getConfig();
res.json({
api_base: DataService.getConfig().api_base,
current_station: DataService.getConfig().current_station,
api_base: cfg.api_base,
current_station: cfg.current_station,
stations: DataService.getStations(),
lines: DataService.getLines(),
fares: DataService.getFares(),
transfers: DataService.getConfig().transfers || [],
promotion: DataService.getConfig().promotion || { name: '', discount: 1 }
transfers: cfg.transfers || [],
promotion: cfg.promotion || { name: '', discount: 1 },
lua_versions: cfg.lua_versions || {}
});
});
@@ -219,6 +221,12 @@ router.put('/config', async (req, res) => {
if (!(d >= 0 && d <= 1)) return res.status(400).json({ ok: false, error: 'promotion.discount must be between 0 and 1' });
cfg.promotion = { name: String(p.name || ''), discount: d };
}
if (incoming.lua_versions && typeof incoming.lua_versions === 'object') {
cfg.lua_versions = {
...(cfg.lua_versions || {}),
...(incoming.lua_versions || {})
};
}
await DataService.saveConfig(cfg);
appendReqLog(req, { category: 'admin', type: 'update_config_generic', detail: incoming });
io.emit('config:updated', cfg);
+2 -1
View File
@@ -221,7 +221,8 @@ router.get('/fares/query', (req, res) => {
router.get('/config', (req, res) => {
const cfg = DataService.getConfig();
res.json({
promotion: { name: cfg.promotion?.name || '', discount: cfg.promotion?.discount ?? 1 }
promotion: { name: cfg.promotion?.name || '', discount: cfg.promotion?.discount ?? 1 },
lua_versions: cfg.lua_versions || {}
});
});
+34 -9
View File
@@ -21,14 +21,39 @@ const pool = mysql.createPool({
queueLimit: 0
});
const DEFAULT_LUA_VERSIONS = {
ticketmachine: 'v1.5.8',
gate: 'v1.5.8'
};
function normalizeLuaVersions(input) {
const src = (input && typeof input === 'object') ? input : {};
return {
ticketmachine: String(src.ticketmachine || DEFAULT_LUA_VERSIONS.ticketmachine),
gate: String(src.gate || DEFAULT_LUA_VERSIONS.gate)
};
}
function normalizeConfig(input) {
const src = (input && typeof input === 'object') ? input : {};
return {
...src,
api_base: String(src.api_base || 'http://127.0.0.1:23333/api'),
current_station: (src.current_station && typeof src.current_station === 'object')
? src.current_station
: { name: 'Station1', code: '01-01' },
transfers: Array.isArray(src.transfers) ? src.transfers : [],
promotion: {
name: String(src?.promotion?.name || ''),
discount: Number(src?.promotion?.discount ?? 1)
},
lua_versions: normalizeLuaVersions(src.lua_versions)
};
}
// In-memory cache for synchronous read access
const cache = {
config: {
api_base: 'http://127.0.0.1:23333/api',
current_station: { name: 'Station1', code: '01-01' },
transfers: [],
promotion: { name: '', discount: 1 }
},
config: normalizeConfig({}),
stations: [],
lines: [],
fares: [],
@@ -66,7 +91,7 @@ const DataService = {
// Load Cache
const [configs] = await conn.query('SELECT v FROM kv_store WHERE k = ?', ['config']);
if (configs.length > 0) cache.config = configs[0].v;
if (configs.length > 0) cache.config = normalizeConfig(configs[0].v);
else await conn.query('INSERT INTO kv_store (k, v) VALUES (?, ?)', ['config', JSON.stringify(cache.config)]);
const [stations] = await conn.query('SELECT data FROM stations');
@@ -114,8 +139,8 @@ const DataService = {
// Config
getConfig: () => cache.config,
saveConfig: async (cfg) => {
cache.config = cfg;
await pool.query('INSERT INTO kv_store (k, v) VALUES (?, ?) ON DUPLICATE KEY UPDATE v = ?', ['config', JSON.stringify(cfg), JSON.stringify(cfg)]);
cache.config = normalizeConfig(cfg);
await pool.query('INSERT INTO kv_store (k, v) VALUES (?, ?) ON DUPLICATE KEY UPDATE v = ?', ['config', JSON.stringify(cache.config), JSON.stringify(cache.config)]);
},
// Stations