<新增> 1、前端对应增加命令终端与数据监控,命令终端支持自定义命令
This commit is contained in:
parent
6ef960525c
commit
742d9b36a0
|
|
@ -129,7 +129,9 @@ uint8_t dc_get_data_type_len(uint8_t data_type);
|
|||
|
||||
void dc_set_signal_val_from_str(void *p_data, uint8_t data_type, const std::string &str);
|
||||
|
||||
uint32_t dc_get_signal_count(const char *type);
|
||||
|
||||
int dc_get_signal_info_by_id(const char *type, uint32_t id, std::string &saddr, std::string &desc, std::string &data_type, uint8_t &ctrl_type, std::vector<std::string> &link_saddrs);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2242,6 +2242,41 @@ LOCAL void dc_show_signals(stru_signal_map &dc_signal_map)
|
|||
cout << endl;
|
||||
}
|
||||
|
||||
uint32_t dc_get_signal_count(const char *type)
|
||||
{
|
||||
if(nullptr == type) return 0;
|
||||
if(0 == strcmp(type, "out")) return g_datacenter.signal_out.signal_id;
|
||||
if(0 == strcmp(type, "in")) return g_datacenter.signal_in.signal_id;
|
||||
if(0 == strcmp(type, "yk")) return g_datacenter.signal_yk.signal_id;
|
||||
if(0 == strcmp(type, "ao")) return g_datacenter.signal_ao.signal_id;
|
||||
if(0 == strcmp(type, "param")) return g_datacenter.signal_param.signal_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dc_get_signal_info_by_id(const char *type, uint32_t id, std::string &saddr, std::string &desc, std::string &data_type, uint8_t &ctrl_type, std::vector<std::string> &link_saddrs)
|
||||
{
|
||||
if(nullptr == type) return -1;
|
||||
|
||||
stru_signal *p_signal = nullptr;
|
||||
if(0 == strcmp(type, "out")) p_signal = dc_find_signal_by_id(id, g_datacenter.signal_out);
|
||||
if(0 == strcmp(type, "in")) p_signal = dc_find_signal_by_id(id, g_datacenter.signal_in);
|
||||
if(0 == strcmp(type, "yk")) p_signal = dc_find_signal_by_id(id, g_datacenter.signal_yk);
|
||||
if(0 == strcmp(type, "ao")) p_signal = dc_find_signal_by_id(id, g_datacenter.signal_ao);
|
||||
if(0 == strcmp(type, "param")) p_signal = dc_find_signal_by_id(id, g_datacenter.signal_param);
|
||||
if(nullptr == p_signal)
|
||||
{
|
||||
MY_LOG_E("signal id %d not found", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
saddr = p_signal->saddr;
|
||||
desc = p_signal->desc;
|
||||
data_type = dc_get_data_type_str_by_id(p_signal->data_type);
|
||||
ctrl_type = p_signal->ctrl_type;
|
||||
link_saddrs = p_signal->link_saddrs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL void dc_show_out_signals()
|
||||
{
|
||||
using namespace std;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -569,6 +569,53 @@ LOCAL void ws_send_large_text(unsigned long conn_id, const char *type, const std
|
|||
}
|
||||
}
|
||||
|
||||
LOCAL std::string ws_build_dc_data_json(const std::vector<const char*> &types)
|
||||
{
|
||||
cJSON *resp = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(resp, "type", "dc_data");
|
||||
for(size_t si = 0; si < types.size(); si++)
|
||||
{
|
||||
cJSON *arr = cJSON_CreateArray();
|
||||
uint32_t count = dc_get_signal_count(types[si]);
|
||||
for(uint32_t j = 0; j < count; j++)
|
||||
{
|
||||
uint32_t id;
|
||||
uint8_t ctrl_type;
|
||||
std::string saddr, desc, data_type;
|
||||
std::vector<std::string> link_saddrs;
|
||||
if(0 != dc_get_signal_info_by_id(types[si], j, saddr, desc, data_type, ctrl_type, link_saddrs))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cJSON *item = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(item, "id", j);
|
||||
cJSON_AddStringToObject(item, "saddr", saddr.c_str());
|
||||
cJSON_AddStringToObject(item, "desc", desc.c_str());
|
||||
cJSON_AddStringToObject(item, "type", data_type.c_str());
|
||||
|
||||
cJSON_AddNumberToObject(item, "ctrl_type", ctrl_type);
|
||||
std::string link_str;
|
||||
for(size_t l = 0; l < link_saddrs.size(); l++)
|
||||
{
|
||||
if(l > 0) link_str += ", ";
|
||||
link_str += link_saddrs[l];
|
||||
}
|
||||
cJSON_AddStringToObject(item, "link_saddrs", link_str.c_str());
|
||||
|
||||
cJSON_AddItemToArray(arr, item);
|
||||
}
|
||||
cJSON_AddItemToObject(resp, types[si], arr);
|
||||
}
|
||||
char *p_tx = cJSON_Print(resp);
|
||||
std::string result;
|
||||
if(p_tx)
|
||||
{
|
||||
result = p_tx;
|
||||
free(p_tx);
|
||||
}
|
||||
cJSON_Delete(resp);
|
||||
return result;
|
||||
}
|
||||
|
||||
LOCAL std::string ws_cmd_exec(const char *cmd_line)
|
||||
{
|
||||
|
|
@ -680,9 +727,57 @@ void ws_recv(struct mg_connection *c, const char* p_rx, uint16_t rx_len)
|
|||
cJSON *data = cJSON_GetObjectItem(root, "data");
|
||||
if(data && cJSON_IsString(data) && data->valuestring)
|
||||
{
|
||||
bool is_dc = (0 == strncmp(data->valuestring, "datacenter", 10));
|
||||
std::string result = ws_cmd_exec(data->valuestring);
|
||||
ws_send_binary(c->id, result.data(), result.size());
|
||||
if(is_dc)
|
||||
{
|
||||
std::vector<const char*> dc_types;
|
||||
const char *sub = data->valuestring + 10;
|
||||
while(*sub == ' ' || *sub == '\t') sub++;
|
||||
if(0 == strcmp(sub, "all") || 0 == strncmp(sub, "all ", 4))
|
||||
{
|
||||
dc_types = {"out", "in", "yk", "ao", "param"};
|
||||
}
|
||||
else if(0 == strcmp(sub, "out") || 0 == strncmp(sub, "out ", 4)) dc_types = {"out"};
|
||||
else if(0 == strcmp(sub, "in") || 0 == strncmp(sub, "in ", 3)) dc_types = {"in"};
|
||||
else if(0 == strcmp(sub, "yk") || 0 == strncmp(sub, "yk ", 3)) dc_types = {"yk"};
|
||||
else if(0 == strcmp(sub, "ao") || 0 == strncmp(sub, "ao ", 3)) dc_types = {"ao"};
|
||||
else if(0 == strcmp(sub, "param") || 0 == strncmp(sub, "param ", 6)) dc_types = {"param"};
|
||||
else dc_types = {"out", "in", "yk", "ao", "param"};
|
||||
|
||||
std::string dc_json = ws_build_dc_data_json(dc_types);
|
||||
if(!dc_json.empty())
|
||||
{
|
||||
ws_send_binary(c->id, dc_json.data(), dc_json.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
if(0 == strcmp(type->valuestring, "get_cmds"))
|
||||
{
|
||||
unsigned int count = 0;
|
||||
stru_cmd *cmds = cmd_manager_get_commands(&count);
|
||||
cJSON *resp = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(resp, "type", "cmd_list");
|
||||
cJSON *arr = cJSON_CreateArray();
|
||||
for(unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
cJSON *item = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(item, "name", cmds[i].name);
|
||||
cJSON_AddStringToObject(item, "desc", cmds[i].desc);
|
||||
cJSON_AddItemToArray(arr, item);
|
||||
}
|
||||
cJSON_AddItemToObject(resp, "cmds", arr);
|
||||
char *p_tx = cJSON_Print(resp);
|
||||
if(p_tx)
|
||||
{
|
||||
ws_send_one(c->id, p_tx, strlen(p_tx));
|
||||
free(p_tx);
|
||||
}
|
||||
cJSON_Delete(resp);
|
||||
cJSON_Delete(root);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ body.login-page #main-content { margin-left: 0; display: flex; align-items: cent
|
|||
.dash-card.ao { border-top: 4px solid #4CAF50; }
|
||||
.dash-card.param { border-top: 4px solid #9C27B0; }
|
||||
.dash-card.monitor { border-top: 4px solid #607D8B; }
|
||||
.dash-card.terminal { border-top: 4px solid #00BCD4; }
|
||||
|
||||
/* === Page Header === */
|
||||
.page-header {
|
||||
|
|
@ -589,3 +590,87 @@ body.login-page #main-content { margin-left: 0; display: flex; align-items: cent
|
|||
.term-resp { color: #d4d4d4; }
|
||||
.term-err { color: #f44747; }
|
||||
.term-info { color: #6a9955; }
|
||||
|
||||
/* === 命令终端 — 命令列表 === */
|
||||
.terminal-cmd-list {
|
||||
padding: 8px 10px;
|
||||
background: #252526;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
max-height: 120px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.cmd-list-hint {
|
||||
color: #6a9955;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
.cmd-tag {
|
||||
display: inline-block;
|
||||
padding: 3px 10px;
|
||||
background: #3c3c3c;
|
||||
color: #d4d4d4;
|
||||
border-radius: 4px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.cmd-tag:hover {
|
||||
background: #4CAF50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* === 数据中心页面 === */
|
||||
.datacenter-toolbar {
|
||||
background: var(--card-bg);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
padding: 12px 20px;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.dc-tab-bar {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
.dc-tab {
|
||||
padding: 6px 16px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
color: var(--text-secondary);
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.dc-tab:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.dc-tab.active {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.dc-search {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
width: 200px;
|
||||
}
|
||||
.dc-search:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.dc-count {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ var App = (function() {
|
|||
{ hash: '#yk', label: '⚡ 遥控 (yk)' },
|
||||
{ hash: '#ao', label: '🔧 参数 (ao)' },
|
||||
{ hash: '#param', label: '⚙ 定值 (param)' },
|
||||
{ hash: '#datacenter', label: '📊 数据中心' },
|
||||
{ hash: '#monitor', label: '📋 数据监控' },
|
||||
{ hash: '#terminal', label: '💻 命令终端' }
|
||||
];
|
||||
|
|
@ -111,7 +112,7 @@ var App = (function() {
|
|||
}
|
||||
|
||||
// 页面进入后立即推送缓存数据(如有)
|
||||
var stMap = { '#out': 'out', '#in': 'in', '#yk': 'yk', '#ao': 'ao', '#param': 'param' };
|
||||
var stMap = { '#out': 'out', '#in': 'in', '#yk': 'yk', '#ao': 'ao', '#param': 'param', '#datacenter': 'dc_data', '#terminal': 'cmd_list' };
|
||||
var st = stMap[hash];
|
||||
if (st && page.onData && lastDataCache[st]) {
|
||||
page.onData(lastDataCache[st]);
|
||||
|
|
@ -138,8 +139,28 @@ var App = (function() {
|
|||
|
||||
/* ---- WS 下行数据分发 ---- */
|
||||
function onWsMessage(data, raw) {
|
||||
if (raw instanceof ArrayBuffer && currentPage && currentPage.onBinary) {
|
||||
if (raw instanceof ArrayBuffer) {
|
||||
var decoder = new TextDecoder('utf-8');
|
||||
var text = decoder.decode(raw);
|
||||
try {
|
||||
var parsed = JSON.parse(text);
|
||||
if (parsed && parsed.type === 'dc_data') {
|
||||
var cache = lastDataCache['dc_data'] || {};
|
||||
if (parsed.out) cache.out = parsed.out;
|
||||
if (parsed.in) cache.in = parsed.in;
|
||||
if (parsed.yk) cache.yk = parsed.yk;
|
||||
if (parsed.ao) cache.ao = parsed.ao;
|
||||
if (parsed.param) cache.param = parsed.param;
|
||||
lastDataCache['dc_data'] = cache;
|
||||
if (currentHash === '#datacenter' && currentPage && currentPage.onData) {
|
||||
currentPage.onData(parsed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch(e) {}
|
||||
if (currentPage && currentPage.onBinary) {
|
||||
currentPage.onBinary(raw);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -150,6 +171,22 @@ var App = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (data.type === 'cmd_list') {
|
||||
lastDataCache['cmd_list'] = data;
|
||||
if (currentHash === '#terminal' && currentPage && currentPage.onData) {
|
||||
currentPage.onData(data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.type === 'dc_data') {
|
||||
lastDataCache['dc_data'] = data;
|
||||
if (currentPage && currentPage.onData && currentHash === '#datacenter') {
|
||||
currentPage.onData(data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var signalTypes = ['out', 'in', 'yk', 'ao', 'param'];
|
||||
for (var i = 0; i < signalTypes.length; i++) {
|
||||
var st = signalTypes[i];
|
||||
|
|
@ -183,6 +220,7 @@ var App = (function() {
|
|||
registerPage('#yk', YkPage);
|
||||
registerPage('#ao', AoPage);
|
||||
registerPage('#param', ParamPage);
|
||||
registerPage('#datacenter', DatacenterPage);
|
||||
registerPage('#monitor', MonitorPage);
|
||||
registerPage('#terminal', TerminalPage);
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ var DashboardPage = {
|
|||
{ cls: 'yk', icon: '⚡', title: '遥控', desc: 'yk — 遥控分合闸控制', hash: '#yk' },
|
||||
{ cls: 'ao', icon: '🔧', title: '参数', desc: 'ao — 模拟输出参数设定', hash: '#ao' },
|
||||
{ cls: 'param', icon: '⚙', title: '定值', desc: 'param — 多定值区参数管理', hash: '#param' },
|
||||
{ cls: 'monitor', icon: '📋', title: '数据监控', desc: '实时查看 WebSocket 交互数据', hash: '#monitor' }
|
||||
{ cls: 'monitor', icon: '📋', title: '数据监控', desc: '实时查看 WebSocket 交互数据', hash: '#monitor' },
|
||||
{ cls: 'terminal', icon: '💻', title: '命令终端', desc: '实时命令行操作 RTU 系统', hash: '#terminal' }
|
||||
];
|
||||
|
||||
var html = '<div class="page-header"><h2>功能导航</h2><p>选择需要管理的信号类型进入对应功能页</p></div>';
|
||||
|
|
@ -692,6 +693,7 @@ var MonitorPage = (function() {
|
|||
var TerminalPage = (function() {
|
||||
var history = [];
|
||||
var historyIdx = 0;
|
||||
var cmdList = [];
|
||||
|
||||
function append(text, cls) {
|
||||
var el = document.getElementById('term-output');
|
||||
|
|
@ -703,6 +705,32 @@ var TerminalPage = (function() {
|
|||
el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
|
||||
function renderCmdList() {
|
||||
var el = document.getElementById('term-cmd-list');
|
||||
if (!el) return;
|
||||
if (cmdList.length === 0) {
|
||||
el.innerHTML = '<span class="cmd-list-hint">等待命令列表...</span>';
|
||||
return;
|
||||
}
|
||||
var html = '';
|
||||
for (var i = 0; i < cmdList.length; i++) {
|
||||
var cmd = cmdList[i];
|
||||
html += '<span class="cmd-tag" data-cmd="' + cmd.name + '" title="' + cmd.desc + '">' + cmd.name + '</span>';
|
||||
}
|
||||
el.innerHTML = html;
|
||||
|
||||
var tags = el.querySelectorAll('.cmd-tag');
|
||||
for (var k = 0; k < tags.length; k++) {
|
||||
tags[k].onclick = function() {
|
||||
var input = document.getElementById('term-input');
|
||||
if (input) {
|
||||
input.value = this.getAttribute('data-cmd') + ' ';
|
||||
input.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
render: function(container) {
|
||||
history = [];
|
||||
|
|
@ -710,6 +738,7 @@ var TerminalPage = (function() {
|
|||
container.innerHTML = ''
|
||||
+ '<div class="page-header"><h2>命令终端</h2><p>输入 RTU 命令,Enter 发送,↑↓ 历史记录</p></div>'
|
||||
+ '<div class="terminal-wrap">'
|
||||
+ '<div class="terminal-cmd-list" id="term-cmd-list"></div>'
|
||||
+ '<div class="terminal-output" id="term-output"></div>'
|
||||
+ '<div class="terminal-input-line">'
|
||||
+ '<span class="terminal-prompt">cmd > </span>'
|
||||
|
|
@ -750,11 +779,22 @@ var TerminalPage = (function() {
|
|||
}
|
||||
};
|
||||
|
||||
renderCmdList();
|
||||
append('输入 help 查看所有命令', 'term-info');
|
||||
},
|
||||
|
||||
onData: function(data) {
|
||||
if (data) append(data, 'term-resp');
|
||||
if (data && data.cmds) {
|
||||
cmdList = data.cmds;
|
||||
renderCmdList();
|
||||
return;
|
||||
}
|
||||
if (data && typeof data === 'string') {
|
||||
append(data, 'term-resp');
|
||||
} else if (data && data.type === 'cmd_list') {
|
||||
cmdList = data.cmds;
|
||||
renderCmdList();
|
||||
}
|
||||
},
|
||||
|
||||
onBinary: function(ab) {
|
||||
|
|
@ -766,9 +806,150 @@ var TerminalPage = (function() {
|
|||
onEnter: function() {
|
||||
var input = document.getElementById('term-input');
|
||||
if (input) setTimeout(function() { input.focus(); }, 100);
|
||||
renderCmdList();
|
||||
if (cmdList.length === 0) {
|
||||
WsClient.send({type:'get_cmds'});
|
||||
}
|
||||
},
|
||||
|
||||
onLeave: function() {
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
/* ========================================================================
|
||||
* 数据中心页面
|
||||
* ======================================================================== */
|
||||
var DatacenterPage = (function() {
|
||||
var allData = {};
|
||||
var activeTab = 'out';
|
||||
var searchText = '';
|
||||
|
||||
var COLUMNS = ['id', 'saddr', 'desc', '数据类型', 'ctrl_type', 'link_saddrs'];
|
||||
|
||||
function renderTable() {
|
||||
var data = allData[activeTab] || [];
|
||||
var tbody = document.getElementById('dc-tbody');
|
||||
if (!tbody) return;
|
||||
|
||||
if (data.length === 0) {
|
||||
tbody.innerHTML = '<tr class="empty-row"><td colspan="6">暂无数据</td></tr>';
|
||||
document.getElementById('dc-count').textContent = '0';
|
||||
return;
|
||||
}
|
||||
|
||||
var rows = data;
|
||||
if (searchText) {
|
||||
var st = searchText.toLowerCase();
|
||||
rows = data.filter(function(item) {
|
||||
return (item.saddr && item.saddr.toLowerCase().indexOf(st) !== -1)
|
||||
|| (item.desc && item.desc.toLowerCase().indexOf(st) !== -1);
|
||||
});
|
||||
}
|
||||
document.getElementById('dc-count').textContent = rows.length + ' / ' + data.length;
|
||||
|
||||
if (rows.length === 0) {
|
||||
tbody.innerHTML = '<tr class="empty-row"><td colspan="6">无匹配结果</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var item = rows[i];
|
||||
html += '<tr>'
|
||||
+ '<td>' + fmtVal(item.id) + '</td>'
|
||||
+ '<td>' + fmtVal(item.saddr) + '</td>'
|
||||
+ '<td>' + fmtVal(item.desc) + '</td>'
|
||||
+ '<td>' + fmtVal(item.type) + '</td>'
|
||||
+ '<td>' + fmtVal(CTRL_TYPE_MAP[item.ctrl_type] || item.ctrl_type) + '</td>'
|
||||
+ '<td style="max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="' + fmtVal(item.link_saddrs) + '">' + fmtVal(item.link_saddrs) + '</td>'
|
||||
+ '</tr>';
|
||||
}
|
||||
tbody.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderHeaders() {
|
||||
var thead = document.getElementById('dc-thead');
|
||||
if (!thead) return;
|
||||
var html = '';
|
||||
for (var i = 0; i < COLUMNS.length; i++) {
|
||||
html += '<th>' + COLUMNS[i] + '</th>';
|
||||
}
|
||||
thead.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderTabs() {
|
||||
var types = ['out', 'in', 'yk', 'ao', 'param'];
|
||||
var labels = { out: '注册 (out)', in: '链接注册 (in)', yk: '遥控 (yk)', ao: '参数 (ao)', param: '定值 (param)' };
|
||||
var el = document.getElementById('dc-tab-bar');
|
||||
if (!el) return;
|
||||
var html = '';
|
||||
for (var i = 0; i < types.length; i++) {
|
||||
var t = types[i];
|
||||
var cls = t === activeTab ? 'dc-tab active' : 'dc-tab';
|
||||
html += '<span class="' + cls + '" data-tab="' + t + '">' + labels[t] + '</span>';
|
||||
}
|
||||
el.innerHTML = html;
|
||||
var tabs = el.querySelectorAll('.dc-tab');
|
||||
for (var k = 0; k < tabs.length; k++) {
|
||||
tabs[k].onclick = function() {
|
||||
activeTab = this.getAttribute('data-tab');
|
||||
searchText = '';
|
||||
document.getElementById('dc-search').value = '';
|
||||
renderTabs();
|
||||
renderHeaders();
|
||||
renderTable();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
render: function(container) {
|
||||
allData = {};
|
||||
activeTab = 'out';
|
||||
searchText = '';
|
||||
container.innerHTML = ''
|
||||
+ '<div class="page-header"><h2>数据中心</h2><p>查看所有信号数据,按类型分表,支持搜索</p></div>'
|
||||
+ '<div class="datacenter-toolbar">'
|
||||
+ '<div class="dc-tab-bar" id="dc-tab-bar"></div>'
|
||||
+ '<input type="text" class="dc-search" id="dc-search" placeholder="搜索 saddr 或 desc...">'
|
||||
+ '<span class="dc-count" id="dc-count">0</span>'
|
||||
+ '</div>'
|
||||
+ '<div class="table-card"><div class="table-wrapper">'
|
||||
+ '<table class="signal-table"><thead><tr id="dc-thead"></tr></thead><tbody id="dc-tbody"></tbody></table>'
|
||||
+ '</div></div>';
|
||||
|
||||
renderTabs();
|
||||
renderHeaders();
|
||||
renderTable();
|
||||
|
||||
var searchInput = document.getElementById('dc-search');
|
||||
if (searchInput) {
|
||||
searchInput.oninput = function() {
|
||||
searchText = this.value;
|
||||
renderTable();
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
onEnter: function() {
|
||||
},
|
||||
|
||||
onLeave: function() {
|
||||
allData = {};
|
||||
},
|
||||
|
||||
onData: function(data) {
|
||||
if (!data || typeof data !== 'object') return;
|
||||
if (data.out) allData.out = data.out;
|
||||
if (data.in) allData.in = data.in;
|
||||
if (data.yk) allData.yk = data.yk;
|
||||
if (data.ao) allData.ao = data.ao;
|
||||
if (data.param) allData.param = data.param;
|
||||
if (data.out || data.in || data.yk || data.ao || data.param) {
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ var WsClient = (function() {
|
|||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
ws.send(JSON.stringify({ type: 'get_cmds' }));
|
||||
};
|
||||
|
||||
ws.onclose = function() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue