8b3159b529
Оптическая скамья (opticsbench) — merger thinlens + mirror + refraction - 4 режима: «Свободная сборка» / «Линза» / «Зеркало» / «Преломление» - Все 3 движка слиты в OpticsBenchSim (1583 строк) - Backward compat: #thinlens / #mirrors / #refraction → #opticsbench - Удалены: thinlens.js, mirror.js, refraction.js Радиоактивный распад (radioactive) — новая сима - Monte-Carlo распад: λ·dt вероятность на тик, частицы меняют цвет, эмитируются α/β/γ - Real-time N(t) график с теоретической кривой N₀·exp(-λt) - 7 изотопов: ¹⁴C, ¹³¹I, ¹³⁷Cs, ²²⁶Ra, ⁴⁰K, ²³⁸U-chain, ²³⁵U-chain - Цепочки распадов (U-238: 14 шагов сокращены до 5 ключевых) - Dating mode для C-14: t = ln(N₀/N)/λ - HUD: периодов прошло, % распалось, активность в Бк Тепловые двигатели (heatengine) — новая сима - 4 цикла: Карно / Отто / Дизель / Брайтон - PV-диаграмма с замкнутым циклом, заполненной площадью работы - Аналитически точные изотермы (PV=nRT) и адиабаты (PV^γ=const) - Анимированный поршень с резервуарами (красный T_h / синий T_c) - Частицы газа, скорость ∝ √T - Hover-tooltips с формулами для каждого сегмента Логические схемы (logic) — новая сима для информатики - Drag-drop конструктор: 12 типов компонентов (INPUT/CLOCK/OUTPUT/AND/OR/NOT/XOR/NAND/NOR/XNOR/BUF/wire) - Топологическая сортировка для propagation, цветовая подсветка HIGH/LOW - Авто-генерация булевого выражения (∧ ∨ ¬ ⊕) - Авто-таблица истинности (до 2^6 = 64 строк) - 6 пресетов: полусумматор, полный сумматор, RS-триггер, D-триггер, декодер 2-в-4, мультиплексор 2-в-1 Стехиометрия (stoichiometry) — новая сима - 10 реакций: Zn+HCl, H₂+O₂, CH₄+O₂, N₂+H₂ (Габер), Al+CuSO₄, Mg+O₂, CaCO₃→, HCl+NaOH, KMnO₄→, C₂H₅OH+O₂ - Sliders с переключением m/n/V (для газов V=n·22.4 при н.у.) - Анимация частиц при реакции, подсветка лимитирующего реагента - Пошаговый расчёт m→n→n_product→m_product с KaTeX - HUD: лимит, избытки, теоретический выход Каталог: 33 → 35 сим (5 новых − 3 удалённых merger) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
120 lines
6.8 KiB
JavaScript
120 lines
6.8 KiB
JavaScript
'use strict';
|
|
/* admin → sims (simulations) section */
|
|
(function () {
|
|
'use strict';
|
|
let inited = false;
|
|
|
|
// Full list of available (non-null id) sims mirrored from /lab
|
|
const ADMIN_SIMS = [
|
|
{ id: 'graph', cat: 'Математика', title: 'График функции' },
|
|
{ id: 'graphtransform', cat: 'Математика', title: 'Трансформации графиков' },
|
|
{ id: 'geometry', cat: 'Математика', title: 'Планиметрия' },
|
|
{ id: 'triangle', cat: 'Математика', title: 'Геометрия треугольника' },
|
|
{ id: 'quadratic', cat: 'Математика', title: 'Корни квадратного уравнения' },
|
|
{ id: 'stereo', cat: 'Математика', title: 'Стереометрия 3D' },
|
|
{ id: 'probability', cat: 'Математика', title: 'Теория вероятностей' },
|
|
{ id: 'trigcircle', cat: 'Математика', title: 'Тригонометрическая окружность' },
|
|
{ id: 'normaldist', cat: 'Математика', title: 'Нормальное распределение' },
|
|
{ id: 'projectile', cat: 'Физика', title: 'Бросок тела' },
|
|
{ id: 'pendulum', cat: 'Физика', title: 'Маятник' },
|
|
{ id: 'collision', cat: 'Физика', title: 'Столкновение шаров' },
|
|
{ id: 'emfield', cat: 'Физика', title: 'Электромагнитные поля' },
|
|
{ id: 'circuit', cat: 'Физика', title: 'Электрические цепи' },
|
|
{ id: 'hydrostatics', cat: 'Физика', title: 'Гидростатика' },
|
|
{ id: 'dynamics', cat: 'Физика', title: 'Динамика' },
|
|
{ id: 'opticsbench', cat: 'Физика', title: 'Оптическая скамья' },
|
|
{ id: 'isoprocess', cat: 'Физика', title: 'Изопроцессы' },
|
|
{ id: 'waves', cat: 'Физика', title: 'Волны и звук' },
|
|
{ id: 'heatengine', cat: 'Физика', title: 'Тепловые двигатели' },
|
|
{ id: 'radioactive', cat: 'Физика', title: 'Радиоактивный распад' },
|
|
{ id: 'logic', cat: 'Физика', title: 'Логические схемы' },
|
|
{ id: 'molphys', cat: 'Химия', title: 'Молекулярная физика' },
|
|
{ id: 'chemistry', cat: 'Химия', title: 'Химические реакции' },
|
|
{ id: 'equilibrium', cat: 'Химия', title: 'Химическое равновесие' },
|
|
{ id: 'electrolysis', cat: 'Химия', title: 'Электролиз' },
|
|
{ id: 'bohratom', cat: 'Химия', title: 'Атом Бора' },
|
|
{ id: 'orbitals', cat: 'Химия', title: 'Молекулярные орбитали' },
|
|
{ id: 'titration', cat: 'Химия', title: 'pH и кривая титрования' },
|
|
{ id: 'chemsandbox', cat: 'Химия', title: 'Химическая песочница' },
|
|
{ id: 'stoichiometry', cat: 'Химия', title: 'Стехиометрия' },
|
|
{ id: 'crystal', cat: 'Химия', title: 'Кристаллическая решётка' },
|
|
{ id: 'celldivision', cat: 'Биология', title: 'Деление клетки' },
|
|
{ id: 'photosynthesis', cat: 'Биология', title: 'Фотосинтез и дыхание' },
|
|
{ id: 'angrybirds', cat: 'Игры', title: 'Angry Birds Physics' },
|
|
];
|
|
|
|
let _simsSettings = { module_disabled: false, disabled_ids: [] };
|
|
|
|
async function load() {
|
|
try {
|
|
const data = await LS.api('/api/settings/sims');
|
|
_simsSettings = data;
|
|
_render();
|
|
} catch(e) { LS.toast('Ошибка загрузки настроек: ' + e.message, 'error'); }
|
|
}
|
|
|
|
function _render() {
|
|
// master toggle
|
|
const masterChk = document.getElementById('sims-master-chk');
|
|
if (masterChk) masterChk.checked = !_simsSettings.module_disabled;
|
|
|
|
// per-sim cards
|
|
const grid = document.getElementById('sims-grid');
|
|
const dis = new Set(_simsSettings.disabled_ids || []);
|
|
// group by category
|
|
const byCat = {};
|
|
ADMIN_SIMS.forEach(s => { (byCat[s.cat] = byCat[s.cat] || []).push(s); });
|
|
|
|
let html = '';
|
|
Object.entries(byCat).forEach(([cat, sims]) => {
|
|
html += `<div style="grid-column:1/-1;font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--text-3);margin-top:12px;margin-bottom:2px">${esc(cat)}</div>`;
|
|
sims.forEach(s => {
|
|
const enabled = !dis.has(s.id);
|
|
html += `<div class="perm-card${enabled ? ' enabled' : ''}" id="simcard-${s.id}">
|
|
<div class="perm-info">
|
|
<div class="perm-label">${esc(s.title)}</div>
|
|
<div class="perm-desc" style="font-size:11px;margin-top:2px;opacity:.7">${esc(s.id)}</div>
|
|
</div>
|
|
<label class="perm-toggle" title="${enabled ? 'Отключить' : 'Включить'}">
|
|
<input type="checkbox" ${enabled ? 'checked' : ''} onchange="simToggleOne('${s.id}', this.checked)" />
|
|
<span class="perm-track"></span>
|
|
<span class="perm-thumb"></span>
|
|
</label>
|
|
</div>`;
|
|
});
|
|
});
|
|
grid.innerHTML = html;
|
|
if (window.lucide) lucide.createIcons();
|
|
}
|
|
|
|
async function simsMasterToggle(checked) {
|
|
try {
|
|
await LS.api('/api/settings/sims', { method: 'PUT', body: JSON.stringify({ module_disabled: !checked }) });
|
|
_simsSettings.module_disabled = !checked;
|
|
LS.toast(checked ? 'Модуль симуляций включён' : 'Модуль симуляций отключён', checked ? 'success' : 'warning');
|
|
} catch(e) { LS.toast('Ошибка: ' + e.message, 'error'); }
|
|
}
|
|
|
|
async function simToggleOne(simId, enabled) {
|
|
const dis = new Set(_simsSettings.disabled_ids || []);
|
|
if (enabled) dis.delete(simId); else dis.add(simId);
|
|
const disabled_ids = [...dis];
|
|
try {
|
|
await LS.api('/api/settings/sims', { method: 'PUT', body: JSON.stringify({ disabled_ids }) });
|
|
_simsSettings.disabled_ids = disabled_ids;
|
|
const card = document.getElementById('simcard-' + simId);
|
|
if (card) card.classList.toggle('enabled', enabled);
|
|
LS.toast(enabled ? `«${simId}» включена` : `«${simId}» отключена`, enabled ? 'success' : 'warning');
|
|
} catch(e) { LS.toast('Ошибка: ' + e.message, 'error'); }
|
|
}
|
|
|
|
window.simsMasterToggle = simsMasterToggle;
|
|
window.simToggleOne = simToggleOne;
|
|
|
|
window.AdminSections = window.AdminSections || {};
|
|
window.AdminSections.sims = {
|
|
init: async () => { if (inited) return; inited = true; await load(); },
|
|
reload: load,
|
|
};
|
|
})();
|