diff --git a/backend/src/controllers/adminController.js b/backend/src/controllers/adminController.js index 75439f9..f94f6c4 100644 --- a/backend/src/controllers/adminController.js +++ b/backend/src/controllers/adminController.js @@ -525,7 +525,7 @@ function getFeatures(_req, res) { function updateFeatures(req, res) { const allowed = ['crossword', 'hangman', 'pet', 'red_book', 'collection', 'flashcards', 'knowledge_map', 'board', 'biochem', 'live_quiz', 'classroom', - 'gamification']; + 'gamification', 'assistant']; const updates = req.body; const stmt = db.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES (?, ?)"); const getOld = db.prepare("SELECT value FROM app_settings WHERE key = ?"); diff --git a/backend/src/controllers/assistantController.js b/backend/src/controllers/assistantController.js index bfe6b25..e13a512 100644 --- a/backend/src/controllers/assistantController.js +++ b/backend/src/controllers/assistantController.js @@ -62,6 +62,21 @@ const FAQ = [ // ── Сам помощник ── { id: 'assistant-off', q: 'Как выключить помощника?', a: 'Профиль → «Настройки» → «Помощник Квантик». Можно выключить совсем или скрыть конкретные подсказки кнопкой «Не показывать».', url: '/profile', keywords: ['помощник','выключ','ассистент','подсказк','квантик','скрыть'] }, { id: 'assistant-tour', q: 'Как пройти тур заново?', a: 'Нажми на меня и выбери «Тур по системе» — проведу по разделам ещё раз.', url: null, keywords: ['тур','онбординг','обзор','заново'] }, + { id: 'assistant-can', q: 'О чём тебя можно спросить?', a: 'Спрашивай «как сделать…»: вырезать учебник, создать карточки, начать тест, сохранить доску, разобрать ошибки, включить тёмную тему. Ещё я ищу уроки, курсы и файлы по платформе.', url: null, keywords: ['умеешь','помощь','спросить','что можешь','help','команд','о чём'] }, + // ── Профиль / безопасность ── + { id: 'password', q: 'Как сменить пароль?', a: 'Профиль → «Безопасность» → смена пароля.', url: '/profile', keywords: ['пароль','сменить','смена','безопасн','password'] }, + { id: 'avatar', q: 'Как поменять имя или аватар?', a: 'Профиль → «Аккаунт»: отображаемое имя и аватар.', url: '/profile', keywords: ['имя','аватар','профиль','фото','никнейм'] }, + // ── Флешкарты подробнее ── + { id: 'deck-create', q: 'Как создать колоду карточек?', a: 'В «Флешкартах» нажми создать колоду и задай название — затем добавляй карточки.', url: '/flashcards', keywords: ['колод','создать','набор','карточк'] }, + { id: 'deck-bulk', q: 'Как добавить много карточек сразу?', a: 'В колоде есть «Добавить список» — вставь пары «вопрос — ответ» построчно, можно с картинками.', url: '/flashcards', keywords: ['массов','список','импорт','много','сразу'] }, + { id: 'srs', q: 'Как работает интервальное повторение?', a: 'После ответа карточка получает срок следующего показа: лёгкие — реже, трудные — чаще. Так запоминается надолго.', url: '/flashcards', keywords: ['интервал','повторен','srs','память','алгоритм'] }, + // ── Прогресс / поиск / экзамен9 ── + { id: 'progress-subject', q: 'Как посмотреть прогресс по предмету?', a: 'На дашборде есть виджет «Прогресс по предметам» (средний процент) и история результатов.', url: '/dashboard', keywords: ['прогресс','предмет','процент','средн','статистик'] }, + { id: 'find-topic', q: 'Как быстро найти тему или урок?', a: 'Поиск (Ctrl+K) ищет уроки, курсы, файлы и вопросы по названию. Я тоже поищу, если спросишь.', url: null, keywords: ['найти','тема','урок','поиск','быстро'] }, + { id: 'exam9', q: 'Что такое «Подготовка к экзамену 9»?', a: 'Тренажёр для ЦТ/ЦЭ по математике 9: задания по темам, режимы экзамена и тренировки, разбор ошибок.', url: '/exam-prep/math9', keywords: ['экзамен 9','math9','цт','цэ','подготовка','9 класс'] }, + // ── Питомец / без класса ── + { id: 'feed-pet', q: 'Как покормить и погладить питомца?', a: 'На странице питомца есть кнопки: погладить (раз в минуту) и покормить (раз в 30 минут) — за это монеты и XP.', url: '/pet', keywords: ['покорм','погладит','питомец','еда','уход'] }, + { id: 'no-class', q: 'Можно заниматься без класса?', a: 'Да — учебники, тесты, карточки, лаборатория и питомец доступны и без класса. Класс нужен для заданий от учителя.', url: '/dashboard', keywords: ['без класса','самостоят','один','сам'] }, ]; /* ── Источники проактивных подсказок (всё уже есть в БД) ──────────────── */ diff --git a/backend/src/server.js b/backend/src/server.js index ec45f0c..887dbc0 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -183,7 +183,7 @@ app.use('/api/classroom', classroomRoutes); app.use('/api/games', gamesRoutes); app.use('/api/knowledge-map', requireFeature('knowledge_map'), knowledgeMapRoutes); app.use('/api/pet', requireFeature('pet'), petRoutes); -app.use('/api/assistant', requireFeature('pet'), require('./routes/assistant')); +app.use('/api/assistant', requireFeature('assistant'), require('./routes/assistant')); app.use('/api/collection', requireFeature('collection'), collectionRoutes); app.use('/api/red-book', requireFeature('red_book'), redBookRoutes); app.use('/api/biochem', requireFeature('biochem'), require('./routes/biochem')); diff --git a/frontend/js/admin/sections/games.js b/frontend/js/admin/sections/games.js index 69cd05f..8b403e1 100644 --- a/frontend/js/admin/sections/games.js +++ b/frontend/js/admin/sections/games.js @@ -16,6 +16,7 @@ { key: 'biochem', label: 'Биохимия', desc: 'Молекулярный редактор, задачи на построение молекул и реакции', icon: 'flask-conical' }, { key: 'live_quiz', label: 'Живая викторина', desc: 'Синхронная викторина в реальном времени для всего класса', icon: 'radio' }, { key: 'classroom', label: 'Онлайн-уроки (classroom)', desc: 'Синхронные онлайн-уроки с доской и видео', icon: 'video' }, + { key: 'assistant', label: 'Помощник «Квантик»', desc: 'Плавающий помощник: подсказки по разделам, напоминания и «Спроси Квантика»', icon: 'sparkles' }, ]; const FS_FEATURES = [ diff --git a/frontend/js/assistant.js b/frontend/js/assistant.js index 5202f06..03b5f0b 100644 --- a/frontend/js/assistant.js +++ b/frontend/js/assistant.js @@ -293,6 +293,9 @@ '.asst-ans-link{display:inline-block;margin-top:4px;color:#9B5DE5;font-weight:700;font-size:.78rem;text-decoration:none;}', '.asst-ans-sec{font-size:.66rem;font-weight:800;color:#8a94a6;text-transform:uppercase;letter-spacing:.03em;margin:12px 0 2px;}', '.asst-ans-box{max-height:46vh;overflow:auto;}', + '.asst-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px;}', + '.asst-chip{border:1px solid #e2e8f0;background:#f8fafc;border-radius:99px;padding:5px 10px;font:600 .72rem Manrope,sans-serif;color:#475569;cursor:pointer;text-align:left;}', + '.asst-chip:hover{border-color:#9B5DE5;color:#9B5DE5;}', '.asst-empty{font-size:.82rem;color:#8a94a6;padding:6px 0;}', // на мобиле сайдбар — выезжающая шторка, контент во всю ширину → к левому краю '@media(max-width:768px){.asst-root,.app-layout ~ .asst-root,.app-layout.sb-collapsed ~ .asst-root{left:12px;bottom:18px;}.asst-fab{width:48px;height:48px;}}', @@ -351,10 +354,22 @@ } /* ── «Спроси Квантика» ───────────────────────────────────────────────── */ + var SUGGESTIONS = [ + 'Как вырезать кусок учебника?', + 'Как создать карточки?', + 'Как начать тест?', + 'Как сохранить доску себе?', + 'Где мои домашние задания?', + 'Как включить тёмную тему?', + ]; function openAsk() { + var chips = '
' + + SUGGESTIONS.map(function (q) { return ''; }).join('') + + '
'; openBubble( '
Спроси Квантика
' + '' + + chips + '
', {}); var inp = bubble.querySelector('.asst-ask-in'); var box = bubble.querySelector('.asst-ans-box'); @@ -362,6 +377,9 @@ var t = null; inp.addEventListener('input', function () { clearTimeout(t); t = setTimeout(function () { runAsk(inp.value, box); }, 350); }); inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') { clearTimeout(t); runAsk(inp.value, box); } }); + bubble.querySelectorAll('.asst-chip').forEach(function (c) { + c.addEventListener('click', function () { inp.value = c.textContent; runAsk(c.textContent, box); inp.focus(); }); + }); } function runAsk(q, box) { q = (q || '').trim();