// === ПРИЛОЖЕНИЕ "ПОМОЩНИК ПО СКИДКАМ" === // Состояние приложения let state = { currentPage: 'home', chatHistory: [], testCurrent: null, testScore: 0, testQuestionIndex: 0, testAnswers: [] }; // === Инициализация === function init() { setupNavigation(); setupSearch(); setupUpload(); setupQuickSolutions(); renderLessons(); renderErrors(); renderInstructions(); renderFAQ(); renderTariffs(); setupCalculator(); setupAssistant(); setupTests(); setupAdmin(); loadState(); } // === Навигация === function setupNavigation() { // Клик по меню document.querySelectorAll('.nav-item[data-page]').forEach(item => { item.addEventListener('click', (e) => { e.preventDefault(); const page = item.dataset.page; navigateTo(page); // Мобильное меню if (window.innerWidth <= 1024) { document.getElementById('sidebar').classList.remove('open'); } }); }); // Клик по фичам на главной document.querySelectorAll('.feature-card').forEach(card => { card.addEventListener('click', () => { const page = card.dataset.page; if (page) navigateTo(page); }); }); // Мобильное меню document.getElementById('openSidebar').addEventListener('click', () => { document.getElementById('sidebar').classList.add('open'); }); document.getElementById('closeSidebar').addEventListener('click', () => { document.getElementById('sidebar').classList.remove('open'); }); } function navigateTo(page) { // Скрыть все страницы document.querySelectorAll('.page').forEach(p => p.classList.remove('active')); document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active')); // Показать нужную document.getElementById(`page-${page}`).classList.add('active'); document.querySelector(`.nav-item[data-page="${page}"]`)?.classList.add('active'); state.currentPage = page; saveState(); } // === Поиск === function setupSearch() { const searchHandler = () => { const query = document.getElementById('searchInput').value.trim().toLowerCase(); if (!query) return; performSearch(query); }; document.getElementById('searchBtn').addEventListener('click', searchHandler); document.getElementById('searchInput').addEventListener('keypress', (e) => { if (e.key === 'Enter') searchHandler(); }); // Поиск с главной document.getElementById('homeSearchBtn').addEventListener('click', () => { const query = document.getElementById('homeSearchInput').value.trim(); if (query) { navigateTo('search'); document.getElementById('searchInput').value = query; performSearch(query.toLowerCase()); } }); document.getElementById('homeSearchInput').addEventListener('keypress', (e) => { if (e.key === 'Enter') { const query = e.target.value.trim(); if (query) { navigateTo('search'); document.getElementById('searchInput').value = query; performSearch(query.toLowerCase()); } } }); // Быстрые вопросы document.querySelectorAll('.qq-btn').forEach(btn => { btn.addEventListener('click', () => { const q = btn.dataset.q; navigateTo('assistant'); setTimeout(() => { document.getElementById('chatInput').value = q; sendChatMessage(q); }, 300); }); }); // Поиск ошибок document.getElementById('errorSearchInput').addEventListener('input', (e) => { const query = e.target.value.toLowerCase(); filterErrors(query); }); } function performSearch(query) { const results = []; // Поиск в ошибках KB.errors.forEach(err => { if ( err.code.toLowerCase().includes(query) || err.title.toLowerCase().includes(query) || err.meaning.toLowerCase().includes(query) ) { results.push({ type: 'error', title: `Ошибка ${err.code}: ${err.title}`, preview: err.meaning, data: err }); } }); // Поиск в уроках KB.lessons.forEach(lesson => { if ( lesson.title.toLowerCase().includes(query) || lesson.description.toLowerCase().includes(query) ) { results.push({ type: 'lesson', title: `Урок: ${lesson.title}`, preview: lesson.description, data: lesson }); } }); // Поиск в инструкциях KB.instructions.forEach(inst => { if ( inst.title.toLowerCase().includes(query) || inst.category.toLowerCase().includes(query) ) { results.push({ type: 'instruction', title: `Инструкция: ${inst.title}`, preview: inst.steps.slice(0, 3).join(' → ') + '...', data: inst }); } }); // Поиск в FAQ KB.faq.forEach(f => { if ( f.question.toLowerCase().includes(query) || f.answer.toLowerCase().includes(query) ) { results.push({ type: 'faq', title: `FAQ: ${f.question}`, preview: f.answer.slice(0, 150) + '...', data: f }); } }); // Отображение результатов const container = document.getElementById('searchResults'); if (results.length === 0) { container.innerHTML = `

По запросу "${escapeHtml(query)}" ничего не найдено.

