feat(permissions): B7 — пресеты-профили прав (применение к классу одним кликом)
PRESETS (student): «Полный доступ», «Режим фокуса» (без магазина/испытаний), «Ограниченный» (+ без лаборатории), «Сбросить к стандарту роли». GET /api/permissions/presets + POST /api/permissions/class/:id/preset (admin). Рефактор: общий applyPermsToClass() (карта key→1/0/inherit) — его используют и bulk, и preset. В блоке «Массово по классу» — кнопки пресетов (с подтверждением). Тест: список + применение focus/reset + валидация. Backend pass (3 baseline-Auth). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
let _permData = null;
|
||||
let _bulkTargets = null; // { classes:[{id,name,students:[]}] }
|
||||
let _bulkClassId = null;
|
||||
let _presets = null; // { student:[{id,label,desc,perms}] }
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
@@ -24,6 +25,7 @@
|
||||
if (!root) return;
|
||||
try { _bulkTargets = await LS.accessTargets(); }
|
||||
catch { _bulkTargets = { classes: [] }; }
|
||||
if (!_presets) { try { _presets = await LS.permissionsPresets(); } catch { _presets = { student: [] }; } }
|
||||
renderBulk();
|
||||
}
|
||||
function renderBulk() {
|
||||
@@ -39,13 +41,19 @@
|
||||
<span style="font-size:13px;color:var(--text-1)">${esc(d.label)}</span>
|
||||
<span style="display:inline-flex;gap:6px">${btn(d.key, 1, 'включить всем', 'transparent')}${btn(d.key, 0, 'выключить всем', 'transparent')}${btn(d.key, 'null', 'сбросить', 'var(--border-h,#eee)')}</span>
|
||||
</div>`).join('');
|
||||
const presets = (_presets && _presets.student) || [];
|
||||
const presetBar = (cls && presets.length) ? `
|
||||
<div style="margin-bottom:12px;padding-bottom:10px;border-bottom:1px solid var(--border-h,#eee)">
|
||||
<span style="font-size:12px;color:var(--muted);margin-right:6px">Пресет-профиль:</span>
|
||||
${presets.map(p => `<button onclick="applyPreset('${esc(p.id)}')" title="${esc(p.desc)}" style="padding:5px 11px;margin:3px 3px 0 0;border:1px solid var(--border);border-radius:8px;background:var(--accent-soft,#eef2ff);color:var(--accent,#4f46e5);cursor:pointer;font-family:inherit;font-size:12px">${esc(p.label)}</button>`).join('')}
|
||||
</div>` : '';
|
||||
root.innerHTML = `
|
||||
<div style="font-weight:600;margin-bottom:6px">Массово по классу</div>
|
||||
<div style="font-size:12px;color:var(--muted);margin-bottom:10px">Выставить личное правило сразу всем ученикам класса (переопределяет роль). «Сбросить» — вернуть наследование роли.</div>
|
||||
<select onchange="selBulkClass(this.value)" style="padding:8px 12px;border:1.5px solid var(--border);border-radius:9px;font-family:inherit;font-size:0.9rem;min-width:220px">
|
||||
<option value="">— выберите класс —</option>${opts}
|
||||
</select>
|
||||
<div style="margin-top:10px">${cls ? (rows || '<p style="color:var(--muted);font-size:12px">Нет студенческих прав.</p>') : '<p style="color:var(--muted);font-size:12px">Выберите класс.</p>'}</div>`;
|
||||
<div style="margin-top:10px">${cls ? (presetBar + (rows || '<p style="color:var(--muted);font-size:12px">Нет студенческих прав.</p>')) : '<p style="color:var(--muted);font-size:12px">Выберите класс.</p>'}</div>`;
|
||||
}
|
||||
function selBulkClass(v) { _bulkClassId = v ? Number(v) : null; renderBulk(); }
|
||||
async function bulkPerm(permission, enabled) {
|
||||
@@ -63,6 +71,19 @@
|
||||
LS.toast(`Готово: затронуто учеников — ${r.affected}`, 'success');
|
||||
} catch (e) { LS.toast('Ошибка: ' + e.message, 'error'); }
|
||||
}
|
||||
async function applyPreset(presetId) {
|
||||
if (!_bulkClassId) return;
|
||||
const cls = ((_bulkTargets && _bulkTargets.classes) || []).find(c => c.id === _bulkClassId);
|
||||
const p = ((_presets && _presets.student) || []).find(x => x.id === presetId);
|
||||
const ok = await LS.confirm(
|
||||
`Применить пресет «${p ? p.label : presetId}» ко всем ученикам класса «${cls ? cls.name : ''}»?`,
|
||||
{ title: 'Применить пресет', confirmText: 'Применить' });
|
||||
if (!ok) return;
|
||||
try {
|
||||
const r = await LS.applyClassPreset(_bulkClassId, presetId);
|
||||
LS.toast(`Пресет применён: ${r.affected} учеников`, 'success');
|
||||
} catch (e) { LS.toast('Ошибка: ' + e.message, 'error'); }
|
||||
}
|
||||
|
||||
function permCard(role, def, en, labelOf) {
|
||||
const enabled = en[def.key];
|
||||
@@ -205,6 +226,7 @@
|
||||
window.loadPermLog = loadPermLog;
|
||||
window.selBulkClass = selBulkClass;
|
||||
window.bulkPerm = bulkPerm;
|
||||
window.applyPreset = applyPreset;
|
||||
|
||||
window.AdminSections = window.AdminSections || {};
|
||||
window.AdminSections.permissions = {
|
||||
|
||||
Reference in New Issue
Block a user