// src/modules/router.js import $ from 'jquery'; import { StatisticsPage } from '../pages/Statistics.js'; import { Subscriptions } from '../pages/Subscriptions.js'; import { Components } from '../pages/Components.js'; import { APITokens } from '../pages/APITokens.js'; import { getEnabledComponents } from './app.js'; import { OVPNConfig } from '../pages/OVPN.js'; import { TDNSConfig } from '../pages/TDNS.js'; import { FRRConfig } from '../pages/FRR.js'; import { ROSConfig } from '../pages/ROS.js'; import { DNSMASQConfig } from '../pages/DNSMASQ.js'; import { SRMPage } from '../pages/SRM.js'; import { SettingsPage } from '../pages/Settings.js'; import { LogsPage } from '../pages/Logs.js'; import { NetworkResourcesPage } from '../pages/NetworkResources.js'; import { UnlockSitePage } from '../pages/UnlockSite.js'; import { LocalStoragesPage } from '../pages/LocalStorages.js'; // Переменная для отслеживания текущего активного хеша (для корректного unmount) let currentRouteHash = ''; // 1. Определение ВСЕХ возможных пунктов меню const allMenuItems = [ { label: 'Статистика', path: 'stats', component: null }, { label: 'Подписки', path: 'subscriptions', component: null }, { label: 'Настройки', path: 'settings', component: null }, { label: 'Компоненты', path: 'components', component: null }, { label: 'API', path: 'api', component: null }, { label: 'Настройка OVPN', path: 'ovpn', component: 'ru.kirillius.pf.sdn.External.API.Components.OVPN' }, { label: 'Настройка TDNS', path: 'tdns', component: 'ru.kirillius.pf.sdn.External.API.Components.TDNS' }, { label: 'Настройка FRR', path: 'frr', component: 'ru.kirillius.pf.sdn.External.API.Components.FRR' }, { label: 'Настройка ROS', path: 'ros', component: 'ru.kirillius.pf.sdn.External.API.Components.ROS' }, { label: 'Настройка DNSMASQ', path: 'dnsmasq', component: 'ru.kirillius.pf.sdn.External.API.Components.DNSMASQ' }, { label: 'SRM', path: 'srm', component: 'ru.kirillius.pf.sdn.External.API.Components.SRM' }, { label: 'Журнал', path: 'logs', component: null }, { label: 'Сетевые ресурсы', path: 'network-resources', component: null }, { label: 'Разблокировка сайта', path: 'unlock-site', component: null }, { label: 'Локальные хранилища', path: 'local-storages', component: null }, ]; // 2. Определение страниц const routes = { '#stats': { render: StatisticsPage.render, mount: StatisticsPage.mount, unmount: StatisticsPage.unmount }, '#subscriptions': { render: Subscriptions.render, mount: Subscriptions.mount, unmount: Subscriptions.unmount }, '#settings': { render: SettingsPage.render, mount: SettingsPage.mount, unmount: SettingsPage.unmount }, '#components': { render: Components.render, mount: Components.mount, unmount: Components.unmount }, '#api': { render: APITokens.render, mount: APITokens.mount, unmount: APITokens.unmount }, '#ovpn': { render: OVPNConfig.render, mount: OVPNConfig.mount, unmount: OVPNConfig.unmount }, '#tdns': { render: TDNSConfig.render, mount: TDNSConfig.mount, unmount: TDNSConfig.unmount }, '#frr': { render: FRRConfig.render, mount: FRRConfig.mount, unmount: FRRConfig.unmount }, '#ros': { render: ROSConfig.render, mount: ROSConfig.mount, unmount: ROSConfig.unmount }, '#dnsmasq': { render: DNSMASQConfig.render, mount: DNSMASQConfig.mount, unmount: DNSMASQConfig.unmount }, '#srm': { render: SRMPage.render, mount: SRMPage.mount, unmount: SRMPage.unmount }, '#logs': { render: LogsPage.render, mount: LogsPage.mount, unmount: LogsPage.unmount }, '#network-resources': { render: NetworkResourcesPage.render, mount: NetworkResourcesPage.mount, unmount: NetworkResourcesPage.unmount }, '#unlock-site': { render: UnlockSitePage.render, mount: UnlockSitePage.mount, unmount: UnlockSitePage.unmount }, '#local-storages': { render: LocalStoragesPage.render, mount: LocalStoragesPage.mount, unmount: LocalStoragesPage.unmount } }; // 🔥 Убедитесь, что здесь НЕТ слова 'export' function getFilteredMenuItems() { const enabled = getEnabledComponents(); return allMenuItems.filter(item => { if (item.component === null) { return true; } return enabled.includes(item.component); }); } // 3. Функция рендеринга страницы (без изменений) export function renderPage(hash) { const $contentArea = $('#content-area'); const key = hash.startsWith('#') ? hash : '#' + hash; // Если страница уже открыта, просто обновляем меню и выходим if (currentRouteHash === key) { $('.menu-item').removeClass('active'); $(`.menu-item[data-path="${key.substring(1)}"]`).addClass('active'); return; } const previousKey = currentRouteHash || '#stats'; // Шаг 1: Если мы меняем страницу, и предыдущая страница имеет unmount, вызываем его if (previousKey !== key && routes[previousKey] && routes[previousKey].unmount) { routes[previousKey].unmount(); } if (routes[key]) { // Рендерим HTML $contentArea.html(routes[key].render()); // Вызываем функцию монтирования routes[key].mount(); // Обновляем активный пункт меню $('.menu-item').removeClass('active'); $(`.menu-item[data-path="${key.substring(1)}"]`).addClass('active'); // Обновляем hash в адресной строке if (window.location.hash !== key) { history.pushState(null, null, key); } // Шаг 2: Успешно обновили страницу, сохраняем новый хеш currentRouteHash = key; } else { // Если путь не найден, перенаправляем на "Статистику" window.location.hash = 'stats'; } } // 4. Обработчик изменения хеша в браузере (для навигации по истории) $(window).on('hashchange', function() { renderPage(window.location.hash); }); // 🔥 Оставляем ТОЛЬКО ОДИН экспорт в конце файла export { getFilteredMenuItems };