Попробуйте:
• Задать вопрос в AI-помощнике
• Посмотреть раздел "Ошибки" или "FAQ"

`; } else { container.innerHTML = results.map(r => `

${escapeHtml(r.title)}

${escapeHtml(r.preview)}

`).join(''); // Клик по результату container.querySelectorAll('.search-result-item').forEach(item => { item.addEventListener('click', () => { const type = item.dataset.type; const id = item.dataset.id; if (type === 'error') showErrorModal(KB.errors.find(e => e.id === id)); if (type === 'lesson') showLessonModal(KB.lessons.find(l => l.id === id)); if (type === 'instruction') navigateTo('instructions'); if (type === 'faq') navigateTo('faq'); }); }); } } // === Загрузка скриншотов === function setupUpload() { const dropzone = document.getElementById('uploadDropzone'); const input = document.getElementById('uploadInput'); const btn = document.getElementById('uploadBtn'); btn.addEventListener('click', () => input.click()); input.addEventListener('change', (e) => { if (e.target.files.length > 0) handleUpload(e.target.files[0]); }); // Drag & drop dropzone.addEventListener('dragover', (e) => { e.preventDefault(); dropzone.classList.add('dragover'); }); dropzone.addEventListener('dragleave', () => { dropzone.classList.remove('dragover'); }); dropzone.addEventListener('drop', (e) => { e.preventDefault(); dropzone.classList.remove('dragover'); if (e.dataTransfer.files.length > 0) { handleUpload(e.dataTransfer.files[0]); } }); // Клик по всей карточке dropzone.addEventListener('click', (e) => { if (e.target !== btn && e.target !== input) input.click(); }); } function handleUpload(file) { if (!file.type.startsWith('image/')) { alert('Пожалуйста, загрузите изображение (PNG, JPG, JPEG)'); return; } const modal = document.getElementById('uploadModal'); const body = document.getElementById('uploadModalBody'); modal.style.display = 'flex'; // Имитация анализа (в реальности здесь будет OCR API) setTimeout(() => { // Демонстрационный ответ const demoErrors = [ { detected: 'Ошибка 403: Нет прав на создание скидки', confidence: 85, solution: KB.errors[0] }, { detected: 'Ошибка TARIFF_NOT_FOUND', confidence: 70, solution: KB.errors[1] } ]; const result = demoErrors[Math.floor(Math.random() * demoErrors.length)]; body.innerHTML = `
🔍

Анализ завершён

Уверенность распознавания: ${result.confidence}%

📋 Я вижу ошибку:

${result.detected}

📖 Что это значит

${result.solution.meaning}

⚠️ Возможные причины

    ${result.solution.causes.map(c => `
  1. ${c}
  2. `).join('')}

✅ Что сделать

    ${result.solution.solution.map(s => `
  1. ${s}
  2. `).join('')}
${result.solution.contact ? `

📞 Если не помогло

${result.solution.contact}

` : ''}
`; }, 2000); } // === Быстрые решения === function setupQuickSolutions() { document.querySelectorAll('.solution-card').forEach(card => { card.addEventListener('click', () => { const key = card.dataset.solution; const solution = KB.quickSolutions[key]; if (solution) showQuickSolution(solution); }); }); } function showQuickSolution(solution) { const modal = document.getElementById('errorModal'); const title = document.getElementById('errorModalTitle'); const body = document.getElementById('errorModalBody'); title.textContent = solution.title; body.innerHTML = `

📋 Алгоритм действий

    ${solution.steps.map(s => `
  1. ${s}
  2. `).join('')}
${solution.contact ? `

📞 Контакты

${solution.contact}

` : ''} `; modal.style.display = 'flex'; } // === Рендер уроков === function renderLessons() { const container = document.getElementById('lessonsList'); container.innerHTML = KB.lessons.map(lesson => `
${lesson.icon}
${lesson.title}
${lesson.description}
⏱ ${lesson.duration}
`).join(''); container.querySelectorAll('.lesson-card').forEach(card => { card.addEventListener('click', () => { const lesson = KB.lessons.find(l => l.id === card.dataset.id); showLessonModal(lesson); }); }); } function showLessonModal(lesson) { const modal = document.getElementById('lessonModal'); const title = document.getElementById('lessonModalTitle'); const body = document.getElementById('lessonModalBody'); title.textContent = lesson.title; body.innerHTML = `
${lesson.content}
`; modal.style.display = 'flex'; } // === Рендер ошибок === function renderErrors() { renderErrorsGrid(KB.errors); } function renderErrorsGrid(errors) { const container = document.getElementById('errorsGrid'); if (errors.length === 0) { container.innerHTML = '

Ошибки не найдены

'; return; } container.innerHTML = errors.map(err => `
Код: ${err.code}
${err.title}
${err.meaning}
`).join(''); container.querySelectorAll('.error-card').forEach(card => { card.addEventListener('click', () => { const err = KB.errors.find(e => e.id === card.dataset.id); showErrorModal(err); }); }); } function filterErrors(query) { const filtered = KB.errors.filter(err => err.code.toLowerCase().includes(query) || err.title.toLowerCase().includes(query) || err.meaning.toLowerCase().includes(query) ); renderErrorsGrid(filtered); } function showErrorModal(err) { const modal = document.getElementById('errorModal'); const title = document.getElementById('errorModalTitle'); const body = document.getElementById('errorModalBody'); title.textContent = `Ошибка ${err.code}`; body.innerHTML = `

