RTU_ALL_AI/config/web/js/pages/terminal.js

156 lines
4.2 KiB
JavaScript

/**
* @file terminal.js
* @brief 命令终端页面 — 按钮面板 + 输入框
* @details 连接后自动获取命令列表,按模块分组生成按钮。
* 点击按钮将命令名填充到输入框,用户可继续输入子命令参数。
* 回车执行,输出显示在下方窗口。
*/
var TermCommands = [];
Router.register('#terminal', function(c) {
c.innerHTML =
'<div class="card">' +
' <div class="card-header"><span>' + I18n.t('term.title') + '</span></div>' +
' <div class="terminal-wrap">' +
' <div class="cmd-panels" id="cmd-panels">' +
' <div style="padding:16px;color:#888;">' + (I18n.t('term.loading') || '正在加载命令列表...') + '</div>' +
' </div>' +
' <div class="terminal-output" id="term-out">' + I18n.t('term.welcome') + '</div>' +
' <div class="terminal-input-row">' +
' <span class="terminal-prompt">RTU&gt;</span>' +
' <input class="terminal-input" id="term-input" placeholder="点击上方按钮填充命令,或直接输入..." ' +
' autocomplete="off" onkeydown="handleTermKey(event)">' +
' </div>' +
' </div>' +
'</div>';
if (TermCommands.length > 0)
{
renderCmdPanels(TermCommands);
}
else
{
WsClient.send({ type: 'get_cmds' });
}
});
/* ---- 命令分组 ---- */
function groupCommands(cmds)
{
var groups = {};
for (var i = 0; i < cmds.length; i++)
{
var mod = 'other';
var name = cmds[i].name;
if (name.indexOf('datacenter') === 0) mod = 'datacenter';
else if (name.indexOf('iec') === 0) mod = 'iec';
else if (name.indexOf('plc') === 0) mod = 'plc';
else if (name.indexOf('self_ptl') === 0) mod = 'self_ptl';
else if (name.indexOf('modbus_m') === 0) mod = 'modbus_m';
else if (name === 'help' || name === 'version') mod = 'system';
if (!groups[mod]) groups[mod] = [];
groups[mod].push(cmds[i]);
}
return groups;
}
var groupMeta = {
'datacenter': { icon: '&#x1F4CA;', label: '数据中心' },
'iec': { icon: '&#x26A1;', label: 'IEC-104' },
'plc': { icon: '&#x1F39B;', label: 'PLC 逻辑' },
'self_ptl': { icon: '&#x1F517;', label: '自协议' },
'modbus_m': { icon: '&#x1F4E1;', label: 'Modbus 主站' },
'system': { icon: '&#x2699;', label: '系统' },
'other': { icon: '&#x1F4E6;', label: '其他' },
};
/* ---- 渲染命令面板 ---- */
function renderCmdPanels(cmds)
{
TermCommands = cmds;
var panels = document.getElementById('cmd-panels');
if (!panels) return;
var groups = groupCommands(cmds);
var html = '';
for (var mod in groups)
{
var meta = groupMeta[mod] || { icon: '', label: mod };
html += '<div class="cmd-group">';
html += '<div class="cmd-group-title">' + meta.icon + ' ' + meta.label + '</div>';
html += '<div class="cmd-group-btns">';
for (var j = 0; j < groups[mod].length; j++)
{
var cmd = groups[mod][j];
html += '<button class="cmd-btn" title="' + esc(cmd.desc || '') + '" ' +
'onclick="fillTermCmd(\'' + esc(cmd.name) + '\')">' +
'<span class="cmd-btn-name">' + esc(cmd.name) + '</span>' +
'<span class="cmd-btn-desc">' + esc(cmd.desc || '') + '</span>' +
'</button>';
}
html += '</div></div>';
}
panels.innerHTML = html;
}
/* ---- 填充命令到输入框 ---- */
function fillTermCmd(cmd)
{
var input = document.getElementById('term-input');
if (!input) return;
input.value = cmd + ' ';
input.focus();
}
/* ---- 回车执行 ---- */
function handleTermKey(e)
{
if (e.key !== 'Enter') return;
var input = document.getElementById('term-input');
var out = document.getElementById('term-out');
if (!input || !out) return;
var cmd = input.value.trim();
if (!cmd) return;
/* 本地清屏 */
if (cmd === 'clear')
{
out.textContent = '';
input.value = '';
return;
}
/* 显示已执行命令 */
out.textContent += '\n> ' + cmd + '\n';
out.scrollTop = out.scrollHeight;
/* 发送到后端 */
WsClient.send({ type: 'cmd', data: cmd });
input.value = '';
}
/* ---- WebSocket 二进制消息追加到输出窗口 ---- */
function termOnBinary(text)
{
var out = document.getElementById('term-out');
if (!out) return;
out.textContent += text;
out.scrollTop = out.scrollHeight;
}