refactor: simplified status page
This commit is contained in:
49
frontend/src/public/css/status.css
Normal file
49
frontend/src/public/css/status.css
Normal file
@@ -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;
|
||||||
|
}
|
||||||
@@ -3,318 +3,78 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Проверка связи с Backend</title>
|
<title>Проверка сервера</title>
|
||||||
<style>
|
<link rel="stylesheet" href="../css/normalize.css">
|
||||||
* {
|
<link rel="stylesheet" href="../css/status.css">
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
background: white;
|
|
||||||
border-radius: 20px;
|
|
||||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
||||||
padding: 40px;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header h1 {
|
|
||||||
color: #333;
|
|
||||||
font-size: 2.5rem;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header p {
|
|
||||||
color: #666;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-card {
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 15px;
|
|
||||||
padding: 30px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
border-left: 5px solid #6c757d;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-card.active {
|
|
||||||
border-left-color: #28a745;
|
|
||||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-card.error {
|
|
||||||
border-left-color: #dc3545;
|
|
||||||
background: linear-gradient(135deg, #f8d7da 0%, #f5c6cb 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-info {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-title {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
color: #333;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-indicator {
|
|
||||||
padding: 8px 20px;
|
|
||||||
border-radius: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-indicator.offline {
|
|
||||||
background: #dc3545;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-indicator.online {
|
|
||||||
background: #28a745;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-details {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 10px 0;
|
|
||||||
border-bottom: 1px solid #dee2e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-item:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-label {
|
|
||||||
color: #666;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-value {
|
|
||||||
color: #333;
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
font-weight: 600;
|
|
||||||
max-width: 300px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-value.success {
|
|
||||||
color: #28a745;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-value.error {
|
|
||||||
color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
flex: 1;
|
|
||||||
padding: 15px 25px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 10px;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary {
|
|
||||||
background: #f8f9fa;
|
|
||||||
color: #333;
|
|
||||||
border: 2px solid #dee2e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary:hover {
|
|
||||||
background: #e9ecef;
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: not-allowed;
|
|
||||||
transform: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
display: inline-block;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border: 3px solid rgba(255,255,255,.3);
|
|
||||||
border-radius: 50%;
|
|
||||||
border-top-color: white;
|
|
||||||
animation: spin 1s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-container {
|
|
||||||
margin-top: 30px;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 20px;
|
|
||||||
max-height: 200px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-title {
|
|
||||||
color: #333;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-entry {
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
padding: 5px 0;
|
|
||||||
border-bottom: 1px solid #dee2e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-entry:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-entry.success {
|
|
||||||
color: #28a745;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-entry.error {
|
|
||||||
color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-entry.info {
|
|
||||||
color: #17a2b8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timestamp {
|
|
||||||
color: #6c757d;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.config-warning {
|
|
||||||
background: #fff3cd;
|
|
||||||
border: 1px solid #ffeaa7;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 15px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
color: #856404;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
.container {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<h1>Проверка сервера</h1>
|
||||||
<div class="header">
|
|
||||||
<h1>🔍 Проверка связи</h1>
|
|
||||||
<p>Мониторинг подключения к Backend серверу</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="config-warning" id="configWarning" style="display: none;">
|
<div id="status" class="status checking">
|
||||||
⚠️ Конфигурация загружена с запасного URL. Проверьте подключение.
|
Проверяем подключение...
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-card" id="statusCard">
|
|
||||||
<div class="status-info">
|
|
||||||
<div class="status-title">Статус Backend сервера</div>
|
|
||||||
<div class="status-indicator offline" id="statusIndicator">Проверка...</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="status-details">
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Backend URL:</span>
|
|
||||||
<span class="detail-value" id="backendUrl">Загрузка...</span>
|
|
||||||
</div>
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Статус:</span>
|
|
||||||
<span class="detail-value" id="backendStatus">Проверяется...</span>
|
|
||||||
</div>
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Время ответа:</span>
|
|
||||||
<span class="detail-value" id="responseTime">—</span>
|
|
||||||
</div>
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Последняя проверка:</span>
|
|
||||||
<span class="detail-value" id="lastCheck">—</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="actions">
|
|
||||||
<button class="btn btn-primary" id="checkBtn" onclick="checkBackend()">
|
|
||||||
<span>🔄 Проверить соединение</span>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-secondary" id="autoCheckBtn" onclick="toggleAutoCheck()">
|
|
||||||
<span>⏱️ Автопроверка: ВЫКЛ</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="log-container">
|
|
||||||
<div class="log-title">Журнал проверок:</div>
|
|
||||||
<div id="logEntries"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/status.js"></script>
|
<div id="info" class="info">
|
||||||
|
Адрес: <span id="url" class="url">http://localhost:3000</span><br>
|
||||||
|
Время ответа: <span id="time">—</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="error" class="error hidden">
|
||||||
|
<strong>Ошибка:</strong> <span id="error-message"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Простая функция проверки сервера
|
||||||
|
async function checkServer() {
|
||||||
|
const statusElement = document.getElementById('status');
|
||||||
|
const timeElement = document.getElementById('time');
|
||||||
|
const urlElement = document.getElementById('url');
|
||||||
|
const errorElement = document.getElementById('error');
|
||||||
|
const errorMessageElement = document.getElementById('error-message');
|
||||||
|
const serverUrl = 'http://localhost:3000';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Пытаемся подключиться к серверу
|
||||||
|
const startTime = new Date();
|
||||||
|
const response = await fetch(serverUrl);
|
||||||
|
const endTime = new Date();
|
||||||
|
|
||||||
|
// Вычисляем время ответа
|
||||||
|
const responseTime = endTime - startTime;
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
// Сервер доступен
|
||||||
|
statusElement.textContent = '✅ Сервер работает!';
|
||||||
|
statusElement.className = 'status online';
|
||||||
|
timeElement.textContent = responseTime + ' мс';
|
||||||
|
|
||||||
|
// Скрываем сообщение об ошибке
|
||||||
|
errorElement.classList.add('hidden');
|
||||||
|
} else {
|
||||||
|
// Сервер ответил с ошибкой
|
||||||
|
statusElement.textContent = '❌ Ошибка подключения';
|
||||||
|
statusElement.className = 'status offline';
|
||||||
|
timeElement.textContent = responseTime + ' мс';
|
||||||
|
|
||||||
|
// Показываем детали ошибки
|
||||||
|
errorMessageElement.textContent =
|
||||||
|
'HTTP ' + response.status + ': ' + response.statusText;
|
||||||
|
errorElement.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Не удалось подключиться к серверу
|
||||||
|
statusElement.textContent = '❌ Сервер недоступен';
|
||||||
|
statusElement.className = 'status offline';
|
||||||
|
timeElement.textContent = '—';
|
||||||
|
|
||||||
|
// Показываем детали ошибки
|
||||||
|
errorMessageElement.textContent = error.message;
|
||||||
|
errorElement.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запускаем проверку при загрузке страницы
|
||||||
|
window.onload = checkServer;
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -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 => `
|
|
||||||
<div class="log-entry ${log.type}">
|
|
||||||
<span class="timestamp">[${log.timestamp}]</span>
|
|
||||||
${log.success
|
|
||||||
? `✅ Успешно (${log.responseTime}ms)`
|
|
||||||
: `❌ Ошибка: ${log.errorMessage}`
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
`).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 = '<span class="loading"></span> Проверка...';
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user