feat: 新增客户端问题主动上报与控制台问题汇总功能
1. 客户端 (ticketmachine.lua): 修改 showAlert 支持详细错误并主动上报,使用 pcall 包装主循环捕获 Fatal Error 并上报。 2. 服务端 (data.js, api.js): 增加 issues 数据表,提供 /report_issue 和 /issues 接口。 3. 控制台 (index.html, index.js): 添加“问题汇总”菜单及界面状态管理。
This commit is contained in:
@@ -1191,6 +1191,29 @@ router.get('/export', (req, res) => {
|
||||
res.json(DataService.buildExportPayload());
|
||||
});
|
||||
|
||||
// Issues
|
||||
router.post('/report_issue', async (req, res) => {
|
||||
const r = req.body || {};
|
||||
const item = {
|
||||
ts: Number(r.ts || Date.now()),
|
||||
device: String(r.device || 'unknown'),
|
||||
machine_id: String(r.machine_id || ''),
|
||||
station_code: String(r.station_code || ''),
|
||||
error_msg: String(r.error_msg || ''),
|
||||
detail: String(r.detail || ''),
|
||||
type: 'issue'
|
||||
};
|
||||
await DataService.appendIssue(item);
|
||||
io.emit('issue:new', item);
|
||||
appendReqLog(req, { category: 'device', type: 'report_issue', detail: item });
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
router.get('/issues', (req, res) => {
|
||||
const issues = DataService.getIssues();
|
||||
res.json({ ok: true, issues });
|
||||
});
|
||||
|
||||
// Ticket Operations
|
||||
router.post('/tickets/sale', async (req, res) => {
|
||||
const { start, terminal, train_type, cost, station_code, device, trips_total, trips_remaining } = req.body || {};
|
||||
|
||||
+15
-1
@@ -64,7 +64,8 @@ const cache = {
|
||||
icCardIndex: {},
|
||||
icCardEvents: [],
|
||||
statsTicket: [],
|
||||
statsGate: []
|
||||
statsGate: [],
|
||||
issues: []
|
||||
};
|
||||
|
||||
const DataService = {
|
||||
@@ -88,6 +89,7 @@ const DataService = {
|
||||
await conn.query(`CREATE TABLE IF NOT EXISTS ticket_events (id INT AUTO_INCREMENT PRIMARY KEY, data JSON)`);
|
||||
await conn.query(`CREATE TABLE IF NOT EXISTS stats_ticket (id INT AUTO_INCREMENT PRIMARY KEY, data JSON)`);
|
||||
await conn.query(`CREATE TABLE IF NOT EXISTS stats_gate (id INT AUTO_INCREMENT PRIMARY KEY, data JSON)`);
|
||||
await conn.query(`CREATE TABLE IF NOT EXISTS issues (id INT AUTO_INCREMENT PRIMARY KEY, data JSON)`);
|
||||
|
||||
// Load Cache
|
||||
const [configs] = await conn.query('SELECT v FROM kv_store WHERE k = ?', ['config']);
|
||||
@@ -126,6 +128,9 @@ const DataService = {
|
||||
const [statsG] = await conn.query('SELECT data FROM stats_gate');
|
||||
cache.statsGate = statsG.map(r => r.data);
|
||||
|
||||
const [issues] = await conn.query('SELECT data FROM issues');
|
||||
cache.issues = issues.map(r => r.data);
|
||||
|
||||
console.log('DataService initialized with MySQL');
|
||||
} finally {
|
||||
conn.release();
|
||||
@@ -511,6 +516,15 @@ const DataService = {
|
||||
},
|
||||
getStatsGate: () => cache.statsGate,
|
||||
|
||||
// Issues
|
||||
appendIssue: async (item) => {
|
||||
cache.issues.push(item);
|
||||
try {
|
||||
await pool.query('INSERT INTO issues (data) VALUES (?)', [JSON.stringify(item)]);
|
||||
} catch(e) { console.error('appendIssue error', e); }
|
||||
},
|
||||
getIssues: () => cache.issues,
|
||||
|
||||
// Export
|
||||
buildExportPayload: () => ({
|
||||
config: DataService.getConfig(),
|
||||
|
||||
Reference in New Issue
Block a user