This commit is contained in:
2026-03-16 18:57:22 +03:00
parent 65eca64a5f
commit 668e62d652
18 changed files with 6386 additions and 1347 deletions

View File

@@ -33,8 +33,6 @@
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
}
.logo {
@@ -56,7 +54,6 @@
display: flex;
gap: 15px;
align-items: center;
flex-wrap: wrap;
}
.nav a {
@@ -64,7 +61,6 @@
text-decoration: none;
padding: 10px 20px;
border-radius: 30px;
transition: 0.2s;
}
.nav a:hover {
@@ -83,33 +79,6 @@
padding: 8px 20px !important;
}
.profile-link i {
font-size: 18px;
}
.user-avatar {
width: 35px;
height: 35px;
background: #3b82f6;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.user-name {
font-weight: 500;
}
.admin-badge {
background: #f59e0b;
color: white;
padding: 2px 8px;
border-radius: 20px;
font-size: 12px;
margin-left: 5px;
}
.back-link {
display: inline-block;
margin-bottom: 20px;
@@ -206,8 +175,10 @@
.section-title {
font-size: 24px;
color: #0b1c34;
margin: 30px 0 20px;
margin: 40px 0 20px;
font-weight: 600;
border-bottom: 2px solid #dee9f5;
padding-bottom: 10px;
}
.about-me {
@@ -219,35 +190,82 @@
font-size: 16px;
}
.experience-item, .education-item {
.experience-item {
background: #f9fcff;
border-radius: 20px;
padding: 25px;
margin-bottom: 20px;
border-left: 4px solid #3b82f6;
}
.item-header {
.experience-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
margin-bottom: 10px;
flex-wrap: wrap;
gap: 10px;
}
.item-title {
.experience-title {
font-size: 20px;
font-weight: 700;
color: #0b1c34;
}
.experience-company {
font-size: 18px;
color: #3b82f6;
font-weight: 600;
margin-bottom: 5px;
}
.experience-period {
color: #4f7092;
font-size: 14px;
display: flex;
align-items: center;
gap: 5px;
}
.experience-description {
margin-top: 15px;
padding: 15px;
background: white;
border-radius: 15px;
line-height: 1.6;
color: #1f3f60;
white-space: pre-line;
border-left: 3px solid #10b981;
}
.education-item {
background: #f9fcff;
border-radius: 20px;
padding: 20px;
margin-bottom: 15px;
}
.education-header {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
flex-wrap: wrap;
}
.education-institution {
font-size: 18px;
font-weight: 700;
color: #0b1c34;
}
.item-subtitle {
.education-specialty {
color: #3b82f6;
font-weight: 600;
margin-bottom: 10px;
font-size: 16px;
margin-bottom: 5px;
}
.item-period {
.education-year {
color: #4f7092;
font-size: 14px;
}
@@ -256,7 +274,7 @@
background: #eef4fa;
border-radius: 30px;
padding: 30px;
margin: 30px 0;
margin: 40px 0 20px;
}
.contact-grid {
@@ -310,7 +328,6 @@
.btn-primary:hover {
background: #1b3f6b;
transform: translateY(-2px);
}
.btn-outline {
@@ -349,6 +366,15 @@
font-size: 14px;
color: #1f3f60;
}
.admin-badge {
background: #f59e0b;
color: white;
padding: 2px 8px;
border-radius: 20px;
font-size: 12px;
margin-left: 5px;
}
</style>
</head>
<body>
@@ -356,10 +382,10 @@
<div class="header">
<div class="logo">
<i class="fas fa-briefcase"></i>
МП.Ярмарка
Rabota.Today
</div>
<div class="nav" id="nav">
<!-- Навигация будет заполнена динамически -->
<!-- Навигация -->
</div>
</div>
@@ -371,7 +397,7 @@
</div>
<script>
const API_BASE_URL = 'http://localhost:8000/api';
const API_BASE_URL = window.location.protocol + '//' + window.location.host + '/api';
let currentUser = null;
// Получаем ID резюме из URL
@@ -385,9 +411,7 @@
if (token) {
try {
const response = await fetch(`${API_BASE_URL}/user`, {
headers: {
'Authorization': `Bearer ${token}`
}
headers: { 'Authorization': `Bearer ${token}` }
});
if (response.ok) {
@@ -403,12 +427,13 @@
updateNavigation();
}
// Обновление навигации
function updateNavigation() {
const nav = document.getElementById('nav');
if (currentUser) {
// Пользователь авторизован
const firstName = currentUser.full_name.split(' ')[0];
const adminBadge = currentUser.is_admin ? '<span class="admin-badge">Admin</span>' : '';
nav.innerHTML = `
<a href="/">Главная</a>
<a href="/vacancies">Вакансии</a>
@@ -416,13 +441,10 @@
<a href="/favorites">Избранное</a>
<a href="/applications">Отклики</a>
<a href="/profile" class="profile-link">
<i class="fas fa-user-circle"></i>
<span class="user-name">${escapeHtml(currentUser.full_name.split(' ')[0])}</span>
${currentUser.is_admin ? '<span class="admin-badge">Admin</span>' : ''}
<i class="fas fa-user-circle"></i> ${firstName} ${adminBadge}
</a>
`;
} else {
// Пользователь не авторизован
nav.innerHTML = `
<a href="/">Главная</a>
<a href="/vacancies">Вакансии</a>
@@ -470,27 +492,37 @@
const experienceHtml = resume.work_experience && resume.work_experience.length > 0
? resume.work_experience.map(exp => `
<div class="experience-item">
<div class="item-header">
<span class="item-title">${escapeHtml(exp.position)}</span>
<span class="item-period">${escapeHtml(exp.period || 'Период не указан')}</span>
<div class="experience-header">
<span class="experience-title">${escapeHtml(exp.position)}</span>
<span class="experience-period">
<i class="far fa-calendar"></i> ${escapeHtml(exp.period || 'Период не указан')}
</span>
</div>
<div class="item-subtitle">${escapeHtml(exp.company)}</div>
<div class="experience-company">
<i class="fas fa-building"></i> ${escapeHtml(exp.company)}
</div>
${exp.description ? `
<div class="experience-description">
<strong>📋 Обязанности и достижения:</strong>
<p style="margin-top: 10px;">${escapeHtml(exp.description).replace(/\n/g, '<br>')}</p>
</div>
` : ''}
</div>
`).join('')
: '<p style="color: #4f7092;">Опыт работы не указан</p>';
: '<p style="color: #4f7092; text-align: center; padding: 20px;">Опыт работы не указан</p>';
// Формируем блок с образованием
const educationHtml = resume.education && resume.education.length > 0
? resume.education.map(edu => `
<div class="education-item">
<div class="item-header">
<span class="item-title">${escapeHtml(edu.institution)}</span>
<span class="item-period">${escapeHtml(edu.graduation_year || 'Год не указан')}</span>
<div class="education-header">
<span class="education-institution">${escapeHtml(edu.institution)}</span>
<span class="education-year">${escapeHtml(edu.graduation_year || 'Год не указан')}</span>
</div>
<div class="item-subtitle">${escapeHtml(edu.specialty || 'Специальность не указана')}</div>
<div class="education-specialty">${escapeHtml(edu.specialty || 'Специальность не указана')}</div>
</div>
`).join('')
: '<p style="color: #4f7092;">Образование не указано</p>';
: '<p style="color: #4f7092; text-align: center; padding: 20px;">Образование не указано</p>';
container.innerHTML = `
<div class="resume-header">
@@ -550,7 +582,10 @@
<p style="color: #1f3f60; margin-bottom: 20px;">
Контактные данные доступны только авторизованным работодателям
</p>
<a href="/login" class="btn btn-primary">Войти как работодатель</a>
${!token ?
'<a href="/login" class="btn btn-primary">Войти как работодатель</a>' :
'<p class="btn btn-primary" style="opacity: 0.6;">Только для работодателей</p>'
}
</div>
`}
</div>
@@ -560,10 +595,6 @@
<button class="btn btn-primary" onclick="contactCandidate()">
<i class="fas fa-paper-plane"></i> Связаться
</button>
` : !token ? `
<button class="btn btn-primary" onclick="redirectToLogin()">
<i class="fas fa-sign-in-alt"></i> Войдите чтобы увидеть контакты
</button>
` : ''}
<button class="btn btn-outline" onclick="saveToFavorites()">
@@ -577,7 +608,6 @@
`;
}
// Связаться с кандидатом
function contactCandidate() {
const token = localStorage.getItem('accessToken');
@@ -586,11 +616,9 @@
return;
}
// Здесь можно открыть модальное окно с формой сообщения
alert('Функция связи будет доступна в ближайшее время');
}
// Добавить в избранное
function saveToFavorites() {
const token = localStorage.getItem('accessToken');
@@ -604,7 +632,6 @@
alert('Резюме добавлено в избранное');
}
// Поделиться резюме
function shareResume() {
const url = window.location.href;
navigator.clipboard.writeText(url).then(() => {
@@ -614,14 +641,12 @@
});
}
// Редирект на страницу входа
function redirectToLogin() {
if (confirm('Для просмотра контактов нужно войти в систему. Перейти на страницу входа?')) {
window.location.href = '/login';
}
}
// Экранирование HTML
function escapeHtml(unsafe) {
if (!unsafe) return '';
return unsafe.toString()
@@ -632,7 +657,6 @@
.replace(/'/g, "&#039;");
}
// Загрузка при старте
checkAuth().then(() => {
loadResume();
});