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 обновлены
This commit is contained in:
@@ -406,6 +406,27 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;b
|
||||
.audit-details:hover{text-decoration:underline}
|
||||
.audit-details-body{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:12px;max-height:60vh;overflow:auto}
|
||||
.audit-details-body pre{margin:0;white-space:pre-wrap;word-break:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.78rem;line-height:1.45;color:var(--text)}
|
||||
.audit-details-body.audit-loading{opacity:.6}
|
||||
.audit-details-head{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}
|
||||
.audit-pill{background:var(--card);border:1px solid var(--border);border-radius:999px;padding:3px 10px;font-size:.72rem;color:var(--muted)}
|
||||
.audit-changes{display:flex;flex-direction:column;gap:12px}
|
||||
.audit-change{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:10px 12px}
|
||||
.audit-change-title{font-weight:600;font-size:.82rem;margin-bottom:6px}
|
||||
.audit-change-stats{display:flex;flex-wrap:wrap;gap:10px;font-size:.75rem;margin-bottom:8px}
|
||||
.audit-change-line{font-size:.8rem;line-height:1.6;word-break:break-word}
|
||||
.audit-tag-del,.audit-tag-add{display:inline-block;min-width:52px;font-size:.7rem;text-transform:uppercase;letter-spacing:.03em;padding:1px 6px;border-radius:4px;margin-right:6px}
|
||||
.audit-tag-del{background:rgba(239,68,68,.14);color:#dc2626}
|
||||
.audit-tag-add{background:rgba(22,163,74,.14);color:#16a34a}
|
||||
.audit-stat-add{color:#16a34a;font-weight:600}
|
||||
.audit-stat-del{color:#dc2626;font-weight:600}
|
||||
.audit-stat-muted{color:var(--muted)}
|
||||
.audit-diff{white-space:pre-wrap;word-break:break-word;font-size:.85rem;line-height:1.6;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:10px;max-height:40vh;overflow:auto}
|
||||
.audit-diff-add{background:rgba(22,163,74,.18);color:#14532d;text-decoration:none;border-radius:3px;padding:0 2px}
|
||||
.audit-diff-del{background:rgba(239,68,68,.16);color:#7f1d1d;border-radius:3px;padding:0 2px}
|
||||
.audit-truncated{margin-top:6px;font-size:.72rem;color:#b45309}
|
||||
.audit-raw{margin-top:12px;font-size:.78rem;color:var(--muted)}
|
||||
.audit-raw summary{cursor:pointer}
|
||||
.audit-raw pre{margin-top:8px;background:var(--card);border:1px solid var(--border);border-radius:6px;padding:10px}
|
||||
|
||||
/* --- AI Correction --- */
|
||||
.ai-btn{background:none;border:none;color:var(--muted);cursor:pointer;font-size:1.1rem;padding:4px 8px;border-radius:6px;transition:color .15s,background .15s;vertical-align:middle;margin-left:6px}
|
||||
|
||||
Reference in New Issue
Block a user