183 lines
6.4 KiB
JavaScript
183 lines
6.4 KiB
JavaScript
/**
|
|
* @file datacenter.js
|
|
* @brief RTU_ALL_AI 数据中心 — 结构化 JSON 数据 + 搜索过滤 + 批量添加
|
|
*/
|
|
Router.register('#datacenter', function(c) { DcPage.render(c); });
|
|
|
|
var DcPage = (function() {
|
|
var allData = {};
|
|
var activeTab = 'out';
|
|
var searchText = '';
|
|
var selectedSet = {};
|
|
var MAX_SIGNALS = 500;
|
|
|
|
function getVisibleData() {
|
|
var data = allData[activeTab] || [];
|
|
if (!searchText) return data;
|
|
var st = searchText.toLowerCase();
|
|
return data.filter(function(x) {
|
|
return (x.saddr && x.saddr.toLowerCase().indexOf(st) !== -1)
|
|
|| (x.desc && x.desc.toLowerCase().indexOf(st) !== -1);
|
|
});
|
|
}
|
|
|
|
function getSelectedCount() {
|
|
var c = 0;
|
|
for (var k in selectedSet) { if (selectedSet.hasOwnProperty(k)) c++; }
|
|
return c;
|
|
}
|
|
|
|
function updateSelBar() {
|
|
var b = document.getElementById('dc-sel-bar');
|
|
var l = document.getElementById('dc-sel-label');
|
|
if (!b || !l) return;
|
|
var n = getSelectedCount();
|
|
b.style.display = n > 0 ? 'flex' : 'none';
|
|
l.textContent = I18n.t('dc.sel_count').replace('{n}', n);
|
|
}
|
|
|
|
function renderTabs() {
|
|
var types = ['out', 'yk', 'ao', 'param'];
|
|
var labels = { out: '注册 (out)', yk: '遥控 (yk)', ao: '参数 (ao)', param: '定值 (param)' };
|
|
var el = document.getElementById('dc-tab-bar');
|
|
if (!el) return;
|
|
var h = '';
|
|
types.forEach(function(t) {
|
|
h += '<button class="dc-tab' + (t === activeTab ? ' active' : '')
|
|
+ '" onclick="DcPage.switchTab(\'' + t + '\')">' + labels[t] + '</button>';
|
|
});
|
|
el.innerHTML = h;
|
|
}
|
|
|
|
function doAddSelected() {
|
|
var visible = getVisibleData(), items = [];
|
|
visible.forEach(function(x) { if (selectedSet[x.saddr]) items.push(x); });
|
|
if (items.length === 0) { toast(I18n.t('dc.no_selected'), 'error'); return; }
|
|
var existing = SignalStore.get(activeTab);
|
|
if (existing.length + items.length > MAX_SIGNALS) {
|
|
toast('MAX ' + MAX_SIGNALS + ' exceeded', 'error'); return;
|
|
}
|
|
if (!confirm(I18n.t('dc.confirm_add').replace('{n}', items.length) + ' -> ' + activeTab.toUpperCase())) return;
|
|
var ok = 0;
|
|
items.forEach(function(x) {
|
|
WsClient.send({ saddr: x.saddr, signal_type: activeTab, curd: 'add', setting_zone: '0', signal_data: '' });
|
|
ok++;
|
|
});
|
|
toast('Added ' + ok + ' to ' + activeTab.toUpperCase(), 'success');
|
|
selectedSet = {};
|
|
DcPage._renderTable();
|
|
updateSelBar();
|
|
}
|
|
|
|
function renderTable() {
|
|
var data = getVisibleData();
|
|
var tbody = document.getElementById('dc-tbody');
|
|
var cntEl = document.getElementById('dc-count');
|
|
if (!tbody) return;
|
|
if (cntEl) cntEl.textContent = data.length + ' / ' + (allData[activeTab] || []).length;
|
|
|
|
var allChk = data.length > 0 && data.every(function(x) { return !!selectedSet[x.saddr]; });
|
|
var thEl = document.getElementById('dc-thead');
|
|
if (thEl) thEl.innerHTML = '<th style="width:36px"><input type="checkbox" id="dc-cb-all"'
|
|
+ (allChk ? ' checked' : '') + ' onchange="DcPage._toggleAll()"></th>'
|
|
+ '<th>id</th><th>saddr</th><th>desc</th><th>type</th>';
|
|
|
|
if (data.length === 0) {
|
|
tbody.innerHTML = '<tr class="empty-row"><td colspan="5">' + I18n.t('dc.no_signal') + '</td></tr>';
|
|
return;
|
|
}
|
|
|
|
var h = '';
|
|
data.forEach(function(x) {
|
|
var chk = !!selectedSet[x.saddr];
|
|
h += '<tr><td><input type="checkbox"' + (chk ? ' checked' : '')
|
|
+ ' onchange="DcPage._toggleRow(\'' + esc(x.saddr) + '\')"></td>'
|
|
+ '<td class="cell-mono">' + fmtVal(x.id) + '</td>'
|
|
+ '<td class="cell-mono">' + esc(x.saddr) + '</td>'
|
|
+ '<td>' + esc(x.desc || '') + '</td>'
|
|
+ '<td class="cell-mono">' + esc(x.type || '') + '</td>'
|
|
+ '</tr>';
|
|
});
|
|
tbody.innerHTML = h;
|
|
}
|
|
|
|
/**
|
|
* @brief 从后端 dc_data JSON 加载信号列表 (替代文本解析)
|
|
*/
|
|
function loadFromDcData(dc) {
|
|
allData = {};
|
|
['out', 'yk', 'ao', 'param'].forEach(function(t) {
|
|
if (!dc[t] || !Array.isArray(dc[t])) return;
|
|
allData[t] = dc[t].map(function(s) {
|
|
return {
|
|
id: s.id, saddr: s.saddr || '', desc: s.desc || '',
|
|
type: s.type || '', ctrl_type: s.ctrl_type || 0,
|
|
link_saddrs: s.link_saddrs || ''
|
|
};
|
|
});
|
|
});
|
|
DcPage._renderTable();
|
|
toast(I18n.t('dc.refreshed'), 'success');
|
|
}
|
|
|
|
function refreshAll() {
|
|
allData = { out: [], yk: [], ao: [], param: [] };
|
|
toast(I18n.t('dc.querying'), 'info');
|
|
/* 发送 datacenter all 命令,后端会在响应中附加 dc_data JSON */
|
|
WsClient.send({ type: 'cmd', data: 'datacenter all' });
|
|
}
|
|
|
|
return {
|
|
render: function(container) {
|
|
allData = {}; activeTab = 'out'; searchText = ''; selectedSet = {};
|
|
container.innerHTML = '<div class="card">'
|
|
+ '<div class="card-header"><span>' + I18n.t('dc.title') + '</span>'
|
|
+ '<div class="btn-group">'
|
|
+ '<button class="btn btn-primary btn-sm" onclick="DcPage.refreshAll()">' + I18n.t('dc.refresh') + '</button>'
|
|
+ '</div></div>'
|
|
+ '<div class="dc-toolbar">'
|
|
+ '<div class="dc-tab-bar" id="dc-tab-bar"></div>'
|
|
+ '<input class="form-input dc-search" id="dc-search" placeholder="' + I18n.t('dc.search_placeholder') + '" oninput="DcPage._search()">'
|
|
+ '<span class="dc-count" id="dc-count">0</span>'
|
|
+ '</div>'
|
|
+ '<div class="dc-sel-bar" id="dc-sel-bar" style="display:none">'
|
|
+ '<span class="dc-sel-label" id="dc-sel-label"></span>'
|
|
+ '<button class="btn btn-primary btn-sm" onclick="DcPage._addSelected()">' + I18n.t('dc.add_to_config') + '</button>'
|
|
+ '</div>'
|
|
+ '<div class="table-wrap"><table class="signal-table dc-table">'
|
|
+ '<thead id="dc-thead"></thead>'
|
|
+ '<tbody id="dc-tbody"></tbody>'
|
|
+ '</table></div></div>';
|
|
renderTabs();
|
|
renderTable();
|
|
},
|
|
onDcData: loadFromDcData,
|
|
refreshAll: refreshAll,
|
|
switchTab: function(t) {
|
|
activeTab = t; searchText = ''; selectedSet = {};
|
|
var inp = document.getElementById('dc-search'); if (inp) inp.value = '';
|
|
renderTabs(); DcPage._renderTable(); updateSelBar();
|
|
},
|
|
_renderTable: renderTable,
|
|
_search: function() {
|
|
var inp = document.getElementById('dc-search');
|
|
searchText = inp ? inp.value : '';
|
|
renderTable();
|
|
},
|
|
_toggleAll: function() {
|
|
var cb = document.getElementById('dc-cb-all');
|
|
var allChk = cb ? cb.checked : false;
|
|
var v = getVisibleData();
|
|
if (allChk) { v.forEach(function(x) { selectedSet[x.saddr] = true; }); }
|
|
else { v.forEach(function(x) { delete selectedSet[x.saddr]; }); }
|
|
renderTable(); updateSelBar();
|
|
},
|
|
_toggleRow: function(saddr) {
|
|
if (selectedSet[saddr]) { delete selectedSet[saddr]; }
|
|
else { selectedSet[saddr] = true; }
|
|
renderTable(); updateSelBar();
|
|
},
|
|
_addSelected: doAddSelected
|
|
};
|
|
})();
|