'use strict'; /* admin → sessions section: sessions timeline + drawer detail */ (function () { 'use strict'; let inited = false; let allSessions = []; let openDrawerId = null; async function load() { const subject = document.getElementById('t-subject').value; document.getElementById('t-body').innerHTML = '
'; openDrawerId = null; try { allSessions = await LS.adminGetSessions({ subject: subject || undefined }); renderSessions(); } catch (e) { document.getElementById('t-body').innerHTML = `
Ошибка: ${esc(e.message)}
`; } } function sessPctRing(pct) { const { pctClass } = AdminCtx; const pc = pctClass(pct); const colorMap = {'pct-hi':'var(--green)','pct-mid':'var(--amber)','pct-lo':'var(--pink)'}; const color = colorMap[pc] || 'var(--text-3)'; const circ = 106.8; const dash = (pct / 100 * circ).toFixed(1); return ` ${pct}% `; } function renderSessions() { const { MODES, fmtDate, fmtTime } = AdminCtx; const modeF = document.getElementById('t-mode').value; const searchF = document.getElementById('t-search').value.toLowerCase(); const filtered = allSessions.filter(s => { if (modeF && s.mode !== modeF) return false; if (searchF && !s.user_name.toLowerCase().includes(searchF) && !s.user_email.toLowerCase().includes(searchF)) return false; return true; }); document.getElementById('t-count').textContent = `${filtered.length} тестов`; if (!filtered.length) { document.getElementById('t-body').innerHTML = '
Нет тестов
'; return; } const groups = {}; filtered.forEach(s => { const key = fmtDate(s.started_at); (groups[key] = groups[key] || []).push(s); }); document.getElementById('t-body').innerHTML = Object.entries(groups).map(([date, sessions]) => `
${date}
${sessions.map(s => { const ring = s.percent !== null ? sessPctRing(s.percent) : `
`; return `
${ring}
${esc(s.user_name)}
${esc(s.subject_name||'?')} · ${MODES[s.mode]||s.mode}
${s.score??'—'} / ${s.total}
${fmtTime(s.duration_sec)}
`; }).join('')}
` ).join(''); } async function toggleDrawer(id) { const drawerEl = document.getElementById('tdrawer-' + id); const drawer = document.getElementById('drawer-' + id); const trow = document.getElementById('trow-' + id); if (openDrawerId && openDrawerId !== id) { document.getElementById('tdrawer-' + openDrawerId)?.classList.remove('open'); document.getElementById('drawer-' + openDrawerId)?.classList.remove('open'); document.getElementById('trow-' + openDrawerId)?.classList.remove('open'); } if (openDrawerId === id) { drawerEl.classList.remove('open'); drawer.classList.remove('open'); trow.classList.remove('open'); openDrawerId = null; return; } openDrawerId = id; trow.classList.add('open'); drawerEl.classList.add('open'); requestAnimationFrame(() => drawer.classList.add('open')); const inner = document.getElementById('drawer-inner-' + id); if (inner.dataset.loaded) return; inner.dataset.loaded = '1'; try { const d = await LS.adminGetSessionDetail(id); renderDrawer(inner, d); } catch (e) { inner.innerHTML = `
Ошибка: ${esc(e.message)}
`; } } function renderDrawer(el, d) { const { MODES, pctClass, fmtDate, fmtTime, renderMath } = AdminCtx; const pct = d.score !== null && d.total ? Math.round((d.score/d.total)*100) : null; const pc = pctClass(pct); const correct = d.questions.filter(q => q.is_correct).length; const wrong = d.questions.filter(q => !q.is_correct && q.chosen_option_id).length; const skipped = d.questions.filter(q => !q.chosen_option_id).length; const qHtml = d.questions.map((q,i) => { const status = !q.chosen_option_id ? 'skipped' : q.is_correct ? 'correct' : 'wrong'; const badgeTxt = { correct:'Верно', wrong:'Неверно', skipped:'Пропущено' }[status]; const opts = q.options.map(o => { const isCor = o.is_correct, isCho = o.id === q.chosen_option_id; let cls='', icon=''; if (isCor) { cls='correct-opt'; icon=''; } else if (isCho && !isCor) { cls='chosen-wrong'; icon=''; } return `
${icon}${esc(o.text)}
`; }).join(''); const expl = q.explanation ? `
Пояснение: ${esc(q.explanation)}
` : ''; return `
Вопрос ${i+1}${badgeTxt}${q.time_spent_sec?q.time_spent_sec+' сек':''}
${esc(q.text)}
${opts}
${expl}
`; }).join(''); el.innerHTML = `
${esc(d.user_name)}
${esc(d.user_email)} · ${d.subject_name||'?'} · ${MODES[d.mode]||d.mode} · ${fmtDate(d.started_at)}
${pct !== null ? pct+'%' : '—'}
${correct}
Верно
${wrong}
Неверно
${skipped}
Пропущено
${fmtTime(d.duration_sec)}
Время
${qHtml||'
Вопросы не найдены
'}
`; renderMath(el); if (window.lucide) lucide.createIcons(); } // Expose handlers window.loadSessions = load; window.renderSessions = renderSessions; window.toggleDrawer = toggleDrawer; window.AdminSections = window.AdminSections || {}; window.AdminSections.sessions = { init: async () => { if (inited) return; inited = true; await load(); }, reload: load, }; })();