From fe1a28f97a04ed52e562819f7c728184e4f94338 Mon Sep 17 00:00:00 2001 From: Nikolai Papin Date: Fri, 19 Dec 2025 21:04:07 +0300 Subject: [PATCH] refactor: simplified status page --- frontend/src/public/css/status.css | 49 ++++ frontend/src/public/html/status.html | 378 +++++---------------------- frontend/src/public/js/status.js | 318 ---------------------- 3 files changed, 118 insertions(+), 627 deletions(-) create mode 100644 frontend/src/public/css/status.css delete mode 100644 frontend/src/public/js/status.js diff --git a/frontend/src/public/css/status.css b/frontend/src/public/css/status.css new file mode 100644 index 0000000..5717782 --- /dev/null +++ b/frontend/src/public/css/status.css @@ -0,0 +1,49 @@ +/* Стили для страницы с проверкой подключения к бекенду */ + body { + font-family: Arial, sans-serif; + margin: 50px; + text-align: center; + } + + h1 { + color: #333; + } + + .status { + font-size: 24px; + margin: 30px; + padding: 20px; + border-radius: 10px; + display: inline-block; + } + + .online { + background-color: #d4edda; + color: #155724; + border: 2px solid #c3e6cb; + } + + .offline { + background-color: #f8d7da; + color: #721c24; + border: 2px solid #f5c6cb; + } + + .checking { + background-color: #fff3cd; + color: #856404; + border: 2px solid #ffeaa7; + } + + .info { + margin-top: 20px; + padding: 10px; + background-color: #f8f9fa; + border-radius: 5px; + display: inline-block; + } + + .url { + color: #0066cc; + font-weight: bold; + } diff --git a/frontend/src/public/html/status.html b/frontend/src/public/html/status.html index 05dab41..760809e 100644 --- a/frontend/src/public/html/status.html +++ b/frontend/src/public/html/status.html @@ -3,318 +3,78 @@ - Проверка связи с Backend - + Проверка сервера + + -
-
-

🔍 Проверка связи

-

Мониторинг подключения к Backend серверу

-
- - - -
-
-
Статус Backend сервера
-
Проверка...
-
- -
-
- Backend URL: - Загрузка... -
-
- Статус: - Проверяется... -
-
- Время ответа: - -
-
- Последняя проверка: - -
-
-
- -
- - -
- -
-
Журнал проверок:
-
-
+

Проверка сервера

+ +
+ Проверяем подключение... +
+ +
+ Адрес: http://localhost:3000
+ Время ответа: +
+ + - + diff --git a/frontend/src/public/js/status.js b/frontend/src/public/js/status.js deleted file mode 100644 index 06effd5..0000000 --- a/frontend/src/public/js/status.js +++ /dev/null @@ -1,318 +0,0 @@ -class BackendMonitor { - constructor() { - this.config = null; - this.isChecking = false; - this.autoCheckInterval = null; - this.autoCheckEnabled = false; - this.checkInterval = 30000; // 30 секунд - this.logs = []; - - this.init(); - } - - async init() { - await this.loadConfig(); - await this.checkBackend(); - - // Начинаем автопроверку если в конфиге указано - if (this.config?.autoCheck === true) { - this.enableAutoCheck(); - } - } - - async loadConfig() { - try { - // Пробуем загрузить конфиг с сервера - const response = await fetch('/config.json'); - if (!response.ok) throw new Error('Failed to load config'); - - this.config = await response.json(); - this.updateUI('configLoaded'); - - } catch (error) { - console.warn('Не удалось загрузить конфигурацию:', error); - - // Используем запасную конфигурацию - this.config = { - backendUrl: 'http://localhost:3000', - healthCheckEndpoint: '/', - timeout: 5000, - environment: 'fallback', - autoCheck: false - }; - - this.showConfigWarning(); - this.updateUI('configFallback'); - } - } - - async checkBackend() { - if (this.isChecking) return; - - this.isChecking = true; - this.updateUI('checking'); - - const startTime = Date.now(); - let isSuccess = false; - let responseTime = null; - let errorMessage = null; - let details = {}; - - try { - // Проверяем доступность сервера - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), this.config.timeout || 10000); - - const response = await fetch(this.config.backendUrl + (this.config.healthCheckEndpoint || ''), { - method: 'GET', - headers: { - 'Accept': 'application/json', - }, - signal: controller.signal - }); - - clearTimeout(timeoutId); - - responseTime = Date.now() - startTime; - - if (response.ok) { - isSuccess = true; - try { - const data = await response.json(); - details = data; - } catch (e) { - details = { message: 'Сервер доступен' }; - } - } else { - errorMessage = `HTTP ${response.status}: ${response.statusText}`; - } - - } catch (error) { - responseTime = Date.now() - startTime; - errorMessage = this.getErrorMessage(error); - } - - this.isChecking = false; - - // Записываем лог - this.addLog(isSuccess, responseTime, errorMessage, details); - - // Обновляем UI - this.updateUI(isSuccess ? 'success' : 'error', { - responseTime, - errorMessage, - details - }); - } - - getErrorMessage(error) { - if (error.name === 'AbortError') { - return 'Таймаут запроса'; - } - if (error.message.includes('Failed to fetch')) { - return 'Сеть недоступна'; - } - if (error.message.includes('net::ERR_CONNECTION_REFUSED')) { - return 'Соединение отклонено'; - } - return error.message || 'Неизвестная ошибка'; - } - - addLog(isSuccess, responseTime, errorMessage, details) { - const timestamp = new Date().toLocaleTimeString(); - const logEntry = { - timestamp, - success: isSuccess, - responseTime, - errorMessage, - details, - type: isSuccess ? 'success' : 'error' - }; - - this.logs.unshift(logEntry); // Добавляем в начало - - // Храним только последние 10 записей - if (this.logs.length > 10) { - this.logs.pop(); - } - - this.updateLogsUI(); - } - - updateLogsUI() { - const logContainer = document.getElementById('logEntries'); - if (!logContainer) return; - - logContainer.innerHTML = this.logs.map(log => ` -
- [${log.timestamp}] - ${log.success - ? `✅ Успешно (${log.responseTime}ms)` - : `❌ Ошибка: ${log.errorMessage}` - } -
- `).join(''); - } - - updateUI(state, data = {}) { - const statusCard = document.getElementById('statusCard'); - const statusIndicator = document.getElementById('statusIndicator'); - const backendUrl = document.getElementById('backendUrl'); - const backendStatus = document.getElementById('backendStatus'); - const responseTime = document.getElementById('responseTime'); - const lastCheck = document.getElementById('lastCheck'); - const checkBtn = document.getElementById('checkBtn'); - - if (!statusCard) return; - - switch(state) { - case 'configLoaded': - backendUrl.textContent = this.config.backendUrl; - backendUrl.className = 'detail-value success'; - break; - - case 'configFallback': - backendUrl.textContent = `${this.config.backendUrl} (запасной)`; - backendUrl.className = 'detail-value error'; - break; - - case 'checking': - statusCard.className = 'status-card'; - statusIndicator.textContent = 'Проверка...'; - statusIndicator.className = 'status-indicator offline'; - backendStatus.textContent = 'Выполняется проверка...'; - backendStatus.className = 'detail-value'; - checkBtn.disabled = true; - checkBtn.innerHTML = ' Проверка...'; - break; - - case 'success': - statusCard.className = 'status-card active'; - statusIndicator.textContent = 'Online'; - statusIndicator.className = 'status-indicator online'; - backendStatus.textContent = '✅ Сервер доступен'; - backendStatus.className = 'detail-value success'; - responseTime.textContent = `${data.responseTime} ms`; - lastCheck.textContent = new Date().toLocaleTimeString(); - checkBtn.disabled = false; - checkBtn.innerHTML = '🔄 Проверить соединение'; - break; - - case 'error': - statusCard.className = 'status-card error'; - statusIndicator.textContent = 'Offline'; - statusIndicator.className = 'status-indicator offline'; - backendStatus.textContent = `❌ ${data.errorMessage}`; - backendStatus.className = 'detail-value error'; - responseTime.textContent = data.responseTime ? `${data.responseTime} ms` : '—'; - lastCheck.textContent = new Date().toLocaleTimeString(); - checkBtn.disabled = false; - checkBtn.innerHTML = '🔄 Проверить соединение'; - break; - } - } - - showConfigWarning() { - const warning = document.getElementById('configWarning'); - if (warning) { - warning.style.display = 'block'; - } - } - - toggleAutoCheck() { - if (this.autoCheckEnabled) { - this.disableAutoCheck(); - } else { - this.enableAutoCheck(); - } - } - - enableAutoCheck() { - this.autoCheckEnabled = true; - this.autoCheckInterval = setInterval(() => { - this.checkBackend(); - }, this.checkInterval); - - const btn = document.getElementById('autoCheckBtn'); - if (btn) { - btn.innerHTML = '⏸️ Автопроверка: ВКЛ'; - } - - this.addLog(false, null, null, { type: 'info', message: 'Автопроверка включена' }); - } - - disableAutoCheck() { - this.autoCheckEnabled = false; - if (this.autoCheckInterval) { - clearInterval(this.autoCheckInterval); - this.autoCheckInterval = null; - } - - const btn = document.getElementById('autoCheckBtn'); - if (btn) { - btn.innerHTML = '⏱️ Автопроверка: ВЫКЛ'; - } - - this.addLog(false, null, null, { type: 'info', message: 'Автопроверка выключена' }); - } - - // Дополнительные проверки - async runExtendedTests() { - const tests = [ - { name: 'Пинг сервера', endpoint: '' }, - { name: 'API Health', endpoint: this.config.healthCheckEndpoint || '/' }, - { name: 'Версия API', endpoint: '/api/version' } - ]; - - const results = []; - - for (const test of tests) { - try { - const start = Date.now(); - const response = await fetch(this.config.backendUrl + test.endpoint, { - signal: AbortSignal.timeout(5000) - }); - const time = Date.now() - start; - - results.push({ - name: test.name, - success: response.ok, - time, - status: response.status - }); - } catch (error) { - results.push({ - name: test.name, - success: false, - time: null, - error: error.message - }); - } - } - - return results; - } -} - -// Глобальные функции для вызова из HTML -let monitor; - -function checkBackend() { - if (!monitor) { - monitor = new BackendMonitor(); - } else { - monitor.checkBackend(); - } -} - -function toggleAutoCheck() { - if (!monitor) { - monitor = new BackendMonitor(); - } - monitor.toggleAutoCheck(); -} - -// Инициализация при загрузке страницы -document.addEventListener('DOMContentLoaded', () => { - monitor = new BackendMonitor(); -});