Files
Learn_System/frontend/js/admin/sections/stats.js
T
Maxim Dolgolyov 92030b462c feat(admin): phase 2 — split admin.js into 13 section modules
Replace ~3500L admin.js monolith with thin orchestrator (~700L) +

14 IIFE-wrapped per-section modules under /js/admin/sections/.

Section modules expose AdminSections.<name>.init/reload (lazy init via

switchTab/router) and re-expose onclick handlers via window.X for

backward compat. Shared helpers (MODES/DIFFS, fmtDate, pctClass,

renderMath, qTypeBadge, pagination) live in /js/admin/_shared.js

exposed on window.AdminCtx.

switchTab now dispatches to AdminSections via ROUTE_TO_SECTION map;

non-extracted system tabs (topics/audit/errors/health/classroom/avatars)

remain inline in admin.js. user-panel overlay markup untouched — Phase 6

will remove it.
2026-05-16 22:50:14 +03:00

51 lines
2.4 KiB
JavaScript

'use strict';
/* admin → stats section */
(function () {
'use strict';
let inited = false;
async function load() {
try {
const s = await LS.adminGetStats();
document.getElementById('stats-grid').innerHTML = `
<div class="stat-card" style="--stat-top:var(--violet)">
<div class="stat-card-icon" style="background:rgba(155,93,229,0.1)"><i data-lucide="users" class="stat-icon"></i></div>
<div class="stat-val violet">${s.totalUsers}</div>
<div class="stat-label">Пользователей</div>
</div>
<div class="stat-card" style="--stat-top:var(--cyan)">
<div class="stat-card-icon" style="background:rgba(6,214,224,0.1)"><i data-lucide="file-text" class="stat-icon"></i></div>
<div class="stat-val cyan">${s.totalTests}</div>
<div class="stat-label">Тестов пройдено</div>
</div>
<div class="stat-card" style="--stat-top:var(--green)">
<div class="stat-card-icon" style="background:rgba(6,214,100,0.1)"><i data-lucide="target" class="stat-icon"></i></div>
<div class="stat-val green">${s.avgScore ?? '—'}%</div>
<div class="stat-label">Средний результат</div>
</div>`;
if (window.lucide) lucide.createIcons();
const subjEl = document.getElementById('subj-stats');
if (!s.bySubject?.length) { subjEl.innerHTML = '<div class="empty">Нет данных</div>'; return; }
subjEl.innerHTML = s.bySubject.map(b => {
const pct = b.avg_pct ?? 0;
const barColor = pct >= 75 ? 'var(--green)' : pct >= 50 ? 'var(--amber)' : 'var(--pink)';
return `<div class="subj-stat">
<div><div class="subj-stat-name">${esc(b.name)}</div><div class="subj-stat-info">${b.tests} тестов</div></div>
<div>
<div class="subj-stat-pct">${b.avg_pct ?? '—'}%</div>
<div style="width:60px;height:3px;background:rgba(15,23,42,0.06);border-radius:99px;margin-top:5px;overflow:hidden"><div style="width:${pct}%;height:100%;background:${barColor};border-radius:99px"></div></div>
</div>
</div>`;
}).join('');
} catch (e) {
LS.state.error(document.getElementById('stats-grid'), e, load);
}
}
window.AdminSections = window.AdminSections || {};
window.AdminSections.stats = {
init: async () => { if (inited) return; inited = true; await load(); },
reload: load,
};
})();