a08120c568
- Dashboard browser: search box + sort dropdown (name/category/author) - Dockerfile + docker-compose.yml - Debug page: log viewer button (/api/logs) - Settings: .tsb full backup export (dashboards+scenes+config) - F1 composite dashboard previously included
130 lines
4.8 KiB
JavaScript
130 lines
4.8 KiB
JavaScript
const PageDebug = {
|
|
_el: null,
|
|
_autoScroll: true,
|
|
_paused: false,
|
|
_rawData: [],
|
|
_fieldData: {},
|
|
_maxRawLines: 200,
|
|
|
|
init() {
|
|
this._el = document.getElementById('page-debug');
|
|
},
|
|
|
|
render() {
|
|
this._el.innerHTML = this._template();
|
|
this._bindEvents();
|
|
WS.on('telemetry', (data) => this._onTelemetry(data));
|
|
},
|
|
|
|
_bindEvents() {
|
|
document.getElementById('debug-clear-btn')?.addEventListener('click', () => {
|
|
this._rawData = [];
|
|
this._fieldData = {};
|
|
this._renderFields();
|
|
this._renderRaw();
|
|
});
|
|
|
|
document.getElementById('debug-pause-btn')?.addEventListener('click', () => {
|
|
this._paused = !this._paused;
|
|
const btn = document.getElementById('debug-pause-btn');
|
|
btn.textContent = this._paused ? '▶ 继续' : '⏸ 暂停';
|
|
});
|
|
|
|
document.getElementById('debug-autoscroll')?.addEventListener('change', (e) => {
|
|
this._autoScroll = e.target.checked;
|
|
});
|
|
|
|
document.getElementById('debug-show-log')?.addEventListener('click', async () => {
|
|
try {
|
|
const res = await fetch('/api/logs?lines=100');
|
|
const data = await res.json();
|
|
const el = document.getElementById('debug-raw');
|
|
if (el) el.innerHTML = data.lines.map(l =>
|
|
`<span style="color:${l.includes('ERROR')?'red':l.includes('WARNING')?'#f90':l.includes('INFO')?'#888':'#555'}">${l}</span>`
|
|
).join('\n');
|
|
} catch (e) {}
|
|
});
|
|
},
|
|
|
|
_onTelemetry(data) {
|
|
if (this._paused) return;
|
|
|
|
this._fieldData = data;
|
|
this._renderFields();
|
|
|
|
const timestamp = new Date().toISOString();
|
|
this._rawData.push({ timestamp, data: { ...data } });
|
|
if (this._rawData.length > this._maxRawLines) {
|
|
this._rawData.shift();
|
|
}
|
|
this._renderRaw();
|
|
},
|
|
|
|
_renderFields() {
|
|
const container = document.getElementById('debug-fields');
|
|
if (!container) return;
|
|
|
|
const keys = Object.keys(this._fieldData).filter(k => k !== 'raw');
|
|
container.innerHTML = keys.map(k => {
|
|
const val = this._fieldData[k];
|
|
const displayVal = typeof val === 'number' ? val.toFixed(3) : val;
|
|
return `
|
|
<div class="debug-field">
|
|
<div class="debug-field-name">${k}</div>
|
|
<div class="debug-field-value">${displayVal}</div>
|
|
</div>`;
|
|
}).join('') || '<div style="color:var(--text-tertiary);padding:20px;">等待数据...</div>';
|
|
},
|
|
|
|
_renderRaw() {
|
|
const el = document.getElementById('debug-raw');
|
|
if (!el) return;
|
|
|
|
const lines = this._rawData.map(entry => {
|
|
const ts = entry.timestamp.substring(11, 23);
|
|
const preview = JSON.stringify(entry.data).substring(0, 300);
|
|
return `<span style="color:var(--text-tertiary)">[${ts}]</span> <span style="color:var(--accent)">→</span> ${preview}`;
|
|
});
|
|
|
|
el.innerHTML = lines.join('\n') || '等待数据...';
|
|
|
|
if (this._autoScroll) {
|
|
el.scrollTop = el.scrollHeight;
|
|
}
|
|
},
|
|
|
|
cleanup() {
|
|
WS.off('telemetry', this._onTelemetry);
|
|
},
|
|
|
|
_template() {
|
|
return `
|
|
<div class="debug-container">
|
|
<div class="debug-toolbar animated">
|
|
<h2 style="font-size:20px;font-weight:700;">数据测试</h2>
|
|
<span style="flex:1;"></span>
|
|
<button id="debug-pause-btn" class="btn btn-sm btn-secondary">⏸ 暂停</button>
|
|
<button id="debug-clear-btn" class="btn btn-sm btn-secondary">清空</button>
|
|
<label style="display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-secondary);">
|
|
<input type="checkbox" id="debug-autoscroll" checked> 自动滚动
|
|
</label>
|
|
<button id="debug-show-log" class="btn btn-sm btn-secondary">📄 日志</button>
|
|
</div>
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;flex:1;min-height:0;">
|
|
<div style="overflow-y:auto;">
|
|
<h4 style="font-size:14px;color:var(--text-secondary);margin-bottom:12px;">解析后的数据字段</h4>
|
|
<div id="debug-fields">
|
|
<div style="color:var(--text-tertiary);padding:20px;">等待数据...</div>
|
|
</div>
|
|
</div>
|
|
<div style="overflow-y:auto;">
|
|
<h4 style="font-size:14px;color:var(--text-secondary);margin-bottom:12px;">原始 JSON 数据流</h4>
|
|
<div id="debug-raw" class="debug-data"></div>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
};
|
|
|
|
window.PageDebug = PageDebug;
|