Загрузка данных


<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <title>Авторизация с CAPTCHA</title>
  <style>
    /* CSS стили страницы и капчи */
    body {
      font-family: Arial, sans-serif;
      background-color: #f0f2f5;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
    }

    .login-card {
      background: #ffffff;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.1);
      width: 320px;
      text-align: center;
    }

    .form-group {
      margin-bottom: 15px;
      text-align: left;
    }

    .form-group label {
      display: block;
      margin-bottom: 5px;
      font-weight: bold;
      color: #333;
    }

    .form-group input {
      width: 100%;
      padding: 8px 10px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }

    /* Стили для CAPTCHA */
    .captcha-title {
      font-size: 0.9em;
      font-weight: bold;
      margin-top: 15px;
      color: #444;
    }

    .hint {
      margin: 5px 0 15px;
      color: #666;
      font-size: 0.8em;
      font-style: italic;
    }

    .captcha-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 15px;
      margin-bottom: 15px;
    }

    .grid {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 6px;
      width: 206px;
      height: 206px;
      border: 2px dashed #ccc;
      border-radius: 8px;
      padding: 4px;
      background-color: #f9f9f9;
    }

    .slot {
      width: 98px;
      height: 98px;
      border: 1px solid #ddd;
      border-radius: 4px;
      background-color: #eaeaea;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #aaa;
    }

    .slot:empty::before {
      content: "●";
    }

    .fragments {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 6px;
      width: 206px;
    }

    .fragment {
      width: 98px;
      height: 98px;
      border: 2px solid #007bff;
      border-radius: 4px;
      cursor: grab;
      user-select: none;
      background-color: white;
      box-shadow: 0 2px 5px rgba(0,0,0,0.1);
    }

    .fragment:active {
      cursor: grabbing;
    }

    #message {
      margin: 10px 0;
      padding: 8px;
      border-radius: 5px;
      font-size: 0.85em;
      font-weight: bold;
      display: none;
    }

    .success {
      background-color: #d4edda;
      color: #155724;
      display: block !important;
    }

    .error {
      background-color: #f8d7da;
      color: #721c24;
      display: block !important;
    }

    button[type="submit"] {
      width: 100%;
      padding: 10px;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      font-size: 1em;
      cursor: pointer;
    }

    button[type="submit"]:hover {
      background: #0056b3;
    }
  </style>
</head>
<body>

<div class="login-card">
  <h2>Вход в систему</h2>

  <form id="loginForm" onsubmit="return handleLogin(event)">
    <div class="form-group">
      <label for="username">Логин:</label>
      <input type="text" id="username" required placeholder="Введите логин">
    </div>

    <div class="form-group">
      <label for="password">Пароль:</label>
      <input type="password" id="password" required placeholder="Введите пароль">
    </div>

    <!-- Блок Капчи -->
    <div class="captcha-title">Проверка: Соберите рисунок</div>
    <div class="hint">Перетащите картинки на свои места</div>

    <div class="captcha-container">
      <!-- Зоны для сборки -->
      <div class="grid" id="grid"></div>

      <!-- Перетаскиваемые фрагменты -->
      <div class="fragments" id="fragments"></div>
    </div>

    <p id="message"></p>

    <button type="submit">Войти</button>
  </form>
</div>

<script>
  // Массив фрагментов с их верными позициями
  const fragmentsData = [
    { src: '1.png', position: 0 },
    { src: '2.png', position: 1 },
    { src: '3.png', position: 2 },
    { src: '4.png', position: 3 }
  ];

  let isCaptchaPassed = false;

  const gridContainer = document.getElementById('grid');
  const fragmentsContainer = document.getElementById('fragments');
  const message = document.getElementById('message');

  // Вспомогательная функция перемешивания (чтобы элементы появлялись случайно)
  function shuffle(array) {
    return [...array].sort(() => Math.random() - 0.5);
  }

  // Генерация слотов
  function renderGrid() {
    gridContainer.innerHTML = '';
    for (let i = 0; i < 4; i++) {
      const slot = document.createElement('div');
      slot.className = 'slot';
      slot.dataset.position = i;
      slot.addEventListener('dragover', dragOver);
      slot.addEventListener('drop', drop);
      gridContainer.appendChild(slot);
    }
  }

  // Генерация перетаскиваемых картинок в случайном порядке
  function renderFragments() {
    fragmentsContainer.innerHTML = '';
    const shuffledData = shuffle(fragmentsData);

    shuffledData.forEach(item => {
      const img = document.createElement('img');
      img.src = item.src;
      img.alt = `Фрагмент ${item.position + 1}`;
      img.className = 'fragment';
      img.draggable = true;
      img.dataset.position = item.position;
      img.addEventListener('dragstart', dragStart);
      fragmentsContainer.appendChild(img);
    });
  }

  // Обработчики Drag and Drop
  function dragStart(e) {
    e.dataTransfer.setData('text/plain', e.target.dataset.position);
    e.dataTransfer.effectAllowed = 'move';
  }

  function dragOver(e) {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
  }

  function drop(e) {
    e.preventDefault();
    
    // Получаем слот назначения (если бросили на имеющуюся картинку — находим родительский слот)
    let slot = e.target;
    if (!slot.classList.contains('slot')) {
      slot = slot.closest('.slot');
    }
    if (!slot) return;

    const draggedPosition = e.dataTransfer.getData('text/plain');
    const draggedImg = document.querySelector(`.fragment[data-position="${draggedPosition}"]`);
    if (!draggedImg) return;

    // Если слот уже занят другим фрагментом, возвращаем старый обратно в список
    if (slot.children.length > 0) {
      fragmentsContainer.appendChild(slot.children[0]);
    }

    // Вставляем перемещаемый элемент
    slot.appendChild(draggedImg);

    // Проверяем правильность сборки
    checkCompletion();
  }

  // Проверка выполнения капчи
  function checkCompletion() {
    const slots = document.querySelectorAll('.slot');
    let correctCount = 0;
    let filledCount = 0;

    slots.forEach(slot => {
      const img = slot.querySelector('img');
      if (img) {
        filledCount++;
        if (img.dataset.position === slot.dataset.position) {
          correctCount++;
        }
      }
    });

    if (filledCount === 4) {
      if (correctCount === 4) {
        message.textContent = '✅ Картинка собрана верна!';
        message.className = 'success';
        isCaptchaPassed = true;
      } else {
        message.textContent = '❌ Неправильно! Попробуйте еще раз.';
        message.className = 'error';
        isCaptchaPassed = false;
      }
    } else {
      message.className = '';
      message.textContent = '';
      isCaptchaPassed = false;
    }
  }

  // Обработка отправки формы
  function handleLogin(event) {
    event.preventDefault(); // Предотвращаем перезагрузку страницы

    if (!isCaptchaPassed) {
      alert('Пожалуйста, правильно соберите капчу перед входом!');
      return false;
    }

    alert('Успешная авторизация!');
    // Здесь вы можете перенаправить пользователя или отправить AJAX-запрос:
    // window.location.href = '/dashboard';
    return true;
  }

  // Инициализация при загрузке страницы
  document.addEventListener('DOMContentLoaded', () => {
    renderGrid();
    renderFragments();
  });
</script>

</body>
</html>