From 73bc623fdf73e1847b789f129d9694affbf3eae3 Mon Sep 17 00:00:00 2001 From: shats Date: Thu, 12 Feb 2026 22:33:43 +0700 Subject: [PATCH] feat(MikrotikTools): add ping functionality alongside traceroute with mode selection and result handling --- frontend/src/MikrotikTools.jsx | 259 +++++++++++++++++++++++++++------ 1 file changed, 214 insertions(+), 45 deletions(-) diff --git a/frontend/src/MikrotikTools.jsx b/frontend/src/MikrotikTools.jsx index 5f39395..c6b315f 100644 --- a/frontend/src/MikrotikTools.jsx +++ b/frontend/src/MikrotikTools.jsx @@ -31,9 +31,12 @@ function MikrotikTools() { const [target, setTarget] = useState(''); const [maxHops, setMaxHops] = useState(30); + const [mode, setMode] = useState('traceroute'); // 'traceroute' | 'ping' + const [running, setRunning] = useState(false); const [hops, setHops] = useState([]); const [analysis, setAnalysis] = useState([]); + const [pingResult, setPingResult] = useState(null); const [useDns, setUseDns] = useState(true); const [serverSearch, setServerSearch] = useState(''); @@ -77,50 +80,73 @@ function MikrotikTools() { } }; - const handleRunTraceroute = async () => { + const handleRunCheck = async () => { if (!serverId) { notify.error('Выберите сервер (jumphost)'); return; } - if (!target || String(target).trim() === '') { - notify.error('Укажите домен или IP для трассировки'); + + const trimmedTarget = String(target || '').trim(); + if (!trimmedTarget) { + notify.error('Укажите домен или IP назначения'); return; } setRunning(true); setHops([]); setAnalysis([]); + setPingResult(null); try { - const body = { - serverId, - target: String(target).trim(), - useDns, - }; - // gatewayRef может быть как ID gateway, так и IP/строка — - // для простоты, если в meta есть ip — используем его как gatewayIp. - if (gatewayMeta?.ip) { - body.gatewayIp = gatewayMeta.ip; - } - // Max hops - const hopsNum = Number(maxHops); - if (Number.isFinite(hopsNum) && hopsNum > 0) { - body.maxHops = hopsNum; - } + if (mode === 'traceroute') { + const body = { + serverId, + target: trimmedTarget, + useDns, + }; + if (gatewayMeta?.ip) { + body.gatewayIp = gatewayMeta.ip; + } + const hopsNum = Number(maxHops); + if (Number.isFinite(hopsNum) && hopsNum > 0) { + body.maxHops = hopsNum; + } - const res = await api.post('/mikrotik/traceroute', body); - const data = res?.data || {}; - if (!data.ok) { - notify.error(data.error || 'Трассировка завершилась с ошибкой'); - return; - } + const res = await api.post('/mikrotik/traceroute', body); + const data = res?.data || {}; + if (!data.ok) { + notify.error(data.error || 'Трассировка завершилась с ошибкой'); + return; + } - const hopsList = Array.isArray(data.hops) ? data.hops : []; - setHops(hopsList); - setAnalysis(buildTracerouteAnalysis(hopsList, networkConfig, servers, body.target)); + const hopsList = Array.isArray(data.hops) ? data.hops : []; + setHops(hopsList); + setAnalysis(buildTracerouteAnalysis(hopsList, networkConfig, servers, body.target)); + } else { + // mode === 'ping' + const body = { + serverId, + target: trimmedTarget, + count: 4, + }; + if (gatewayMeta?.ip) { + body.gatewayIp = gatewayMeta.ip; + } + + const res = await api.post('/mikrotik/ping', body); + const data = res?.data || {}; + if (data.ok === false) { + notify.error(data.error || 'Ping завершился с ошибкой'); + return; + } + setPingResult({ + target: trimmedTarget, + ...data, + }); + } } catch (error) { - console.error('[MikrotikTools] traceroute failed', error); - notify.error(error?.message || 'Ошибка при выполнении трассировки'); + console.error('[MikrotikTools] check failed', error); + notify.error(error?.message || 'Ошибка при выполнении проверки'); } finally { setRunning(false); } @@ -132,6 +158,7 @@ function MikrotikTools() { setTarget(''); setHops([]); setAnalysis([]); + setPingResult(null); }; const jumphostServers = useMemo( @@ -180,7 +207,7 @@ function MikrotikTools() {
@@ -277,7 +304,25 @@ function MikrotikTools() {
-

Параметры проверки

+
+

Параметры проверки

+
+ + +
+
{loading && !networkConfig ? ( @@ -397,17 +442,19 @@ function MikrotikTools() {
-
- - setMaxHops(e.target.value)} - /> -
+ {mode === 'traceroute' && ( +
+ + setMaxHops(e.target.value)} + /> +
+ )}
@@ -424,7 +471,7 @@ function MikrotikTools() {
- Этот параметр также передаётся на MikroTik как use-dns. + Для traceroute параметр также передаётся на MikroTik как use-dns.
@@ -443,16 +490,17 @@ function MikrotikTools() {
+ {mode === 'traceroute' && (

Результаты трассировки

@@ -588,7 +636,127 @@ function MikrotikTools() { )}
+ )} + {mode === 'ping' && ( +
+
+

Результаты ping

+
+
+ {!pingResult ? ( +
+ Результаты ping появятся здесь после запуска проверки. +
+ ) : ( +
+ + + + + + + + + + + + {(() => { + const avg = typeof pingResult.avgMs === 'number' ? pingResult.avgMs : null; + const loss = typeof pingResult.loss === 'number' ? pingResult.loss : null; + + let severity = 'ok'; + if (loss != null && loss >= 50) severity = 'danger'; + else if ((loss != null && loss > 0) || (avg != null && avg > 200)) severity = 'warn'; + + const rowClass = + severity === 'danger' + ? 'table-danger' + : severity === 'warn' + ? 'table-warning' + : ''; + + return ( + + + + + + + + ); + })()} + +
ЦельСреднее, мсМин / Макс, мсПотериОценка
+
+ + {pingResult.target || target || '—'} + + {gatewayMeta?.ip && ( + + через gateway {gatewayMeta.ip} + + )} +
+
+ {avg != null ? ( + 200 + ? 'text-danger fw-semibold' + : avg > 120 + ? 'text-warning fw-semibold' + : '' + } + > + {avg.toFixed(1)} + + ) : ( + '—' + )} + + {pingResult.minMs != null ? pingResult.minMs.toFixed(1) : '—'} /{' '} + {pingResult.maxMs != null ? pingResult.maxMs.toFixed(1) : '—'} + + {loss != null ? ( + = 50 + ? 'badge bg-red-lt text-red' + : loss > 0 + ? 'badge bg-yellow-lt text-yellow' + : 'badge bg-green-lt text-green' + } + > + {loss}% + + ) : ( + '—' + )} + + {severity === 'danger' && ( + Плохое качество + )} + {severity === 'warn' && ( + + Возможные проблемы + + )} + + {loss === 0 + ? 'Все пакеты доставлены' + : loss != null + ? `Потеряно пакетов: ${loss}%` + : 'Нет данных о потере пакетов'} + +
+
+ )} +
+
+ )} + + {mode === 'traceroute' && (

@@ -612,6 +780,7 @@ function MikrotikTools() { )}

+ )}