diff --git a/frontend/js/labs/_tasks.js b/frontend/js/labs/_tasks.js new file mode 100644 index 0000000..26c5001 --- /dev/null +++ b/frontend/js/labs/_tasks.js @@ -0,0 +1,155 @@ +'use strict'; +/* LabTasks — лёгкий фреймворк учебных заданий для симуляций (Фаза 1 плана). + * Превращает «песочницу» в учебный инструмент: задание → ответ числом с допуском → + * проверка/подсказка/прогресс. Данные — LAB_TASKS[simId] = [{q, formula?, a, tol, unit?, hint?}]. + * Рендерится панелью в теорию (loadTheory дописывает LabTasks.mountHtml). Ответы + * проверяются на клиенте (учебные, не оценочные) — без обращения к серверу. */ +(function (global) { + + /* ── Данные заданий (наполняется по симуляциям) ── */ + var LAB_TASKS = { + quadratic: [ + { q: 'Найди дискриминант уравнения ниже.', formula: 'x^2 - 5x + 6 = 0', a: 1, tol: 0.01, hint: 'D = b² − 4ac' }, + { q: 'Сколько действительных корней у уравнения x² + 2x + 5 = 0?', a: 0, tol: 0.01, hint: 'Если D < 0 — корней нет' }, + { q: 'Чему равна абсцисса вершины параболы y = x² − 4x + 1?', a: 2, tol: 0.01, hint: 'x вершины = −b / (2a)' }, + ], + trigcircle: [ + { q: 'Чему равен sin 30°? (десятичной дробью)', a: 0.5, tol: 0.02, hint: 'sin — это ордината (y) точки на окружности' }, + { q: 'Чему равен cos 90°?', a: 0, tol: 0.02, hint: 'cos — это абсцисса (x) точки' }, + { q: 'Чему равен tg 45°?', a: 1, tol: 0.02, hint: 'tg = sin / cos' }, + ], + normaldist: [ + { q: 'Какая доля значений попадает в интервал ±1σ? (например 0.68)', a: 0.68, tol: 0.03, hint: 'Правило 68–95–99.7' }, + { q: 'Какая доля попадает в ±2σ?', a: 0.95, tol: 0.03, hint: 'Правило 68–95–99.7' }, + ], + projectile: [ + { q: 'При каком угле броска дальность максимальна (без сопротивления)? В градусах.', a: 45, tol: 1, hint: 'Дальность ∝ sin(2α), максимум при 2α = 90°' }, + ], + pendulum: [ + { q: 'Период математического маятника длиной 1 м при g ≈ 9.8 м/с²? В секундах.', a: 2.0, tol: 0.15, formula: 'T = 2\\pi\\sqrt{L/g}', hint: 'Подставь L = 1, g = 9.8' }, + ], + }; + + var ICON_CHECK = ''; + var ICON_X = ''; + var ICON_TASK = ''; + var ICON_TROPHY = ''; + + function esc(s) { return (global.LS && LS.esc) ? LS.esc(s) : String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c]; }); } + + /* состояние прохождения (сбрасывается при перезагрузке — задел под persist в Фазе 2) */ + var state = {}; + function st(simId) { + if (!state[simId]) state[simId] = { idx: 0, done: LAB_TASKS[simId].map(function () { return false; }) }; + return state[simId]; + } + + function ensureStyle() { + if (document.getElementById('lt-style')) return; + var s = document.createElement('style'); s.id = 'lt-style'; + s.textContent = [ + '.lt-host{margin-top:18px;}', + '.lt-panel{border:1.5px solid rgba(155,93,229,.25);border-radius:14px;padding:14px 15px;background:rgba(155,93,229,.05);}', + '.lt-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;}', + '.lt-lbl{display:inline-flex;align-items:center;gap:6px;font-size:.74rem;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:var(--violet,#9B5DE5);}', + '.lt-dots{display:inline-flex;gap:5px;}', + '.lt-dot{width:7px;height:7px;border-radius:50%;background:rgba(155,93,229,.25);}', + '.lt-dot.ok{background:var(--green,#06D664);}', + '.lt-dot.cur{box-shadow:0 0 0 2px rgba(155,93,229,.35);}', + '.lt-q{font-size:.9rem;line-height:1.5;color:var(--text,#0f172a);margin-bottom:8px;}', + '.lt-formula{margin:6px 0 10px;}', + '.lt-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}', + '.lt-input{width:120px;padding:8px 11px;border:1.5px solid var(--border-h,#cbd5e1);border-radius:9px;font:inherit;font-size:.88rem;background:var(--surface,#fff);color:var(--text,#0f172a);}', + '.lt-unit{font-size:.82rem;color:var(--text-3,#56687A);}', + '.lt-btn{padding:8px 16px;border:none;border-radius:9px;background:var(--violet,#9B5DE5);color:#fff;font:700 .82rem Manrope,sans-serif;cursor:pointer;}', + '.lt-btn:hover{background:#8347d4;}', + '.lt-fb{margin-top:9px;font-size:.84rem;font-weight:600;min-height:1px;}', + '.lt-fb.ok{color:var(--green,#06A552);}', + '.lt-fb.err{color:var(--pink,#E23C8E);}', + '.lt-fb.warn{color:var(--amber,#D9831A);}', + '.lt-done{text-align:center;padding:20px 14px;}', + '.lt-done .ic{color:var(--violet,#9B5DE5);}', + '.lt-done-t{font-weight:800;font-size:.95rem;margin-top:6px;}', + '.lt-done-s{font-size:.8rem;color:var(--text-3,#56687A);margin-top:2px;}', + '#theory-toggle.lt-has{position:relative;}', + '#theory-toggle.lt-has::after{content:"";position:absolute;top:5px;right:5px;width:7px;height:7px;border-radius:50%;background:var(--violet,#9B5DE5);box-shadow:0 0 0 2px var(--bg,#EEF2FF);}', + ].join(''); + document.head.appendChild(s); + } + + function inner(simId) { + var list = LAB_TASKS[simId]; if (!list) return ''; + var s = st(simId); + var total = list.length, solved = s.done.filter(Boolean).length; + if (solved === total) { + return '