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
+84 -14
View File
@@ -1,7 +1,8 @@
local DEFAULT_SERVER_BASE = "http://ticket.fse-media.group"
local DEFAULT_SERVER_PATH = "/api/tickets/check"
local GATE_OPEN_SECONDS = 2
local VERSION = "v1.5.7"
local VERSION = "v1.5.8"
local VERSION_CHECK_INTERVAL = 60
local CONFIG_PATH = "gate_config.json"
@@ -26,6 +27,15 @@ local function trim(s)
return (tostring(s or ""):gsub("^%s+", ""):gsub("%s+$", ""))
end
local function normalizeVersionTag(v)
local s = trim(v)
if #s == 0 then return "" end
if s:sub(1, 1):lower() ~= "v" then
s = "v" .. s
end
return s:lower()
end
local function splitCsv(s)
local out = {}
s = trim(s)
@@ -80,6 +90,8 @@ local inspection = peripheral.find("ticket_inspection_machine")
local serverConnected = nil
local serverLastChangeTs = 0
local expectedGateVersion = nil
local versionMismatch = nil
local function setServerConnected(ok)
if serverConnected == ok then return end
@@ -126,10 +138,20 @@ local function drawVersionIndicator(w)
local s = tostring(VERSION or "")
if #s == 0 then return end
if w < #s then return end
local markerColor = colors.yellow
if versionMismatch == true then
markerColor = colors.red
elseif versionMismatch == false then
markerColor = colors.lime
end
termDev.setBackgroundColor(colors.black)
termDev.setTextColor(colors.gray)
termDev.setCursorPos(1, 1)
termDev.write(s)
if w >= (#s + 1) then
termDev.setTextColor(markerColor)
termDev.write("*")
end
termDev.setTextColor(colors.white)
end
@@ -337,6 +359,23 @@ local function refreshStationNameMap(serverBase)
return true
end
local function refreshRemoteLuaVersion(serverBase)
serverBase = trim(serverBase or "")
if #serverBase == 0 then return false end
local url = serverBase:gsub("/+$", "") .. "/api/public/config"
local ok, parsed = getJSON(url)
if not ok or type(parsed) ~= "table" then return false end
local remote = normalizeVersionTag(type(parsed.lua_versions) == "table" and parsed.lua_versions.gate or nil)
if #remote == 0 then
expectedGateVersion = nil
versionMismatch = nil
return true
end
expectedGateVersion = remote
versionMismatch = (remote ~= normalizeVersionTag(VERSION))
return true
end
local function inferStationCodeFromName(name)
local key = normKey(name or "")
if #key == 0 then return "" end
@@ -655,6 +694,10 @@ pcall(function()
refreshStationNameMap(guessBaseFromStatusURL(serverURL))
end)
pcall(function()
refreshRemoteLuaVersion(guessBaseFromStatusURL(serverURL))
end)
if not inspection then
if modeBySide == nil then
draw("Missing peripheral:", "ticket_inspection_machine", colors.red)
@@ -667,18 +710,6 @@ if next(stationSet) == nil then
error("No station codes configured")
end
local stationListText = table.concat(cfg.station_codes, ",")
local function readyLine1()
if not modeBySide then
return "Ready (" .. mode:upper() .. ")"
end
local f = modeBySide.front and modeBySide.front:upper() or "-"
local b = modeBySide.back and modeBySide.back:upper() or "-"
return "Ready (BI) F:" .. f .. " B:" .. b
end
draw(readyLine1(), "Station: " .. stationListText, colors.lime)
local stationCodesPayload = {}
for k, _ in pairs(stationSet) do table.insert(stationCodesPayload, k) end
table.sort(stationCodesPayload)
@@ -785,6 +816,37 @@ local function actionForSide(side)
return modeBySide[side] or mode
end
local function shortModeLabel(v)
v = trim(v):lower()
if v == "exit" then return "OUT" end
return "IN"
end
local function readyLine1()
if not modeBySide then
return "READY " .. shortModeLabel(mode)
end
return "F " .. shortModeLabel(modeBySide.front or "") .. " B " .. shortModeLabel(modeBySide.back or "")
end
local function readyLine2()
if not modeBySide then
return "ST " .. stationCodeForSide(nil)
end
local frontCode = stationCodeForSide("front")
local backCode = stationCodeForSide("back")
if frontCode == backCode then
return "ST " .. frontCode
end
return "F " .. frontCode .. " B " .. backCode
end
local function drawReadyScreen()
draw(readyLine1(), readyLine2(), colors.lime)
end
drawReadyScreen()
local function collectInspectionDevices(side, modeBySideRef)
local sideKnown = trimSide(side) ~= nil
local inspectionDevs = {}
@@ -1278,11 +1340,19 @@ local function processInspectionEvent(eventName, ev)
end
end
local versionTimer = os.startTimer(VERSION_CHECK_INTERVAL)
while true do
local ev = pack(os.pullEvent())
if ev[1] == "ticket_scanned" or ev[1] == "ic_card_scanned" then
processInspectionEvent(ev[1], ev)
os.sleep(0.35)
draw(readyLine1(), "Station: " .. stationListText, colors.lime)
drawReadyScreen()
elseif ev[1] == "timer" and ev[2] == versionTimer then
pcall(function()
refreshRemoteLuaVersion(guessBaseFromStatusURL(serverURL))
end)
drawReadyScreen()
versionTimer = os.startTimer(VERSION_CHECK_INTERVAL)
end
end