/
potogon
/
statbit
Обзор
Документация
Войти
/
potogon
/
statbit
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
coping.html
492 строки
17 KB
Alex
fix color
28 июл 2026, 19:50
28 июл 2026, 19:50
2d94fcf
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Копинг-тест</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #f4f6f9; color: #222; line-height: 1.5; } .container { max-width: 800px; margin: 0 auto; padding: 20px; } header { background: #4a6fa5; color: #fff; padding: 20px; text-align: center; } header h1 { font-size: 1.4rem; } .back-link { display: inline-block; margin-bottom: 16px; color: #4a6fa5; text-decoration: none; font-size: 0.9rem; } .card { background: #fff; border-radius: 12px; padding: 20px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } .intro-text { background: #eaf2fb; border-left: 4px solid #4a6fa5; padding: 16px; border-radius: 8px; margin-bottom: 20px; font-size: 0.95rem; color: #2c3e50; } .form-group { margin-bottom: 14px; } .form-group label { display: block; margin-bottom: 6px; font-weight: 500; color: #333; } .form-group input, .form-group select { width: 100%; padding: 10px 12px; border: 1px solid #d0d7de; border-radius: 8px; font-size: 1rem; background: #fff; } .form-group input:focus, .form-group select:focus { outline: none; border-color: #4a6fa5; box-shadow: 0 0 0 3px rgba(74,111,165,0.15); } .question { background: #fff; border-radius: 12px; padding: 18px; margin-bottom: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } .question-number { display: inline-block; background: #4a6fa5; color: #fff; width: 28px; height: 28px; border-radius: 50%; text-align: center; line-height: 28px; font-size: 0.85rem; font-weight: 600; margin-right: 8px; } .question-text { font-size: 1rem; color: #2c3e50; margin-bottom: 12px; line-height: 1.4; } .options-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 8px; } .option { display: flex; align-items: center; padding: 10px 12px; border: 1px solid #e0e0e0; border-radius: 8px; cursor: pointer; transition: all 0.15s; user-select: none; background: #fff; } .option:hover { background: #f4f6f9; border-color: #4a6fa5; } .option.selected { background: #eaf2fb; border-color: #4a6fa5; font-weight: 500; } .option input { margin-right: 8px; cursor: pointer; flex-shrink: 0; } .option label { cursor: pointer; flex: 1; font-size: 0.9rem; } .progress-bar { position: sticky; top: 0; background: #fff; padding: 10px 16px; border-radius: 8px; margin-bottom: 16px; box-shadow: 0 2px 6px rgba(0,0,0,0.08); z-index: 10; display: flex; align-items: center; gap: 12px; } .progress-track { flex: 1; height: 8px; background: #e5e7eb; border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; background: #4a6fa5; width: 0%; transition: width 0.3s; } .progress-text { font-size: 0.85rem; color: #666; white-space: nowrap; } .btn { display: block; width: 100%; background: #4a6fa5; color: #fff; padding: 14px; border-radius: 10px; border: none; font-size: 1rem; font-weight: 500; cursor: pointer; margin-top: 20px; transition: background 0.15s; } .btn:hover:not(:disabled) { background: #3a5a8c; } .btn:disabled { background: #a0aec0; cursor: not-allowed; } .result-card { background: #fff; border-radius: 12px; padding: 24px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } .result-card h2 { text-align: center; margin-bottom: 20px; color: #2c3e50; } .scales-list { display: grid; gap: 10px; margin-bottom: 20px; } .scale-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; background: #f9fafb; border-radius: 8px; border-left: 4px solid #4a6fa5; } .scale-name { font-size: 0.95rem; color: #333; } .scale-value { font-weight: 700; color: #4a6fa5; font-size: 1.1rem; } .hidden { display: none; } @media (max-width: 600px) { .container { padding: 12px; } header h1 { font-size: 1.2rem; } .question, .card { padding: 14px; } .options-grid { grid-template-columns: 1fr; } } </style> </head> <body> <header> <h1>Копинг-тест</h1> </header> <div class="container"> <a href="index.html" class="back-link">← Назад к списку тестов</a> <!-- Шаг 1: Ввод данных --> <div id="step-intro"> <div class="card"> <h2 style="margin-bottom:16px;color:#2c3e50;">Данные участника</h2> <div class="form-group"> <label for="fio">ФИО *</label> <input type="text" id="fio" required placeholder="Иванов Иван Иванович"> </div> <div class="form-group"> <label for="age">Возраст *</label> <input type="number" id="age" min="1" max="120" required placeholder="25"> </div> <div class="form-group"> <label for="gender">Пол *</label> <select id="gender" required> <option value="">— Выберите —</option> <option value="Мужской">Мужской</option> <option value="Женский">Женский</option> </select> </div> <button class="btn" id="startBtn">Начать тест</button> </div> </div> <!-- Шаг 2: Вопросы --> <div id="step-questions" class="hidden"></div> <!-- Шаг 3: Результат --> <div id="step-result" class="hidden"></div> </div> <script src="config.js"></script> <script> // 50 утверждений const STATEMENTS = [ 'Сосредотачивался на том, что мне нужно было делать дальше – на следующем шаге.', 'Начинал что-то делать, зная, что это все равно не будет работать: главное – делать хоть что-нибудь.', 'Пытался склонить вышестоящих к тому, чтобы они изменили свое мнение.', 'Говорил с другими, чтобы больше узнать о ситуации.', 'Критиковал и укорял себя.', 'Пытался не сжигать за собой мосты, оставляя все, как оно есть.', 'Надеялся на чудо.', 'Смирился с судьбой: бывает, что мне не везет.', 'Вел себя, как будто ничего не произошло.', 'Старался не показывать своих чувств.', 'Пытался увидеть в ситуации и что-то положительное.', 'Спал больше обычного.', 'Срывал свою досаду на тех, кто навлек на меня проблемы.', 'Искал сочувствия и понимания у кого-нибудь.', 'Во мне возникала потребность выразить себя творчески.', 'Пытался забыть все это.', 'Обращался за помощью к специалистам.', 'Менялся или рос как личность в положительную сторону.', 'Извинялся или старался как-то все загладить.', 'Составлял план действий и следовал ему.', 'Старался дать какой-то выход своим чувствам.', 'Понимал, что я сам вызвал эту проблему.', 'Набирался опыта в этой ситуации.', 'Говорил с кем-либо, кто мог конкретно помочь в этой ситуации.', 'Пытался улучшить свое самочувствие едой, выпивкой, курением или лекарствами.', 'Рисковал напропалую.', 'Старался действовать не слишком поспешно, не доверяясь первому порыву.', 'Находил новую веру во что-то.', 'Вновь открывал для себя что-то важное в жизни.', 'Что-то менял так, что все уладилось.', 'В целом избегал общения с людьми.', 'Не допускал это до себя, стараясь об этом особенно не задумываться.', 'Спрашивал совета у родственника или друга, которых уважал.', 'Старался, чтобы другие не узнали, как плохо обстоят дела.', 'Отказывался воспринимать все это слишком серьезно.', 'Говорил с кем-то о том, что я чувствую.', 'Стоял на своем и боролся за то, чего хотел.', 'Вымещал это на других людях.', 'Пользовался прошлым опытом – мне приходилось уже попадать в такие ситуации.', 'Знал, что надо делать, и удваивал свои усилия, чтобы все наладить.', 'Отказывался верить, что это действительно произошло.', 'Я давал себе обещание, что в следующий раз все будет по-другому.', 'Находил пару других способов решения проблемы.', 'Старался, чтобы мои эмоции не слишком мешали мне в других делах.', 'Что-то менял в себе.', 'Хотел, чтобы все это скорее как-то образовалось и кончилось.', 'Представлял себе, фантазировал, как все это могло бы обернуться.', 'Молился.', 'Прокручивал в уме, что мне сказать или сделать.', 'Думал о том, как бы в данной ситуации действовал человек, которым я восхищаюсь, и старался подражать ему.' ]; const ANSWER_LABELS = [ 'Никогда', 'Редко', 'Иногда', 'Часто' ]; // Шкалы и номера вопросов (1-based) const SCALES = { 'Конфронтативный': [2, 3, 13, 21, 26, 37], 'Дистанцирование': [8, 9, 11, 16, 32, 35], 'Самоконтроль': [6, 10, 27, 34, 44, 49, 50], 'Поиск соц. поддержки': [4, 14, 17, 24, 33, 36], 'Принятие ответственности': [5, 19, 22, 42], 'Бегство-избегание': [7, 12, 25, 31, 38, 41, 46, 47], 'Планирование': [1, 20, 30, 39, 40, 43], 'Положительная переоценка': [15, 18, 23, 28, 29, 45, 48] }; const state = { answers: new Array(50).fill(null), // значения 0-3 или null fio: '', age: '', gender: '' }; const stepIntro = document.getElementById('step-intro'); const stepQuestions = document.getElementById('step-questions'); const stepResult = document.getElementById('step-result'); document.getElementById('startBtn').addEventListener('click', () => { const fio = document.getElementById('fio').value.trim(); const age = document.getElementById('age').value.trim(); const gender = document.getElementById('gender').value; if (!fio || !age || !gender) { alert('Пожалуйста, заполните все поля.'); return; } if (isNaN(age) || age < 1 || age > 120) { alert('Введите корректный возраст.'); return; } state.fio = fio; state.age = age; state.gender = gender; renderQuestions(); stepIntro.classList.add('hidden'); stepQuestions.classList.remove('hidden'); window.scrollTo(0, 0); }); function renderQuestions() { let html = ` <div class="intro-text"> Ниже приведён список утверждений, описывающих различные способы поведения в трудной ситуации. Оказавшись в трудной ситуации, вы… Выберите один вариант ответа для каждого утверждения, который наиболее точно описывает ваше обычное поведение. </div> <div class="progress-bar"> <div class="progress-track"><div class="progress-fill" id="progressFill"></div></div> <div class="progress-text" id="progressText">0 / 50</div> </div> `; STATEMENTS.forEach((text, idx) => { const qNum = idx + 1; html += `<div class="question" data-q="${idx}">`; html += `<div style="margin-bottom:10px;"><span class="question-number">${qNum}</span><span class="question-text">${escapeHtml(text)}</span></div>`; html += `<div class="options-grid">`; ANSWER_LABELS.forEach((label, val) => { const inputId = `q${idx}_v${val}`; html += ` <div class="option" data-value="${val}"> <input type="radio" name="q${idx}" id="${inputId}" value="${val}"> <label for="${inputId}">${label} (${val})</label> </div> `; }); html += `</div></div>`; }); html += `<button class="btn" id="submitBtn">Завершить тест</button>`; stepQuestions.innerHTML = html; // Обработчики выбора document.querySelectorAll('.option').forEach(optEl => { const input = optEl.querySelector('input'); optEl.addEventListener('click', (e) => { if (e.target === input) { // Нативный клик по radio — уже выбран } else { input.checked = true; } // Обновляем визуал группы const question = optEl.closest('.question'); question.querySelectorAll('.option').forEach(o => o.classList.remove('selected')); optEl.classList.add('selected'); // Сохраняем ответ const qIdx = parseInt(question.dataset.q); state.answers[qIdx] = parseInt(optEl.dataset.value); updateProgress(); }); }); document.getElementById('submitBtn').addEventListener('click', submitTest); updateProgress(); } function updateProgress() { const answered = state.answers.filter(a => a !== null).length; const pct = (answered / 50) * 100; document.getElementById('progressFill').style.width = pct + '%'; document.getElementById('progressText').textContent = `${answered} / 50`; } function calculateScales() { const scales = {}; for (const [name, questions] of Object.entries(SCALES)) { let sum = 0; questions.forEach(qNum => { const val = state.answers[qNum - 1]; if (val !== null) sum += val; }); scales[name] = sum; } return scales; } async function submitTest() { // Проверка полноты const unanswered = state.answers.findIndex(a => a === null); if (unanswered !== -1) { alert(`Пожалуйста, ответьте на вопрос ${unanswered + 1}.`); const el = document.querySelector(`[data-q="${unanswered}"]`); if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' }); return; } const scales = calculateScales(); const payload = { fio: state.fio, age: state.age, gender: state.gender, answers: state.answers, scales: scales, testName: 'Копинг-тест' }; const btn = document.getElementById('submitBtn'); btn.disabled = true; btn.textContent = 'Отправка результатов…'; try { const res = await fetch(CONFIG.apiUrl, { method: 'POST', headers: { 'Content-Type': 'text/plain;charset=utf-8' }, body: JSON.stringify({ action: 'saveResult', payload }) }); const json = await res.json(); if (!json.ok) throw new Error(json.error || 'Ошибка сохранения'); } catch (err) { alert('Ошибка при сохранении: ' + err.message + '\nРезультаты не были отправлены.'); btn.disabled = false; btn.textContent = 'Завершить тест'; return; } // Показ результата renderResult(scales); stepQuestions.classList.add('hidden'); stepResult.classList.remove('hidden'); window.scrollTo(0, 0); } function renderResult(scales) { let html = `<div class="result-card"> <h2>Спасибо за участие!</h2> <a href="index.html" class="btn">Вернуться на главную</a> </div>`; stepResult.innerHTML = html; } function escapeHtml(s) { return String(s).replace(/[&<>"']/g, c => ({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[c])); } </script> </body> </html>