resume detail meta
This commit is contained in:
@@ -3,11 +3,59 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Резюме | Rabota.Today</title>
|
||||
|
||||
<!-- Базовые SEO теги -->
|
||||
<title id="pageTitle">Резюме | Rabota.Today</title>
|
||||
<meta name="description" id="metaDescription" content="Подробная информация о резюме кандидата на Rabota.Today. Опыт работы, образование, навыки, контактная информация.">
|
||||
<meta name="keywords" content="резюме, поиск сотрудников, кандидат, Rabota.Today, подбор персонала">
|
||||
<meta name="author" content="Rabota.Today">
|
||||
<meta name="robots" content="index, follow">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="profile">
|
||||
<meta property="og:url" id="ogUrl" content="https://yarmarka.rabota.today/">
|
||||
<meta property="og:title" id="ogTitle" content="Резюме | Rabota.Today">
|
||||
<meta property="og:description" id="ogDescription" content="Подробная информация о резюме кандидата на Rabota.Today">
|
||||
<meta property="og:image" id="ogImage" content="https://yarmarka.rabota.today/static/images/og-image-resume.jpg">
|
||||
<meta property="og:site_name" content="Rabota.Today">
|
||||
<meta property="og:locale" content="ru_RU">
|
||||
<meta property="profile:first_name" id="profileFirstName" content="">
|
||||
<meta property="profile:last_name" id="profileLastName" content="">
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" id="twitterTitle" content="Резюме | Rabota.Today">
|
||||
<meta name="twitter:description" id="twitterDescription" content="Подробная информация о резюме кандидата на Rabota.Today">
|
||||
<meta name="twitter:image" id="twitterImage" content="https://yarmarka.rabota.today/static/images/og-image-resume.jpg">
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" id="canonicalUrl" href="https://yarmarka.rabota.today/">
|
||||
|
||||
<!-- Дополнительные SEO метатеги -->
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="theme-color" content="#0b1c34">
|
||||
|
||||
<!-- Структурированные данные (JSON-LD) для резюме -->
|
||||
<script type="application/ld+json" id="structuredData">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Person",
|
||||
"name": "",
|
||||
"jobTitle": "",
|
||||
"description": "",
|
||||
"worksFor": [],
|
||||
"alumniOf": [],
|
||||
"knowsAbout": [],
|
||||
"url": ""
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||
<!-- Подключаем библиотеку для генерации QR-кодов -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script>
|
||||
|
||||
<style>
|
||||
/* ... все существующие стили ... */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -183,7 +231,6 @@
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.qr-button:hover {
|
||||
@@ -443,11 +490,13 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.6);
|
||||
align-items: center;
|
||||
background: rgba(0,0,0,0.7);
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
backdrop-filter: blur(5px);
|
||||
overflow-y: auto;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.qr-modal.active {
|
||||
@@ -455,11 +504,6 @@
|
||||
animation: fadeIn 0.3s;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.qr-modal-content {
|
||||
background: white;
|
||||
border-radius: 40px;
|
||||
@@ -469,17 +513,17 @@
|
||||
position: relative;
|
||||
box-shadow: 0 30px 60px rgba(0,0,0,0.3);
|
||||
animation: slideUp 0.3s;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from { transform: translateY(30px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
margin: auto;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.qr-modal-close {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-bottom: 20px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 20px;
|
||||
@@ -492,21 +536,30 @@
|
||||
justify-content: center;
|
||||
color: #4f7092;
|
||||
transition: 0.2s;
|
||||
z-index: 10;
|
||||
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.qr-modal-close:hover {
|
||||
background: #dbeafe;
|
||||
color: #0b1c34;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.qr-modal h2 {
|
||||
color: #0b1c34;
|
||||
margin-bottom: 10px;
|
||||
font-size: 28px;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
word-break: break-word;
|
||||
padding-right: 40px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: white;
|
||||
padding-top: 0;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.qr-modal h2 i {
|
||||
@@ -573,10 +626,13 @@
|
||||
padding: 15px;
|
||||
background: #f0f7ff;
|
||||
border-radius: 20px;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.qr-stat-item {
|
||||
text-align: center;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.qr-stat-value {
|
||||
@@ -594,7 +650,7 @@
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 12px;
|
||||
margin: 25px 0;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.qr-action-btn {
|
||||
@@ -640,6 +696,7 @@
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #dee9f5;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.qr-share-btn {
|
||||
@@ -736,6 +793,16 @@
|
||||
to { transform: translateX(0%); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from { transform: translateY(30px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.resume-header {
|
||||
flex-direction: column;
|
||||
@@ -749,75 +816,7 @@
|
||||
.qr-button {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Улучшенные стили для модального окна с прокруткой */
|
||||
.qr-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.7);
|
||||
align-items: flex-start; /* Изменено с center на flex-start */
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
backdrop-filter: blur(5px);
|
||||
overflow-y: auto; /* Добавляем прокрутку для всего модального окна */
|
||||
padding: 20px 0; /* Отступы сверху и снизу */
|
||||
}
|
||||
|
||||
.qr-modal.active {
|
||||
display: flex;
|
||||
animation: fadeIn 0.3s;
|
||||
}
|
||||
|
||||
.qr-modal-content {
|
||||
background: white;
|
||||
border-radius: 40px;
|
||||
padding: 40px;
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
box-shadow: 0 30px 60px rgba(0,0,0,0.3);
|
||||
animation: slideUp 0.3s;
|
||||
margin: auto; /* Центрирование по вертикали при возможности */
|
||||
max-height: 90vh; /* Ограничиваем высоту */
|
||||
overflow-y: auto; /* Внутренняя прокрутка если контент не помещается */
|
||||
}
|
||||
|
||||
/* Улучшенная кнопка закрытия - всегда видима */
|
||||
.qr-modal-close {
|
||||
position: sticky; /* Меняем с absolute на sticky */
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-bottom: 20px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 20px;
|
||||
background: #eef4fa;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #4f7092;
|
||||
transition: 0.2s;
|
||||
z-index: 10;
|
||||
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.qr-modal-close:hover {
|
||||
background: #dbeafe;
|
||||
color: #0b1c34;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* Фиксированная кнопка закрытия для мобильных */
|
||||
@media (max-width: 768px) {
|
||||
.qr-modal-content {
|
||||
padding: 30px 20px;
|
||||
width: 95%;
|
||||
@@ -831,161 +830,6 @@
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Заголовок с фиксацией */
|
||||
.qr-modal h2 {
|
||||
color: #0b1c34;
|
||||
margin-bottom: 10px;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
word-break: break-word;
|
||||
padding-right: 40px; /* Место для кнопки закрытия */
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: white;
|
||||
padding-top: 0;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/* Контейнер для QR с центрированием */
|
||||
.qr-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background: #f9fcff;
|
||||
border-radius: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Статистика */
|
||||
.qr-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
background: #f0f7ff;
|
||||
border-radius: 20px;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.qr-stat-item {
|
||||
text-align: center;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.qr-stat-value {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #0b1c34;
|
||||
}
|
||||
|
||||
.qr-stat-label {
|
||||
font-size: 12px;
|
||||
color: #4f7092;
|
||||
}
|
||||
|
||||
/* Сетка действий */
|
||||
.qr-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 12px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.qr-action-btn {
|
||||
padding: 14px;
|
||||
border-radius: 30px;
|
||||
border: none;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
transition: 0.2s;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.qr-action-btn.primary {
|
||||
background: #0b1c34;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.qr-action-btn.primary:hover {
|
||||
background: #1b3f6b;
|
||||
}
|
||||
|
||||
.qr-action-btn.secondary {
|
||||
background: #eef4fa;
|
||||
color: #1f3f60;
|
||||
}
|
||||
|
||||
.qr-action-btn.secondary:hover {
|
||||
background: #dbeafe;
|
||||
}
|
||||
|
||||
.qr-action-btn i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* Кнопки шеринга */
|
||||
.qr-share-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #dee9f5;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.qr-share-btn {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 22px;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.qr-share-btn.whatsapp {
|
||||
background: #25D366;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.qr-share-btn.telegram {
|
||||
background: #0088cc;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.qr-share-btn.email {
|
||||
background: #ea4335;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.qr-share-btn:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Анимации */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from { transform: translateY(30px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -993,7 +837,7 @@
|
||||
<div class="header">
|
||||
<div class="logo" onclick="window.location.href='/'">
|
||||
<i class="fas fa-briefcase"></i>
|
||||
МП.Ярмарка
|
||||
Rabota.Today
|
||||
</div>
|
||||
<div class="nav" id="nav">
|
||||
<!-- Навигация будет заполнена динамически -->
|
||||
@@ -1098,6 +942,74 @@
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
// Функция для обновления SEO тегов
|
||||
function updateSEOTags(resume) {
|
||||
const decodedName = decodeHtmlEntities(resume.full_name || '');
|
||||
const nameParts = decodedName.split(' ');
|
||||
const firstName = nameParts[0] || '';
|
||||
const lastName = nameParts.slice(1).join(' ') || '';
|
||||
const decodedPosition = decodeHtmlEntities(resume.desired_position || 'Специалист');
|
||||
const salary = resume.desired_salary || 'Зарплата не указана';
|
||||
const about = resume.about_me || 'Профессиональный опыт и навыки';
|
||||
|
||||
const shortAbout = about.length > 160 ? about.substring(0, 157) + '...' : about;
|
||||
const experienceCount = resume.work_experience ? resume.work_experience.length : 0;
|
||||
const skillsList = resume.tags ? resume.tags.map(t => t.name).join(', ') : '';
|
||||
|
||||
const seoDescription = `${decodedName} - ${decodedPosition}. ${salary}. Опыт работы: ${experienceCount} мест. Навыки: ${skillsList}. ${shortAbout}`;
|
||||
|
||||
document.title = `${decodedName} - ${decodedPosition} | Rabota.Today`;
|
||||
|
||||
document.querySelector('meta[name="description"]')?.setAttribute('content', seoDescription.substring(0, 320));
|
||||
document.querySelector('meta[name="keywords"]')?.setAttribute('content', `${decodedName}, ${decodedPosition}, резюме, поиск сотрудников, навыки: ${skillsList}`);
|
||||
|
||||
document.querySelector('meta[property="og:title"]')?.setAttribute('content', `${decodedName} - ${decodedPosition}`);
|
||||
document.querySelector('meta[property="og:description"]')?.setAttribute('content', seoDescription.substring(0, 300));
|
||||
document.querySelector('meta[property="og:url"]')?.setAttribute('content', window.location.href);
|
||||
document.querySelector('meta[property="profile:first_name"]')?.setAttribute('content', firstName);
|
||||
document.querySelector('meta[property="profile:last_name"]')?.setAttribute('content', lastName);
|
||||
|
||||
document.querySelector('meta[name="twitter:title"]')?.setAttribute('content', `${decodedName} - ${decodedPosition}`);
|
||||
document.querySelector('meta[name="twitter:description"]')?.setAttribute('content', seoDescription.substring(0, 300));
|
||||
|
||||
document.querySelector('link[rel="canonical"]')?.setAttribute('href', window.location.href);
|
||||
|
||||
const workExperience = (resume.work_experience || []).map(exp => ({
|
||||
"@type": "OrganizationRole",
|
||||
"roleName": exp.position,
|
||||
"startDate": exp.period ? exp.period.split('–')[0] : null,
|
||||
"endDate": exp.period ? exp.period.split('–')[1] : null,
|
||||
"organization": { "@type": "Organization", "name": exp.company }
|
||||
}));
|
||||
|
||||
const education = (resume.education || []).map(edu => ({
|
||||
"@type": "EducationalOccupationalCredential",
|
||||
"credentialCategory": "Degree",
|
||||
"name": edu.specialty,
|
||||
"educationalLevel": edu.institution,
|
||||
"dateCreated": edu.graduation_year
|
||||
}));
|
||||
|
||||
const structuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Person",
|
||||
"name": decodedName,
|
||||
"jobTitle": decodedPosition,
|
||||
"description": resume.about_me || "",
|
||||
"worksFor": workExperience,
|
||||
"alumniOf": education,
|
||||
"knowsAbout": resume.tags ? resume.tags.map(t => t.name) : [],
|
||||
"url": window.location.href
|
||||
};
|
||||
|
||||
const scriptElement = document.getElementById('structuredData');
|
||||
if (scriptElement) {
|
||||
scriptElement.textContent = JSON.stringify(structuredData, null, 2);
|
||||
}
|
||||
|
||||
console.log('✅ SEO теги для резюме обновлены');
|
||||
}
|
||||
|
||||
// Проверка авторизации
|
||||
async function checkAuth() {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
@@ -1121,7 +1033,6 @@
|
||||
updateNavigation();
|
||||
}
|
||||
|
||||
// Обновление навигации
|
||||
function updateNavigation() {
|
||||
const nav = document.getElementById('nav');
|
||||
|
||||
@@ -1160,6 +1071,10 @@
|
||||
}
|
||||
|
||||
currentResume = await response.json();
|
||||
|
||||
// Обновляем SEO теги
|
||||
updateSEOTags(currentResume);
|
||||
|
||||
renderResume(currentResume);
|
||||
|
||||
} catch (error) {
|
||||
@@ -1176,7 +1091,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Отображение резюме с QR-кнопкой
|
||||
// Отображение резюме
|
||||
function renderResume(resume) {
|
||||
const container = document.getElementById('resumeDetail');
|
||||
const token = localStorage.getItem('accessToken');
|
||||
@@ -1315,11 +1230,9 @@
|
||||
|
||||
// ========== ФУНКЦИИ ДЛЯ QR-КОДА ==========
|
||||
|
||||
// Открыть модальное окно с QR
|
||||
function openQRModal() {
|
||||
if (!currentResume) return;
|
||||
|
||||
// Декодируем имя
|
||||
const decodedName = decodeHtmlEntities(currentResume.full_name || '');
|
||||
const decodedPosition = decodeHtmlEntities(currentResume.desired_position || '');
|
||||
|
||||
@@ -1328,43 +1241,32 @@
|
||||
const resumeUrl = window.location.origin + '/resume/' + resumeId;
|
||||
document.getElementById('qrResumeUrl').textContent = resumeUrl.replace('https://', '').replace('http://', '');
|
||||
|
||||
// Обновляем статистику
|
||||
document.getElementById('qrViewCount').textContent = ++qrViewCount;
|
||||
document.getElementById('qrViewBadge').textContent = qrViewCount;
|
||||
|
||||
// Количество мест работы
|
||||
const expCount = currentResume.work_experience ? currentResume.work_experience.length : 0;
|
||||
document.getElementById('qrExperienceCount').textContent = expCount;
|
||||
|
||||
// Желаемая должность
|
||||
document.getElementById('qrPosition').textContent = decodedPosition || '—';
|
||||
|
||||
// Генерируем QR-код
|
||||
generateQRCodeWithLogo(resumeUrl);
|
||||
|
||||
document.getElementById('qrModal').classList.add('active');
|
||||
}
|
||||
|
||||
// Закрыть модальное окно
|
||||
function closeQRModal() {
|
||||
document.getElementById('qrModal').classList.remove('active');
|
||||
}
|
||||
|
||||
// Генерация QR-кода с иконкой пользователя
|
||||
function generateQRCodeWithLogo(text) {
|
||||
const canvas = document.getElementById('qrCanvas');
|
||||
const logoOverlay = document.getElementById('qrLogoOverlay');
|
||||
const logoIcon = document.getElementById('qrLogoIcon');
|
||||
|
||||
// Настройки QR-кода
|
||||
const options = {
|
||||
width: 250,
|
||||
height: 250,
|
||||
color: {
|
||||
dark: '#0b1c34',
|
||||
light: '#ffffff'
|
||||
},
|
||||
errorCorrectionLevel: 'H' // высокая коррекция ошибок для логотипа
|
||||
color: { dark: '#0b1c34', light: '#ffffff' },
|
||||
errorCorrectionLevel: 'H'
|
||||
};
|
||||
|
||||
QRCode.toCanvas(canvas, text, options, function(error) {
|
||||
@@ -1372,9 +1274,6 @@
|
||||
console.error('Error generating QR code:', error);
|
||||
showNotification('Ошибка генерации QR-кода', 'error');
|
||||
} else {
|
||||
console.log('QR code generated successfully');
|
||||
|
||||
// Показываем оверлей с иконкой пользователя
|
||||
logoOverlay.style.display = 'flex';
|
||||
logoIcon.style.display = 'block';
|
||||
logoIcon.className = 'fas fa-user';
|
||||
@@ -1382,32 +1281,24 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Скачать QR-код
|
||||
function downloadQR() {
|
||||
const canvas = document.getElementById('qrCanvas');
|
||||
|
||||
// Создаем временный canvas для объединения QR и иконки
|
||||
const combinedCanvas = document.createElement('canvas');
|
||||
combinedCanvas.width = canvas.width;
|
||||
combinedCanvas.height = canvas.height;
|
||||
const ctx = combinedCanvas.getContext('2d');
|
||||
|
||||
// Рисуем QR-код
|
||||
ctx.drawImage(canvas, 0, 0);
|
||||
|
||||
// Рисуем иконку поверх
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.beginPath();
|
||||
ctx.arc(125, 125, 35, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = '#3b82f6';
|
||||
ctx.font = '30px "Font Awesome 6 Free"';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText('', 125, 125); // Unicode для иконки user
|
||||
ctx.fillText('', 125, 125);
|
||||
|
||||
// Скачиваем
|
||||
const link = document.createElement('a');
|
||||
const decodedName = decodeHtmlEntities(currentResume.full_name || '');
|
||||
const filename = `resume_${decodedName.toLowerCase().replace(/[^a-zа-я0-9]/g, '_')}.png`;
|
||||
@@ -1418,7 +1309,6 @@
|
||||
showNotification('QR-код скачан', 'success');
|
||||
}
|
||||
|
||||
// Копировать ссылку на резюме
|
||||
function copyResumeLink() {
|
||||
const url = window.location.origin + '/resume/' + resumeId;
|
||||
navigator.clipboard.writeText(url).then(() => {
|
||||
@@ -1428,14 +1318,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Сохранить в контакты (vCard)
|
||||
function saveToContacts() {
|
||||
if (!currentResume) return;
|
||||
|
||||
const decodedName = decodeHtmlEntities(currentResume.full_name || '');
|
||||
const decodedPosition = decodeHtmlEntities(currentResume.desired_position || '');
|
||||
|
||||
// Создаем vCard
|
||||
const vCard = `BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN:${decodedName}
|
||||
@@ -1448,36 +1336,31 @@ END:VCARD`;
|
||||
|
||||
const blob = new Blob([vCard], { type: 'text/vcard' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `${decodedName}.vcf`;
|
||||
link.click();
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
showNotification('Контакт сохранен', 'success');
|
||||
}
|
||||
|
||||
// Распечатать QR
|
||||
function printQR() {
|
||||
const canvas = document.getElementById('qrCanvas');
|
||||
const decodedName = decodeHtmlEntities(currentResume.full_name || '');
|
||||
const decodedPosition = decodeHtmlEntities(currentResume.desired_position || '');
|
||||
|
||||
const printWindow = window.open('', '_blank');
|
||||
|
||||
printWindow.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>QR-код резюме ${decodedName}</title>
|
||||
<style>
|
||||
body { display: flex; justify-content: center; align-items: center; height: 100vh; flex-direction: column; font-family: Arial; margin: 0; padding: 20px; }
|
||||
h2 { color: #0b1c34; text-align: center; word-break: break-word; }
|
||||
h3 { color: #3b82f6; text-align: center; }
|
||||
img { max-width: 300px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); border-radius: 20px; }
|
||||
.url { color: #4f7092; margin-top: 20px; word-break: break-all; text-align: center; }
|
||||
.position { margin-bottom: 20px; color: #1f3f60; }
|
||||
</style>
|
||||
<head><title>QR-код резюме ${decodedName}</title>
|
||||
<style>
|
||||
body { display: flex; justify-content: center; align-items: center; height: 100vh; flex-direction: column; font-family: Arial; margin: 0; padding: 20px; }
|
||||
h2 { color: #0b1c34; text-align: center; word-break: break-word; }
|
||||
h3 { color: #3b82f6; text-align: center; }
|
||||
img { max-width: 300px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); border-radius: 20px; }
|
||||
.url { color: #4f7092; margin-top: 20px; word-break: break-all; text-align: center; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>${escapeHtml(decodedName)}</h2>
|
||||
@@ -1487,109 +1370,63 @@ END:VCARD`;
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
printWindow.document.close();
|
||||
printWindow.focus();
|
||||
printWindow.print();
|
||||
}
|
||||
|
||||
// Поделиться QR в соцсетях
|
||||
function shareQR(platform) {
|
||||
const url = window.location.origin + '/resume/' + resumeId;
|
||||
const decodedName = decodeHtmlEntities(currentResume.full_name || '');
|
||||
const text = `Резюме ${decodedName} на Rabota.Today`;
|
||||
|
||||
let shareUrl = '';
|
||||
|
||||
switch(platform) {
|
||||
case 'whatsapp':
|
||||
shareUrl = `https://wa.me/?text=${encodeURIComponent(text + ' ' + url)}`;
|
||||
break;
|
||||
case 'telegram':
|
||||
shareUrl = `https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`;
|
||||
break;
|
||||
case 'email':
|
||||
shareUrl = `mailto:?subject=${encodeURIComponent('Резюме ' + decodedName)}&body=${encodeURIComponent(text + '\n\n' + url)}`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (shareUrl) {
|
||||
window.open(shareUrl, '_blank');
|
||||
case 'whatsapp': shareUrl = `https://wa.me/?text=${encodeURIComponent(text + ' ' + url)}`; break;
|
||||
case 'telegram': shareUrl = `https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`; break;
|
||||
case 'email': shareUrl = `mailto:?subject=${encodeURIComponent('Резюме ' + decodedName)}&body=${encodeURIComponent(text + '\n\n' + url)}`; break;
|
||||
}
|
||||
if (shareUrl) window.open(shareUrl, '_blank');
|
||||
}
|
||||
|
||||
// Связаться с кандидатом
|
||||
function contactCandidate() {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
|
||||
if (!token) {
|
||||
redirectToLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
showNotification('Функция связи будет доступна в ближайшее время', 'info');
|
||||
}
|
||||
|
||||
// Добавить в избранное
|
||||
function saveToFavorites() {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
|
||||
if (!token) {
|
||||
if (confirm('Для добавления в избранное нужно войти в систему. Перейти на страницу входа?')) {
|
||||
window.location.href = '/login';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
showNotification('Резюме добавлено в избранное', 'success');
|
||||
}
|
||||
|
||||
// Поделиться резюме
|
||||
function shareResume() {
|
||||
const url = window.location.href;
|
||||
|
||||
if (navigator.share) {
|
||||
navigator.share({
|
||||
title: document.title,
|
||||
url: url
|
||||
}).catch(() => {
|
||||
copyResumeLink();
|
||||
});
|
||||
navigator.share({ title: document.title, url: url }).catch(() => copyResumeLink());
|
||||
} else {
|
||||
copyResumeLink();
|
||||
}
|
||||
}
|
||||
|
||||
function redirectToLogin() {
|
||||
if (confirm('Для просмотра контактов нужно войти в систему. Перейти на страницу входа?')) {
|
||||
window.location.href = '/login';
|
||||
}
|
||||
}
|
||||
|
||||
// Показать уведомление
|
||||
function showNotification(message, type = 'info') {
|
||||
const notification = document.getElementById('notification');
|
||||
notification.className = `notification ${type}`;
|
||||
notification.innerHTML = message;
|
||||
notification.style.display = 'block';
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.display = 'none';
|
||||
}, 3000);
|
||||
setTimeout(() => { notification.style.display = 'none'; }, 3000);
|
||||
}
|
||||
|
||||
// Закрытие модального окна по клику вне
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('qrModal');
|
||||
if (event.target === modal) {
|
||||
modal.classList.remove('active');
|
||||
}
|
||||
if (event.target === modal) modal.classList.remove('active');
|
||||
};
|
||||
|
||||
// Инициализация
|
||||
checkAuth().then(() => {
|
||||
loadResume();
|
||||
});
|
||||
checkAuth().then(() => loadResume());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user