📖 Что это значит

${err.meaning}

⚠️ Почему возникает

    ${err.causes.map(c => `
  1. ${c}
  2. `).join('')}

✅ Что сделать

    ${err.solution.map(s => `
  1. ${s}
  2. `).join('')}
${err.contact ? `

📞 Если не помогло

${err.contact}

` : ''} `; modal.style.display = 'flex'; } // === Рендер инструкций === function renderInstructions() { const container = document.getElementById('instructionsList'); const categories = [...new Set(KB.instructions.map(i => i.category))]; container.innerHTML = categories.map(cat => `

${cat}

${KB.instructions.filter(i => i.category === cat).map(inst => `
${inst.icon}
${inst.title}
`).join('')}
`).join(''); container.querySelectorAll('.instruction-card').forEach(card => { card.addEventListener('click', () => { const inst = KB.instructions.find(i => i.id === card.dataset.id); showInstructionModal(inst); }); }); } function showInstructionModal(inst) { const modal = document.getElementById('lessonModal'); const title = document.getElementById('lessonModalTitle'); const body = document.getElementById('lessonModalBody'); title.textContent = inst.title; body.innerHTML = `

Категория: ${inst.category}

Пошаговая инструкция

    ${inst.steps.map((step, i) => `
  1. ${step}
  2. `).join('')}
`; modal.style.display = 'flex'; } // === Рендер FAQ === function renderFAQ() { const container = document.getElementById('faqList'); container.innerHTML = KB.faq.map((f, i) => `
${f.question} +
${f.answer}
`).join(''); container.querySelectorAll('.faq-card').forEach(card => { card.addEventListener('click', () => { card.classList.toggle('active'); }); }); } // === Калькулятор === function renderTariffs() { const select = document.getElementById('calcTariff'); select.innerHTML = KB.tariffs.map(t => `` ).join(''); } function setupCalculator() { document.getElementById('calcBtn').addEventListener('click', calculateDiscount); } function calculateDiscount() { const tariffId = document.getElementById('calcTariff').value; const type = document.getElementById('calcType').value; const amount = parseFloat(document.getElementById('calcAmount').value); const period = parseInt(document.getElementById('calcPeriod').value); const reason = document.getElementById('calcReason').value; // Валидация if (!amount || amount <= 0) { alert('Введите корректный размер скидки'); return; } if (!reason) { alert('Выберите основание для скидки'); return; } const tariff = KB.tariffs.find(t => t.id === tariffId); let discountAmount, finalPrice, totalSavings; if (type === 'percent') { if (amount > 100) { alert('Процентная скидка не может быть больше 100%'); return; } discountAmount = (tariff.price * amount) / 100; finalPrice = tariff.price - discountAmount; totalSavings = discountAmount * period; } else { if (amount >= tariff.price) { alert('Фиксированная скидка не может превышать абонентскую плату'); return; } discountAmount = amount; finalPrice = tariff.price - discountAmount; totalSavings = discountAmount * period; } const container = document.getElementById('calcResult'); container.style.display = 'block'; container.innerHTML = `

Результат расчета

