Files
crm.clientright.ru/view_server_logs.html

341 lines
11 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Просмотр серверных логов AI Drawer</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 2px solid #007bff;
}
.status {
padding: 10px 15px;
border-radius: 5px;
font-weight: bold;
}
.status.success {
background: #d4edda;
color: #155724;
}
.status.error {
background: #f8d7da;
color: #721c24;
}
.status.warning {
background: #fff3cd;
color: #856404;
}
.controls {
margin-bottom: 20px;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
}
.btn-primary {
background: #007bff;
color: white;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-danger {
background: #dc3545;
color: white;
}
.btn:hover {
opacity: 0.8;
}
.log-container {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 5px;
padding: 15px;
max-height: 600px;
overflow-y: auto;
font-family: 'Courier New', monospace;
font-size: 12px;
white-space: pre-wrap;
}
.log-entry {
margin: 5px 0;
padding: 8px;
border-radius: 3px;
border-left: 4px solid #ccc;
}
.log-info {
border-left-color: #17a2b8;
background: #d1ecf1;
}
.log-success {
border-left-color: #28a745;
background: #d4edda;
}
.log-warning {
border-left-color: #ffc107;
background: #fff3cd;
}
.log-error {
border-left-color: #dc3545;
background: #f8d7da;
}
.log-debug {
border-left-color: #6c757d;
background: #e2e3e5;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: #f8f9fa;
padding: 15px;
border-radius: 5px;
border-left: 4px solid #007bff;
}
.stat-title {
font-size: 12px;
color: #6c757d;
margin-bottom: 5px;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #007bff;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>📋 Серверные логи AI Drawer</h1>
<div id="server-status" class="status">Проверка...</div>
</div>
<div class="stats" id="stats-container">
<!-- Статистика будет загружена здесь -->
</div>
<div class="controls">
<button class="btn btn-primary" onclick="loadLogs()">🔄 Обновить</button>
<button class="btn btn-secondary" onclick="loadLogs(100)">📄 Последние 100</button>
<button class="btn btn-secondary" onclick="loadLogs(500)">📄 Последние 500</button>
<button class="btn btn-danger" onclick="clearLogs()">🗑️ Очистить все</button>
<button class="btn btn-secondary" onclick="exportLogs()">💾 Экспорт</button>
</div>
<div id="log-container" class="log-container">
Загрузка логов...
</div>
</div>
<script>
let currentLogs = [];
function updateStatus(message, type = 'info') {
const statusEl = document.getElementById('server-status');
statusEl.textContent = message;
statusEl.className = `status ${type}`;
}
function updateStats(logs) {
const statsContainer = document.getElementById('stats-container');
const totalLogs = logs.length;
const errorLogs = logs.filter(log => log.data.type === 'error').length;
const warningLogs = logs.filter(log => log.data.type === 'warning').length;
const successLogs = logs.filter(log => log.data.type === 'success').length;
const uniqueDevices = new Set(logs.map(log => log.data.screenSize)).size;
const uniqueBrowsers = new Set(logs.map(log => log.data.userAgent?.split(' ')[0])).size;
statsContainer.innerHTML = `
<div class="stat-card">
<div class="stat-title">Всего записей</div>
<div class="stat-value">${totalLogs}</div>
</div>
<div class="stat-card">
<div class="stat-title">Ошибки</div>
<div class="stat-value" style="color: #dc3545;">${errorLogs}</div>
</div>
<div class="stat-card">
<div class="stat-title">Предупреждения</div>
<div class="stat-value" style="color: #ffc107;">${warningLogs}</div>
</div>
<div class="stat-card">
<div class="stat-title">Успешные</div>
<div class="stat-value" style="color: #28a745;">${successLogs}</div>
</div>
<div class="stat-card">
<div class="stat-title">Устройства</div>
<div class="stat-value">${uniqueDevices}</div>
</div>
<div class="stat-card">
<div class="stat-title">Браузеры</div>
<div class="stat-value">${uniqueBrowsers}</div>
</div>
`;
}
function displayLogs(logs) {
const container = document.getElementById('log-container');
currentLogs = logs;
if (logs.length === 0) {
container.innerHTML = 'Логи не найдены';
return;
}
const logHTML = logs.map(log => {
const type = log.data.type || 'info';
const details = log.data.details ?
`\nДетали: ${JSON.stringify(log.data.details, null, 2)}` : '';
return `
<div class="log-entry log-${type}">
<strong>[${log.timestamp}] ${log.data.type?.toUpperCase() || 'INFO'}:</strong> ${log.data.message}
${details}
<div style="margin-top: 5px; font-size: 10px; color: #6c757d;">
Устройство: ${log.data.screenSize || 'N/A'} |
Браузер: ${log.data.userAgent?.split(' ')[0] || 'N/A'}
</div>
</div>
`;
}).join('');
container.innerHTML = logHTML;
updateStats(logs);
}
function loadLogs(limit = 50) {
updateStatus('Загрузка логов...', 'info');
fetch(`/test_log_server.php?action=read&limit=${limit}`)
.then(response => response.json())
.then(data => {
if (data.success) {
displayLogs(data.logs);
updateStatus(`Загружено ${data.logs.length} записей`, 'success');
} else {
updateStatus(`Ошибка: ${data.message}`, 'error');
}
})
.catch(error => {
updateStatus(`Ошибка подключения: ${error.message}`, 'error');
});
}
function clearLogs() {
if (!confirm('Вы уверены, что хотите очистить все логи?')) {
return;
}
updateStatus('Очистка логов...', 'warning');
fetch('/test_log_server.php?action=clear')
.then(response => response.json())
.then(data => {
if (data.success) {
updateStatus('Логи очищены', 'success');
document.getElementById('log-container').innerHTML = 'Логи очищены';
document.getElementById('stats-container').innerHTML = '';
} else {
updateStatus(`Ошибка: ${data.message}`, 'error');
}
})
.catch(error => {
updateStatus(`Ошибка подключения: ${error.message}`, 'error');
});
}
function exportLogs() {
if (currentLogs.length === 0) {
alert('Нет логов для экспорта');
return;
}
const logText = currentLogs.map(log => {
const details = log.data.details ?
`\nДетали: ${JSON.stringify(log.data.details, null, 2)}` : '';
return `[${log.timestamp}] ${log.data.type?.toUpperCase() || 'INFO'}: ${log.data.message}${details}`;
}).join('\n\n');
const blob = new Blob([logText], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `ai-drawer-server-logs-${new Date().toISOString().slice(0, 19)}.txt`;
a.click();
URL.revokeObjectURL(url);
updateStatus('Логи экспортированы', 'success');
}
// Загружаем логи при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
loadLogs();
// Автообновление каждые 30 секунд
setInterval(() => {
loadLogs();
}, 30000);
});
</script>
</body>
</html>