Загрузка данных
<!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>