4b23d768f2
Блок formula вставляет tex в HTML без экранирования, поэтому литеральная "меньше"-скобка (напр. в "0 le r lt d") принималась браузером за HTML-тег и формула не рендерилась (показывался сырой $$...$$). Заменено на \lt и \gt (KaTeX рендерит их как отношения). - seed_ctmath_lessons_rest.js: исправлены 4 формулы в исходнике (числа, модуль, показ/лог равносильности, производная-монотонность). - fix_ctmath_formula_lt.js: фикс уже залитых блоков курса 13 (dry/--apply). Флешкарты не затронуты (mathHtmlFC через textContent экранирует сам). Запись (UPDATE 4 блоков) запускает пользователь. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
177 lines
17 KiB
JavaScript
177 lines
17 KiB
JavaScript
'use strict';
|
||
/*
|
||
* Уроки остальных блоков курса «ЦЭ/ЦТ — Математика» (по PLAN.md, шаблон пилотов).
|
||
* Числа · Преобразования · Уравнения(×2) · Функции · Прогрессии/текстовые ·
|
||
* Планиметрия · Продвинутое. Форматы блоков — под рендер lesson.html
|
||
* (text/heading/callout esc-only; математика $…$/$$…$$; callout.style). Идемпотентно.
|
||
* node backend/scripts/seed_ctmath_lessons_rest.js [--dry]
|
||
*/
|
||
const db = require('../src/db/db');
|
||
const DRY = process.argv.includes('--dry');
|
||
const COURSE_TITLE = 'ЦЭ/ЦТ — Математика';
|
||
const course = db.prepare("SELECT id FROM courses WHERE subject_slug='math' AND title=?").get(COURSE_TITLE);
|
||
if (!course) { console.error('Нет курса. Сначала seed_ctmath_course.js'); process.exit(1); }
|
||
|
||
const H = (text, level = 2) => ['heading', { text, level }];
|
||
const P = (text) => ['text', { text }];
|
||
const F = (tex, label) => ['formula', label ? { label, tex } : { tex }];
|
||
const CI = (text) => ['callout', { style: 'info', text }];
|
||
const CW = (text) => ['callout', { style: 'warning', text }];
|
||
const CS = (text) => ['callout', { style: 'success', text }];
|
||
const SIM = (simId, caption) => ['sim', { simId, caption }];
|
||
const FC = (front, back) => ['flashcard', { front, back }];
|
||
const QZ = (question, options, correctIndex) => ['quiz', { question, options, correctIndex }];
|
||
const PR = () => CI('Тренажёр по теме — в модуле /exam-prep/ctmath (реальные задания ЦТ прошлых лет) и в практике по теме.');
|
||
|
||
const LESSONS = [
|
||
{ section: 'Числа и вычисления', title: 'Числа, делимость и проценты', read: 8, blocks: [
|
||
H('Числа, делимость и проценты'),
|
||
P('Действительные числа на координатной прямой нужно уметь оценивать и сравнивать. Деление с остатком записывается формулой ниже.'),
|
||
F('n = d\\cdot q + r,\\qquad 0\\le r\\lt d', 'Деление с остатком'),
|
||
P('Проценты: $p\\%$ числа $a$ равно $\\dfrac{p}{100}\\cdot a$. Увеличение на $p\\%$ — умножение на $\\left(1+\\dfrac{p}{100}\\right)$, уменьшение — на $\\left(1-\\dfrac{p}{100}\\right)$.'),
|
||
F('\\text{НОД}(a,b)\\cdot\\text{НОК}(a,b)=a\\cdot b', 'Связь НОД и НОК'),
|
||
H('Разбор А4', 3),
|
||
P('Делитель $15$, неполное частное $k$, остаток $7$. Тогда делимое $n=15k+7$.'),
|
||
CS('Ответ: $n=15k+7$.'),
|
||
H('Разбор (проценты)', 3),
|
||
P('$15\\%$ числа равны $33$. Число $=33:0{,}15=220$, а $20\\%$ от него $=44$.'),
|
||
CS('Ответ: $44$.'),
|
||
FC('Деление с остатком', '$n=dq+r,\\ 0\\le r<d$'),
|
||
FC('$\\text{НОД}\\cdot\\text{НОК}$', '$a\\cdot b$'),
|
||
FC('$p\\%$ от $a$', '$\\dfrac{p}{100}\\,a$'),
|
||
QZ('20% некоторого числа равны 40. Само число равно:', ['200', '80', '160', '20'], 0),
|
||
PR(),
|
||
]},
|
||
{ section: 'Алгебраические преобразования', title: 'Степени, корни, дроби', read: 9, blocks: [
|
||
H('Преобразования выражений: степени, корни, дроби'),
|
||
F('a^m\\cdot a^n=a^{m+n},\\quad (a^m)^n=a^{mn},\\quad a^{-n}=\\dfrac{1}{a^n},\\quad a^{m/n}=\\sqrt[n]{a^m}', 'Степени'),
|
||
F('\\sqrt[n]{ab}=\\sqrt[n]{a}\\,\\sqrt[n]{b},\\qquad \\sqrt[n]{a^n}=|a|\\ (n\\text{ — чётное})', 'Корни'),
|
||
F('(a\\pm b)^2=a^2\\pm2ab+b^2,\\qquad a^2-b^2=(a-b)(a+b)', 'Формулы сокращённого умножения'),
|
||
P('ОДЗ выражения: под корнем чётной степени — неотрицательное число; знаменатель не равен нулю; аргумент логарифма положителен.'),
|
||
CW('В задании А10 проверяют именно ОДЗ: при каком значении выражение имеет смысл.'),
|
||
H('Разбор А10', 3),
|
||
P('При $a=-4$ из $\\sqrt{a}$, $\\sqrt[3]{a}$, $\\dfrac{1}{a+4}$ смысл имеет только $\\sqrt[3]{a}$: корень нечётной степени из отрицательного определён; $\\sqrt{-4}$ — нет; $\\dfrac{1}{0}$ — деление на ноль.'),
|
||
CS('Ответ: $\\sqrt[3]{a}$.'),
|
||
FC('$a^m\\cdot a^n$', '$a^{m+n}$'),
|
||
FC('$a^{m/n}$', '$\\sqrt[n]{a^m}$'),
|
||
FC('$a^2-b^2$', '$(a-b)(a+b)$'),
|
||
QZ('Значение $a^{1/2}$ при $a=9$:', ['3', '4,5', '81', '18'], 0),
|
||
PR(),
|
||
]},
|
||
{ section: 'Уравнения и неравенства', title: 'Квадратные, рациональные, модуль', read: 11, blocks: [
|
||
H('Квадратные и рациональные уравнения и неравенства. Модуль'),
|
||
F('x_{1,2}=\\dfrac{-b\\pm\\sqrt{D}}{2a},\\ \\ D=b^2-4ac;\\qquad x_1x_2=\\dfrac{c}{a},\\ \\ x_1+x_2=-\\dfrac{b}{a}', 'Квадратное уравнение и теорема Виета'),
|
||
SIM('quadratic', 'Корни квадратного уравнения и дискриминант'),
|
||
P('Метод интервалов: разложить на множители, отметить нули, расставить знаки по промежуткам. Учитывать кратность корня (при чётной кратности знак не меняется).'),
|
||
F('|x|=a\\Rightarrow x=\\pm a\\ (a\\ge0);\\qquad |f(x)|\\lt a\\Leftrightarrow -a\\lt f(x)\\lt a', 'Модуль'),
|
||
CI('Двойное неравенство $a\\le f(x)<b$ решают как систему; целые решения отбирают на полученном промежутке.'),
|
||
H('Разбор А5', 3),
|
||
P('Произведение действительных корней уравнения $x^2-5x+6=0$ по теореме Виета равно $6$ (корни $2$ и $3$).'),
|
||
CS('Ответ: $6$.'),
|
||
H('Разбор (целые решения)', 3),
|
||
P('Сколько целых решений у неравенства $-4<2x-1\\le5$? Имеем $-1{,}5<x\\le3$, то есть $x\\in\\{-1,0,1,2,3\\}$ — пять решений.'),
|
||
CS('Ответ: $5$.'),
|
||
FC('Дискриминант', '$D=b^2-4ac$'),
|
||
FC('Виет: сумма и произведение корней', '$x_1+x_2=-\\dfrac{b}{a},\\ x_1x_2=\\dfrac{c}{a}$'),
|
||
FC('$|f(x)|<a$', '$-a<f(x)<a$'),
|
||
QZ('Сумма корней уравнения $x^2-7x+12=0$:', ['7', '12', '-7', '3'], 0),
|
||
PR(),
|
||
]},
|
||
{ section: 'Уравнения и неравенства', title: 'Показательные, логарифмические, иррациональные', read: 12, blocks: [
|
||
H('Показательные, логарифмические, иррациональные уравнения и неравенства'),
|
||
F('a^{f}=a^{g}\\Leftrightarrow f=g;\\qquad \\log_a f=\\log_a g\\Leftrightarrow f=g\\gt 0', 'Равносильные переходы'),
|
||
F('\\sqrt{f}=g\\ \\Leftrightarrow\\ \\begin{cases}g\\ge0\\\\ f=g^2\\end{cases}', 'Иррациональное уравнение'),
|
||
CI('Метод рационализации (для неравенств): знак $\\log_a f-\\log_a g$ совпадает со знаком $(a-1)(f-g)$; знак $a^{f}-a^{g}$ — со знаком $(a-1)(f-g)$. Экономит время на сложных неравенствах.'),
|
||
CW('В логарифмических всегда выписывайте ОДЗ: аргумент $>0$, основание $>0$ и $\\ne1$.'),
|
||
H('Разбор В11', 3),
|
||
P('$\\log_2^2 x-3\\log_2 x+2=0$. Замена $t=\\log_2 x$: $t^2-3t+2=0$, $t=1$ или $t=2$, откуда $x=2$ или $x=4$; их произведение $8$.'),
|
||
CS('Ответ: $8$.'),
|
||
H('Разбор В14', 3),
|
||
P('Наименьшее целое решение неравенства $3^{x}>9$: так как основание $>1$, получаем $x>2$, наименьшее целое $x=3$.'),
|
||
CS('Ответ: $3$.'),
|
||
FC('$a^{f}=a^{g}$', '$f=g$'),
|
||
FC('$\\log_a f=\\log_a g$', '$f=g>0$'),
|
||
FC('Знак $\\log_a f-\\log_a g$ (рационализация)', 'как у $(a-1)(f-g)$'),
|
||
QZ('$\\log_3 81$ равно:', ['4', '3', '27', '9'], 0),
|
||
PR(),
|
||
]},
|
||
{ section: 'Функции и производная', title: 'Функции, графики, производная', read: 11, blocks: [
|
||
H('Функции: свойства, графики, производная'),
|
||
P('Ключевые свойства: ОДЗ, чётность (если $f(-x)=f(x)$ — чётная, график симметричен относительно $Oy$; если $f(-x)=-f(x)$ — нечётная), монотонность, нули.'),
|
||
SIM('graphtransform', 'Преобразования графиков: сдвиги и растяжения'),
|
||
F('f\'\\gt 0\\Rightarrow\\text{возрастает};\\quad f\'\\lt 0\\Rightarrow\\text{убывает};\\quad f\'=0\\ \\text{со сменой знака}\\Rightarrow\\text{экстремум}', 'Производная и поведение функции'),
|
||
H('Разбор В2 (квадратичная)', 3),
|
||
P('$f(x)=x^2-6x+5$: нули $1$ и $5$ (их сумма $6$); $f(0)=5$; вершина при $x=3$, наименьшее значение $f(3)=-4$.'),
|
||
CS('Сумма нулей $=6$; наименьшее значение $=-4$.'),
|
||
H('Разбор В19 (производная)', 3),
|
||
P('$f(x)=x^3-3x^2+5$: $f\'(x)=3x^2-6x=3x(x-2)$; функция возрастает на $(-\\infty;0]$ и $[2;+\\infty)$, убывает на $[0;2]$.'),
|
||
CS('Промежутки возрастания: $(-\\infty;0]$ и $[2;+\\infty)$.'),
|
||
FC('Чётная функция', '$f(-x)=f(x)$, симметрия относительно $Oy$'),
|
||
FC('$(x^n)\'$', '$n x^{n-1}$'),
|
||
FC('Признак возрастания', '$f\'(x)>0$'),
|
||
QZ('Функция $y=x^2$ является:', ['чётной', 'нечётной', 'ни чётной, ни нечётной', 'периодической'], 0),
|
||
PR(),
|
||
]},
|
||
{ section: 'Прогрессии и текстовые задачи', title: 'Прогрессии и текстовые задачи', read: 10, blocks: [
|
||
H('Прогрессии и текстовые задачи'),
|
||
F('a_n=a_1+(n-1)d,\\qquad S_n=\\dfrac{a_1+a_n}{2}\\,n', 'Арифметическая прогрессия'),
|
||
F('b_n=b_1 q^{\\,n-1},\\qquad S_n=\\dfrac{b_1(q^{n}-1)}{q-1}\\ (q\\ne1)', 'Геометрическая прогрессия'),
|
||
P('Текстовые задачи: проценты; движение ($s=vt$); работа (производительность $=\\dfrac{1}{t}$); смеси и сплавы (масса вещества $=$ доля $\\times$ масса смеси).'),
|
||
H('Разбор В6', 3),
|
||
P('$b_3=12$, $b_5=48$ (знаменатель положителен): $q^2=\\dfrac{48}{12}=4$, $q=2$, $b_1=\\dfrac{12}{4}=3$. Сумма первых четырёх членов $3+6+12+24=45$.'),
|
||
CS('Ответ: $45$.'),
|
||
H('Разбор (сплавы)', 3),
|
||
P('Сплав массой $200$ г содержит $30\\%$ меди. Масса меди $=0{,}3\\cdot200=60$ г. На таких долях строятся уравнения смесей.'),
|
||
FC('$n$-й член арифм. прогрессии', '$a_n=a_1+(n-1)d$'),
|
||
FC('Сумма геом. прогрессии', '$S_n=\\dfrac{b_1(q^n-1)}{q-1}$'),
|
||
FC('Путь', '$s=v\\cdot t$'),
|
||
QZ('В арифметической прогрессии $a_1=2$, $d=3$. Тогда $a_4$ равно:', ['11', '14', '8', '9'], 0),
|
||
PR(),
|
||
]},
|
||
{ section: 'Планиметрия', title: 'Треугольники, четырёхугольники, окружность', read: 11, blocks: [
|
||
H('Планиметрия: треугольники, четырёхугольники, окружность'),
|
||
F('S_\\triangle=\\tfrac12 a h_a=\\tfrac12 ab\\sin C;\\qquad \\dfrac{a}{\\sin A}=2R;\\qquad c^2=a^2+b^2-2ab\\cos C', 'Треугольник'),
|
||
SIM('triangle', 'Геометрия треугольника'),
|
||
P('Прямоугольный треугольник: гипотенуза $=2R$ (радиус описанной окружности). Правильный $n$-угольник связывает сторону, радиус описанной $R$ и вписанной $r$ окружностей.'),
|
||
CI('Вписанный угол равен половине центрального, опирающегося на ту же дугу.'),
|
||
H('Разбор В5', 3),
|
||
P('В прямоугольном треугольнике радиус описанной окружности $R=13$, один катет $10$. Гипотенуза $=2R=26$, второй катет $=\\sqrt{26^2-10^2}=\\sqrt{576}=24$.'),
|
||
CS('Ответ: $24$.'),
|
||
H('Разбор В10 (правильный шестиугольник)', 3),
|
||
P('У правильного шестиугольника со стороной $a$: $R=a$, $r=\\dfrac{\\sqrt3}{2}a$, площадь $S=\\dfrac{3\\sqrt3}{2}a^2$.'),
|
||
FC('Площадь треугольника', '$\\tfrac12 ab\\sin C$'),
|
||
FC('Теорема синусов', '$\\dfrac{a}{\\sin A}=2R$'),
|
||
FC('Вписанный угол', 'половина центрального на ту же дугу'),
|
||
QZ('Гипотенуза прямоугольного треугольника, вписанного в окружность радиуса 5, равна:', ['10', '5', '2,5', '25'], 0),
|
||
PR(),
|
||
]},
|
||
{ section: 'Продвинутое и комбинированное', title: 'Параметры и комбинированные задачи', read: 10, blocks: [
|
||
H('Задачи с параметрами и комбинированные задачи'),
|
||
P('Параметр — буква, от которой зависит ответ. Два подхода: аналитический (исследовать решение по параметру) и графический (семейство графиков и их пересечения).'),
|
||
CI('Частый приём: выразить параметр $a=\\varphi(x)$ и смотреть, сколько решений даёт горизонтальная прямая $y=a$ (число пересечений с графиком $\\varphi$).'),
|
||
P('Комбинированные задачи смешивают темы (алгебра и геометрия, прогрессии и проценты). Стратегия: разбить на подзадачи, аккуратно следя за ОДЗ и единицами.'),
|
||
CI('Продвинутый уровень подробно — в плане курса (Сканави, Высоцкий «Параметры», Прасолов). Здесь — общая стратегия и ориентиры.'),
|
||
FC('Графический метод для параметра', '$a=\\varphi(x)$; число решений = число пересечений $y=a$ с графиком'),
|
||
FC('Уравнение $x^2=a$: число решений', '$a>0$ — два, $a=0$ — одно, $a<0$ — нет'),
|
||
QZ('При каком $a$ уравнение $x^2=a$ имеет ровно одно решение?', ['a=0', 'a>0', 'a<0', 'при любом'], 0),
|
||
PR(),
|
||
]},
|
||
];
|
||
|
||
console.log(DRY ? '[DRY-RUN]' : '[APPLY]', 'курс id=', course.id);
|
||
const insLesson = db.prepare('INSERT INTO lessons (course_id, title, order_index, is_published, section_id, read_time) VALUES (?,?,?,1,?,?)');
|
||
const insBlock = db.prepare('INSERT INTO lesson_blocks (lesson_id, type, order_index, data) VALUES (?,?,?,?)');
|
||
const secOrder = {};
|
||
for (const L of LESSONS) {
|
||
const sec = db.prepare('SELECT id FROM course_sections WHERE course_id=? AND title=?').get(course.id, L.section);
|
||
if (!sec) { console.log(` [skip] нет секции «${L.section}»`); continue; }
|
||
const ex = db.prepare('SELECT id FROM lessons WHERE course_id=? AND title=?').get(course.id, L.title);
|
||
if (ex) { console.log(` есть урок: «${L.title}» (id ${ex.id}) — пропуск`); continue; }
|
||
secOrder[sec.id] = (secOrder[sec.id] || 0) + 1;
|
||
if (DRY) { console.log(` + [${L.section}] «${L.title}» (${L.blocks.length} блоков)`); continue; }
|
||
const lid = insLesson.run(course.id, L.title, secOrder[sec.id], sec.id, L.read).lastInsertRowid;
|
||
L.blocks.forEach(([type, data], bi) => insBlock.run(lid, type, bi, JSON.stringify(data)));
|
||
console.log(` + [${L.section}] «${L.title}» (id ${lid}, ${L.blocks.length} блоков)`);
|
||
}
|
||
console.log(DRY ? 'DRY-RUN: ничего не записано.' : 'Готово. Уроки остальных блоков добавлены (черновик курса).');
|