feat(modules): soft delete with restore and active filter
This commit is contained in:
+26
-10
@@ -32,14 +32,17 @@ function renderModules(total) {
|
||||
list.innerHTML = '<div class="empty">Модулей пока нет. Нажмите «Добавить модуль».</div>';
|
||||
} else {
|
||||
list.innerHTML = modulesList.map(m => `
|
||||
<div class="item module-item" data-id="${m.id}">
|
||||
<div class="item module-item${m.is_active ? '' : ' module-off'}" data-id="${m.id}">
|
||||
<div class="module-info">
|
||||
<div class="module-name">${esc(m.name)}</div>
|
||||
<div class="module-name">${esc(m.name)}${m.is_active ? '' : ' <span class="module-badge">Отключён</span>'}</div>
|
||||
<div class="module-meta">${m.lessons_count} ${mPlural(m.lessons_count, 'занятие', 'занятия', 'занятий')} · ${m.entries_count} ${mPlural(m.entries_count, 'запись', 'записи', 'записей')}</div>
|
||||
</div>
|
||||
<div class="student-actions">
|
||||
<button class="btn-link" type="button" data-edit-module="${m.id}">Изменить</button>
|
||||
<button class="btn-del" type="button" data-del-module="${m.id}" title="Удалить">×</button>
|
||||
${m.is_active
|
||||
? `<button class="btn-link" type="button" data-edit-module="${m.id}">Изменить</button>
|
||||
<button class="btn-link danger" type="button" data-off-module="${m.id}">Отключить</button>`
|
||||
: `<button class="btn-link" type="button" data-on-module="${m.id}">Включить</button>
|
||||
<button class="btn-link" type="button" data-edit-module="${m.id}">Изменить</button>`}
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
@@ -75,15 +78,26 @@ function closeModuleModal() {
|
||||
document.getElementById('moduleModal').classList.remove('open');
|
||||
}
|
||||
|
||||
async function deleteModule(id) {
|
||||
async function disableModule(id) {
|
||||
const m = modulesList.find(x => x.id === id);
|
||||
const msg = m && m.entries_count > 0
|
||||
? `Удалить модуль «${m.name}»? У ${m.entries_count} связанных записей тема будет очищена.`
|
||||
: 'Удалить этот модуль?';
|
||||
? `Отключить модуль «${m.name}»? Он станет недоступен для выбора, у ${m.entries_count} связанных записей тема сохранится.`
|
||||
: `Отключить модуль${m ? ` «${m.name}»` : ''}? Он станет недоступен для выбора.`;
|
||||
if (!confirm(msg)) return;
|
||||
const res = await fetch(`${API}/api/modules/${id}`, { method: 'DELETE', headers: hdr() });
|
||||
if (res.ok) {
|
||||
showToast('Модуль удалён');
|
||||
showToast('Модуль отключён');
|
||||
loadModules();
|
||||
} else {
|
||||
const err = await res.json().catch(() => ({}));
|
||||
alert(err.error || 'Ошибка');
|
||||
}
|
||||
}
|
||||
|
||||
async function enableModule(id) {
|
||||
const res = await fetch(`${API}/api/modules/${id}/restore`, { method: 'PUT', headers: hdr() });
|
||||
if (res.ok) {
|
||||
showToast('Модуль включён');
|
||||
loadModules();
|
||||
} else {
|
||||
const err = await res.json().catch(() => ({}));
|
||||
@@ -202,8 +216,10 @@ document.getElementById('moduleSearch').addEventListener('input', () => {
|
||||
document.getElementById('moduleList').addEventListener('click', e => {
|
||||
const ed = e.target.closest('[data-edit-module]');
|
||||
if (ed) { openModuleModal(parseInt(ed.dataset.editModule, 10)); return; }
|
||||
const dl = e.target.closest('[data-del-module]');
|
||||
if (dl) deleteModule(parseInt(dl.dataset.delModule, 10));
|
||||
const off = e.target.closest('[data-off-module]');
|
||||
if (off) { disableModule(parseInt(off.dataset.offModule, 10)); return; }
|
||||
const on = e.target.closest('[data-on-module]');
|
||||
if (on) enableModule(parseInt(on.dataset.onModule, 10));
|
||||
});
|
||||
|
||||
(async () => {
|
||||
|
||||
Reference in New Issue
Block a user