功能(设备ID调试): 添加调试埋点与文档以定位设备ID缺失问题
创建调试环境配置文件与调试会话记录文档,在前端页面、票据面板以及后端公共接口的设备ID解析各阶段添加调试埋点,收集原始设备数据与处理后的结果,用于验证相关假设以定位设备ID不显示的根因。
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
DEBUG_SERVER_URL=http://127.0.0.1:7777/event
|
||||||
|
DEBUG_SESSION_ID=device-id-missing
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Debug Session: device-id-missing
|
||||||
|
- **Status**: [OPEN]
|
||||||
|
- **Issue**: 数据记录中的设备 ID 当前全部未显示,界面只看到“机器ID:”后没有具体值。
|
||||||
|
- **Debug Server**: http://127.0.0.1:7777/event
|
||||||
|
- **Log File**: .dbg/trae-debug-log-device-id-missing.ndjson
|
||||||
|
|
||||||
|
## Reproduction Steps
|
||||||
|
1. 使用售票机完成一次售票。
|
||||||
|
2. 使用闸机完成一次进站或出站。
|
||||||
|
3. 打开后台或票据时间线页面查看“机器ID”字段。
|
||||||
|
4. 观察“机器ID:”后方是否为空。
|
||||||
|
|
||||||
|
## Hypotheses & Verification
|
||||||
|
| ID | Hypothesis | Likelihood | Effort | Evidence |
|
||||||
|
|----|------------|------------|--------|----------|
|
||||||
|
| A | 后端接口返回的事件对象里根本没有 `device` / `detail.device` 字段 | High | Low | Pending |
|
||||||
|
| B | 前端格式化函数读到了值,但后续字符串拼接或编码问题把值丢掉了 | High | Low | Pending |
|
||||||
|
| C | 售票与检票两类事件的数据结构不同,当前前端只兼容了其中一类 | Med | Low | Pending |
|
||||||
|
| D | 设备端 Lua 确实上报了 ID,但服务端在写库或对外返回时被覆盖成空串 | Med | Med | Pending |
|
||||||
|
| E | 页面实际运行的不是当前工作区这份前端代码,导致本地修改未生效 | Med | Med | Pending |
|
||||||
|
|
||||||
|
## Log Evidence
|
||||||
|
- 2026-07-10: 已启动 Debug Server `http://127.0.0.1:7777/event`
|
||||||
|
- 2026-07-10: 已在 `[public.js]` 的票据时间线组装处添加 A/C 埋点
|
||||||
|
- 2026-07-10: 已在 `[index.js]` 与 `[ticket-board.html]` 的设备 ID 格式化处添加 B 埋点
|
||||||
|
|
||||||
|
## Verification Conclusion
|
||||||
|
[Pending]
|
||||||
+94
-2
@@ -694,8 +694,39 @@ router.get('/tickets/:id', async (req, res, next) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const formattedEvents = events.map(e => {
|
const formattedEvents = events.map(e => {
|
||||||
|
// #region debug-point A:public-ticket-event-raw
|
||||||
|
(() => {
|
||||||
|
const fs = require('fs');
|
||||||
|
let u = 'http://127.0.0.1:7777/event';
|
||||||
|
let s = 'device-id-missing';
|
||||||
|
try {
|
||||||
|
const env = fs.readFileSync('.dbg/device-id-missing.env', 'utf8');
|
||||||
|
u = env.match(/DEBUG_SERVER_URL=(.+)/)?.[1] || u;
|
||||||
|
s = env.match(/DEBUG_SESSION_ID=(.+)/)?.[1] || s;
|
||||||
|
} catch {}
|
||||||
|
fetch(u, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sessionId: s,
|
||||||
|
runId: 'pre-fix',
|
||||||
|
hypothesisId: 'A',
|
||||||
|
location: 'server/routes/public.js:696',
|
||||||
|
msg: '[DEBUG] public ticket event raw',
|
||||||
|
data: {
|
||||||
|
type: e?.type || '',
|
||||||
|
action: e?.action || '',
|
||||||
|
ticket_id: e?.ticket_id || '',
|
||||||
|
device: e?.device ?? null,
|
||||||
|
detail_device: e?.detail?.device ?? null
|
||||||
|
},
|
||||||
|
ts: Date.now()
|
||||||
|
})
|
||||||
|
}).catch(() => {});
|
||||||
|
})();
|
||||||
|
// #endregion
|
||||||
if (e.type === 'sale') {
|
if (e.type === 'sale') {
|
||||||
return {
|
const mapped = {
|
||||||
type: 'sale',
|
type: 'sale',
|
||||||
ts: e.ts,
|
ts: e.ts,
|
||||||
station_name: e.station_name || nameFor(e.station_code),
|
station_name: e.station_name || nameFor(e.station_code),
|
||||||
@@ -708,6 +739,36 @@ router.get('/tickets/:id', async (req, res, next) => {
|
|||||||
trips_total: e.trips_total ?? 0,
|
trips_total: e.trips_total ?? 0,
|
||||||
amount: e.cost ?? 0
|
amount: e.cost ?? 0
|
||||||
};
|
};
|
||||||
|
// #region debug-point A:public-ticket-event-sale-mapped
|
||||||
|
(() => {
|
||||||
|
const fs = require('fs');
|
||||||
|
let u = 'http://127.0.0.1:7777/event';
|
||||||
|
let s = 'device-id-missing';
|
||||||
|
try {
|
||||||
|
const env = fs.readFileSync('.dbg/device-id-missing.env', 'utf8');
|
||||||
|
u = env.match(/DEBUG_SERVER_URL=(.+)/)?.[1] || u;
|
||||||
|
s = env.match(/DEBUG_SESSION_ID=(.+)/)?.[1] || s;
|
||||||
|
} catch {}
|
||||||
|
fetch(u, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sessionId: s,
|
||||||
|
runId: 'pre-fix',
|
||||||
|
hypothesisId: 'A',
|
||||||
|
location: 'server/routes/public.js:701',
|
||||||
|
msg: '[DEBUG] public sale event mapped',
|
||||||
|
data: {
|
||||||
|
ticket_id: mapped.ticket_id || '',
|
||||||
|
device: mapped.device ?? null,
|
||||||
|
station_code: mapped.station_code || ''
|
||||||
|
},
|
||||||
|
ts: Date.now()
|
||||||
|
})
|
||||||
|
}).catch(() => {});
|
||||||
|
})();
|
||||||
|
// #endregion
|
||||||
|
return mapped;
|
||||||
} else if (e.type === 'status') {
|
} else if (e.type === 'status') {
|
||||||
return {
|
return {
|
||||||
type: 'status',
|
type: 'status',
|
||||||
@@ -720,11 +781,42 @@ router.get('/tickets/:id', async (req, res, next) => {
|
|||||||
trips_remaining: e.trips_remaining ?? e.rides_remaining ?? null
|
trips_remaining: e.trips_remaining ?? e.rides_remaining ?? null
|
||||||
};
|
};
|
||||||
} else if (e.type === 'check') {
|
} else if (e.type === 'check') {
|
||||||
return {
|
const mapped = {
|
||||||
...e,
|
...e,
|
||||||
station_name: e.station_name || nameFor(e.station_code),
|
station_name: e.station_name || nameFor(e.station_code),
|
||||||
station_en: e.station_code ? enNameFor(e.station_code) : (e.station_en || '')
|
station_en: e.station_code ? enNameFor(e.station_code) : (e.station_en || '')
|
||||||
};
|
};
|
||||||
|
// #region debug-point C:public-ticket-event-check-mapped
|
||||||
|
(() => {
|
||||||
|
const fs = require('fs');
|
||||||
|
let u = 'http://127.0.0.1:7777/event';
|
||||||
|
let s = 'device-id-missing';
|
||||||
|
try {
|
||||||
|
const env = fs.readFileSync('.dbg/device-id-missing.env', 'utf8');
|
||||||
|
u = env.match(/DEBUG_SERVER_URL=(.+)/)?.[1] || u;
|
||||||
|
s = env.match(/DEBUG_SESSION_ID=(.+)/)?.[1] || s;
|
||||||
|
} catch {}
|
||||||
|
fetch(u, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sessionId: s,
|
||||||
|
runId: 'pre-fix',
|
||||||
|
hypothesisId: 'C',
|
||||||
|
location: 'server/routes/public.js:718',
|
||||||
|
msg: '[DEBUG] public check event mapped',
|
||||||
|
data: {
|
||||||
|
ticket_id: mapped.ticket_id || '',
|
||||||
|
action: mapped.action || '',
|
||||||
|
device: mapped.device ?? null,
|
||||||
|
station_code: mapped.station_code || ''
|
||||||
|
},
|
||||||
|
ts: Date.now()
|
||||||
|
})
|
||||||
|
}).catch(() => {});
|
||||||
|
})();
|
||||||
|
// #endregion
|
||||||
|
return mapped;
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -350,6 +350,29 @@ createApp({
|
|||||||
const action = getTicketEventAction(ev);
|
const action = getTicketEventAction(ev);
|
||||||
let deviceId = String(ev?.device || ev?.device_id || ev?.detail?.device || ev?.detail?.device_id || ev?.["设备编号"] || ev?.["机器ID"] || '---').trim();
|
let deviceId = String(ev?.device || ev?.device_id || ev?.detail?.device || ev?.detail?.device_id || ev?.["设备编号"] || ev?.["机器ID"] || '---').trim();
|
||||||
const dStr = deviceId.toLowerCase();
|
const dStr = deviceId.toLowerCase();
|
||||||
|
|
||||||
|
// #region debug-point B:index-ticket-device-before-map
|
||||||
|
fetch('http://127.0.0.1:7777/event', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sessionId: 'device-id-missing',
|
||||||
|
runId: 'pre-fix',
|
||||||
|
hypothesisId: 'B',
|
||||||
|
location: 'web/index.js:351',
|
||||||
|
msg: '[DEBUG] admin ticket formatter raw device',
|
||||||
|
data: {
|
||||||
|
type,
|
||||||
|
action,
|
||||||
|
raw_device: ev?.device ?? null,
|
||||||
|
raw_device_id: ev?.device_id ?? null,
|
||||||
|
raw_detail_device: ev?.detail?.device ?? null,
|
||||||
|
resolved_before_map: deviceId
|
||||||
|
},
|
||||||
|
ts: Date.now()
|
||||||
|
})
|
||||||
|
}).catch(() => {});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
if (dStr === 'gate') {
|
if (dStr === 'gate') {
|
||||||
deviceId = '闸机';
|
deviceId = '闸机';
|
||||||
@@ -364,6 +387,26 @@ createApp({
|
|||||||
deviceId = '售票机';
|
deviceId = '售票机';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region debug-point B:index-ticket-device-after-map
|
||||||
|
fetch('http://127.0.0.1:7777/event', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sessionId: 'device-id-missing',
|
||||||
|
runId: 'pre-fix',
|
||||||
|
hypothesisId: 'B',
|
||||||
|
location: 'web/index.js:373',
|
||||||
|
msg: '[DEBUG] admin ticket formatter mapped device',
|
||||||
|
data: {
|
||||||
|
type,
|
||||||
|
action,
|
||||||
|
mapped_device: deviceId
|
||||||
|
},
|
||||||
|
ts: Date.now()
|
||||||
|
})
|
||||||
|
}).catch(() => {});
|
||||||
|
// #endregion
|
||||||
const timeStr = formatTime(ev?.ts || ev?.["时间戳"]);
|
const timeStr = formatTime(ev?.ts || ev?.["时间戳"]);
|
||||||
|
|
||||||
if (type === 'sale' || type === '售票') {
|
if (type === 'sale' || type === '售票') {
|
||||||
|
|||||||
@@ -322,6 +322,29 @@
|
|||||||
const stationEn = event.station_en || event['站点英文'] || '';
|
const stationEn = event.station_en || event['站点英文'] || '';
|
||||||
let deviceId = String(event.device || event.device_id || event.detail?.device || event.detail?.device_id || event['设备编号'] || event['机器ID'] || '').trim();
|
let deviceId = String(event.device || event.device_id || event.detail?.device || event.detail?.device_id || event['设备编号'] || event['机器ID'] || '').trim();
|
||||||
const dStr = deviceId.toLowerCase();
|
const dStr = deviceId.toLowerCase();
|
||||||
|
|
||||||
|
// #region debug-point B:ticket-board-device-before-map
|
||||||
|
fetch('http://127.0.0.1:7777/event', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sessionId: 'device-id-missing',
|
||||||
|
runId: 'pre-fix',
|
||||||
|
hypothesisId: 'B',
|
||||||
|
location: 'web/ticket-board.html:323',
|
||||||
|
msg: '[DEBUG] public ticket formatter raw device',
|
||||||
|
data: {
|
||||||
|
type,
|
||||||
|
action,
|
||||||
|
raw_device: event.device ?? null,
|
||||||
|
raw_device_id: event.device_id ?? null,
|
||||||
|
raw_detail_device: event.detail?.device ?? null,
|
||||||
|
resolved_before_map: deviceId
|
||||||
|
},
|
||||||
|
ts: Date.now()
|
||||||
|
})
|
||||||
|
}).catch(() => {});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
if (dStr === 'gate') {
|
if (dStr === 'gate') {
|
||||||
deviceId = '闸机';
|
deviceId = '闸机';
|
||||||
@@ -338,6 +361,26 @@
|
|||||||
deviceId = '售票机';
|
deviceId = '售票机';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region debug-point B:ticket-board-device-after-map
|
||||||
|
fetch('http://127.0.0.1:7777/event', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sessionId: 'device-id-missing',
|
||||||
|
runId: 'pre-fix',
|
||||||
|
hypothesisId: 'B',
|
||||||
|
location: 'web/ticket-board.html:345',
|
||||||
|
msg: '[DEBUG] public ticket formatter mapped device',
|
||||||
|
data: {
|
||||||
|
type,
|
||||||
|
action,
|
||||||
|
mapped_device: deviceId
|
||||||
|
},
|
||||||
|
ts: Date.now()
|
||||||
|
})
|
||||||
|
}).catch(() => {});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
if (stationEn && deviceId) return `${stationEn} (${deviceId})`;
|
if (stationEn && deviceId) return `${stationEn} (${deviceId})`;
|
||||||
if (deviceId) return `设备:${deviceId}`;
|
if (deviceId) return `设备:${deviceId}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user