feat(ct-math): каркас курса ЦЭ/ЦТ на банке questions (темы + draft-курс + секции)
- backend/scripts/seed_ctmath_course.js — идемпотентный аддитивный seed: +6 тем (Преобразование выражений/Модуль/Иррациональные ур./Показательные ур./ Производная/Параметры), DRAFT-курс «ЦЭ/ЦТ — Математика» + 9 секций. Применён на живой БД: course id=13 (is_published=0), topics 72-77, sections 27-35. Существующие данные не тронуты; повторный запуск ничего не дублирует. - BUILD_ON_QUESTIONS.md: уточнения инспекции банка (year=2025 = «Экзамен 9», без тем; реальный ЦТ-11 = ~733 размеч., Часть B = fill-blank → гоча mode='ct') + блок «Состояние реализации». - README: статус каркаса. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
'use strict';
|
||||
/*
|
||||
* Каркас курса «ЦЭ/ЦТ — Математика» на существующем банке questions.
|
||||
* План: plans/ct-math/ (BUILD_ON_QUESTIONS.md).
|
||||
* ИДЕМПОТЕНТЕН и АДДИТИВЕН: добавляет недостающие темы (topics),
|
||||
* создаёт DRAFT-курс (is_published=0) + 9 секций. Существующие данные не трогает.
|
||||
* Запуск: node backend/scripts/seed_ctmath_course.js (применить)
|
||||
* node backend/scripts/seed_ctmath_course.js --dry (только показать план)
|
||||
*/
|
||||
const db = require('../src/db/db');
|
||||
const DRY = process.argv.includes('--dry');
|
||||
const MATH_ID = 3;
|
||||
|
||||
// 1) Недостающие темы под модульную карту (см. BUILD_ON_QUESTIONS §3)
|
||||
const NEW_TOPICS = [
|
||||
'Преобразование выражений',
|
||||
'Модуль',
|
||||
'Иррациональные уравнения',
|
||||
'Показательные уравнения',
|
||||
'Производная',
|
||||
'Параметры',
|
||||
];
|
||||
|
||||
// 2) Секции курса = 9 блоков (PLAN §3)
|
||||
const SECTIONS = [
|
||||
'Числа и вычисления',
|
||||
'Алгебраические преобразования',
|
||||
'Уравнения и неравенства',
|
||||
'Функции и производная',
|
||||
'Тригонометрия',
|
||||
'Прогрессии и текстовые задачи',
|
||||
'Планиметрия',
|
||||
'Стереометрия',
|
||||
'Продвинутое и комбинированное',
|
||||
];
|
||||
|
||||
const COURSE_TITLE = 'ЦЭ/ЦТ — Математика';
|
||||
const COURSE_DESC = 'Подготовка к ЦЭ/ЦТ по математике: 30 заданий (часть А — А1–А10, часть В — В1–В20). Теория по темам, тренажёр на банке заданий прошлых лет, карточки формул, пробные варианты.';
|
||||
|
||||
function topicExists(name) {
|
||||
return db.prepare('SELECT id FROM topics WHERE subject_id=? AND LOWER(name)=LOWER(?)').get(MATH_ID, name);
|
||||
}
|
||||
function adminId() {
|
||||
const u = db.prepare("SELECT id FROM users WHERE role='admin' ORDER BY id LIMIT 1").get()
|
||||
|| db.prepare('SELECT id FROM users ORDER BY id LIMIT 1').get();
|
||||
return u && u.id;
|
||||
}
|
||||
|
||||
let addedTopics = 0, skippedTopics = 0;
|
||||
console.log(DRY ? '[DRY-RUN] план изменений:' : '[APPLY] вношу изменения:');
|
||||
|
||||
console.log('\n— Темы (topics) —');
|
||||
for (const name of NEW_TOPICS) {
|
||||
const ex = topicExists(name);
|
||||
if (ex) { console.log(` есть: ${name} (id ${ex.id})`); skippedTopics++; continue; }
|
||||
if (DRY) { console.log(` + добавить: ${name}`); addedTopics++; continue; }
|
||||
const id = db.prepare('INSERT INTO topics (subject_id,name) VALUES (?,?)').run(MATH_ID, name).lastInsertRowid;
|
||||
console.log(` + добавлено: ${name} (id ${id})`);
|
||||
addedTopics++;
|
||||
}
|
||||
|
||||
console.log('\n— Курс (courses) —');
|
||||
let course = db.prepare("SELECT id,is_published FROM courses WHERE subject_slug='math' AND title=?").get(COURSE_TITLE);
|
||||
let courseId;
|
||||
if (course) {
|
||||
courseId = course.id;
|
||||
console.log(` есть курс «${COURSE_TITLE}» (id ${courseId}, ${course.is_published ? 'published' : 'draft'})`);
|
||||
} else if (DRY) {
|
||||
console.log(` + создать DRAFT-курс «${COURSE_TITLE}» (created_by=${adminId()})`);
|
||||
} else {
|
||||
const by = adminId();
|
||||
// cover_emoji не указываем — применится дефолт схемы; в коде эмодзи не вводим
|
||||
courseId = db.prepare(
|
||||
'INSERT INTO courses (subject_slug,title,description,is_published,created_by) VALUES (?,?,?,0,?)'
|
||||
).run('math', COURSE_TITLE, COURSE_DESC, by).lastInsertRowid;
|
||||
console.log(` + создан DRAFT-курс «${COURSE_TITLE}» (id ${courseId}, created_by=${by})`);
|
||||
}
|
||||
|
||||
console.log('\n— Секции (course_sections) —');
|
||||
if (!courseId && DRY) {
|
||||
SECTIONS.forEach((t, i) => console.log(` + секция [${i + 1}] ${t}`));
|
||||
} else if (courseId) {
|
||||
SECTIONS.forEach((title, i) => {
|
||||
const ex = db.prepare('SELECT id FROM course_sections WHERE course_id=? AND title=?').get(courseId, title);
|
||||
if (ex) { console.log(` есть: [${i + 1}] ${title} (id ${ex.id})`); return; }
|
||||
if (DRY) { console.log(` + секция [${i + 1}] ${title}`); return; }
|
||||
const id = db.prepare('INSERT INTO course_sections (course_id,title,order_index) VALUES (?,?,?)').run(courseId, title, i + 1).lastInsertRowid;
|
||||
console.log(` + секция [${i + 1}] ${title} (id ${id})`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`\nИтог: темы +${addedTopics} (есть ${skippedTopics}); курс id=${courseId || '(dry)'}; секций ${SECTIONS.length}.`);
|
||||
console.log(DRY ? 'DRY-RUN: ничего не записано.' : 'Готово. Курс создан как ЧЕРНОВИК (is_published=0) — ученикам не виден до публикации.');
|
||||
Reference in New Issue
Block a user