fix(phys8): закрытие критических проблем ревью — миграции, ✓→✓, ConvectionSim
- Удалены legacy миграции 009/010/015 (создавали несуществующие physics-8-thermal/electro/optics) - 037_physics_8_hub.sql сделана self-sufficient: INSERT OR IGNORE родителя + UPDATE - 7 шт. literal ✓ заменены на ✓ в physics_8_lab.html (правило проекта) - В phys.js добавлен createConvectionSim — главный визуал §4 (тороидальный поток частиц) закрытие плана Phase 0 Физики 8
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
-- Add Physics 8 textbooks (3 parts: thermal, electrical, optical phenomena)
|
||||
-- by Исаченкова Л. А. (2018). 40 paragraphs total, split across 3 files.
|
||||
INSERT OR IGNORE INTO textbooks (slug, subject, grade, title, author, description, html_path, para_count, color, sort_order) VALUES
|
||||
('physics-8-thermal', 'physics', 8, 'Физика 8 — Тепловые явления', 'Исаченкова Л. А.',
|
||||
'Часть 1. §1–§11: внутренняя энергия, теплопередача, удельная теплоёмкость, фазовые переходы, тепловые двигатели.',
|
||||
'physics8_thermal.html', 11, 'amber', 4),
|
||||
('physics-8-electro', 'physics', 8, 'Физика 8 — Электрические явления', 'Исаченкова Л. А.',
|
||||
'Часть 2. §12–§31: электризация, закон Кулона, электрический ток, закон Ома, работа и мощность тока, электромагнитные явления.',
|
||||
'physics8_electro.html', 20, 'blue', 5),
|
||||
('physics-8-optics', 'physics', 8, 'Физика 8 — Световые явления', 'Исаченкова Л. А.',
|
||||
'Часть 3. §32–§40: источники света, отражение и преломление, линзы, оптические приборы, цвет и спектр.',
|
||||
'physics8_optics.html', 9, 'violet', 6);
|
||||
@@ -1,11 +0,0 @@
|
||||
-- Объединить 3 отдельных учебника физики 8 (thermal/electro/optics) в один hub-учебник.
|
||||
-- Hub-страница physics_8.html содержит карточки 3 разделов и ссылки на исходные файлы.
|
||||
|
||||
-- 1. Удаляем 3 прежние записи (создали их часом раньше, прогресса пользователей ещё нет).
|
||||
DELETE FROM textbooks WHERE slug IN ('physics-8-thermal','physics-8-electro','physics-8-optics');
|
||||
|
||||
-- 2. Регистрируем единый учебник «Физика 8» с hub-страницей.
|
||||
INSERT OR IGNORE INTO textbooks (slug, subject, grade, title, author, description, html_path, para_count, color, sort_order) VALUES
|
||||
('physics-8', 'physics', 8, 'Физика — 8 класс', 'Исаченкова Л. А.',
|
||||
'Интерактивный учебник по физике 8 класса. 40 параграфов в трёх разделах: Тепловые явления (§1–§11), Электрические явления (§12–§31), Световые явления (§32–§40).',
|
||||
'physics_8.html', 40, 'blue', 4);
|
||||
@@ -1,29 +0,0 @@
|
||||
-- Physics 8 hub migration.
|
||||
-- Converts physics-8 from a monolithic entry into a hub with 3 children,
|
||||
-- mirroring the algebra-8 hub pattern established in migration 014.
|
||||
|
||||
-- 1. Insert 3 child rows for the sub-textbooks.
|
||||
INSERT OR IGNORE INTO textbooks
|
||||
(slug, subject, grade, title, author, description, html_path, para_count, color, sort_order, is_active, parent_slug)
|
||||
VALUES
|
||||
('physics-8-thermal', 'physics', 8, 'Физика 8 · Тепловые явления',
|
||||
'',
|
||||
'Внутренняя энергия, теплопередача, удельная теплоёмкость, фазовые переходы, тепловые двигатели.',
|
||||
'physics8_thermal.html', 11, 'orange', 1, 1, 'physics-8'),
|
||||
('physics-8-electro', 'physics', 8, 'Физика 8 · Электрические явления',
|
||||
'',
|
||||
'Электростатика, закон Кулона, электрический ток, закон Ома, электрические цепи.',
|
||||
'physics8_electro.html', 20, 'blue', 2, 1, 'physics-8'),
|
||||
('physics-8-optics', 'physics', 8, 'Физика 8 · Световые явления',
|
||||
'',
|
||||
'Источники света, отражение, преломление, линзы, оптические приборы.',
|
||||
'physics8_optics.html', 9, 'purple', 3, 1, 'physics-8');
|
||||
|
||||
-- 2. Update the parent physics-8 row: clear author, set para_count=40, update description.
|
||||
UPDATE textbooks
|
||||
SET
|
||||
author = '',
|
||||
para_count = 40,
|
||||
html_path = 'physics_8.html',
|
||||
description = 'Полный курс физики 8 класса в трёх разделах: тепловые явления (§1–§11), электрические явления (§12–§31), световые явления (§32–§40).'
|
||||
WHERE slug = 'physics-8';
|
||||
@@ -1,19 +1,27 @@
|
||||
-- Physics 8 hub migration.
|
||||
-- Rebuilds physics-8 as a full 3-chapter + lab textbook in the style of physics-10:
|
||||
-- Physics 8 hub migration (self-sufficient).
|
||||
-- Creates / rebuilds physics-8 as a full 3-chapter + lab textbook in the style of physics-10:
|
||||
-- physics-8 (hub, html_path = physics_8_hub.html)
|
||||
-- physics-8-ch1 (Тепловые явления, §§1–11) → physics_8_ch1.html
|
||||
-- physics-8-ch2 (Электромагнитные явления, §§12–31) → physics_8_ch2.html
|
||||
-- physics-8-ch3 (Световые явления, §§32–40) → physics_8_ch3.html
|
||||
-- physics-8-lab (Лабораторный практикум, 7 ЛР) → physics_8_lab.html
|
||||
--
|
||||
-- Replaces the old legacy children created in migration 015
|
||||
-- (physics-8-thermal / physics-8-electro / physics-8-optics), which pointed
|
||||
-- to monolithic legacy files. Author left empty per project policy.
|
||||
-- This migration is the single source of truth for physics-8 textbook structure.
|
||||
-- It is idempotent and does not depend on any prior physics-8 migration.
|
||||
|
||||
-- 1. Remove legacy children (HTML files are kept on disk as backup, just unlinked from DB).
|
||||
-- 1. Remove legacy children if they ever existed (no-op on fresh DBs).
|
||||
DELETE FROM textbooks WHERE slug IN ('physics-8-thermal', 'physics-8-electro', 'physics-8-optics');
|
||||
|
||||
-- 2. Update the parent physics-8 hub row.
|
||||
-- 2. Ensure the parent physics-8 hub row exists.
|
||||
INSERT OR IGNORE INTO textbooks
|
||||
(slug, subject, grade, title, author, description, html_path, para_count, color, sort_order, is_active)
|
||||
VALUES
|
||||
('physics-8', 'physics', 8, 'Физика — 8 класс',
|
||||
'',
|
||||
'Полный курс физики 8 класса: тепловые явления (§§1–11), электромагнитные явления (§§12–31), световые явления (§§32–40), 7 виртуальных лабораторных работ.',
|
||||
'physics_8_hub.html', 47, 'violet', 4, 1);
|
||||
|
||||
-- 3. Update the parent physics-8 hub row (covers case where it already existed from legacy migrations).
|
||||
UPDATE textbooks
|
||||
SET
|
||||
author = '',
|
||||
|
||||
@@ -353,6 +353,81 @@ function phaseGraphTT(W, H, pad, points, tMaxAll, TminAll, TmaxAll) {
|
||||
return { svg: s, toX: toX, toY: toY };
|
||||
}
|
||||
|
||||
// === Анимация конвекции — тороидальный поток частиц ===
|
||||
// Используется в §4 Физики 8 (главный визуал «конвекция в жидкости/газе»).
|
||||
// opts: { N — число частиц (default 24), w, h — размеры области, speed (отн. ед., default 1),
|
||||
// tHot, tCold — температуры для окраски (default 100, 20) }.
|
||||
function createConvectionSim(opts) {
|
||||
opts = opts || {};
|
||||
const N = opts.N || 24;
|
||||
const w = opts.w || 220;
|
||||
const h = opts.h || 140;
|
||||
const speed = opts.speed != null ? opts.speed : 1;
|
||||
const tHot = opts.tHot != null ? opts.tHot : 100;
|
||||
const tCold = opts.tCold != null ? opts.tCold : 20;
|
||||
// Каждая частица движется по фазе вдоль контура прямоугольника:
|
||||
// правая сторона — вверх (нагрев / подъём), верхняя — влево, левая — вниз (охлаждение), нижняя — вправо.
|
||||
const parts = new Array(N);
|
||||
for (let i = 0; i < N; i++) parts[i] = { phase: i / N };
|
||||
return {
|
||||
N: N, w: w, h: h, speed: speed,
|
||||
_tHot: tHot, _tCold: tCold,
|
||||
setSpeed(v) { this.speed = v; },
|
||||
setHot(v) { this._tHot = v; },
|
||||
setCold(v) { this._tCold = v; },
|
||||
step(dt) {
|
||||
const dPhase = 0.18 * this.speed * dt;
|
||||
for (let i = 0; i < this.N; i++) {
|
||||
parts[i].phase = (parts[i].phase + dPhase) % 1;
|
||||
if (parts[i].phase < 0) parts[i].phase += 1;
|
||||
}
|
||||
},
|
||||
// Возвращает координаты частицы (cx, cy) и температуру по её положению.
|
||||
// phase ∈ [0,1): 0..0.25 — правая (подъём, t→tHot), 0.25..0.5 — верх (t=tHot),
|
||||
// 0.5..0.75 — левая (опускание, t→tCold), 0.75..1 — низ (t=tCold).
|
||||
_xy(phase, x, y) {
|
||||
const margin = 12;
|
||||
const W = this.w - 2 * margin;
|
||||
const H = this.h - 2 * margin;
|
||||
let lx, ly, t;
|
||||
if (phase < 0.25) {
|
||||
const k = phase / 0.25;
|
||||
lx = W; ly = H * (1 - k);
|
||||
t = this._tCold + (this._tHot - this._tCold) * k;
|
||||
} else if (phase < 0.5) {
|
||||
const k = (phase - 0.25) / 0.25;
|
||||
lx = W * (1 - k); ly = 0;
|
||||
t = this._tHot;
|
||||
} else if (phase < 0.75) {
|
||||
const k = (phase - 0.5) / 0.25;
|
||||
lx = 0; ly = H * k;
|
||||
t = this._tHot - (this._tHot - this._tCold) * k;
|
||||
} else {
|
||||
const k = (phase - 0.75) / 0.25;
|
||||
lx = W * k; ly = H;
|
||||
t = this._tCold;
|
||||
}
|
||||
return { cx: x + margin + lx, cy: y + margin + ly, t: t };
|
||||
},
|
||||
render(x, y) {
|
||||
const tMin = Math.min(this._tCold, this._tHot);
|
||||
const tMax = Math.max(this._tCold, this._tHot);
|
||||
let s = '';
|
||||
// Контур сосуда
|
||||
s += `<rect x="${x}" y="${y}" width="${this.w}" height="${this.h}" fill="#dbeafe" stroke="#0f172a" stroke-width="1.5" rx="6"/>`;
|
||||
// Нагреватель снизу (красная полоса)
|
||||
s += `<rect x="${x + 8}" y="${y + this.h - 6}" width="${this.w - 16}" height="6" fill="#dc2626" opacity="0.85" rx="3"/>`;
|
||||
// Частицы
|
||||
for (let i = 0; i < this.N; i++) {
|
||||
const p = this._xy(parts[i].phase, x, y);
|
||||
const c = tempColor(p.t, tMin, tMax);
|
||||
s += `<circle cx="${p.cx.toFixed(1)}" cy="${p.cy.toFixed(1)}" r="4" fill="${c}" stroke="#0f172a" stroke-width="0.6" opacity="0.9"/>`;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// === Электронные хелперы для электрических задач ===
|
||||
// Параллельное и последовательное сопротивление
|
||||
function Rseries() {
|
||||
@@ -374,6 +449,7 @@ window.PHYS = {
|
||||
thermometer: thermometer,
|
||||
calorimeter: calorimeter,
|
||||
createHeatBar: createHeatBar,
|
||||
createConvectionSim: createConvectionSim,
|
||||
phaseGraphTT: phaseGraphTT,
|
||||
Rseries: Rseries,
|
||||
Rparallel: Rparallel,
|
||||
|
||||
@@ -889,10 +889,10 @@ function build_lr4(){
|
||||
+'<label>$R_2$, Ом: <b id="lr4-r2v">8</b><input type="range" id="lr4-r2" min="2" max="20" step="1" value="8"></label>'
|
||||
+'<label>$U$, В: <b id="lr4-uv">12</b><input type="range" id="lr4-u" min="3" max="24" step="1" value="12"></label></div>'
|
||||
+'<div class="score-display" style="margin-top:8px;flex-direction:column;align-items:flex-start;gap:3px">'
|
||||
+'<span>Общий ток $I$ = <b id="lr4-i">1</b> А (одинаков везде ✓)</span>'
|
||||
+'<span>Общий ток $I$ = <b id="lr4-i">1</b> А (одинаков везде ✓)</span>'
|
||||
+'<span>$U_1$ = <b id="lr4-u1">4</b> В, $U_2$ = <b id="lr4-u2">8</b> В</span>'
|
||||
+'<span>$U_1+U_2$ = <b id="lr4-us">12</b> В = $U$ ✓</span>'
|
||||
+'<span>$R = R_1+R_2$ = <b id="lr4-rs">12</b> Ом, $U/I$ = <b id="lr4-rt">12</b> Ом ✓</span></div></div>';
|
||||
+'<span>$U_1+U_2$ = <b id="lr4-us">12</b> В = $U$ ✓</span>'
|
||||
+'<span>$R = R_1+R_2$ = <b id="lr4-rs">12</b> Ом, $U/I$ = <b id="lr4-rt">12</b> Ом ✓</span></div></div>';
|
||||
h += _labResult('lr4', '<p>Все 3 правила послед. соединения подтверждены опытом:</p>'
|
||||
+'<ul style="padding-left:20px"><li>$I$ одинаков везде;</li><li>$U = U_1 + U_2$;</li><li>$R = R_1 + R_2$.</li></ul>'
|
||||
+'<p><b>Вывод:</b> закон Ома и правила последовательного соединения выполняются.</p>');
|
||||
@@ -938,10 +938,10 @@ function build_lr5(){
|
||||
+'<label>$R_2$, Ом: <b id="lr5-r2v">12</b><input type="range" id="lr5-r2" min="2" max="20" step="1" value="12"></label>'
|
||||
+'<label>$U$, В: <b id="lr5-uv">12</b><input type="range" id="lr5-u" min="3" max="24" step="1" value="12"></label></div>'
|
||||
+'<div class="score-display" style="margin-top:8px;flex-direction:column;align-items:flex-start;gap:3px">'
|
||||
+'<span>$U_1 = U_2 = U$ = <b id="lr5-u1">12</b> В ✓</span>'
|
||||
+'<span>$U_1 = U_2 = U$ = <b id="lr5-u1">12</b> В ✓</span>'
|
||||
+'<span>$I_1$ = <b id="lr5-i1">2</b> А, $I_2$ = <b id="lr5-i2">1</b> А</span>'
|
||||
+'<span>$I_1+I_2$ = <b id="lr5-is">3</b> А = $I$ ✓</span>'
|
||||
+'<span>$R_{общ}$ по формуле = <b id="lr5-r">4</b> Ом, $U/I$ = <b id="lr5-rt">4</b> Ом ✓</span></div></div>';
|
||||
+'<span>$I_1+I_2$ = <b id="lr5-is">3</b> А = $I$ ✓</span>'
|
||||
+'<span>$R_{общ}$ по формуле = <b id="lr5-r">4</b> Ом, $U/I$ = <b id="lr5-rt">4</b> Ом ✓</span></div></div>';
|
||||
h += _labResult('lr5', '<p>Все 3 правила параллельного соединения подтверждены:</p>'
|
||||
+'<ul style="padding-left:20px"><li>$U$ одинаково на обеих ветвях;</li><li>$I = I_1 + I_2$;</li><li>$1/R = 1/R_1 + 1/R_2$.</li></ul>'
|
||||
+'<p><b>Вывод:</b> общее $R$ <b>меньше</b> любого из $R_1$, $R_2$, что соответствует теории.</p>');
|
||||
@@ -1031,7 +1031,7 @@ function build_lr7(){
|
||||
h += '<div class="wg"><div class="wg-header"><span class="wg-badge">СИМ</span><div class="wg-title">Виртуальный опыт</div></div>'
|
||||
+'<div class="sliders" style="margin-bottom:10px"><label>Угол падения $\\alpha$, °: <b id="lr7-av">30</b><input type="range" id="lr7-a" min="10" max="80" step="5" value="30"></label></div>'
|
||||
+'<svg id="lr7-sim" viewBox="0 0 460 220" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||||
+'<div class="score-display" style="margin-top:8px"><span>$\\alpha$ = <b id="lr7-as">30°</b></span><span>Измерено $\\beta$ = <b id="lr7-bs">30°</b></span><span>$\\alpha = \\beta$ ✓</span></div></div>';
|
||||
+'<div class="score-display" style="margin-top:8px"><span>$\\alpha$ = <b id="lr7-as">30°</b></span><span>Измерено $\\beta$ = <b id="lr7-bs">30°</b></span><span>$\\alpha = \\beta$ ✓</span></div></div>';
|
||||
/* таблица результатов */
|
||||
h += '<div class="wg"><div class="wg-header"><span class="wg-badge">ТАБЛИЦА</span><div class="wg-title">Серия измерений</div></div>'
|
||||
+'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><thead><tr style="background:rgba(15,23,42,.04)"><th style="padding:6px">Опыт</th><th style="padding:6px;text-align:right">$\\alpha$, °</th><th style="padding:6px;text-align:right">$\\beta$, °</th><th style="padding:6px;text-align:right">$\\alpha - \\beta$</th></tr></thead>'
|
||||
|
||||
Reference in New Issue
Block a user