97 lines
4.0 KiB
JavaScript
97 lines
4.0 KiB
JavaScript
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="#" data-img="${API}/api/files/${f.token}" 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}" data-img="${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" data-restore="${e.id}" title="Восстановить">Восстановить</button>
|
|
<button class="del-btn" data-hard="${e.id}" title="Удалить навсегда (вместе с файлами)">×</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(); showToast(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 || 'Ошибка'); }
|
|
}
|
|
|
|
document.getElementById('emptyBtn').addEventListener('click', emptyTrash);
|
|
document.getElementById('imgModal').addEventListener('click', e => e.currentTarget.classList.remove('open'));
|
|
|
|
document.getElementById('grid').addEventListener('click', e => {
|
|
const rs = e.target.closest('[data-restore]');
|
|
if (rs) { restoreEntry(parseInt(rs.dataset.restore, 10)); return; }
|
|
const hd = e.target.closest('[data-hard]');
|
|
if (hd) { hardDelete(parseInt(hd.dataset.hard, 10)); }
|
|
});
|
|
|
|
(async () => {
|
|
if (await checkAuth()) {
|
|
buildSidebar(document.body.dataset.page);
|
|
loadTrash();
|
|
}
|
|
})(); |