const ACTION_LABELS = { 'auth.login': 'Вход в систему', 'settings.update': 'Изменены настройки', 'user.create': 'Создан пользователь', 'user.update': 'Изменён пользователь', 'user.delete': 'Удалён пользователь', 'ip.ban': 'Заблокирован IP-адрес', 'ip.unban': 'Разблокирован IP-адрес', 'group.create': 'Создана группа', 'group.update': 'Изменена группа', 'group.delete': 'Удалена группа', 'group.photo.create': 'Загружена фото группы', 'group.photo.update': 'Изменено фото группы', 'group.photo.reorder': 'Изменён порядок фото группы', 'group.photo.set_cover': 'Обновлена обложка группы', 'group.photo.delete': 'Удалено фото группы', 'branch.create': 'Создан филиал', 'branch.update': 'Изменён филиал', 'branch.delete': 'Удалён филиал', 'student.create': 'Добавлен ученик', 'student.update': 'Изменён ученик', 'student.delete': 'Удалён ученик', 'student.batch-group': 'Ученики перенесены в группу', 'entry.update': 'Изменена запись', 'entry.photo.update': 'Изменено фото записи', 'entry.photo.set_main': 'Главное фото записи', 'entry.photo.delete': 'Удалено фото записи', 'entry.soft-delete': 'Запись в корзину', 'entry.restore': 'Запись восстановлена', 'entry.permanent-delete': 'Запись удалена безвозвратно', 'link.create': 'Создана ссылка', 'link.update': 'Изменена ссылка', 'link.delete': 'Удалена ссылка', 'backup.download': 'Скачан бэкап', 'backup.restore': 'Выполнено восстановление', 'entry.ai.auto-check': 'ИИ-автопроверка записи', 'entry.ai.retry': 'Повтор ИИ-проверки записи', 'entry.ai.recheck': 'Запись отправлена на ИИ-проверку', 'entry.ai.revert': 'Возвращён оригинал текста записи', 'entry.ai.error': 'Ошибка ИИ-проверки записи', 'ai.wake': 'Воркер ИИ разбужен вручную', 'ai.enabled': 'Переключена автопроверка ИИ', 'ai.requeue-failed': 'Ошибочные записи возвращены в очередь ИИ', }; const AUDIT_PAGE_SIZE = 50; let auditPage = 1; let auditTotal = 0; let auditRows = []; function fmtTime(t) { try { return new Date(t).toLocaleString('ru'); } catch { return t || ''; } } function dt(t) { if (!t) return ''; if (typeof t === 'object') { return esc(JSON.stringify(t).slice(0, 120)); } try { const o = JSON.parse(t); return esc(JSON.stringify(o).slice(0, 120)); } catch { return esc(String(t).slice(0, 120)); } } function fullTarget(t) { if (!t) return ''; if (typeof t === 'object') return JSON.stringify(t, null, 2); try { return JSON.stringify(JSON.parse(t), null, 2); } catch { return String(t); } } function renderPager(container, page, totalPages, onPageChange) { if (totalPages <= 1) { container.innerHTML = ''; return; } const pages = []; const maxVisible = 5; let start = Math.max(1, page - Math.floor(maxVisible / 2)); let end = Math.min(totalPages, start + maxVisible - 1); if (end - start + 1 < maxVisible) start = Math.max(1, end - maxVisible + 1); for (let i = start; i <= end; i++) pages.push(i); let html = ''; if (page > 1) html += ``; if (start > 1) { html += ``; if (start > 2) html += `…`; } for (const p of pages) html += ``; if (end < totalPages) { if (end < totalPages - 1) html += `…`; html += ``; } if (page < totalPages) html += ``; container.innerHTML = html; container.querySelectorAll('button').forEach(b => b.addEventListener('click', () => onPageChange(parseInt(b.dataset.page, 10)))); } async function loadAudit() { const el = document.getElementById('auditTable').querySelector('tbody'); el.innerHTML = '