op-packages/luci-app-iperf3-server/luasrc/view/iperf3-server/iperf3-server_status.htm
github-actions[bot] 32600acc60 🌴 Sync 2026-03-05 23:51:42
2026-03-05 23:51:42 +08:00

182 lines
5.7 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<fieldset class="cbi-section">
<legend><%:Status%></legend>
<div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
<div id="iperf3_status">-</div>
<button class="btn cbi-button cbi-button-apply" id="btn_start" type="button"><%:Start%></button>
<button class="btn cbi-button cbi-button-reset" id="btn_stop" type="button"><%:Stop%></button>
<button class="btn cbi-button cbi-button-action" id="btn_restart" type="button"><%:Restart%></button>
<span id="iperf3_busy" style="display:none; color:#999;">...</span>
</div>
<div id="iperf3_list" style="margin-top:8px;"></div>
</fieldset>
<script type="text/javascript">
//<![CDATA[
(function () {
var token = '<%=token%>';
function esc(s) {
if (s === null || s === undefined) return '';
return String(s).replace(/[&<>"']/g, function (c) {
return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]);
});
}
function setBusy(b) {
document.getElementById('iperf3_busy').style.display = b ? '' : 'none';
document.getElementById('btn_start').disabled = b;
document.getElementById('btn_stop').disabled = b;
document.getElementById('btn_restart').disabled = b;
}
function badge(text, color) {
return '<span style="color:' + color + '">' + text + '</span>';
}
function stateBadge(it) {
// 新字段优先it.state旧字段兼容it.running
var st = it.state;
if (!st) {
if (it.enable === false || it.enable === "0") st = "disabled";
else st = it.running ? "running" : "stopped";
}
if (st === "running") return badge('<%:Running%>', 'green');
if (st === "delay") return badge('<%:Delay%>', '#d67f00');
if (st === "conflict") return badge('<%:Conflict%>', 'red');
if (st === "disabled") return badge('<%:Disabled%>', '#999');
return badge('<%:Stopped%>', '#999');
}
function overallBadge(data) {
// controller 返回 data.running=true 表示至少一个 running
// 如果没有 running但存在 delay/conflict也给更准确的总体状态
if (data && data.running) {
return badge('<%:Running%>', 'green');
}
var hasDelay = false, hasConflict = false;
if (data && data.servers && data.servers.length) {
for (var i = 0; i < data.servers.length; i++) {
var st = data.servers[i].state;
if (st === "delay") hasDelay = true;
else if (st === "conflict") hasConflict = true;
}
}
if (hasConflict) return badge('<%:Conflict%>', 'red');
if (hasDelay) return badge('<%:Delay%>', '#d67f00');
return badge('<%:Not running%>', 'red');
}
function translateDetail(detail) {
// detail 来自 controller 的英文字符串,这里做映射为可翻译字符串
// 未命中映射时,直接原样显示
var map = {
"disabled in config": "<%:disabled in config%>",
"delay pending (sleep)": "<%:delay pending (sleep)%>",
"listening and iperf3 process found": "<%:listening and iperf3 process found%>",
"port is listening but not iperf3 (occupied)": "<%:port is listening but not iperf3 (occupied)%>",
"not listening": "<%:not listening%>"
};
return map[detail] || detail || "";
}
function renderStatus(data) {
var s = document.getElementById('iperf3_status');
s.innerHTML = overallBadge(data);
var list = document.getElementById('iperf3_list');
var html = '';
if (data && data.servers && data.servers.length) {
html += '<ul>';
for (var i = 0; i < data.servers.length; i++) {
var it = data.servers[i];
var port = esc(it.port);
var en = (it.enable !== false) && (it.enable !== "0");
// 旧字段 pid 兼容
var pidInfo = '';
if (it.pid) {
pidInfo = ' <span style="color:#999"><%:PID%> ' + esc(it.pid) + '</span>';
}
// 监听信息(新字段 listen
var listenInfo = '';
if (typeof it.listen === "boolean") {
listenInfo = it.listen
? ' <span style="color:#999">[<%:LISTEN%>]</span>'
: ' <span style="color:#999">[<%:NO LISTEN%>]</span>';
}
// detail来自 controller
var dt = translateDetail(it.detail);
var detail = dt ? (' <span style="color:#999">(' + esc(dt) + ')</span>') : '';
html += '<li>'
+ '<%:Port%> ' + port + ' : '
+ stateBadge(it)
+ pidInfo
+ listenInfo
+ detail
+ (en ? '' : ' <span style="color:#999">(<%:disabled%>)</span>')
+ '</li>';
}
html += '</ul>';
// 状态说明(简短)
html += '<div style="margin-top:6px; color:#999;">'
+ '<span><%:Delay%></span>: <%:starting after configured delay%> &nbsp; '
+ '<span><%:Conflict%></span>: <%:port is occupied%>'
+ '</div>';
}
list.innerHTML = html;
}
function refresh() {
XHR.get('<%=luci.dispatcher.build_url("admin/services/iperf3-server/status")%>', null,
function (x, data) { renderStatus(data || {}); }
);
}
function doAction(url, confirmText) {
if (confirmText && !window.confirm(confirmText)) return;
setBusy(true);
XHR.post(url, { token: token }, function (x, data) {
setBusy(false);
refresh();
});
}
document.getElementById('btn_start').addEventListener('click', function () {
doAction('<%=luci.dispatcher.build_url("admin/services/iperf3-server/start")%>', '<%:Start iPerf3 servers?%>');
});
document.getElementById('btn_stop').addEventListener('click', function () {
doAction('<%=luci.dispatcher.build_url("admin/services/iperf3-server/stop")%>', '<%:Stop iPerf3 servers?%>');
});
document.getElementById('btn_restart').addEventListener('click', function () {
doAction('<%=luci.dispatcher.build_url("admin/services/iperf3-server/restart")%>', '<%:Restart iPerf3 servers?%>');
});
// 轮询刷新
XHR.poll(2, '<%=luci.dispatcher.build_url("admin/services/iperf3-server/status")%>', null,
function (x, data) { renderStatus(data || {}); }
);
// 首次刷新
refresh();
})();
//]]>
</script>