Тариф: ${tariff.name}
Абонентская плата: ${tariff.price.toLocaleString('ru-RU')} ₸
Тип скидки: ${type === 'percent' ? `${amount}%` : `${amount.toLocaleString('ru-RU')} ₸`}
Срок действия: ${period} мес.
Итоговая плата в месяц: ${finalPrice.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ₸
Экономия за период: ${totalSavings.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ₸
`; } // === AI-помощник === function setupAssistant() { const input = document.getElementById('chatInput'); const btn = document.getElementById('chatSendBtn'); btn.addEventListener('click', () => { const message = input.value.trim(); if (message) { sendChatMessage(message); input.value = ''; } }); input.addEventListener('keypress', (e) => { if (e.key === 'Enter' && input.value.trim()) { sendChatMessage(input.value.trim()); input.value = ''; } }); // Обратная связь document.getElementById('feedbackYes').addEventListener('click', () => { showFeedbackResponse('Спасибо за оценку! Рад, что помог.'); }); document.getElementById('feedbackNo').addEventListener('click', () => { showFeedbackResponse('Что можно улучшить? Вы можете задать вопрос подробнее или обратиться к руководителю.'); }); } function sendChatMessage(message) { const messagesContainer = document.getElementById('chatMessages'); const feedbackBlock = document.getElementById('feedbackBlock'); // Сообщение пользователя messagesContainer.innerHTML += `

${escapeHtml(message)}

`; // Имитация ответа AI (в реальности здесь будет API) const response = generateAIResponse(message); setTimeout(() => { messagesContainer.innerHTML += `
🤖
${response}
`; messagesContainer.scrollTop = messagesContainer.scrollHeight; feedbackBlock.style.display = 'flex'; }, 800); } function generateAIResponse(message) { const lowerMsg = message.toLowerCase(); // Поиск по базе знаний let bestMatch = null; let bestScore = 0; // Проверка ошибок KB.errors.forEach(err => { const score = calculateSimilarity(lowerMsg, err.code.toLowerCase() + ' ' + err.title.toLowerCase()); if (score > bestScore) { bestScore = score; bestMatch = { type: 'error', data: err }; } }); // Проверка FAQ KB.faq.forEach(f => { const score = calculateSimilarity(lowerMsg, f.question.toLowerCase()); if (score > bestScore) { bestScore = score; bestMatch = { type: 'faq', data: f }; } }); if (bestMatch && bestScore > 0.3) { if (bestMatch.type === 'error') { const err = bestMatch.data; return `

Это ошибка: ${err.code} — ${err.title}

Что это значит: ${err.meaning}

Причины:

Что сделать:

    ${err.solution.map(s => `
  1. ${s}
  2. `).join('')}
${err.contact ? `

Контакты: ${err.contact}

` : ''} `; } else if (bestMatch.type === 'faq') { const f = bestMatch.data; return `

${f.question}

${f.answer}

`; } } // Ответ по умолчанию return `

Я нашёл несколько материалов, которые могут помочь:

Вы можете уточнить вопрос или открыть один из этих разделов.

`; } function calculateSimilarity(s1, s2) { const words1 = s1.split(/\s+/); const words2 = s2.split(/\s+/); const matches = words1.filter(w => words2.some(w2 => w2.includes(w) || w.includes(w2))); return matches.length / Math.max(words1.length, words2.length); } function showFeedbackResponse(text) { const feedbackBlock = document.getElementById('feedbackBlock'); feedbackBlock.innerHTML = `${text}`; setTimeout(() => { feedbackBlock.style.display = 'none'; feedbackBlock.innerHTML = ` Ответ помог? `; setupAssistant(); }, 3000); } // === Тесты === function setupTests() { document.getElementById('startTestBtn').addEventListener('click', startTest); document.getElementById('nextQuestionBtn').addEventListener('click', nextQuestion); document.getElementById('restartTestBtn').addEventListener('click', () => { document.getElementById('testResult').style.display = 'none'; document.getElementById('testsIntro').style.display = 'block'; }); } function startTest() { const test = KB.tests[0]; state.testCurrent = test; state.testScore = 0; state.testQuestionIndex = 0; state.testAnswers = []; document.getElementById('testsIntro').style.display = 'none'; document.getElementById('testContainer').style.display = 'block'; showQuestion(); } function showQuestion() { const test = state.testCurrent; const q = test.questions[state.testQuestionIndex]; document.getElementById('testCounter').textContent = `${state.testQuestionIndex + 1}/${test.questions.length}`; document.getElementById('testProgress').style.width = `${((state.testQuestionIndex) / test.questions.length) * 100}%`; document.getElementById('testQuestion').textContent = q.question; document.getElementById('testAnswers').innerHTML = q.answers.map((a, i) => `
${a}
`).join(''); document.getElementById('testFeedback').className = 'test-feedback'; document.getElementById('testFeedback').style.display = 'none'; document.getElementById('nextQuestionBtn').style.display = 'none'; // Выбор ответа document.querySelectorAll('.test-answer').forEach(ans => { ans.addEventListener('click', () => { document.querySelectorAll('.test-answer').forEach(a => a.classList.remove('selected')); ans.classList.add('selected'); // Проверка const selectedIndex = parseInt(ans.dataset.index); checkAnswer(selectedIndex); }); }); } function checkAnswer(selectedIndex) { const test = state.testCurrent; const q = test.questions[state.testQuestionIndex]; const isCorrect = selectedIndex === q.correct; if (isCorrect) { state.testScore++; } state.testAnswers.push({ question: q.question, selected: selectedIndex, correct: q.correct, isCorrect }); // Показать результат const feedback = document.getElementById('testFeedback'); feedback.textContent = isCorrect ? '✅ Правильно! ' + q.explanation : '❌ Неправильно. ' + q.explanation; feedback.className = 'test-feedback ' + (isCorrect ? '' : 'incorrect'); feedback.style.display = 'block'; // Блокировка ответов document.querySelectorAll('.test-answer').forEach((a, i) => { if (i === q.correct) a.classList.add('correct'); if (i === selectedIndex && !isCorrect) a.classList.add('incorrect'); }); document.getElementById('nextQuestionBtn').style.display = 'inline-block'; } function nextQuestion() { state.testQuestionIndex++; const test = state.testCurrent; if (state.testQuestionIndex >= test.questions.length) { showTestResult(); } else { showQuestion(); } } function showTestResult() { document.getElementById('testContainer').style.display = 'none'; document.getElementById('testResult').style.display = 'block'; const score = state.testScore; const total = state.testCurrent.questions.length; const percentage = (score / total) * 100; document.getElementById('resultScore').textContent = `${score}/${total}`; let message = ''; if (percentage >= 90) { message = '🎉 Отлично! Вы полностью готовы к работе со скидками.'; } else if (percentage >= 70) { message = '👍 Хорошо! Есть небольшие пробелы, но вы готовы к работе.'; } else if (percentage >= 50) { message = '📚 Неплохо, но стоит повторить материал и пройти тест ещё раз.'; } else { message = '⚠️ Рекомендуем пройти обучение ещё раз и внимательно изучить материалы.'; } document.getElementById('resultMessage').textContent = message; } // === Админ-панель === function setupAdmin() { document.querySelectorAll('.admin-tab').forEach(tab => { tab.addEventListener('click', () => { document.querySelectorAll('.admin-tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.admin-panel').forEach(p => p.classList.remove('active')); tab.classList.add('active'); document.getElementById(`admin-${tab.dataset.tab}`).classList.add('active'); }); }); renderAdminPanel('errors'); } function renderAdminPanel(type) { const container = document.getElementById(`admin-${type}`); if (type === 'errors') { container.innerHTML = ` ${KB.errors.map(err => `
${err.code} — ${err.title}
`).join('')} `; } if (type === 'faq') { container.innerHTML = ` ${KB.faq.map(f => `
${f.question}
`).join('')} `; } if (type === 'lessons') { container.innerHTML = ` ${KB.lessons.map(l => `
${l.icon} ${l.title}
${l.description}
`).join('')} `; } if (type === 'instructions') { container.innerHTML = ` ${KB.instructions.map(i => `
${i.icon} ${i.title}
${i.category}
`).join('')} `; } if (type === 'tests') { container.innerHTML = ` ${KB.tests.map(t => `
${t.title}
${t.questions.length} вопросов
`).join('')} `; } } // === Сохранение состояния === function saveState() { localStorage.setItem('discountHelper_state', JSON.stringify({ currentPage: state.currentPage })); } function loadState() { const saved = localStorage.getItem('discountHelper_state'); if (saved) { try { const data = JSON.parse(saved); state.currentPage = data.currentPage || 'home'; } catch (e) {} } navigateTo(state.currentPage); } // === Утилиты === function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // === Закрытие модальных окон === document.getElementById('closeErrorModal').addEventListener('click', () => { document.getElementById('errorModal').style.display = 'none'; }); document.getElementById('closeUploadModal').addEventListener('click', () => { document.getElementById('uploadModal').style.display = 'none'; }); document.getElementById('closeLessonModal').addEventListener('click', () => { document.getElementById('lessonModal').style.display = 'none'; }); // Клик по overlay document.querySelectorAll('.modal-overlay').forEach(overlay => { overlay.addEventListener('click', (e) => { if (e.target === overlay) { overlay.style.display = 'none'; } }); }); // Клавиша Escape document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { document.querySelectorAll('.modal-overlay').forEach(m => m.style.display = 'none'); } }); // === Старт === init();