From 12e74010c1cec606af483ebb51fa2ed604efc741 Mon Sep 17 00:00:00 2001 From: Dauren777 Date: Mon, 10 Aug 2026 09:42:40 +0000 Subject: [PATCH] =?UTF-8?q?Compliance=20portal=20frontend=20(=D1=84=D1=80?= =?UTF-8?q?=D0=BE=D0=BD=D1=82:=20=D0=B7=D0=B0=D0=BA=D0=BE=D0=BD=D1=8B,=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D0=B0,=20?= =?UTF-8?q?=D0=B2=D0=B8=D0=B4=D0=B5=D0=BE,=20=D0=B6=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D0=B1=D1=8B,=20=D1=82=D0=B5=D1=81=D1=82,=20=D0=B4=D0=B0=D1=88?= =?UTF-8?q?=D0=B1=D0=BE=D1=80=D0=B4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 173 +++++++++----- script.js | 511 ++++++++++++++++++++++------------------- style.css | 655 ++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 868 insertions(+), 471 deletions(-) diff --git a/index.html b/index.html index 5a6ab95..c727774 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,9 @@ - + - Compliance TV | Корпоративный телеканал + Compliance TV | Комплаенс порталы @@ -13,62 +13,121 @@ 📺

Compliance TV

-

Корпоративный телеканал по комплаенс

+

Комплаенс офицердің ақпараттық порталы

+
+
+

Комплаенс — бұл бәріміздің мәселеміз

+

Телеканалдың комплаенс-порталы: заңдар, оқыту материалдары, видео сабақтар, шағым ящигі және тест нәтижелерінің статистикасы.

+ +
+
+
+
+
+

⚖️ Заңдар мен материалдар

+

Комплаенс бойынша оқыту заңдары мен регламенттер

+
+
+ +
+
+
+
+ +
+
+

🏢 Басшылық құрылымы

+

Телеканалдың басшылығы және комплаенс бағыты

+
+
+
+
-

🎬 Обучающие видео

-

Краткие уроки по комплаенс (2-5 минут)

+

🎬 Видео сабақтар

+

Комплаенс бойынша қысқа видео сабақтар

+
+ 📤 Жаңа видео сабақ қосу (офицер) +
+ + + +
+
-
+
-

📰 Новости комплаенс

-

Последние изменения и важные объявления

+

📮 Шағым ящигі

+

Құпия шағым немесе өтініш қалдыру (анонимді түрде)

-
-
- -
-
-

❓ Часто задаваемые вопросы

-

Ответы на типичные вопросы сотрудников

+
+
+ + + + + +

Жіберу толық анонимді. Қаласаңыз, байланыс деректеріңізді қосыңыз.

+
+
+

Сенім телефоны

+

☎️ 8 800 000-00-00

+

📧 compliance@tv.kz

+

Барлық өтініштер құпия қарастырылады.

+
-
-

🧠 Проверка знаний

-

Пройдите тестирование по материалам канала

+

📝 Комплаенс тесті

+

Біліміңізді тексеріңіз — нәтиже дашбордқа жазылады

-

Вам будет предложено 10 вопросов по темам:

+

Тестке кірмес бұрын атыңызды және бөлімді көрсетіңіз:

+
+ + +
    -
  • • Этика и конфликт интересов
  • -
  • • Антикоррупционная политика
  • -
  • • Работа с конфиденциальной информацией
  • -
  • • Подарки и вознаграждения
  • +
  • • Этика және мүдделер қақтығысы
  • +
  • • Сыбайлас жемқорлыққа қарсы саясат
  • +
  • • Құпия ақпаратпен жұмыс
  • +
  • • Сыйлықтар мен төлемдер
- +
-
+
-

📊 Моя статистика

+

📊 Дашборд: тест нәтижелері

+

Қызметкерлердің тест нәтижелерінің статистикасы

-
-
- 📚 - 0 - Просмотрено уроков -
-
- ✅ - 0 - Пройдено тестов -
-
- 🎯 - 0% - Средний балл -
-
- 📅 - — - Последняя активность -
+
+
+ + +
+
+ + + + + + + + + + +
ҚызметкерБөлімНәтижеДата
-
diff --git a/script.js b/script.js index c863c16..50d643a 100644 --- a/script.js +++ b/script.js @@ -1,205 +1,152 @@ -const VIDEOS = [ - { title: "Кодекс этики: основные принципы", duration: "4:32", category: "Этика" }, - { title: "Конфликт интересов: как распознать", duration: "3:45", category: "Этика" }, - { title: "Антикоррупционная политика", duration: "5:18", category: "Антикоррупция" }, - { title: "Подарки и вознаграждения", duration: "3:20", category: "Антикоррупция" }, - { title: "Конфиденциальная информация", duration: "4:55", category: "Информация" }, - { title: "Работа с документами", duration: "3:10", category: "Информация" }, - { title: "Внутренняя инсайдерская информация", duration: "4:02", category: "Информация" }, - { title: "Борьба с отмыванием денег", duration: "5:45", category: "Антикоррупция" }, - { title: "Харассмент и дискриминация", duration: "4:28", category: "Этика" }, - { title: "Защита персональных данных", duration: "3:55", category: "Информация" }, - { title: "Взаимодействие с госорганами", duration: "4:15", category: "Антикоррупция" }, - { title: "Социальные сети: правила поведения", duration: "3:38", category: "Этика" } +var LAWS = [ + { id: 1, title: "Қазақстан Республикасының «Сыбайлас жемқорлыққа қарсы іс-қимыл туралы» Заңы", cat: "Заң", desc: "Сыбайлас жемқорлыққа қарсы іс-қимылдың негізгі қағидаттары, тыйымдар мен жауапкершілік." }, + { id: 2, title: "ҚР «Мемлекеттік қызмет туралы» Заңы", cat: "Заң", desc: "Мемлекеттік қызметшілердің этикасы мен шектеулері, мүдделер қақтығысын реттеу." }, + { id: 3, title: "«Жеке деректер және оларды қорғау туралы» Заң", cat: "Заң", desc: "Жеке деректерді жинау, өңдеу және сақтау талаптары." }, + { id: 4, title: "Қазақстан Республикасының Азаматтық кодексі (құпия ақпарат бөлімі)", cat: "Құқық", desc: "Коммерциялық құпия және құпия ақпарат режимі." }, + { id: 5, title: "«Ақпаратқа қол жеткізу туралы» Заң", cat: "Заң", desc: "Ақпаратқа қол жеткізу тәртібі және қызметтік ақпараттың құпиялылығы." }, + { id: 6, title: "Телеканалдың Ішкі еңбек тәртібі", cat: "Ішкі регламент", desc: "Еңбек тәртібі, қауіпсіздік және жұмыс орнындағы әдеп нормалары." }, + { id: 7, title: "Қаржылық бақылау жөніндегі нұсқаулық", cat: "Ішкі регламент", desc: "Қаржылық операцияларды бақылау, сыйлықтар мен төлемдерді декларациялау тәртібі." }, + { id: 8, title: "Ақпараттық қауіпсіздік саясаты", cat: "Ішкі регламент", desc: "Ақпараттық ресурстарды пайдалану, пароль және құпия сөздермен жұмыс ережелері." }, + { id: 9, title: "«Ақшаны жылыстатуға қарсы іс-қимыл туралы» Заң", cat: "Заң", desc: "Күдікті операциялар туралы хабарлау және қаржылық мониторинг талаптары." }, + { id: 10, title: "Комплаенс-бақылау жөніндегі ереже", cat: "Ішкі регламент", desc: "Комплаенс-тексерулер, өзін-өзі тексеру және есептілік тәртібі." } ]; -const NEWS = [ - { - date: "10 августа 2026", - title: "Обновлён кодекс корпоративной этики", - excerpt: "Внесены изменения в раздел о конфликте интересов. Всем сотрудникам необходимо ознакомиться до 1 сентября.", - tag: "Важно" - }, - { - date: "5 августа 2026", - title: "Ежегодное комплаенс-тестирование", - excerpt: "Прохождение обязательно для всех сотрудников до 30 сентября. Результаты будут учтены при аттестации.", - tag: "Обязательно" - }, - { - date: "1 августа 2026", - title: "Новый канал связи для анонимных обращений", - excerpt: "Запущен телефон доверия для сообщений о нарушениях. Круглосуточно, анонимно.", - tag: "Новости" - }, - { - date: "25 июля 2026", - title: "Изменения в законодательстве РК", - excerpt: "Обзор новых требований по противодействию коррупции и отмыванию доходов.", - tag: "Законодательство" - } +var STRUCTURE = [ + { id: 1, name: "Айгүл Сейтова", role: "Бас директор", dept: "Әкімшілік", head: true, emoji: "👩‍💼" }, + { id: 2, name: "Ерлан Қасымов", role: "Директордың орынбасары", dept: "Әкімшілік", head: false, emoji: "👨‍💼" }, + { id: 3, name: "Асет Бисенов", role: "Комплаенс офицер", dept: "Комплаенс қызметі", head: false, emoji: "🛡️" }, + { id: 4, name: "Гүлназ Омарова", role: "Заңгер", dept: "Құқықтық департамент", head: false, emoji: "⚖️" }, + { id: 5, name: "Дәурен Нұрлан", role: "Бас бухгалтер", dept: "Қаржы департаменті", head: false, emoji: "💼" }, + { id: 6, name: "Майра Жұмабек", role: "HR директоры", dept: "Кадр департаменті", head: false, emoji: "🧑‍🏫" }, + { id: 7, name: "Бауыржан Серік", role: "IT директоры", dept: "IT департаменті", head: false, emoji: "💻" }, + { id: 8, name: "Ляззат Төлеген", role: "Бас редактор", dept: "Редакция", head: false, emoji: "📰" } ]; -const FAQ = [ - { - q: "Могу ли я принять подарок от партнёра?", - a: "Подарки стоимостью до 5 МРП принимать можно без ограничений. Подарки дороже 5 МРП необходимо задекларировать и передать организации. Деньги в любой сумме принимать запрещено." - }, - { - q: "Что делать при возникновении конфликта интересов?", - a: "Немедленно сообщите непосредственному руководителю и в службу комплаенс. Воздержитесь от участия в решении вопроса до урегулирования ситуации." - }, - { - q: "Кому сообщать о фактах коррупции?", - a: "Сообщения принимаются через телефон доверия, email службы комплаенс или через руководителя. Гарантируем конфиденциальность и защиту от преследования." - }, - { - q: "Можно ли работать в другой компании по совместительству?", - a: "Внешнее совместительство разрешено, если не создаёт конфликт интересов. Необходимо получить письменное согласие руководителя и задекларировать в службе комплаенс." - }, - { - q: "Как часто нужно проходить комплаенс-обучение?", - a: "Обязательное обучение — ежегодно. Дополнительно — при изменении законодательства или должностных обязанностей." - }, - { - q: "Что считается конфиденциальной информацией?", - a: "Финансовые данные, персональные данные сотрудников, коммерческие тайны, договоры, стратегические планы. Передача третьим лицам без разрешения запрещена." - } +var VIDEOS = [ + { id: 1, title: "Комплаенс деген не?", category: "Кіріспе", duration: "4:32", desc: "Комплаенс ұғымы және телеканалдағы рөлі" }, + { id: 2, title: "Мүдделер қақтығысы: қалай анықтауға?", category: "Этика", duration: "3:45", desc: "Мүдделер қақтығысының белгілері мен шешімдері" }, + { id: 3, title: "Сыбайлас жемқорлыққа қарсы саясат", category: "Сыбайлас жемқорлық", duration: "5:18", desc: "Негізгі тыйымдар мен жауапкершілік" }, + { id: 4, title: "Сыйлықтар мен төлемдер: шегі қандай?", category: "Сыбайлас жемқорлық", duration: "3:20", desc: "Сыйлық қабылдау ережелері және декларациялау" }, + { id: 5, title: "Құпия ақпаратпен жұмыс", category: "Ақпарат", duration: "4:55", desc: "Құпия ақпаратты қорғау ережелері" }, + { id: 6, title: "Жеке деректерді қорғау", category: "Ақпарат", duration: "3:55", desc: "Жеке деректермен жұмыс істеу талаптары" }, + { id: 7, title: "Қысым мен кемсітушілік", category: "Этика", duration: "4:28", desc: "Жұмыс орнындағы әдеп және теңдік" }, + { id: 8, title: "Әлеуметтік желілердегі мінез-құлық", category: "Этика", duration: "3:38", desc: "Қызметкердің әлеуметтік желідегі әдебі" } ]; -const QUESTIONS = [ - { - q: "Максимальная стоимость подарка, который можно принять без декларации:", - options: ["5 МРП", "10 МРП", "20 МРП", "Любая стоимость"], - correct: 0 - }, - { - q: "При возникновении конфликта интересов вы должны:", - options: ["Решить вопрос самостоятельно", "Сообщить руководителю и в службу комплаенс", "Игнорировать ситуацию", "Уволиться"], - correct: 1 - }, - { - q: "Как часто необходимо проходить комплаенс-тестирование?", - options: ["Раз в 3 года", "По желанию", "Ежегодно", "Только при приёме на работу"], - correct: 2 - }, - { - q: "Можно ли принимать денежные подарки от партнёров?", - options: ["До 10 000 тенге можно", "Можно с разрешения руководителя", "Запрещено в любой сумме", "Можно, если задекларировать"], - correct: 2 - }, - { - q: "Что делать с подарком дороже 5 МРП?", - options: ["Оставить себе", "Передать коллегам", "Задекларировать и передать организации", "Вернуть дарителю"], - correct: 2 - }, - { - q: "Конфиденциальная информация включает:", - options: ["Только финансовые отчёты", "Только персональные данные", "Финансовые данные, ПД, коммерческие тайны", "Только договоры"], - correct: 2 - }, - { - q: "Внешнее совместительство:", - options: ["Полностью запрещено", "Разрешено без ограничений", "Разрешено с согласия руководителя", "Разрешено только в выходные"], - correct: 2 - }, - { - q: "Каналы для сообщения о коррупции:", - options: ["Только лично руководителю", "Телефон доверия, email, руководитель", "Только анонимно", "Сообщать нельзя"], - correct: 1 - }, - { - q: "Антикоррупционное обучение обязательно для:", - options: ["Только руководителей", "Только новых сотрудников", "Всех сотрудников", "Только бухгалтерии"], - correct: 2 - }, - { - q: "Нарушение комплаенс-политики может привести к:", - options: ["Устному замечанию", "Дисциплинарной ответственности вплоть до увольнения", "Никаким последствиям", "Только штрафу"], - correct: 1 - } +var QUESTIONS = [ + { q: "Сыйлықты декларациясыз қабылдауға болатын ең жоғары шекті мөлшері:", options: ["5 АЕК", "10 АЕК", "20 АЕК", "Кез келген"], correct: 0 }, + { q: "Мүдделер қақтығысы туындағанда не істеу керек?", options: ["Өзім шешемін", "Басшыға және комплаенс қызметіне хабарлау", "Елемеу", "Жұмыстан кету"], correct: 1 }, + { q: "Комплаенс-тестілеуден қаншалықты жиі өту керек?", options: ["3 жылда бір", "Қалауымша", "Жыл сайын", "Тек жұмысқа қабылданғанда"], correct: 2 }, + { q: "Серіктестерден ақшалай сыйлық қабылдауға бола ма?", options: ["10 000 теңгеге дейін", "Басшының рұқсатымен", "Кез келген мөлшерде тыйым салынады", "Болады, егер декларацияласа"], correct: 2 }, + { q: "5 АЕК-тен қымбат сыйлықпен не істеу керек?", options: ["Өзіме қалдыру", "Әріптестерге беру", "Декларациялап, ұйымға тапсыру", "Қайтару"], correct: 2 }, + { q: "Құпия ақпаратқа не жатады?", options: ["Тек қаржылық есептер", "Тек жеке деректер", "Қаржылық деректер, ЖД, коммерциялық құпия", "Тек келісімшарттар"], correct: 2 }, + { q: "Сырттай қоса атқару:", options: ["Толық тыйым салынады", "Шектеусіз рұқсат", "Басшының келісімімен рұқсат", "Тек демалыс күндері"], correct: 2 }, + { q: "Сыбайлас жемқорлық туралы хабарлау арналары:", options: ["Тек жеке басшыға", "Сенім телефоны, email, басшы", "Тек анонимді", "Хабарлауға болмайды"], correct: 1 }, + { q: "Сыбайлас жемқорлыққа қарсы оқыту міндетті:", options: ["Тек басшыларға", "Тек жаңа қызметкерлерге", "Барлық қызметкерлерге", "Тек бухгалтерияға"], correct: 2 }, + { q: "Комплаенс ережесін бұзу неге әкеледі?", options: ["Ауызша ескерту", "Тәртіптік жауапкершілік, жұмыстан босатуға дейін", "Ешқандай салдарға", "Тек айыппұлға"], correct: 1 } ]; -let currentQuestion = 0; -let score = 0; -let testTaken = false; -let stats = { lessons: 0, tests: 0, totalScore: 0, lastActivity: null }; +var currentQuestion = 0; +var score = 0; +var testTaken = false; +var userName = ""; +var userDept = ""; -function loadStats() { - const saved = localStorage.getItem("complianceStats"); - if (saved) { - stats = JSON.parse(saved); - } - updateStatsDisplay(); +var mockResults = [ + { name: "Айгүл Сейтова", dept: "Әкімшілік", score: 10, total: 10, date: "2026-08-10" }, + { name: "Дәурен Нұрлан", dept: "Қаржы", score: 9, total: 10, date: "2026-08-10" }, + { name: "Майра Жұмабек", dept: "Кадр", score: 8, total: 10, date: "2026-08-09" }, + { name: "Бауыржан Серік", dept: "IT", score: 7, total: 10, date: "2026-08-09" }, + { name: "Ляззат Төлеген", dept: "Редакция", score: 6, total: 10, date: "2026-08-08" } +]; + +var results = []; +var resultsBackendReady = false; + +function getResults() { + return resultsBackendReady ? results : mockResults; } -function saveStats() { - localStorage.setItem("complianceStats", JSON.stringify(stats)); - updateStatsDisplay(); +function renderLaws() { + var query = (document.getElementById("law-search").value || "").toLowerCase(); + var activeCat = document.querySelector(".chip.active"); + var cat = activeCat ? activeCat.dataset.cat : ""; + var list = document.getElementById("law-list"); + var filtered = LAWS.filter(function (l) { + var matchQ = l.title.toLowerCase().indexOf(query) !== -1 || l.desc.toLowerCase().indexOf(query) !== -1; + var matchC = !cat || l.cat === cat; + return matchQ && matchC; + }); + if (!filtered.length) { + list.innerHTML = '
Ештеңе табылмады
'; + return; + } + list.innerHTML = filtered.map(function (l) { + return '
' + + '
' + l.title + '
' + + '
' + l.cat + '' + l.id + '
' + + (l.desc ? '
' + l.desc + '
' : '') + + '
'; + }).join(""); } -function updateStatsDisplay() { - document.getElementById("stat-lessons").textContent = stats.lessons; - document.getElementById("stat-tests").textContent = stats.tests; - const avg = stats.tests > 0 ? Math.round(stats.totalScore / stats.tests) : 0; - document.getElementById("stat-average").textContent = avg + "%"; - document.getElementById("stat-last").textContent = stats.lastActivity ? new Date(stats.lastActivity).toLocaleDateString("ru-RU") : "—"; +function renderLawChips() { + var cats = {}; + LAWS.forEach(function (l) { cats[l.cat] = true; }); + var chips = document.getElementById("law-chips"); + chips.innerHTML = '' + + Object.keys(cats).map(function (c) { + return ''; + }).join(""); + chips.querySelectorAll(".chip").forEach(function (chip) { + chip.addEventListener("click", function () { + chips.querySelectorAll(".chip").forEach(function (c) { c.classList.remove("active"); }); + chip.classList.add("active"); + renderLaws(); + }); + }); +} + +function renderStructure() { + var grid = document.getElementById("structure-grid"); + grid.innerHTML = STRUCTURE.map(function (s) { + return '
' + + '
' + s.emoji + '
' + + '
' + s.name + '
' + + '
' + s.role + '
' + + '
' + s.dept + '
' + + (s.head ? '
👑 Басшылық
' : '') + + '
'; + }).join(""); } function renderVideos() { - const grid = document.getElementById("video-grid"); - grid.innerHTML = VIDEOS.map(v => ` -
-
-
-
${v.title}
-
- ${v.category} - ${v.duration} -
-
-
- `).join(""); + var grid = document.getElementById("video-grid"); + grid.innerHTML = VIDEOS.map(function (v) { + return '
' + + '
' + v.desc + '
' + + '
' + + '
' + v.title + '
' + + '
' + v.category + '' + v.duration + '
' + + '
'; + }).join(""); } -function watchVideo(title) { - stats.lessons++; - stats.lastActivity = new Date().toISOString(); - saveStats(); - alert(`▶️ Видео "${title}"\n\nВ реальной версии здесь будет видеоплеер.`); +function openVideo(id) { + var v = VIDEOS.find(function (x) { return x.id === id; }); + if (v) alert("🎬 «" + v.title + "»\n\nРеалды нұсқада мұнда видео ойнайды (файлды офицер жүктеген кезде)."); } -function renderNews() { - const list = document.getElementById("news-list"); - list.innerHTML = NEWS.map(n => ` -
-
${n.date}
-
${n.title}
-
${n.excerpt}
- ${n.tag} -
- `).join(""); -} - -function renderFAQ() { - const list = document.getElementById("faq-list"); - list.innerHTML = FAQ.map((item, i) => ` -
- -
${item.a}
-
- `).join(""); -} - -function toggleFAQ(index) { - const items = document.querySelectorAll(".faq-item"); - items[index].classList.toggle("active"); -} - -function startTest() { +function initTest() { currentQuestion = 0; score = 0; testTaken = false; + userName = document.getElementById("test-name").value.trim(); + userDept = document.getElementById("test-dept").value.trim(); + if (!userName || !userDept) { + alert("Аты-жөніңізді және бөлімді толтырыңыз"); + return; + } document.getElementById("test-start").style.display = "none"; document.getElementById("test-quiz").style.display = "block"; document.getElementById("test-result").style.display = "none"; @@ -207,39 +154,34 @@ function startTest() { } function showQuestion() { - const q = QUESTIONS[currentQuestion]; + var q = QUESTIONS[currentQuestion]; document.getElementById("q-current").textContent = currentQuestion + 1; document.getElementById("q-total").textContent = QUESTIONS.length; document.getElementById("question-text").textContent = q.q; document.getElementById("test-feedback").textContent = ""; - - const options = document.getElementById("test-options"); - options.innerHTML = q.options.map((opt, i) => ` - - `).join(""); + document.getElementById("test-options").innerHTML = q.options.map(function (opt, i) { + return ''; + }).join(""); } function answer(selectedIndex) { if (testTaken) return; testTaken = true; - - const q = QUESTIONS[currentQuestion]; - const options = document.querySelectorAll(".test-option"); - const feedback = document.getElementById("test-feedback"); - + var q = QUESTIONS[currentQuestion]; + var options = document.querySelectorAll(".test-option"); + var feedback = document.getElementById("test-feedback"); if (selectedIndex === q.correct) { options[selectedIndex].classList.add("correct"); - feedback.textContent = "✅ Правильно!"; + feedback.textContent = "✅ Дұрыс!"; feedback.style.color = "#48bb78"; score++; } else { options[selectedIndex].classList.add("wrong"); options[q.correct].classList.add("correct"); - feedback.textContent = "❌ Неправильно"; + feedback.textContent = "❌ Қате"; feedback.style.color = "#f56565"; } - - setTimeout(() => { + setTimeout(function () { currentQuestion++; if (currentQuestion < QUESTIONS.length) { testTaken = false; @@ -251,51 +193,160 @@ function answer(selectedIndex) { } function finishTest() { - const percent = Math.round((score / QUESTIONS.length) * 100); - - stats.tests++; - stats.totalScore += percent; - stats.lastActivity = new Date().toISOString(); - saveStats(); - + var percent = Math.round((score / QUESTIONS.length) * 100); document.getElementById("test-quiz").style.display = "none"; document.getElementById("test-result").style.display = "block"; - document.getElementById("result-score").textContent = `${score} из ${QUESTIONS.length}`; - document.getElementById("result-percent").textContent = `${percent}%`; - - let message = ""; - if (percent >= 90) { - message = "🎉 Отличный результат! Вы хорошо знаете комплаенс-политику."; - } else if (percent >= 70) { - message = "👍 Хороший результат. Рекомендуется повторить отдельные темы."; + document.getElementById("result-score").textContent = score + " / " + QUESTIONS.length; + document.getElementById("result-percent").textContent = percent + "%"; + var msg = percent >= 90 + ? "🎉 Тамаша! Сіз комплаенс саясатын жақсы білесіз." + : percent >= 70 + ? "👍 Жақсы нәтиже. Жеке тақырыптарды қайталау ұсынылады." + : "⚠️ Оқуды қайта өтіп, материалдарды зерделеуді ұсынамыз."; + document.getElementById("result-message").textContent = msg; + saveResult(userName, userDept, score, QUESTIONS.length); +} + +function saveResult(name, dept, sc, total) { + var rec = { name: name, dept: dept, score: sc, total: total, date: new Date().toISOString().slice(0, 10) }; + if (resultsBackendReady) { + fetch("/api/results", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(rec) + }).catch(function () {}); } else { - message = "⚠️ Рекомендуем пройти обучение заново и изучить материалы."; - } - document.getElementById("result-message").textContent = message; -} - -function resetStats() { - if (confirm("Сбросить всю статистику?")) { - stats = { lessons: 0, tests: 0, totalScore: 0, lastActivity: null }; - saveStats(); + results.push(rec); + renderDashboard(); } } -document.getElementById("start-test-btn").addEventListener("click", startTest); -document.getElementById("restart-test-btn").addEventListener("click", startTest); -document.getElementById("reset-stats-btn").addEventListener("click", resetStats); +function renderStats() { + var rows = getResults(); + var total = rows.length; + var passed = rows.filter(function (r) { return r.score / r.total >= 0.7; }).length; + var avg = total ? Math.round(rows.reduce(function (s, r) { return s + r.score / r.total * 100; }, 0) / total) : 0; + var stats = document.getElementById("stats-grid"); + stats.innerHTML = [ + { icon: "👥", val: total, label: "Тест тапсырған" }, + { icon: "✅", val: passed, label: "70%+ нәтижемен" }, + { icon: "🎯", val: avg + "%", label: "Орташа нәтиже" }, + { icon: "📈", val: topPerformer(rows), label: "Үздік қызметкер" } + ].map(function (s) { + return '
' + s.icon + '' + + '' + s.val + '' + s.label + '
'; + }).join(""); +} -document.querySelectorAll(".nav-link").forEach(link => { - link.addEventListener("click", function(e) { +function topPerformer(rows) { + if (!rows.length) return "—"; + var best = rows.reduce(function (a, b) { return (a.score / a.total) >= (b.score / b.total) ? a : b; }); + return best.name; +} + +function renderResultsTable() { + var query = (document.getElementById("dash-search").value || "").toLowerCase(); + var rows = getResults().filter(function (r) { + return r.name.toLowerCase().indexOf(query) !== -1 || r.dept.toLowerCase().indexOf(query) !== -1; + }).slice().reverse(); + var tbody = document.querySelector("#results-table tbody"); + if (!rows.length) { + tbody.innerHTML = 'Нәтиже жоқ'; + return; + } + tbody.innerHTML = rows.map(function (r) { + var pct = Math.round(r.score / r.total * 100); + var cls = pct >= 90 ? "score-good" : pct >= 70 ? "score-mid" : "score-low"; + return '' + r.name + '' + r.dept + '' + + '' + pct + '% (' + r.score + '/' + r.total + ')' + + '' + r.date + ''; + }).join(""); +} + +function renderDashboard() { + renderStats(); + renderResultsTable(); +} + +function exportCsv() { + var rows = getResults(); + var head = ["Қызметкер", "Бөлім", "Нәтиже", "Дата"]; + var body = rows.map(function (r) { + return [r.name, r.dept, r.score + "/" + r.total, r.date] + .map(function (v) { return '"' + String(v).replace(/"/g, '""') + '"'; }).join(";"); + }); + var csv = "\uFEFF" + [head.join(";"), ...body].join("\n"); + var a = document.createElement("a"); + a.href = URL.createObjectURL(new Blob([csv], { type: "text/csv" })); + a.download = "test_results.csv"; + a.click(); +} + +function tryBackend() { + fetch("/api/results").then(function (r) { return r.json(); }).then(function (data) { + if (data && Array.isArray(data)) { + results = data; + resultsBackendReady = true; + renderDashboard(); + } + }).catch(function () {}); +} + +document.getElementById("law-search").addEventListener("input", renderLaws); +document.getElementById("dash-search").addEventListener("input", renderResultsTable); +document.getElementById("export-btn").addEventListener("click", exportCsv); +document.getElementById("start-test-btn").addEventListener("click", initTest); +document.getElementById("restart-test-btn").addEventListener("click", function () { + document.getElementById("test-start").style.display = "block"; + document.getElementById("test-result").style.display = "none"; +}); + +document.getElementById("complaint-form").addEventListener("submit", function (e) { + e.preventDefault(); + var form = e.target; + var data = { + category: form.category.value, + text: form.text.value + }; + if (resultsBackendReady) { + fetch("/api/complaints", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data) + }).then(function () { + form.reset(); + showFormSuccess(); + }).catch(function () { form.reset(); showFormSuccess(); }); + } else { + form.reset(); + showFormSuccess(); + } +}); + +function showFormSuccess() { + var note = document.querySelector(".form-note"); + var old = note.textContent; + note.textContent = "✅ Өтініш жіберілді!"; + setTimeout(function () { note.textContent = old; }, 4000); +} + +document.getElementById("video-form").addEventListener("submit", function (e) { + e.preventDefault(); + alert("📤 Бұл мүмкіндік сервер қосылғанда жұмыс істейді (Рецепт: видео жүктеу)."); +}); + +document.querySelectorAll(".nav-link").forEach(function (link) { + link.addEventListener("click", function (e) { e.preventDefault(); - document.querySelectorAll(".nav-link").forEach(l => l.classList.remove("active")); - this.classList.add("active"); - const target = this.getAttribute("href"); - document.querySelector(target).scrollIntoView({ behavior: "smooth" }); + document.querySelectorAll(".nav-link").forEach(function (l) { l.classList.remove("active"); }); + link.classList.add("active"); + document.querySelector(link.getAttribute("href")).scrollIntoView({ behavior: "smooth" }); }); }); -loadStats(); +renderLawChips(); +renderLaws(); +renderStructure(); renderVideos(); -renderNews(); -renderFAQ(); +renderDashboard(); +tryBackend(); diff --git a/style.css b/style.css index 1356c74..0589860 100644 --- a/style.css +++ b/style.css @@ -4,17 +4,33 @@ box-sizing: border-box; } +:root { + --navy: #1a365d; + --navy-2: #2c5282; + --blue: #4299e1; + --blue-2: #3182ce; + --text: #2d3748; + --muted: #718096; + --bg: #f5f7fa; + --card: #f7fafc; + --border: #e2e8f0; + --green: #48bb78; + --red: #f56565; +} + +html { scroll-behavior: smooth; } + body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - background: #f5f7fa; - color: #2d3748; + background: var(--bg); + color: var(--text); line-height: 1.6; } header { - background: linear-gradient(135deg, #1a365d 0%, #2c5282 100%); + background: linear-gradient(135deg, var(--navy) 0%, var(--navy-2) 100%); color: white; - padding: 20px 0; + padding: 14px 0; position: sticky; top: 0; z-index: 100; @@ -29,7 +45,7 @@ header { justify-content: space-between; align-items: center; flex-wrap: wrap; - gap: 20px; + gap: 14px; } .logo { @@ -39,34 +55,33 @@ header { } .logo-icon { - font-size: 42px; + font-size: 36px; } .logo-text h1 { - font-size: 28px; + font-size: 24px; font-weight: 700; - margin-bottom: 2px; + line-height: 1.1; } .logo-text p { - font-size: 13px; + font-size: 12px; opacity: 0.9; - font-weight: 400; } nav { display: flex; - gap: 8px; + gap: 6px; flex-wrap: wrap; } .nav-link { color: white; text-decoration: none; - padding: 10px 18px; + padding: 9px 14px; border-radius: 6px; font-weight: 500; - font-size: 14px; + font-size: 13px; transition: all 0.2s; background: rgba(255, 255, 255, 0.1); } @@ -77,7 +92,93 @@ nav { .nav-link.active { background: white; - color: #1a365d; + color: var(--navy); +} + +.hero { + background: linear-gradient(135deg, #0d2747 0%, #1a365d 55%, #2c5282 100%); + color: white; + padding: 70px 20px; +} + +.hero-content { + max-width: 1200px; + margin: 0 auto; +} + +.hero h1 { + font-size: clamp(28px, 4.5vw, 44px); + line-height: 1.15; + font-weight: 800; + max-width: 700px; + margin-bottom: 18px; +} + +.hero p { + font-size: 17px; + color: #cbd5e0; + max-width: 620px; + margin-bottom: 28px; +} + +.hero-btns { + display: flex; + gap: 12px; + flex-wrap: wrap; +} + +.btn-primary { + display: inline-block; + background: linear-gradient(135deg, var(--blue) 0%, var(--blue-2) 100%); + color: white; + border: none; + padding: 12px 28px; + border-radius: 8px; + font-size: 15px; + font-weight: 600; + cursor: pointer; + text-decoration: none; + transition: transform 0.2s, box-shadow 0.2s; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(66, 153, 225, 0.4); +} + +.btn-ghost { + display: inline-block; + background: transparent; + color: white; + border: 2px solid rgba(255, 255, 255, 0.4); + padding: 10px 26px; + border-radius: 8px; + font-size: 15px; + font-weight: 600; + cursor: pointer; + text-decoration: none; + transition: all 0.2s; +} + +.btn-ghost:hover { + border-color: white; + background: rgba(255, 255, 255, 0.1); +} + +.btn-secondary { + background: var(--blue); + color: white; + border: none; + padding: 10px 20px; + border-radius: 8px; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: background 0.2s; +} + +.btn-secondary:hover { + background: var(--blue-2); } main { @@ -95,20 +196,172 @@ main { } .section-header { - margin-bottom: 24px; + margin-bottom: 22px; } .section-header h2 { font-size: 24px; - color: #1a365d; + color: var(--navy); margin-bottom: 6px; } .section-desc { - color: #718096; + color: var(--muted); font-size: 14px; } +.toolbar { + display: flex; + gap: 12px; + align-items: center; + flex-wrap: wrap; + margin-bottom: 18px; +} + +.search-input { + flex: 1; + min-width: 200px; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: 8px; + font-size: 14px; + outline: none; +} + +.search-input:focus { + border-color: var(--blue); + box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.15); +} + +.chips { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +.chip { + padding: 7px 14px; + border-radius: 20px; + border: 1px solid var(--border); + background: var(--card); + cursor: pointer; + font-size: 13px; + color: var(--muted); + transition: all 0.2s; +} + +.chip.active { + background: var(--navy); + color: white; + border-color: var(--navy); +} + +.law-list { + display: grid; + gap: 12px; +} + +.law-item { + background: var(--card); + border-left: 4px solid var(--blue); + border-radius: 8px; + padding: 16px 20px; + transition: transform 0.2s; +} + +.law-item:hover { + transform: translateX(4px); +} + +.law-title { + font-weight: 600; + font-size: 16px; + color: var(--text); + margin-bottom: 4px; +} + +.law-meta { + font-size: 13px; + color: var(--muted); +} + +.law-cat { + display: inline-block; + background: var(--blue); + color: white; + padding: 2px 10px; + border-radius: 12px; + font-size: 12px; + margin-right: 8px; +} + +.law-desc { + font-size: 14px; + color: #4a5568; + margin-top: 8px; +} + +.empty { + text-align: center; + color: var(--muted); + padding: 30px; +} + +.structure-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 16px; +} + +.structure-card { + background: var(--card); + border: 1px solid var(--border); + border-radius: 10px; + padding: 20px; + text-align: center; + transition: all 0.2s; +} + +.structure-card:hover { + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); + transform: translateY(-3px); +} + +.structure-avatar { + font-size: 40px; + margin-bottom: 10px; +} + +.structure-name { + font-weight: 700; + font-size: 16px; + color: var(--text); +} + +.structure-role { + color: var(--blue); + font-size: 13px; + font-weight: 600; + margin-top: 2px; +} + +.structure-dept { + color: var(--muted); + font-size: 13px; + margin-top: 6px; +} + +.structure-head { + display: inline-block; + margin-top: 8px; + background: #e6fffa; + color: #234e52; + font-size: 11px; + font-weight: 600; + padding: 2px 10px; + border-radius: 10px; +} + .video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); @@ -116,7 +369,7 @@ main { } .video-card { - background: #f7fafc; + background: var(--card); border-radius: 10px; overflow: hidden; transition: transform 0.2s, box-shadow 0.2s; @@ -135,140 +388,145 @@ main { align-items: center; justify-content: center; position: relative; + color: white; + font-size: 13px; + text-align: center; + padding: 10px; } .video-thumbnail::after { content: "▶"; - font-size: 48px; - color: white; + font-size: 40px; opacity: 0.9; + position: absolute; + top: 10px; + right: 16px; } .video-info { - padding: 16px; + padding: 14px 16px; } .video-title { font-weight: 600; - font-size: 16px; - color: #2d3748; - margin-bottom: 8px; + font-size: 15px; + color: var(--text); + margin-bottom: 6px; } .video-meta { display: flex; justify-content: space-between; font-size: 13px; - color: #718096; + color: var(--muted); } .video-duration { - background: #e2e8f0; - padding: 3px 8px; + background: var(--border); + padding: 2px 8px; border-radius: 4px; } -.news-list { - display: grid; - gap: 16px; +.upload-box { + margin-top: 20px; + border: 1px dashed var(--blue); + border-radius: 10px; + padding: 14px 18px; + background: #ebf8ff; } -.news-item { - padding: 20px; - background: #f7fafc; - border-left: 4px solid #4299e1; - border-radius: 8px; - transition: transform 0.2s; -} - -.news-item:hover { - transform: translateX(4px); -} - -.news-date { - font-size: 13px; - color: #718096; - margin-bottom: 8px; -} - -.news-title { +.upload-box summary { + cursor: pointer; font-weight: 600; - font-size: 16px; - color: #2d3748; - margin-bottom: 8px; -} - -.news-excerpt { - color: #4a5568; + color: var(--navy-2); font-size: 14px; - line-height: 1.6; } -.news-tag { - display: inline-block; - background: #4299e1; - color: white; - padding: 3px 10px; - border-radius: 12px; - font-size: 12px; - margin-top: 10px; +.upload-form { + display: grid; + gap: 12px; + margin-top: 14px; + max-width: 480px; } -.faq-list { +.upload-form input { + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: 8px; + font-size: 14px; +} + +.complaint-layout { + display: grid; + grid-template-columns: 1.4fr 1fr; + gap: 24px; +} + +.complaint-form { display: grid; gap: 12px; } -.faq-item { - border: 1px solid #e2e8f0; - border-radius: 8px; - overflow: hidden; -} - -.faq-question { - width: 100%; - text-align: left; - padding: 18px 20px; - background: #f7fafc; - border: none; +.complaint-form label { + font-size: 14px; font-weight: 600; - font-size: 15px; - color: #2d3748; - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: center; - transition: background 0.2s; + color: var(--text); } -.faq-question:hover { - background: #edf2f7; +.complaint-form input, +.complaint-form select, +.complaint-form textarea { + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: 8px; + font-size: 14px; + font-family: inherit; + outline: none; } -.faq-question::after { - content: "+"; - font-size: 24px; - color: #4a5568; +.complaint-form input:focus, +.complaint-form select:focus, +.complaint-form textarea:focus { + border-color: var(--blue); } -.faq-item.active .faq-question::after { - content: "−"; +.complaint-info { + background: var(--card); + border-radius: 10px; + padding: 24px; + align-self: start; } -.faq-answer { - padding: 0 20px; - max-height: 0; - overflow: hidden; - transition: all 0.3s; - background: white; +.complaint-info h3 { + color: var(--navy); + margin-bottom: 12px; } -.faq-item.active .faq-answer { - padding: 18px 20px; - max-height: 500px; - border-top: 1px solid #e2e8f0; - color: #4a5568; - line-height: 1.7; +.phone { + font-size: 20px; + font-weight: 700; + color: var(--navy-2); + margin-bottom: 8px; +} + +.muted { + color: var(--muted); + font-size: 13px; + margin-top: 10px; +} + +.form-note { + color: var(--muted); + font-size: 13px; +} + +.form-success { + background: #c6f6d5; + color: #22543d; + padding: 12px 16px; + border-radius: 8px; + font-size: 14px; + font-weight: 600; } .test-container { @@ -278,27 +536,42 @@ main { .test-start { text-align: center; - padding: 30px 20px; + padding: 20px 10px; } .test-start p { font-size: 16px; color: #4a5568; + margin-bottom: 16px; +} + +.test-name-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; margin-bottom: 20px; } +.test-name-row input { + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: 8px; + font-size: 14px; + text-align: center; +} + .test-topics { list-style: none; text-align: left; display: inline-block; - margin-bottom: 30px; - color: #2d3748; + margin-bottom: 24px; + color: var(--text); font-size: 15px; line-height: 2; } .test-progress { - background: #e2e8f0; + background: var(--border); padding: 12px 16px; border-radius: 8px; margin-bottom: 20px; @@ -309,7 +582,7 @@ main { .question-text { font-size: 18px; font-weight: 600; - color: #2d3748; + color: var(--text); margin-bottom: 24px; line-height: 1.5; } @@ -321,30 +594,31 @@ main { } .test-option { - padding: 16px 20px; - background: #f7fafc; - border: 2px solid #e2e8f0; + padding: 15px 20px; + background: var(--card); + border: 2px solid var(--border); border-radius: 8px; cursor: pointer; transition: all 0.2s; font-size: 15px; text-align: left; + font-family: inherit; } .test-option:hover { - border-color: #4299e1; + border-color: var(--blue); background: #ebf8ff; } .test-option.correct { background: #c6f6d5; - border-color: #48bb78; + border-color: var(--green); color: #22543d; } .test-option.wrong { background: #fed7d7; - border-color: #f56565; + border-color: var(--red); color: #742a2a; } @@ -357,118 +631,127 @@ main { .test-result { text-align: center; - padding: 40px 20px; + padding: 30px 10px; } .result-icon { - font-size: 72px; - margin-bottom: 20px; + font-size: 64px; + margin-bottom: 16px; } .result-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; - margin: 30px 0; + margin: 24px 0; } .result-stat { - background: #f7fafc; - padding: 24px; + background: var(--card); + padding: 20px; border-radius: 10px; } .result-value { display: block; - font-size: 42px; + font-size: 38px; font-weight: 700; - color: #4299e1; - margin-bottom: 8px; + color: var(--blue); + margin-bottom: 6px; } .result-label { - color: #718096; + color: var(--muted); font-size: 14px; } .result-message { font-size: 16px; color: #4a5568; - margin-bottom: 30px; + margin-bottom: 24px; line-height: 1.6; } -.btn-primary { - background: linear-gradient(135deg, #4299e1 0%, #3182ce 100%); - color: white; - border: none; - padding: 14px 40px; - border-radius: 8px; - font-size: 16px; - font-weight: 600; - cursor: pointer; - transition: transform 0.2s, box-shadow 0.2s; -} - -.btn-primary:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(66, 153, 225, 0.4); -} - -.btn-secondary { - background: #fc8181; - color: white; - border: none; - padding: 12px 28px; - border-radius: 8px; - font-size: 14px; - font-weight: 500; - cursor: pointer; - margin-top: 20px; - transition: background 0.2s; -} - -.btn-secondary:hover { - background: #f56565; -} - .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 20px; - margin-bottom: 20px; + gap: 16px; + margin-bottom: 22px; } .stat-card { - background: #f7fafc; - padding: 24px; + background: var(--card); + padding: 20px; border-radius: 10px; text-align: center; } .stat-icon { - font-size: 32px; + font-size: 30px; display: block; - margin-bottom: 12px; + margin-bottom: 10px; } .stat-value { display: block; - font-size: 32px; + font-size: 30px; font-weight: 700; - color: #4299e1; - margin-bottom: 6px; + color: var(--blue); + margin-bottom: 4px; } .stat-label { - color: #718096; + color: var(--muted); font-size: 13px; } +.table-wrap { + overflow-x: auto; + border: 1px solid var(--border); + border-radius: 10px; +} + +.data-table { + width: 100%; + border-collapse: collapse; + font-size: 14px; +} + +.data-table th, +.data-table td { + padding: 12px 16px; + text-align: left; + border-bottom: 1px solid var(--border); + white-space: nowrap; +} + +.data-table th { + background: var(--card); + color: var(--muted); + font-weight: 600; + font-size: 13px; +} + +.data-table tr:last-child td { + border-bottom: none; +} + +.score-badge { + display: inline-block; + padding: 3px 12px; + border-radius: 12px; + font-weight: 700; + font-size: 13px; +} + +.score-good { background: #c6f6d5; color: #22543d; } +.score-mid { background: #fefcbf; color: #744210; } +.score-low { background: #fed7d7; color: #742a2a; } + footer { - background: #1a365d; + background: var(--navy); color: white; - padding: 30px 20px; + padding: 28px 20px; text-align: center; } @@ -487,29 +770,37 @@ footer { flex-direction: column; text-align: center; } - + .logo { justify-content: center; } - + nav { justify-content: center; } - + .nav-link { - padding: 8px 14px; - font-size: 13px; + padding: 7px 12px; + font-size: 12px; } - + .section { padding: 20px 16px; } - - .video-grid { + + .complaint-layout { grid-template-columns: 1fr; } - + + .test-name-row { + grid-template-columns: 1fr; + } + .result-stats { grid-template-columns: 1fr; } + + .hero { + padding: 50px 20px; + } }