diff --git a/.gitignore b/.gitignore index 5934af0..22d0862 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Исключения -myapp.exe +vSerf.exe .vscode/ WebServer/cert/* !WebServer/cert/no_cert/ diff --git a/Backend/admin/frontend/assets/js/api/config.js b/Backend/admin/frontend/assets/js/api/config.js index 5a12a46..151cc87 100644 --- a/Backend/admin/frontend/assets/js/api/config.js +++ b/Backend/admin/frontend/assets/js/api/config.js @@ -3,123 +3,94 @@ Работа с конфигурацией ============================================ */ -import { isWailsAvailable, log } from '../utils/helpers.js'; +import { isWailsAvailable } from '../utils/helpers.js'; -/** - * Класс для работы с конфигурацией - */ +// Класс для работы с конфигурацией class ConfigAPI { constructor() { this.available = isWailsAvailable(); } - /** - * Получить конфигурацию - */ + // Получить конфигурацию async getConfig() { if (!this.available) return null; try { return await window.go.admin.App.GetConfig(); } catch (error) { - log(`Ошибка получения конфигурации: ${error.message}`, 'error'); return null; } } - /** - * Сохранить конфигурацию - */ + // Сохранить конфигурацию async saveConfig(configJSON) { if (!this.available) return 'Error: API недоступен'; try { return await window.go.admin.App.SaveConfig(configJSON); } catch (error) { - log(`Ошибка сохранения конфигурации: ${error.message}`, 'error'); return `Error: ${error.message}`; } } - /** - * Включить Proxy Service - */ + // Включить Proxy Service async enableProxyService() { if (!this.available) return; try { await window.go.admin.App.EnableProxyService(); } catch (error) { - log(`Ошибка включения Proxy: ${error.message}`, 'error'); } } - /** - * Отключить Proxy Service - */ + // Отключить Proxy Service async disableProxyService() { if (!this.available) return; try { await window.go.admin.App.DisableProxyService(); } catch (error) { - log(`Ошибка отключения Proxy: ${error.message}`, 'error'); } } - /** - * Перезапустить все сервисы - */ + // Перезапустить все сервисы async restartAllServices() { if (!this.available) return; try { await window.go.admin.App.RestartAllServices(); } catch (error) { - log(`Ошибка перезапуска сервисов: ${error.message}`, 'error'); } } - /** - * Запустить HTTP Service - */ + // Запустить HTTP Service async startHTTPService() { if (!this.available) return; try { await window.go.admin.App.StartHTTPService(); } catch (error) { - log(`Ошибка запуска HTTP: ${error.message}`, 'error'); } } - /** - * Остановить HTTP Service - */ + // Остановить HTTP Service async stopHTTPService() { if (!this.available) return; try { await window.go.admin.App.StopHTTPService(); } catch (error) { - log(`Ошибка остановки HTTP: ${error.message}`, 'error'); } } - /** - * Запустить HTTPS Service - */ + // Запустить HTTPS Service async startHTTPSService() { if (!this.available) return; try { await window.go.admin.App.StartHTTPSService(); } catch (error) { - log(`Ошибка запуска HTTPS: ${error.message}`, 'error'); } } - /** - * Остановить HTTPS Service - */ + // Остановить HTTPS Service async stopHTTPSService() { if (!this.available) return; try { await window.go.admin.App.StopHTTPSService(); } catch (error) { - log(`Ошибка остановки HTTPS: ${error.message}`, 'error'); } } } diff --git a/Backend/admin/frontend/assets/js/api/wails.js b/Backend/admin/frontend/assets/js/api/wails.js index 1cd4ed3..6afe9f0 100644 --- a/Backend/admin/frontend/assets/js/api/wails.js +++ b/Backend/admin/frontend/assets/js/api/wails.js @@ -3,119 +3,91 @@ Обёртка над Wails API ============================================ */ -import { isWailsAvailable, log } from '../utils/helpers.js'; +import { isWailsAvailable } from '../utils/helpers.js'; -/** - * Базовый класс для работы с Wails API - */ +// Базовый класс для работы с Wails API class WailsAPI { constructor() { this.available = isWailsAvailable(); } - /** - * Проверка доступности API - */ + // Проверка доступности API checkAvailability() { if (!this.available) { - log('Wails API недоступен', 'warn'); return false; } return true; } - /** - * Получить статус всех сервисов - */ + // Получить статус всех сервисов async getAllServicesStatus() { if (!this.checkAvailability()) return null; try { return await window.go.admin.App.GetAllServicesStatus(); } catch (error) { - log(`Ошибка получения статуса сервисов: ${error.message}`, 'error'); return null; } } - /** - * Получить список сайтов - */ + // Получить список сайтов async getSitesList() { if (!this.checkAvailability()) return []; try { return await window.go.admin.App.GetSitesList(); } catch (error) { - log(`Ошибка получения списка сайтов: ${error.message}`, 'error'); return []; } } - /** - * Получить список прокси - */ + // Получить список прокси async getProxyList() { if (!this.checkAvailability()) return []; try { return await window.go.admin.App.GetProxyList(); } catch (error) { - log(`Ошибка получения списка прокси: ${error.message}`, 'error'); return []; } } - /** - * Получить правила vAccess - */ + // Получить правила vAccess async getVAccessRules(host, isProxy) { if (!this.checkAvailability()) return { rules: [] }; try { return await window.go.admin.App.GetVAccessRules(host, isProxy); } catch (error) { - log(`Ошибка получения правил vAccess: ${error.message}`, 'error'); return { rules: [] }; } } - /** - * Сохранить правила vAccess - */ + // Сохранить правила vAccess async saveVAccessRules(host, isProxy, configJSON) { if (!this.checkAvailability()) return 'Error: API недоступен'; try { return await window.go.admin.App.SaveVAccessRules(host, isProxy, configJSON); } catch (error) { - log(`Ошибка сохранения правил vAccess: ${error.message}`, 'error'); return `Error: ${error.message}`; } } - /** - * Запустить сервер - */ + // Запустить сервер async startServer() { if (!this.checkAvailability()) return; try { await window.go.admin.App.StartServer(); } catch (error) { - log(`Ошибка запуска сервера: ${error.message}`, 'error'); } } - /** - * Остановить сервер - */ + // Остановить сервер async stopServer() { if (!this.checkAvailability()) return; try { await window.go.admin.App.StopServer(); } catch (error) { - log(`Ошибка остановки сервера: ${error.message}`, 'error'); } } - /** - * Проверить готовность сервисов - */ + // Проверить готовность сервисов async checkServicesReady() { if (!this.checkAvailability()) return false; try { @@ -125,66 +97,51 @@ class WailsAPI { } } - /** - * Открыть папку сайта - */ + // Открыть папку сайта async openSiteFolder(host) { if (!this.checkAvailability()) return; try { await window.go.admin.App.OpenSiteFolder(host); } catch (error) { - log(`Ошибка открытия папки: ${error.message}`, 'error'); } } - /** - * Создать новый сайт - */ + // Создать новый сайт async createNewSite(siteJSON) { if (!this.checkAvailability()) return 'Error: API недоступен'; try { return await window.go.admin.App.CreateNewSite(siteJSON); } catch (error) { - log(`Ошибка создания сайта: ${error.message}`, 'error'); return `Error: ${error.message}`; } } - /** - * Загрузить сертификат для сайта - */ + // Загрузить сертификат для сайта async uploadCertificate(host, certType, certDataBase64) { if (!this.checkAvailability()) return 'Error: API недоступен'; try { return await window.go.admin.App.UploadCertificate(host, certType, certDataBase64); } catch (error) { - log(`Ошибка загрузки сертификата: ${error.message}`, 'error'); return `Error: ${error.message}`; } } - /** - * Перезагрузить SSL сертификаты - */ + // Перезагрузить SSL сертификаты async reloadSSLCertificates() { if (!this.checkAvailability()) return 'Error: API недоступен'; try { return await window.go.admin.App.ReloadSSLCertificates(); } catch (error) { - log(`Ошибка перезагрузки сертификатов: ${error.message}`, 'error'); return `Error: ${error.message}`; } } - /** - * Удалить сайт - */ + // Удалить сайт async deleteSite(host) { if (!this.checkAvailability()) return 'Error: API недоступен'; try { return await window.go.admin.App.DeleteSite(host); } catch (error) { - log(`Ошибка удаления сайта: ${error.message}`, 'error'); return `Error: ${error.message}`; } } diff --git a/Backend/admin/frontend/assets/js/components/proxy.js b/Backend/admin/frontend/assets/js/components/proxy.js index e92fee3..e7284cc 100644 --- a/Backend/admin/frontend/assets/js/components/proxy.js +++ b/Backend/admin/frontend/assets/js/components/proxy.js @@ -7,9 +7,7 @@ import { api } from '../api/wails.js'; import { isWailsAvailable } from '../utils/helpers.js'; import { $ } from '../utils/dom.js'; -/** - * Класс для управления прокси - */ +// Класс для управления прокси export class ProxyManager { constructor() { this.proxiesData = []; @@ -44,9 +42,7 @@ export class ProxyManager { ]; } - /** - * Загрузить список прокси - */ + // Загрузить список прокси async load() { if (isWailsAvailable()) { this.proxiesData = await api.getProxyList(); @@ -57,9 +53,7 @@ export class ProxyManager { this.render(); } - /** - * Отрисовать список прокси - */ + // Отрисовать список прокси render() { const tbody = $('proxyTable')?.querySelector('tbody'); if (!tbody) return; @@ -92,9 +86,7 @@ export class ProxyManager { this.attachEventListeners(); } - /** - * Добавить обработчики событий - */ + // Добавить обработчики событий attachEventListeners() { // Кликабельные ссылки const links = document.querySelectorAll('.clickable-link[data-url]'); @@ -115,9 +107,7 @@ export class ProxyManager { }); } - /** - * Обработчик действий - */ + // Обработчик действий handleAction(action, btn) { const host = btn.getAttribute('data-host'); const index = parseInt(btn.getAttribute('data-index')); @@ -137,9 +127,7 @@ export class ProxyManager { } } - /** - * Открыть ссылку - */ + // Открыть ссылку openLink(url) { if (window.runtime?.BrowserOpenURL) { window.runtime.BrowserOpenURL(url); diff --git a/Backend/admin/frontend/assets/js/components/services.js b/Backend/admin/frontend/assets/js/components/services.js index 4afd517..ee3afc8 100644 --- a/Backend/admin/frontend/assets/js/components/services.js +++ b/Backend/admin/frontend/assets/js/components/services.js @@ -8,9 +8,7 @@ import { $, $$, addClass, removeClass } from '../utils/dom.js'; import { notification } from '../ui/notification.js'; import { sleep, isWailsAvailable } from '../utils/helpers.js'; -/** - * Класс для управления сервисами - */ +// Класс для управления сервисами export class ServicesManager { constructor() { this.serverRunning = true; @@ -40,9 +38,7 @@ export class ServicesManager { } } - /** - * Переключить состояние сервера - */ + // Переключить состояние сервера async toggleServer() { if (this.serverRunning) { await this.stopServer(); @@ -51,9 +47,7 @@ export class ServicesManager { } } - /** - * Запустить сервер - */ + // Запустить сервер async startServer() { this.isOperating = true; this.controlBtn.disabled = true; @@ -80,9 +74,7 @@ export class ServicesManager { this.controlBtn.disabled = false; } - /** - * Остановить сервер - */ + // Остановить сервер async stopServer() { this.isOperating = true; this.controlBtn.disabled = true; @@ -100,9 +92,7 @@ export class ServicesManager { this.controlBtn.disabled = false; } - /** - * Установить статус сервера - */ + // Установить статус сервера setServerStatus(isOnline, text) { this.serverRunning = isOnline; @@ -117,9 +107,7 @@ export class ServicesManager { this.statusText.textContent = text; } - /** - * Установить всем сервисам статус pending - */ + // Установить всем сервисам статус pending setAllServicesPending(text) { const badges = $$('.service-card .badge'); badges.forEach(badge => { @@ -128,9 +116,7 @@ export class ServicesManager { }); } - /** - * Отрисовать статусы сервисов - */ + // Отрисовать статусы сервисов renderServices(data) { const services = [data.http, data.https, data.mysql, data.php, data.proxy]; const cards = $$('.service-card'); @@ -166,9 +152,7 @@ export class ServicesManager { }); } - /** - * Загрузить статусы сервисов - */ + // Загрузить статусы сервисов async loadStatus() { if (isWailsAvailable()) { const data = await api.getAllServicesStatus(); diff --git a/Backend/admin/frontend/assets/js/components/site-creator.js b/Backend/admin/frontend/assets/js/components/site-creator.js index 039fee1..b0be672 100644 --- a/Backend/admin/frontend/assets/js/components/site-creator.js +++ b/Backend/admin/frontend/assets/js/components/site-creator.js @@ -10,9 +10,7 @@ import { notification } from '../ui/notification.js'; import { isWailsAvailable } from '../utils/helpers.js'; import { initCustomSelects } from '../ui/custom-select.js'; -/** - * Класс для создания новых сайтов - */ +// Класс для создания новых сайтов export class SiteCreator { constructor() { this.aliases = []; @@ -23,9 +21,7 @@ export class SiteCreator { }; } - /** - * Открыть страницу создания сайта - */ + // Открыть страницу создания сайта open() { // Скрываем все секции this.hideAllSections(); @@ -43,9 +39,7 @@ export class SiteCreator { setTimeout(() => initCustomSelects(), 100); } - /** - * Скрыть все секции - */ + // Скрыть все секции hideAllSections() { hide($('sectionServices')); hide($('sectionSites')); @@ -55,9 +49,7 @@ export class SiteCreator { hide($('sectionAddSite')); } - /** - * Вернуться на главную - */ + // Вернуться на главную backToMain() { this.hideAllSections(); show($('sectionServices')); @@ -65,9 +57,7 @@ export class SiteCreator { show($('sectionProxy')); } - /** - * Очистить форму - */ + // Очистить форму resetForm() { $('newSiteName').value = ''; $('newSiteHost').value = ''; @@ -107,9 +97,7 @@ export class SiteCreator { labels.forEach(label => label.classList.remove('file-uploaded')); } - /** - * Привязать обработчики событий - */ + // Привязать обработчики событий attachEventListeners() { const createBtn = $('createSiteBtn'); if (createBtn) { @@ -120,9 +108,7 @@ export class SiteCreator { this.setupDragAndDrop(); } - /** - * Настроить Drag & Drop для файлов - */ + // Настроить Drag & Drop для файлов setupDragAndDrop() { const fileWrappers = [ { wrapper: document.querySelector('label[for="certFile"]')?.parentElement, input: $('certFile'), type: 'certificate' }, @@ -171,9 +157,7 @@ export class SiteCreator { }); } - /** - * Парсить aliases из строки (через запятую) - */ + // Парсить aliases из строки (через запятую) parseAliases() { const input = $('newSiteAliasInput'); const value = input?.value.trim(); @@ -190,9 +174,7 @@ export class SiteCreator { .filter(alias => alias.length > 0); } - /** - * Переключить видимость блока загрузки сертификатов - */ + // Переключить видимость блока загрузки сертификатов toggleCertUpload() { const mode = $('certMode')?.value; const block = $('certUploadBlock'); @@ -204,9 +186,7 @@ export class SiteCreator { } } - /** - * Обработать выбор файла сертификата - */ + // Обработать выбор файла сертификата handleCertFile(input, certType) { const file = input.files[0]; const statusId = certType === 'certificate' ? 'certFileStatus' : @@ -257,9 +237,7 @@ export class SiteCreator { reader.readAsText(file); } - /** - * Валидация формы - */ + // Валидация формы validateForm() { const name = $('newSiteName')?.value.trim(); const host = $('newSiteHost')?.value.trim(); @@ -296,9 +274,7 @@ export class SiteCreator { return true; } - /** - * Создать сайт - */ + // Создать сайт async createSite() { if (!this.validateForm()) { return; diff --git a/Backend/admin/frontend/assets/js/components/sites.js b/Backend/admin/frontend/assets/js/components/sites.js index 1aa92b5..230322c 100644 --- a/Backend/admin/frontend/assets/js/components/sites.js +++ b/Backend/admin/frontend/assets/js/components/sites.js @@ -7,9 +7,7 @@ import { api } from '../api/wails.js'; import { isWailsAvailable } from '../utils/helpers.js'; import { $ } from '../utils/dom.js'; -/** - * Класс для управления сайтами - */ +// Класс для управления сайтами export class SitesManager { constructor() { this.sitesData = []; @@ -41,9 +39,7 @@ export class SitesManager { ]; } - /** - * Загрузить список сайтов - */ + // Загрузить список сайтов async load() { if (isWailsAvailable()) { this.sitesData = await api.getSitesList(); @@ -54,9 +50,7 @@ export class SitesManager { this.render(); } - /** - * Отрисовать список сайтов - */ + // Отрисовать список сайтов render() { const tbody = $('sitesTable')?.querySelector('tbody'); if (!tbody) return; @@ -88,9 +82,7 @@ export class SitesManager { this.attachEventListeners(); } - /** - * Добавить обработчики событий - */ + // Добавить обработчики событий attachEventListeners() { // Кликабельные ссылки const links = document.querySelectorAll('.clickable-link[data-url]'); @@ -111,9 +103,7 @@ export class SitesManager { }); } - /** - * Обработчик действий - */ + // Обработчик действий async handleAction(action, btn) { const host = btn.getAttribute('data-host'); const index = parseInt(btn.getAttribute('data-index')); @@ -136,9 +126,7 @@ export class SitesManager { } } - /** - * Открыть ссылку - */ + // Открыть ссылку openLink(url) { if (window.runtime?.BrowserOpenURL) { window.runtime.BrowserOpenURL(url); diff --git a/Backend/admin/frontend/assets/js/components/vaccess.js b/Backend/admin/frontend/assets/js/components/vaccess.js index babbec4..7e8c2b6 100644 --- a/Backend/admin/frontend/assets/js/components/vaccess.js +++ b/Backend/admin/frontend/assets/js/components/vaccess.js @@ -9,9 +9,7 @@ import { notification } from '../ui/notification.js'; import { modal } from '../ui/modal.js'; import { isWailsAvailable } from '../utils/helpers.js'; -/** - * Класс для управления vAccess правилами - */ +// Класс для управления vAccess правилами export class VAccessManager { constructor() { this.vAccessHost = ''; @@ -22,9 +20,7 @@ export class VAccessManager { this.editingField = null; } - /** - * Открыть редактор vAccess - */ + // Открыть редактор vAccess async open(host, isProxy) { this.vAccessHost = host; this.vAccessIsProxy = isProxy; @@ -77,9 +73,7 @@ export class VAccessManager { } } - /** - * Скрыть все секции - */ + // Скрыть все секции hideAllSections() { hide($('sectionServices')); hide($('sectionSites')); @@ -88,9 +82,7 @@ export class VAccessManager { hide($('sectionVAccessEditor')); } - /** - * Вернуться на главную - */ + // Вернуться на главную backToMain() { this.hideAllSections(); show($('sectionServices')); @@ -98,9 +90,7 @@ export class VAccessManager { show($('sectionProxy')); } - /** - * Переключить вкладку - */ + // Переключить вкладку switchTab(tab) { const tabs = document.querySelectorAll('.vaccess-tab[data-tab]'); tabs.forEach(t => { @@ -120,9 +110,7 @@ export class VAccessManager { } } - /** - * Сохранить изменения - */ + // Сохранить изменения async save() { if (isWailsAvailable()) { const config = { rules: this.vAccessRules }; @@ -140,9 +128,7 @@ export class VAccessManager { } } - /** - * Отрисовать список правил - */ + // Отрисовать список правил renderRulesList() { const tbody = $('vAccessTableBody'); const emptyState = $('vAccessEmpty'); @@ -191,9 +177,7 @@ export class VAccessManager { this.attachRulesEventListeners(); } - /** - * Добавить обработчики событий для правил - */ + // Добавить обработчики событий для правил attachRulesEventListeners() { // Drag & Drop const rows = document.querySelectorAll('#vAccessTableBody tr[draggable]'); @@ -223,9 +207,7 @@ export class VAccessManager { }); } - /** - * Добавить новое правило - */ + // Добавить новое правило addRule() { this.vAccessRules.push({ type: 'Disable', @@ -240,17 +222,13 @@ export class VAccessManager { this.renderRulesList(); } - /** - * Удалить правило - */ + // Удалить правило removeRule(index) { this.vAccessRules.splice(index, 1); this.renderRulesList(); } - /** - * Редактировать поле правила - */ + // Редактировать поле правила editRuleField(index, field) { const rule = this.vAccessRules[index]; @@ -271,9 +249,7 @@ export class VAccessManager { } } - /** - * Показать редактор поля - */ + // Показать редактор поля showFieldEditor(index, field) { const rule = this.vAccessRules[index]; const fieldNames = { @@ -328,9 +304,7 @@ export class VAccessManager { }, 100); } - /** - * Добавить значение в поле - */ + // Добавить значение в поле addFieldValue() { const input = $('fieldInput'); const value = input?.value.trim(); @@ -346,9 +320,7 @@ export class VAccessManager { } } - /** - * Удалить значение из поля - */ + // Удалить значение из поля removeFieldValue(value) { if (this.editingField) { const { index, field } = this.editingField; @@ -361,9 +333,7 @@ export class VAccessManager { } } - /** - * Закрыть редактор поля - */ + // Закрыть редактор поля closeFieldEditor() { modal.closeFieldEditor(); this.renderRulesList(); diff --git a/Backend/admin/frontend/assets/js/main.js b/Backend/admin/frontend/assets/js/main.js index 79239be..9e6be38 100644 --- a/Backend/admin/frontend/assets/js/main.js +++ b/Backend/admin/frontend/assets/js/main.js @@ -3,7 +3,7 @@ Точка входа приложения ============================================ */ -import { log, isWailsAvailable, sleep } from './utils/helpers.js'; +import { isWailsAvailable, sleep } from './utils/helpers.js'; import { WindowControls } from './ui/window.js'; import { Navigation } from './ui/navigation.js'; import { notification } from './ui/notification.js'; @@ -18,9 +18,7 @@ import { configAPI } from './api/config.js'; import { initCustomSelects } from './ui/custom-select.js'; import { $ } from './utils/dom.js'; -/** - * Главный класс приложения - */ +// Главный класс приложения class App { constructor() { this.windowControls = new WindowControls(); @@ -32,15 +30,29 @@ class App { this.siteCreator = new SiteCreator(); this.isWails = isWailsAvailable(); - - log('Приложение инициализировано'); } - /** - * Запустить приложение - */ + // Загрузить шаблоны из templates.html + async loadTemplates() { + try { + const response = await fetch('templates.html'); + const html = await response.text(); + document.getElementById('templates-container').innerHTML = html; + } catch (error) { + // Игнорируем ошибку + } + } + + // Получить шаблон по ID + getTemplate(templateId) { + const template = document.getElementById(templateId); + return template ? template.content.cloneNode(true) : null; + } + + // Запустить приложение async start() { - log('Запуск приложения...'); + // Загружаем шаблоны + await this.loadTemplates(); // Скрываем loader если не в Wails if (!this.isWails) { @@ -50,12 +62,6 @@ class App { // Ждём немного перед загрузкой данных await sleep(1000); - if (this.isWails) { - log('Wails API доступен', 'info'); - } else { - log('Wails API недоступен (браузерный режим)', 'warn'); - } - // Загружаем начальные данные await this.loadInitialData(); @@ -75,13 +81,9 @@ class App { // Инициализируем кастомные select'ы initCustomSelects(); - - log('Приложение запущено'); } - /** - * Загрузить начальные данные - */ + // Загрузить начальные данные async loadInitialData() { await Promise.all([ this.servicesManager.loadStatus(), @@ -90,18 +92,14 @@ class App { ]); } - /** - * Запустить автообновление - */ + // Запустить автообновление startAutoRefresh() { setInterval(async () => { await this.loadInitialData(); }, 5000); } - /** - * Привязать кнопки - */ + // Привязать кнопки setupButtons() { // Кнопка добавления сайта const addSiteBtn = $('addSiteBtn'); @@ -139,156 +137,70 @@ class App { } } - /** - * Настроить глобальные обработчики - */ + // Настроить глобальные обработчики setupGlobalHandlers() { - // Глобальная ссылка на sitesManager - window.sitesManager = this.sitesManager; - window.siteCreator = this.siteCreator; - - // Для SiteCreator - window.backToMainFromAddSite = () => { - this.siteCreator.backToMain(); - }; - - window.toggleCertUpload = () => { - this.siteCreator.toggleCertUpload(); - }; - - window.handleCertFileSelect = (input, certType) => { - this.siteCreator.handleCertFile(input, certType); - }; - - // Для vAccess - window.editVAccess = (host, isProxy) => { - this.vAccessManager.open(host, isProxy); - }; - - window.backToMain = () => { - this.vAccessManager.backToMain(); - }; - - window.switchVAccessTab = (tab) => { - this.vAccessManager.switchTab(tab); - }; - - window.saveVAccessChanges = async () => { - await this.vAccessManager.save(); - }; - - window.addVAccessRule = () => { - this.vAccessManager.addRule(); - }; - - // Для Settings - window.loadConfig = async () => { - await this.loadConfigSettings(); - }; - - window.saveSettings = async () => { - await this.saveConfigSettings(); - }; - - // Для модальных окон - window.editSite = (index) => { - this.editSite(index); - }; - - window.editProxy = (index) => { - this.editProxy(index); - }; - - window.setStatus = (status) => { - this.setModalStatus(status); - }; - - window.setProxyStatus = (status) => { - this.setModalStatus(status); - }; - - window.addAliasTag = () => { - this.addAliasTag(); - }; - - window.removeAliasTag = (btn) => { - btn.parentElement.remove(); - }; - - window.saveModalData = async () => { - await this.saveModalData(); - }; - - // Drag & Drop для vAccess - window.dragStart = (event, index) => { - this.vAccessManager.onDragStart(event); - }; - - window.dragOver = (event) => { - this.vAccessManager.onDragOver(event); - }; - - window.drop = (event, index) => { - this.vAccessManager.onDrop(event); - }; - - window.editRuleField = (index, field) => { - this.vAccessManager.editRuleField(index, field); - }; - - window.removeVAccessRule = (index) => { - this.vAccessManager.removeRule(index); - }; - - window.closeFieldEditor = () => { - this.vAccessManager.closeFieldEditor(); - }; - - window.addFieldValue = () => { - this.vAccessManager.addFieldValue(); - }; - - window.removeFieldValue = (value) => { - this.vAccessManager.removeFieldValue(value); - }; - - // Тестовые функции (для браузерного режима) - window.editTestSite = (index) => { - const testSites = [ - {name: 'Локальный сайт', host: '127.0.0.1', alias: ['localhost'], status: 'active', root_file: 'index.html', root_file_routing: true}, - {name: 'Тестовый проект', host: 'test.local', alias: ['*.test.local', 'test.com'], status: 'active', root_file: 'index.php', root_file_routing: false}, - {name: 'API сервис', host: 'api.example.com', alias: ['*.api.example.com'], status: 'inactive', root_file: 'index.php', root_file_routing: true} - ]; - this.sitesManager.sitesData = testSites; - this.editSite(index); - }; - - window.editTestProxy = (index) => { - const testProxies = [ - {enable: true, external_domain: 'git.example.ru', local_address: '127.0.0.1', local_port: '3333', service_https_use: false, auto_https: true}, - {enable: true, external_domain: 'api.example.com', local_address: '127.0.0.1', local_port: '8080', service_https_use: true, auto_https: false}, - {enable: false, external_domain: 'test.example.net', local_address: '127.0.0.1', local_port: '5000', service_https_use: false, auto_https: false} - ]; - this.proxyManager.proxiesData = testProxies; - this.editProxy(index); - }; - - window.openTestLink = (url) => { - this.sitesManager.openLink(url); - }; - - window.openSiteFolder = async (host) => { - await this.sitesManager.handleAction('open-folder', { getAttribute: () => host }); - }; - - window.deleteSiteConfirm = async () => { - await this.deleteSiteConfirm(); - }; + Object.assign(window, { + // Ссылки на менеджеры + sitesManager: this.sitesManager, + siteCreator: this.siteCreator, + + // SiteCreator + backToMainFromAddSite: () => this.siteCreator.backToMain(), + toggleCertUpload: () => this.siteCreator.toggleCertUpload(), + handleCertFileSelect: (input, certType) => this.siteCreator.handleCertFile(input, certType), + + // vAccess + editVAccess: (host, isProxy) => this.vAccessManager.open(host, isProxy), + backToMain: () => this.vAccessManager.backToMain(), + switchVAccessTab: (tab) => this.vAccessManager.switchTab(tab), + saveVAccessChanges: async () => await this.vAccessManager.save(), + addVAccessRule: () => this.vAccessManager.addRule(), + dragStart: (e) => this.vAccessManager.onDragStart(e), + dragOver: (e) => this.vAccessManager.onDragOver(e), + drop: (e) => this.vAccessManager.onDrop(e), + editRuleField: (i, f) => this.vAccessManager.editRuleField(i, f), + removeVAccessRule: (i) => this.vAccessManager.removeRule(i), + closeFieldEditor: () => this.vAccessManager.closeFieldEditor(), + addFieldValue: () => this.vAccessManager.addFieldValue(), + removeFieldValue: (v) => this.vAccessManager.removeFieldValue(v), + + // Settings + loadConfig: async () => await this.loadConfigSettings(), + saveSettings: async () => await this.saveConfigSettings(), + + // Модальные окна + editSite: (i) => this.editSite(i), + editProxy: (i) => this.editProxy(i), + setStatus: (s) => this.setModalStatus(s), + setProxyStatus: (s) => this.setModalStatus(s), + addAliasTag: () => this.addAliasTag(), + removeAliasTag: (btn) => btn.parentElement.remove(), + saveModalData: async () => await this.saveModalData(), + deleteSiteConfirm: async () => await this.deleteSiteConfirm(), + + // Тестовые функции + editTestSite: (i) => { + this.sitesManager.sitesData = [ + {name: 'Локальный сайт', host: '127.0.0.1', alias: ['localhost'], status: 'active', root_file: 'index.html', root_file_routing: true}, + {name: 'Тестовый проект', host: 'test.local', alias: ['*.test.local', 'test.com'], status: 'active', root_file: 'index.php', root_file_routing: false}, + {name: 'API сервис', host: 'api.example.com', alias: ['*.api.example.com'], status: 'inactive', root_file: 'index.php', root_file_routing: true} + ]; + this.editSite(i); + }, + editTestProxy: (i) => { + this.proxyManager.proxiesData = [ + {enable: true, external_domain: 'git.example.ru', local_address: '127.0.0.1', local_port: '3333', service_https_use: false, auto_https: true}, + {enable: true, external_domain: 'api.example.com', local_address: '127.0.0.1', local_port: '8080', service_https_use: true, auto_https: false}, + {enable: false, external_domain: 'test.example.net', local_address: '127.0.0.1', local_port: '5000', service_https_use: false, auto_https: false} + ]; + this.editProxy(i); + }, + openTestLink: (url) => this.sitesManager.openLink(url), + openSiteFolder: async (host) => await this.sitesManager.handleAction('open-folder', { getAttribute: () => host }) + }); } - /** - * Загрузить настройки конфигурации - */ + // Загрузить настройки конфигурации async loadConfigSettings() { if (!isWailsAvailable()) { // Тестовые данные для браузерного режима @@ -310,9 +222,7 @@ class App { $('proxyEnabled').checked = config.Soft_Settings?.proxy_enabled !== false; } - /** - * Сохранить настройки конфигурации - */ + // Сохранить настройки конфигурации async saveConfigSettings() { const saveBtn = $('saveSettingsBtn'); const originalText = saveBtn.querySelector('span').textContent; @@ -353,146 +263,101 @@ class App { } } - /** - * Редактировать сайт - */ + // Редактировать сайт editSite(index) { const site = this.sitesManager.sitesData[index]; if (!site) return; - const content = ` -
-
- -
- - -
-
-
- - -
-
- - -
-
- -
- - -
-
- ${site.alias.map(alias => ` - - ${alias} - - - `).join('')} -
-
-
-
- - -
-
- -
- - Включён -
-
-
-
- `; + const template = this.getTemplate('edit-site-template'); + if (!template) return; - modal.open('Редактировать сайт', content); + const container = document.createElement('div'); + container.appendChild(template); + + // Открываем модальное окно с шаблоном + modal.open('Редактировать сайт', container.innerHTML); window.currentEditType = 'site'; window.currentEditIndex = index; - - // Добавляем кнопку удаления в футер модального окна + + // Заполняем данные ПОСЛЕ открытия модального окна + setTimeout(() => { + const statusBtn = document.querySelector(`[data-status="${site.status}"]`); + if (statusBtn) statusBtn.classList.add('active'); + + const editName = $('editName'); + const editHost = $('editHost'); + const editRootFile = $('editRootFile'); + const editRouting = $('editRouting'); + + if (editName) editName.value = site.name; + if (editHost) editHost.value = site.host; + if (editRootFile) editRootFile.value = site.root_file; + if (editRouting) editRouting.checked = site.root_file_routing; + + // Добавляем alias теги + const aliasContainer = $('aliasTagsContainer'); + if (aliasContainer) { + site.alias.forEach(alias => { + const tag = document.createElement('span'); + tag.className = 'tag'; + tag.innerHTML = `${alias}`; + aliasContainer.appendChild(tag); + }); + } + + // Привязываем обработчик кнопок статуса + document.querySelectorAll('.status-btn').forEach(btn => { + btn.onclick = () => this.setModalStatus(btn.dataset.value); + }); + }, 50); + this.addDeleteButtonToModal(); } - /** - * Редактировать прокси - */ + // Редактировать прокси editProxy(index) { const proxy = this.proxyManager.proxiesData[index]; if (!proxy) return; - const content = ` -
-
- -
- - -
-
-
- - -
-
-
- - -
-
- - -
-
-
-
- -
- - Включён -
-
-
- -
- - Включён -
-
-
-
- `; + const template = this.getTemplate('edit-proxy-template'); + if (!template) return; - modal.open('Редактировать прокси', content); + const container = document.createElement('div'); + container.appendChild(template); + + // Открываем модальное окно с шаблоном + modal.open('Редактировать прокси', container.innerHTML); window.currentEditType = 'proxy'; window.currentEditIndex = index; - - // Убираем кнопку удаления (для прокси не нужна) + + // Заполняем данные ПОСЛЕ открытия модального окна + setTimeout(() => { + const status = proxy.enable ? 'enable' : 'disable'; + const statusBtn = document.querySelector(`[data-status="${status}"]`); + if (statusBtn) statusBtn.classList.add('active'); + + const editDomain = $('editDomain'); + const editLocalAddr = $('editLocalAddr'); + const editLocalPort = $('editLocalPort'); + const editServiceHTTPS = $('editServiceHTTPS'); + const editAutoHTTPS = $('editAutoHTTPS'); + + if (editDomain) editDomain.value = proxy.external_domain; + if (editLocalAddr) editLocalAddr.value = proxy.local_address; + if (editLocalPort) editLocalPort.value = proxy.local_port; + if (editServiceHTTPS) editServiceHTTPS.checked = proxy.service_https_use; + if (editAutoHTTPS) editAutoHTTPS.checked = proxy.auto_https; + + // Привязываем обработчик кнопок статуса + document.querySelectorAll('.status-btn').forEach(btn => { + btn.onclick = () => this.setModalStatus(btn.dataset.value); + }); + }, 50); + this.removeDeleteButtonFromModal(); } - /** - * Установить статус в модальном окне - */ + // Установить статус в модальном окне setModalStatus(status) { const buttons = document.querySelectorAll('.status-btn'); buttons.forEach(btn => { @@ -503,9 +368,7 @@ class App { }); } - /** - * Добавить alias tag - */ + // Добавить alias tag addAliasTag() { const input = $('editAliasInput'); const value = input?.value.trim(); @@ -523,9 +386,7 @@ class App { } } - /** - * Сохранить данные модального окна - */ + // Сохранить данные модального окна async saveModalData() { if (!isWailsAvailable()) { notification.success('Данные сохранены (тестовый режим)', 1000); @@ -540,9 +401,17 @@ class App { } } - /** - * Сохранить данные сайта - */ + // Перезапустить HTTP/HTTPS сервисы + async restartHttpServices() { + notification.show('Перезапуск HTTP/HTTPS...', 'success', 800); + await configAPI.stopHTTPService(); + await configAPI.stopHTTPSService(); + await sleep(500); + await configAPI.startHTTPService(); + await configAPI.startHTTPSService(); + } + + // Сохранить данные сайта async saveSiteData() { const index = window.currentEditIndex; const tags = document.querySelectorAll('#aliasTagsContainer .tag'); @@ -559,29 +428,19 @@ class App { root_file_routing: $('editRouting').checked }; - const configJSON = JSON.stringify(config, null, 4); - const result = await configAPI.saveConfig(configJSON); - + const result = await configAPI.saveConfig(JSON.stringify(config, null, 4)); if (result.startsWith('Error')) { notification.error(result); - } else { - notification.show('Перезапуск HTTP/HTTPS...', 'success', 800); - - await configAPI.stopHTTPService(); - await configAPI.stopHTTPSService(); - await sleep(500); - await configAPI.startHTTPService(); - await configAPI.startHTTPSService(); - - notification.success('Изменения сохранены и применены!', 1000); - await this.sitesManager.load(); - modal.close(); + return; } + + await this.restartHttpServices(); + notification.success('Изменения сохранены и применены!', 1000); + await this.sitesManager.load(); + modal.close(); } - /** - * Сохранить данные прокси - */ + // Сохранить данные прокси async saveProxyData() { const index = window.currentEditIndex; const statusBtn = document.querySelector('.status-btn.active'); @@ -597,29 +456,19 @@ class App { AutoHTTPS: $('editAutoHTTPS').checked }; - const configJSON = JSON.stringify(config, null, 4); - const result = await configAPI.saveConfig(configJSON); - + const result = await configAPI.saveConfig(JSON.stringify(config, null, 4)); if (result.startsWith('Error')) { notification.error(result); - } else { - notification.show('Перезапуск HTTP/HTTPS...', 'success', 800); - - await configAPI.stopHTTPService(); - await configAPI.stopHTTPSService(); - await sleep(500); - await configAPI.startHTTPService(); - await configAPI.startHTTPSService(); - - notification.success('Изменения сохранены и применены!', 1000); - await this.proxyManager.load(); - modal.close(); + return; } + + await this.restartHttpServices(); + notification.success('Изменения сохранены и применены!', 1000); + await this.proxyManager.load(); + modal.close(); } - /** - * Добавить кнопку удаления в модальное окно - */ + // Добавить кнопку удаления в модальное окно addDeleteButtonToModal() { const footer = document.querySelector('.modal-footer'); if (!footer) return; @@ -645,17 +494,13 @@ class App { } } - /** - * Удалить кнопку удаления из модального окна - */ + // Удалить кнопку удаления из модального окна removeDeleteButtonFromModal() { const deleteBtn = document.querySelector('#modalDeleteBtn'); if (deleteBtn) deleteBtn.remove(); } - /** - * Подтверждение удаления сайта - */ + // Подтверждение удаления сайта async deleteSiteConfirm() { const index = window.currentEditIndex; const site = this.sitesManager.sitesData[index]; @@ -685,15 +530,7 @@ class App { } notification.success('✅ Сайт успешно удалён!', 1500); - - // Перезапускаем HTTP/HTTPS - notification.show('Перезапуск серверов...', 'success', 800); - await configAPI.stopHTTPService(); - await configAPI.stopHTTPSService(); - await sleep(500); - await configAPI.startHTTPService(); - await configAPI.startHTTPSService(); - + await this.restartHttpServices(); notification.success('🚀 Серверы перезапущены!', 1000); // Закрываем модальное окно и обновляем список @@ -712,5 +549,3 @@ document.addEventListener('DOMContentLoaded', () => { app.start(); }); -log('vServer Admin Panel загружен'); - diff --git a/Backend/admin/frontend/assets/js/ui/custom-select.js b/Backend/admin/frontend/assets/js/ui/custom-select.js index 1dc5cdf..3698306 100644 --- a/Backend/admin/frontend/assets/js/ui/custom-select.js +++ b/Backend/admin/frontend/assets/js/ui/custom-select.js @@ -5,9 +5,7 @@ import { $ } from '../utils/dom.js'; -/** - * Инициализация всех кастомных select'ов на странице - */ +// Инициализация всех кастомных select'ов на странице export function initCustomSelects() { const selects = document.querySelectorAll('select.form-input'); selects.forEach(select => { @@ -17,9 +15,7 @@ export function initCustomSelects() { }); } -/** - * Создать кастомный select из нативного - */ +// Создать кастомный select из нативного function createCustomSelect(selectElement) { // Помечаем как обработанный selectElement.dataset.customized = 'true'; @@ -88,9 +84,7 @@ function createCustomSelect(selectElement) { }); } -/** - * Открыть/закрыть dropdown - */ +// Открыть/закрыть dropdown function toggleDropdown(wrapper) { const isOpen = wrapper.classList.contains('open'); @@ -104,16 +98,12 @@ function toggleDropdown(wrapper) { } } -/** - * Закрыть dropdown - */ +// Закрыть dropdown function closeDropdown(wrapper) { wrapper.classList.remove('open'); } -/** - * Выбрать опцию - */ +// Выбрать опцию function selectOption(selectElement, wrapper, optionElement, index) { // Обновляем оригинальный select selectElement.selectedIndex = index; diff --git a/Backend/admin/frontend/assets/js/ui/modal.js b/Backend/admin/frontend/assets/js/ui/modal.js index 51a7d86..617b5ec 100644 --- a/Backend/admin/frontend/assets/js/ui/modal.js +++ b/Backend/admin/frontend/assets/js/ui/modal.js @@ -5,9 +5,7 @@ import { $, addClass, removeClass } from '../utils/dom.js'; -/** - * Класс для управления модальными окнами - */ +// Класс для управления модальными окнами export class Modal { constructor() { this.overlay = $('modalOverlay'); @@ -46,39 +44,26 @@ export class Modal { } } - /** - * Открыть модальное окно - * @param {string} title - Заголовок - * @param {string} htmlContent - HTML контент - */ + // Открыть модальное окно open(title, htmlContent) { if (this.title) this.title.textContent = title; if (this.content) this.content.innerHTML = htmlContent; if (this.overlay) addClass(this.overlay, 'show'); } - /** - * Закрыть модальное окно - */ + // Закрыть модальное окно close() { if (this.overlay) removeClass(this.overlay, 'show'); } - /** - * Установить обработчик сохранения - * @param {Function} callback - Функция обратного вызова - */ + // Установить обработчик сохранения onSave(callback) { if (this.saveBtn) { this.saveBtn.onclick = callback; } } - /** - * Открыть редактор поля - * @param {string} title - Заголовок - * @param {string} htmlContent - HTML контент - */ + // Открыть редактор поля openFieldEditor(title, htmlContent) { const fieldTitle = $('fieldEditorTitle'); const fieldContent = $('fieldEditorContent'); @@ -88,9 +73,7 @@ export class Modal { if (this.fieldEditorOverlay) addClass(this.fieldEditorOverlay, 'show'); } - /** - * Закрыть редактор поля - */ + // Закрыть редактор поля closeFieldEditor() { if (this.fieldEditorOverlay) removeClass(this.fieldEditorOverlay, 'show'); } diff --git a/Backend/admin/frontend/assets/js/ui/navigation.js b/Backend/admin/frontend/assets/js/ui/navigation.js index df80919..6de3de7 100644 --- a/Backend/admin/frontend/assets/js/ui/navigation.js +++ b/Backend/admin/frontend/assets/js/ui/navigation.js @@ -5,9 +5,7 @@ import { $, $$, hide, show, removeClass, addClass } from '../utils/dom.js'; -/** - * Класс для управления навигацией - */ +// Класс для управления навигацией export class Navigation { constructor() { this.navItems = $$('.nav-item'); diff --git a/Backend/admin/frontend/assets/js/ui/notification.js b/Backend/admin/frontend/assets/js/ui/notification.js index 3ada21d..88383fe 100644 --- a/Backend/admin/frontend/assets/js/ui/notification.js +++ b/Backend/admin/frontend/assets/js/ui/notification.js @@ -5,21 +5,14 @@ import { $, addClass, removeClass } from '../utils/dom.js'; -/** - * Класс для управления уведомлениями - */ +// Класс для управления уведомлениями export class NotificationManager { constructor() { this.container = $('notification'); this.loader = $('appLoader'); } - /** - * Показать уведомление - * @param {string} message - Текст сообщения - * @param {string} type - Тип (success, error) - * @param {number} duration - Длительность показа (мс) - */ + // Показать уведомление show(message, type = 'success', duration = 1000) { if (!this.container) return; @@ -41,27 +34,17 @@ export class NotificationManager { }, duration); } - /** - * Показать успешное уведомление - * @param {string} message - Текст сообщения - * @param {number} duration - Длительность - */ + // Показать успешное уведомление success(message, duration = 1000) { this.show(message, 'success', duration); } - /** - * Показать уведомление об ошибке - * @param {string} message - Текст сообщения - * @param {number} duration - Длительность - */ + // Показать уведомление об ошибке error(message, duration = 2000) { this.show(message, 'error', duration); } - /** - * Скрыть загрузчик приложения - */ + // Скрыть загрузчик приложения hideLoader() { if (!this.loader) return; diff --git a/Backend/admin/frontend/assets/js/ui/window.js b/Backend/admin/frontend/assets/js/ui/window.js index a11b67b..b455e62 100644 --- a/Backend/admin/frontend/assets/js/ui/window.js +++ b/Backend/admin/frontend/assets/js/ui/window.js @@ -5,9 +5,7 @@ import { $, addClass } from '../utils/dom.js'; -/** - * Класс для управления окном - */ +// Класс для управления окном export class WindowControls { constructor() { this.minimizeBtn = $('minimizeBtn'); diff --git a/Backend/admin/frontend/assets/js/utils/dom.js b/Backend/admin/frontend/assets/js/utils/dom.js index 8de0ac7..9e4abee 100644 --- a/Backend/admin/frontend/assets/js/utils/dom.js +++ b/Backend/admin/frontend/assets/js/utils/dom.js @@ -3,47 +3,29 @@ Утилиты для работы с DOM ============================================ */ -/** - * Получить элемент по ID - * @param {string} id - ID элемента - * @returns {HTMLElement|null} - */ +// Получить элемент по ID export function $(id) { return document.getElementById(id); } -/** - * Получить все элементы по селектору - * @param {string} selector - CSS селектор - * @param {HTMLElement} parent - Родительский элемент - * @returns {NodeList} - */ +// Получить все элементы по селектору export function $$(selector, parent = document) { return parent.querySelectorAll(selector); } -/** - * Показать элемент - * @param {HTMLElement|string} element - Элемент или ID - */ +// Показать элемент export function show(element) { const el = typeof element === 'string' ? $(element) : element; if (el) el.style.display = 'block'; } -/** - * Скрыть элемент - * @param {HTMLElement|string} element - Элемент или ID - */ +// Скрыть элемент export function hide(element) { const el = typeof element === 'string' ? $(element) : element; if (el) el.style.display = 'none'; } -/** - * Переключить видимость элемента - * @param {HTMLElement|string} element - Элемент или ID - */ +// Переключить видимость элемента export function toggle(element) { const el = typeof element === 'string' ? $(element) : element; if (el) { @@ -51,31 +33,19 @@ export function toggle(element) { } } -/** - * Добавить класс - * @param {HTMLElement|string} element - Элемент или ID - * @param {string} className - Имя класса - */ +// Добавить класс export function addClass(element, className) { const el = typeof element === 'string' ? $(element) : element; if (el) el.classList.add(className); } -/** - * Удалить класс - * @param {HTMLElement|string} element - Элемент или ID - * @param {string} className - Имя класса - */ +// Удалить класс export function removeClass(element, className) { const el = typeof element === 'string' ? $(element) : element; if (el) el.classList.remove(className); } -/** - * Переключить класс - * @param {HTMLElement|string} element - Элемент или ID - * @param {string} className - Имя класса - */ +// Переключить класс export function toggleClass(element, className) { const el = typeof element === 'string' ? $(element) : element; if (el) el.classList.toggle(className); diff --git a/Backend/admin/frontend/assets/js/utils/helpers.js b/Backend/admin/frontend/assets/js/utils/helpers.js index db9de03..4affc22 100644 --- a/Backend/admin/frontend/assets/js/utils/helpers.js +++ b/Backend/admin/frontend/assets/js/utils/helpers.js @@ -3,21 +3,12 @@ Вспомогательные функции ============================================ */ -/** - * Ждёт указанное время - * @param {number} ms - Миллисекунды - * @returns {Promise} - */ +// Ждёт указанное время export function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } -/** - * Debounce функция - * @param {Function} func - Функция для debounce - * @param {number} wait - Время задержки - * @returns {Function} - */ +// Debounce функция export function debounce(func, wait) { let timeout; return function executedFunction(...args) { @@ -30,28 +21,9 @@ export function debounce(func, wait) { }; } -/** - * Проверяет доступность Wails API - * @returns {boolean} - */ +// Проверяет доступность Wails API export function isWailsAvailable() { return typeof window.go !== 'undefined' && window.go?.admin?.App !== undefined; } -/** - * Логирование с префиксом - * @param {string} message - Сообщение - * @param {string} type - Тип (log, error, warn, info) - */ -export function log(message, type = 'log') { - const prefix = '🚀 vServer:'; - const styles = { - log: '✅', - error: '❌', - warn: '⚠️', - info: 'ℹ️' - }; - console[type](`${prefix} ${styles[type]} ${message}`); -} - diff --git a/Backend/admin/frontend/index.html b/Backend/admin/frontend/index.html index df23220..9e41a24 100644 --- a/Backend/admin/frontend/index.html +++ b/Backend/admin/frontend/index.html @@ -692,6 +692,8 @@ +
+ diff --git a/Backend/admin/frontend/templates.html b/Backend/admin/frontend/templates.html new file mode 100644 index 0000000..2cf3670 --- /dev/null +++ b/Backend/admin/frontend/templates.html @@ -0,0 +1,102 @@ + + + + + + diff --git a/Backend/tools/message.go b/Backend/tools/message.go index 1db6fc6..887f2c6 100644 --- a/Backend/tools/message.go +++ b/Backend/tools/message.go @@ -73,8 +73,16 @@ func Logs_file(type_log int, service string, message string, log_file string, co colored_text := time.Now().Format("2006-01-02 15:04:05") + type_log_str + service_str + message text := RemoveAnsiCodes(colored_text) + "\n" + // Создаём папку logs если её нет + logsDir := "WebServer/tools/logs" + if _, err := os.Stat(logsDir); os.IsNotExist(err) { + if err := os.MkdirAll(logsDir, 0755); err != nil { + log.Fatal(err) + } + } + // Открываем файл для дозаписи, создаём если нет, права на запись. - file, err := os.OpenFile("WebServer/tools/logs/"+log_files, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + file, err := os.OpenFile(logsDir+"/"+log_files, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Fatal(err) } diff --git a/vSerf.exe b/vSerf.exe deleted file mode 100644 index b5ebb5f..0000000 Binary files a/vSerf.exe and /dev/null differ