/**
* @file dashboard.js
* @brief Dashboard 仪表盘页面 — 信号卡片 + 快捷操作 + 连接状态
*/
Router.register('#dashboard', function(c) {
var types = [
{ t: 'out', key: 'nav.out', descKey: 'dash.out.desc', color: 'var(--accent)' },
{ t: 'in', key: 'nav.in', descKey: 'dash.in.desc', color: 'var(--accent2)' },
{ t: 'yk', key: 'nav.yk', descKey: 'dash.yk.desc', color: 'var(--warning)' },
{ t: 'ao', key: 'nav.ao', descKey: 'dash.ao.desc', color: 'var(--success)' },
{ t: 'param', key: 'nav.param', descKey: 'dash.param.desc', color: '#a78bfa' },
];
var cards = types.map(function(t) {
var count = SignalStore.get(t.t).length;
return '
'
+ '
' + Icon.get(t.icon === 'out' ? 'signal' : t.icon === 'in' ? 'link' : t.icon === 'yk' ? 'zap' : t.icon === 'ao' ? 'sliders' : 'settings') + '
'
+ '
' + count + '
'
+ '
' + I18n.t(t.key) + '
'
+ '
' + I18n.t(t.descKey) + '
'
+ '
';
}).join('');
c.innerHTML = '' + cards + '
'
+ ''
+ ''
+ '
'
+ ''
+ ''
+ ''
+ ''
+ '
'
+ ''
+ ''
+ '
'
+ I18n.t('dash.url') + ': ws://' + location.hostname + ':8080/ws
'
+ I18n.t('dash.status') + ': ' + I18n.t('status.disconnected') + '
'
+ '
';
WsClient.onStatus(function(s) {
var el = document.getElementById('dash-status');
if (el)
{
el.textContent = I18n.t('status.' + s) || s;
el.style.color = s === 'connected' ? 'var(--online)' : s === 'connecting' ? 'var(--warning)' : 'var(--offline)';
}
});
});
var DashActions = {
exportAll: function() {
var types = ['out', 'in', 'yk', 'ao', 'param'];
var xml = '\n\n';
var hasData = false;
types.forEach(function(st) {
var data = SignalStore.get(st);
xml += ' \n';
if (data.length > 0) { hasData = true; data.forEach(function(s, i) { xml += ' \n'; }); }
xml += ' \n';
});
xml += '';
if (!hasData) { toast(I18n.t('toast.no_export'), 'error'); return; }
var blob = new Blob([xml], { type: 'application/xml' });
var a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'rtu_signals_' + Date.now() + '.xml';
a.click();
toast(I18n.t('toast.xml_exported'), 'success');
},
importAll: function() {
var input = document.createElement('input');
input.type = 'file';
input.accept = '.xml';
input.onchange = function(e) {
var file = e.target.files[0];
if (!file) return;
var reader = new FileReader();
reader.onload = function(ev) {
var parser = new DOMParser();
var doc = parser.parseFromString(ev.target.result, 'text/xml');
var err = doc.querySelector('parsererror');
if (err) { toast(I18n.t('toast.xml_parse_error') + ': ' + err.textContent, 'error'); return; }
var nodes = doc.querySelectorAll('signals');
if (nodes.length === 0) { toast(I18n.t('toast.xml_no_signals'), 'error'); return; }
var count = 0;
nodes.forEach(function(el) {
var type = el.getAttribute('type');
if (['out', 'in', 'yk', 'ao', 'param'].indexOf(type) === -1) return;
el.querySelectorAll('signal').forEach(function(sig) {
var saddr = sig.getAttribute('saddr');
if (!saddr || !saddr.trim()) return;
WsClient.send({ saddr: saddr.trim(), signal_type: type, curd: 'add', setting_zone: '0', signal_data: '' });
count++;
});
});
toast(I18n.t('toast.xml_importing') + ' (' + count + ')', 'success');
};
reader.readAsText(file);
};
input.click();
}
};