From cd4b95bb8f18a554fd41d02893714d87e15c13d7 Mon Sep 17 00:00:00 2001 From: shats Date: Sat, 24 Jan 2026 13:59:17 +0700 Subject: [PATCH] feat(NetworkConfigManager): implement MikroTik code generation for individual gateways, enhancing user experience with detailed route generation and error handling --- frontend/src/NetworkConfigManager.jsx | 173 ++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx index 04e38b5..54b8994 100644 --- a/frontend/src/NetworkConfigManager.jsx +++ b/frontend/src/NetworkConfigManager.jsx @@ -1739,6 +1739,165 @@ function NetworkConfigManager() { } }; + // === Генерация кода MikroTik только для одного gateway === + const handleGenerateMikrotikCodeForGateway = async (gateway) => { + if (!gateway) { + notify.error('Gateway не найден'); + return; + } + + setLoading(true); + try { + const blocks = []; + const server = getServerInfo(gateway.serverId); + const serverName = server?.dns || server?.ip || gateway.serverId || '__unassigned__'; + + if (gateway.type === 'recursive') { + // Генерация кода для рекурсивного gateway + if (!gateway.ip) { + notify.error('Gateway без IP адреса - невозможно сгенерировать код'); + setLoading(false); + return; + } + + // Поддержка старого формата (parentGatewayId) и нового (parentGateways) + const parentGatewaysList = gateway.parentGateways && Array.isArray(gateway.parentGateways) && gateway.parentGateways.length > 0 + ? gateway.parentGateways + : (gateway.parentGatewayId ? [{ id: gateway.parentGatewayId, distance: undefined }] : []); + + if (parentGatewaysList.length === 0) { + notify.error('Родительские gateway/интерфейсы не указаны'); + setLoading(false); + return; + } + + let code = `# Рекурсивный маршрут для gateway: ${gateway.ip}\n`; + if (server?.provider) { + code += `# Провайдер: ${server.provider}\n`; + } + if (server?.country) { + code += `# Страна: ${server.country}\n`; + } + code += '\n'; + + let validRoutesCount = 0; + + parentGatewaysList.forEach((parentRef, parentIndex) => { + const parent = getParentGateway(parentRef.id); + + if (!parent) { + code += `# Родительский gateway/интерфейс "${parentRef.id}" не найден, пропущен\n`; + return; + } + + // Определяем IP родителя в зависимости от типа + const parentIp = parent.parentType === 'interface' ? parent.remoteIp : parent.ip; + + if (!parentIp) { + const parentType = parent.parentType === 'interface' ? 'интерфейс' : 'gateway'; + code += `# Родительский ${parentType} не имеет IP, пропущен\n`; + return; + } + + validRoutesCount++; + + // Создаём маршрут для рекурсивного gateway + const parentLabel = parent.parentType === 'interface' + ? `интерфейс ${parent.name || parent.interfaceType || 'interface'} (${parent.remoteIp})` + : `gateway ${parent.ip}`; + + const distanceSuffix = parentRef.distance !== undefined && parentRef.distance !== null ? ` (distance: ${parentRef.distance})` : ''; + code += `# Рекурсивный gateway: ${gateway.ip}${distanceSuffix}\n`; + code += `# Родительский: ${parentLabel}\n`; + + // Формируем gateway: для интерфейсов добавляем имя через %, для gateway - только IP + const gatewayValue = parent.parentType === 'interface' + ? `${parentIp}%${parent.name || parent.interfaceType || 'interface'}` + : parentIp; + + // Создаём маршрут к IP рекурсивного gateway через родительский + const comment = gateway.description + ? `Recursive: ${gateway.description} -> ${parentIp}${distanceSuffix}` + : `Recursive: ${gateway.ip} -> ${parentIp}${distanceSuffix}`; + + // Формируем команду с distance, если указан + const distanceParam = parentRef.distance !== undefined && parentRef.distance !== null ? ` distance=${parentRef.distance}` : ''; + code += `/ip route add dst-address=${gateway.ip}/32 gateway=${gatewayValue}${distanceParam} comment="${comment}"\n`; + + // Если у рекурсивного gateway есть описание с указанием на default route + if (gateway.description && (gateway.description.toLowerCase().includes('default') || gateway.description.toLowerCase().includes('0.0.0.0'))) { + code += `# Дополнительный default route через рекурсивный gateway${distanceSuffix}\n`; + const defaultComment = gateway.description ? `Recursive: ${gateway.description} (default)${distanceSuffix}` : `Recursive: ${gateway.ip} (default)${distanceSuffix}`; + code += `/ip route add dst-address=0.0.0.0/0 gateway=${gatewayValue}${distanceParam} comment="${defaultComment}"\n`; + } + code += '\n'; + }); + + code += '# Проверка созданных маршрутов:\n'; + code += '# /ip route print where comment~"Recursive"\n'; + code += `# Всего создано маршрутов: ${validRoutesCount}\n`; + + if (validRoutesCount > 0) { + blocks.push({ + type: 'recursive-routes', + serverName, + server, + code + }); + } + } else if (gateway.type === 'direct') { + // Генерация кода для прямого gateway + if (!gateway.ip) { + notify.error('Gateway без IP адреса - невозможно сгенерировать код'); + setLoading(false); + return; + } + + let code = `# Прямой маршрут для gateway: ${gateway.ip}\n`; + if (server?.provider) { + code += `# Провайдер: ${server.provider}\n`; + } + if (server?.country) { + code += `# Страна: ${server.country}\n`; + } + code += '\n'; + + const comment = gateway.description + ? `Direct: ${gateway.description}` + : `Direct: ${gateway.ip}`; + + code += `/ip route add dst-address=0.0.0.0/0 gateway=${gateway.ip} comment="${comment}"\n`; + code += '\n'; + code += '# Проверка созданного маршрута:\n'; + code += '# /ip route print where comment~"Direct"\n'; + + blocks.push({ + type: 'direct-route', + serverName, + server, + code + }); + } else { + notify.error('Неизвестный тип gateway'); + setLoading(false); + return; + } + + if (blocks.length === 0) { + notify.error('Нет данных для генерации кода MikroTik для этого gateway'); + return; + } + + setGeneratedMikrotikCode(blocks); + setMikrotikCodeModalOpen(true); + } catch (error) { + console.error('Error generating MikroTik code for gateway:', error); + notify.error('Ошибка при генерации кода MikroTik для этого gateway'); + } finally { + setLoading(false); + } + }; + // === Копирование кода MikroTik === const handleCopyMikrotikCode = async (codeToCopy) => { if (!codeToCopy) { @@ -2132,6 +2291,13 @@ function NetworkConfigManager() { {/* Правая часть: действия */}
+