Files
WhatIDo/public/audit.html
T
dev 54cf5bbfa4 feat(audit): показывать изменения текста записи по шагам
При сохранении записи журнала (PUT /api/entries/:id) сравнивается
состояние до и после, и в audit_log пишется не только факт правки,
но и сами изменения: пословный дифф текста, статистика добавленных
и удалённых слов, а также смена ФИО, группы и темы модуля.

- diff.js: пословный LCS-дифф без зависимостей, обрезка больших
  текстов, сборка изменений по полям записи, облегчённый target
  для списка аудита
- source правки: manual / ai / ai_manual / ai_revert; журнал шлёт
  edit_source, сервер доверяет явному значению и определяет источник
  по description_ai как запасной вариант
- те же диффы пишутся для автопроверки ИИ (entry.ai.auto-check)
  и отката к оригиналу (entry.ai.revert)
- GET /api/audit отдаёт список без diff, GET /api/audit/:id — полный
  target, чтобы не грузить килобайты текста на каждую строку
- Аудит: колонка «Кто», сводка в таблице, модалка с подсветкой
  удалённого и добавленного текста, «было/стало» для полей
- auth.login теперь пишет user_id, иначе колонка «Кто» показывала
  «система»
- diff.selftest.js: 16 тестов диффа; README и AGENTS обновлены
2026-09-27 11:29:17 +03:00

60 lines
2.1 KiB
HTML

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Аудит — Админ-панель</title>
<link rel="stylesheet" href="admin.css">
</head>
<body data-page="audit">
<div class="layout">
<div class="sidebar" id="sidebar"></div>
<div class="main">
<div class="page-head">
<h2>Аудит-журнал</h2>
<p class="page-sub">Действия администратора</p>
</div>
<div class="actions-row">
<select id="auditActionFilter" class="settings-input" style="max-width:280px">
<option value="">Все действия</option>
</select>
<input type="search" id="auditFilter" class="settings-input" placeholder="Фильтр по действию..." style="max-width:300px">
<button class="btn-link" id="auditRefreshBtn" type="button" title="Обновить">Обновить</button>
<span class="hint" id="auditCount"></span>
</div>
<div class="audit-wrap" style="margin-top:14px">
<table class="audit-table" id="auditTable">
<thead>
<tr>
<th>Время</th>
<th>Кто</th>
<th>Действие</th>
<th>Детали</th>
<th>IP</th>
</tr>
</thead>
<tbody></tbody>
</table>
<div class="empty" id="auditEmpty" style="display:none">Записей пока нет.</div>
</div>
<div class="pager" id="auditPager"></div>
</div>
</div>
<div class="modal-overlay" id="auditDetailsModal">
<div class="edit-modal" style="max-width:820px">
<h3 id="auditDetailsTitle">Детали действия</h3>
<div class="audit-details-head" id="auditDetailsHead"></div>
<div class="audit-details-body" id="auditDetailsBody"></div>
<div class="card-foot" style="justify-content:flex-end;gap:8px">
<button type="button" class="cancel" id="auditDetailsCloseBtn">Закрыть</button>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="vendor/lucide.min.js"></script>
<script src="admin.js"></script>
<script src="js/audit.js"></script>
</body>
</html>