function loadClients() { fetch('clients.php') .then(response => response.json()) .then(data => { console.log('Загруженные клиенты:', data); renderClientTable(data); }) .catch(error => { console.error('Ошибка загрузки данных:', error); document.getElementById('client-table').innerHTML = 'Ошибка загрузки'; }); } function renderClientTable(clients) { const table = document.getElementById('client-table'); table.innerHTML = ''; const stats = { LZO: 0, ADAPTIVE: 0, STUB: 0, '—': 0 }; clients.forEach(client => { const row = document.createElement('tr'); // TLS ошибка if (client.tls_error) { row.classList.add('tls-error'); row.title = client.tls_error; } // Сжатие const compression = (client.compression || '—').toUpperCase(); stats[compression] = (stats[compression] || 0) + 1; let compressionClass = 'compression-none'; if (compression === 'LZO') compressionClass = 'compression-lzo'; else if (compression === 'ADAPTIVE') compressionClass = 'compression-adaptive'; else if (compression === 'STUB') compressionClass = 'compression-stub'; // Потери let lossClass = ''; if (client.loss_rate >= 10) lossClass = 'loss-high'; else if (client.loss_rate >= 1) lossClass = 'loss-medium'; row.innerHTML = ` ${client.name} ${client.real_ip} ${client.virtual_ip} ${client.connectedSince} ${formatBytes(client.bytes_received)} ${formatBytes(client.bytes_sent)} ${client.statusLabel} ${client.idleTime || '—'} ${compression} ${client.packets_received ?? '—'} ${client.packets_lost ?? '—'} ${client.loss_rate ?? '—'}% `; table.appendChild(row); }); renderCompressionStats(stats); } function renderCompressionStats(stats) { const container = document.getElementById('compression-stats'); container.innerHTML = ` Сжатие: LZO: ${stats.LZO || 0}, Adaptive: ${stats.ADAPTIVE || 0}, Stub: ${stats.STUB || 0}, Нет: ${stats['—'] || 0} `; } function formatBytes(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; } function loadTlsErrors() { fetch('api/tls-errors.php') .then(res => res.json()) .then(data => { const container = document.getElementById('tls-errors'); container.innerHTML = ''; if (data.tls_errors && data.tls_errors.length > 0) { data.tls_errors.forEach(err => { const div = document.createElement('div'); div.textContent = err; container.appendChild(div); }); } else { container.textContent = 'Нет TLS ошибок.'; } }) .catch(() => { document.getElementById('tls-errors').textContent = 'Ошибка загрузки данных.'; }); } document.addEventListener('DOMContentLoaded', () => { // Вкладки const buttons = document.querySelectorAll('.tab-button'); const tabs = document.querySelectorAll('.tab-content'); buttons.forEach(btn => { btn.addEventListener('click', () => { buttons.forEach(b => b.classList.remove('active')); tabs.forEach(t => t.classList.remove('active')); btn.classList.add('active'); document.getElementById('tab-' + btn.dataset.tab).classList.add('active'); }); }); // Загрузка данных loadClients(); loadTlsErrors(); setInterval(loadClients, 5000); setInterval(loadTlsErrors, 10000); });