This commit is contained in:
2026-03-12 19:23:54 +03:00
commit cd1129ea72
12 changed files with 4692 additions and 0 deletions

407
templates/login.html Normal file
View File

@@ -0,0 +1,407 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Вход | Rabota.Today</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
body {
background: linear-gradient(145deg, #eef5fa 0%, #e0eaf5 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.auth-card {
max-width: 500px;
width: 100%;
background: white;
border-radius: 48px;
box-shadow: 0 40px 80px -20px rgba(0, 40, 80, 0.4);
overflow: hidden;
}
.auth-header {
background: #0b1c34;
color: white;
padding: 40px;
text-align: center;
}
.auth-header h1 {
font-size: 32px;
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
margin-bottom: 10px;
}
.auth-header h1 i {
color: #3b82f6;
background: rgba(255,255,255,0.1);
padding: 12px;
border-radius: 20px;
}
.auth-header p {
color: #9bb8da;
}
.auth-form {
padding: 40px;
}
.tabs {
display: flex;
gap: 10px;
margin-bottom: 30px;
background: #f0f7ff;
padding: 8px;
border-radius: 60px;
}
.tab {
flex: 1;
padding: 15px;
text-align: center;
border-radius: 50px;
cursor: pointer;
font-weight: 600;
transition: 0.2s;
}
.tab.active {
background: white;
color: #0b1c34;
box-shadow: 0 4px 10px rgba(0,0,0,0.05);
}
.form-group {
margin-bottom: 25px;
}
.form-group label {
display: flex;
align-items: center;
gap: 10px;
color: #1f3f60;
font-weight: 600;
margin-bottom: 8px;
}
.form-group label i {
color: #3b82f6;
width: 20px;
}
.form-group input {
width: 100%;
padding: 16px 20px;
border: 2px solid #dee9f5;
border-radius: 30px;
font-size: 16px;
transition: 0.2s;
}
.form-group input:focus {
border-color: #3b82f6;
outline: none;
box-shadow: 0 0 0 4px rgba(59,130,246,0.15);
}
.btn-submit {
width: 100%;
background: #0f2b4f;
color: white;
border: none;
padding: 18px;
border-radius: 50px;
font-weight: 700;
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
transition: 0.2s;
}
.btn-submit:hover {
background: #1b3f6b;
}
.auth-footer {
text-align: center;
margin-top: 25px;
color: #4f7092;
}
.auth-footer a {
color: #0b1c34;
font-weight: 600;
text-decoration: none;
}
.error-message {
background: #fee2e2;
color: #b91c1c;
padding: 12px 20px;
border-radius: 30px;
margin-bottom: 20px;
display: none;
}
.success-message {
background: #e0f2e0;
color: #166534;
padding: 12px 20px;
border-radius: 30px;
margin-bottom: 20px;
display: none;
}
.back-link {
display: inline-block;
margin-top: 20px;
color: #4f7092;
text-decoration: none;
}
.back-link i {
margin-right: 5px;
}
</style>
</head>
<body>
<div class="auth-card">
<div class="auth-header">
<h1>
<i class="fas fa-briefcase"></i>
Rabota.Today
</h1>
<p>Вход в личный кабинет</p>
</div>
<div class="auth-form">
<div class="tabs">
<div class="tab active" onclick="switchTab('login')">Вход</div>
<div class="tab" onclick="switchTab('register')">Регистрация</div>
</div>
<div id="errorMessage" class="error-message"></div>
<div id="successMessage" class="success-message"></div>
<!-- Форма входа -->
<form id="loginForm" onsubmit="handleLogin(event)">
<div class="form-group">
<label><i class="fas fa-envelope"></i> Email</label>
<input type="email" id="loginEmail" placeholder="ivan@example.com" required>
</div>
<div class="form-group">
<label><i class="fas fa-lock"></i> Пароль</label>
<input type="password" id="loginPassword" placeholder="Введите пароль" required>
</div>
<button type="submit" class="btn-submit">
<i class="fas fa-sign-in-alt"></i> Войти
</button>
</form>
<!-- Форма регистрации (скрыта по умолчанию) -->
<form id="registerForm" style="display: none;" onsubmit="handleRegister(event)">
<div class="form-group">
<label><i class="fas fa-user"></i> ФИО</label>
<input type="text" id="regFullName" placeholder="Иванов Иван Иванович" required>
</div>
<div class="form-group">
<label><i class="fas fa-envelope"></i> Email</label>
<input type="email" id="regEmail" placeholder="ivan@example.com" required>
</div>
<div class="form-group">
<label><i class="fas fa-phone"></i> Телефон</label>
<input type="tel" id="regPhone" placeholder="+7 999 123 45 67" required>
</div>
<div class="form-group">
<label><i class="fab fa-telegram"></i> Telegram (опционально)</label>
<input type="text" id="regTelegram" placeholder="@username">
</div>
<div class="form-group">
<label><i class="fas fa-lock"></i> Пароль</label>
<input type="password" id="regPassword" placeholder="Минимум 6 символов" required>
</div>
<div class="form-group">
<label><i class="fas fa-user-tag"></i> Я</label>
<select id="regRole" style="width: 100%; padding: 16px 20px; border: 2px solid #dee9f5; border-radius: 30px;">
<option value="employee">Соискатель</option>
<option value="employer">Работодатель</option>
</select>
</div>
<button type="submit" class="btn-submit">
<i class="fas fa-check-circle"></i> Зарегистрироваться
</button>
</form>
<div class="auth-footer">
<a href="/" class="back-link"><i class="fas fa-arrow-left"></i> На главную</a>
</div>
</div>
</div>
<script>
const API_BASE_URL = 'http://localhost:8000/api';
function switchTab(tab) {
const tabs = document.querySelectorAll('.tab');
const loginForm = document.getElementById('loginForm');
const registerForm = document.getElementById('registerForm');
tabs.forEach(t => t.classList.remove('active'));
if (tab === 'login') {
tabs[0].classList.add('active');
loginForm.style.display = 'block';
registerForm.style.display = 'none';
} else {
tabs[1].classList.add('active');
loginForm.style.display = 'none';
registerForm.style.display = 'block';
}
}
function showError(message) {
const errorEl = document.getElementById('errorMessage');
errorEl.textContent = message;
errorEl.style.display = 'block';
setTimeout(() => {
errorEl.style.display = 'none';
}, 5000);
}
function showSuccess(message) {
const successEl = document.getElementById('successMessage');
successEl.textContent = message;
successEl.style.display = 'block';
setTimeout(() => {
successEl.style.display = 'none';
}, 3000);
}
async function handleLogin(event) {
event.preventDefault();
const email = document.getElementById('loginEmail').value;
const password = document.getElementById('loginPassword').value;
try {
const response = await fetch(`${API_BASE_URL}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || 'Ошибка входа');
}
// Сохраняем токен
localStorage.setItem('accessToken', data.access_token);
localStorage.setItem('userId', data.user_id);
localStorage.setItem('userRole', data.role);
localStorage.setItem('userName', data.full_name);
showSuccess('Вход выполнен успешно!');
// Перенаправляем в зависимости от роли
setTimeout(() => {
if (data.role === 'employer') {
window.location.href = '/profile';
} else {
window.location.href = '/profile';
}
}, 1000);
} catch (error) {
showError(error.message);
}
}
async function handleRegister(event) {
event.preventDefault();
const userData = {
full_name: document.getElementById('regFullName').value,
email: document.getElementById('regEmail').value,
phone: document.getElementById('regPhone').value,
telegram: document.getElementById('regTelegram').value || null,
password: document.getElementById('regPassword').value,
role: document.getElementById('regRole').value
};
// Валидация
if (userData.password.length < 6) {
showError('Пароль должен быть не менее 6 символов');
return;
}
try {
const response = await fetch(`${API_BASE_URL}/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || 'Ошибка регистрации');
}
// Сохраняем токен
localStorage.setItem('accessToken', data.access_token);
localStorage.setItem('userId', data.user_id);
localStorage.setItem('userRole', data.role);
localStorage.setItem('userName', data.full_name);
showSuccess('Регистрация успешна!');
// Перенаправляем в профиль
setTimeout(() => {
window.location.href = '/profile';
}, 1000);
} catch (error) {
showError(error.message);
}
}
// Проверяем, может пользователь уже залогинен
if (localStorage.getItem('accessToken')) {
window.location.href = '/profile';
}
</script>
</body>
</html>