Files
WhatIDo/public/trash.html
T

119 lines
4.4 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="trash">
<div class="layout">
<div class="sidebar" id="sidebar"></div>
<div class="main">
<h2>Корзина</h2>
<div class="trash-head">
<span class="trash-muted" id="trashInfo"></span>
<button class="danger-btn" id="emptyBtn" onclick="emptyTrash()">Очистить корзину</button>
</div>
<div class="grid" id="grid"><div class="empty">Загрузка...</div></div>
<div class="pager" id="pager"></div>
</div>
</div>
<div class="modal-overlay" id="imgModal" onclick="this.classList.remove('open')">
<img id="imgModalSrc">
</div>
<div class="toast" id="toast"></div>
<script src="admin.js"></script>
<script>
const PAGE_SIZE = 20;
let currentEntries = [];
let page = 1;
let totalEntries = 0;
function isImageFile(name) {
return /\.(jpe?g|png|gif|webp|bmp|avif|svg|ico)$/i.test(name || '');
}
function filesHTML(files) {
if (!files || !files.length) return '';
return `<div class="entry-files">${files.map(f =>
isImageFile(f.name)
? `<a class="f-link" href="#" onclick="showImg('${API}/api/files/${f.token}');return false;" title="Открыть">${esc(f.name)}</a>`
: `<a class="f-link" href="${API}/api/files/${f.token}" download title="Скачать">${esc(f.name)}</a>`
).join('')}</div>`;
}
function entryHTML(e) {
return `
<div class="card">
${e.photo_path ? `<img src="${API}${e.photo_path}" onclick="showImg('${API}${e.photo_path}')" alt="">` : ''}
<div class="info">
<div class="name">${esc(e.student_name)}</div>
<div class="group">${esc(e.group_name)}</div>
<div class="desc">${esc(e.description)}</div>
${filesHTML(e.files)}
<div class="trash-time">Удалена: ${new Date(e.deleted_at).toLocaleString('ru')}</div>
</div>
<button class="restore-btn" onclick="restoreEntry(${e.id})" title="Восстановить">Восстановить</button>
<button class="del-btn" onclick="hardDelete(${e.id})" title="Удалить навсегда (вместе с файлами)">&times;</button>
</div>
`;
}
function renderGrid() {
const grid = document.getElementById('grid');
grid.className = 'grid';
grid.innerHTML = currentEntries.length
? currentEntries.map(entryHTML).join('')
: '<div class="empty">Корзина пуста</div>';
document.getElementById('trashInfo').textContent =
totalEntries > 0 ? `Записей в корзине: ${totalEntries}` : '';
document.getElementById('emptyBtn').disabled = totalEntries === 0;
renderPager(document.getElementById('pager'), page, Math.max(1, Math.ceil(totalEntries / PAGE_SIZE)), goPage);
}
async function loadTrash() {
const p = new URLSearchParams();
p.set('limit', PAGE_SIZE);
p.set('offset', (page - 1) * PAGE_SIZE);
const res = await fetch(`${API}/api/trash?${p}`, { headers: hdr() });
const data = await res.json();
currentEntries = data.entries;
totalEntries = data.total;
renderGrid();
}
function goPage(p) { page = p; loadTrash(); }
async function restoreEntry(id) {
const res = await fetch(`${API}/api/entries/${id}/restore`, { method: 'PUT', headers: hdr() });
if (res.ok) { showToast('Запись восстановлена'); loadTrash(); }
else { const err = await res.json(); alert(err.error || 'Ошибка'); }
}
async function hardDelete(id) {
if (!confirm('Удалить запись навсегда? Файлы и фото будут удалены безвозвратно.')) return;
await fetch(`${API}/api/entries/${id}/permanent`, { method: 'DELETE', headers: hdr() });
showToast('Запись удалена навсегда');
loadTrash();
}
async function emptyTrash() {
if (totalEntries === 0) return;
if (!confirm(`Удалить все записи из корзины (${totalEntries})? Файлы будут удалены безвозвратно.`)) return;
const res = await fetch(`${API}/api/trash`, { method: 'DELETE', headers: hdr() });
if (res.ok) { showToast('Корзина очищена'); page = 1; loadTrash(); }
else { const err = await res.json(); alert(err.error || 'Ошибка'); }
}
(async () => {
if (await checkAuth()) {
buildSidebar(document.body.dataset.page);
loadTrash();
}
})();
</script>
</body>
</html>