Compare commits
2 Commits
c1616ac542
...
9839389fc9
| Author | SHA1 | Date | |
|---|---|---|---|
| 9839389fc9 | |||
| ec01a2ae10 |
@@ -1,5 +1,5 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Service, Project, Client, Order, Review, BlogPost, Category, ServiceRequest, HeroBanner, ContactInfo
|
from .models import Service, Project, Client, Order, Review, BlogPost, Category, ServiceRequest, HeroBanner, ContactInfo, Team, Career
|
||||||
from .forms import ProjectForm
|
from .forms import ProjectForm
|
||||||
|
|
||||||
@admin.register(ContactInfo)
|
@admin.register(ContactInfo)
|
||||||
@@ -87,4 +87,96 @@ class CategoryAdmin(admin.ModelAdmin):
|
|||||||
class ServiceRequestAdmin(admin.ModelAdmin):
|
class ServiceRequestAdmin(admin.ModelAdmin):
|
||||||
list_display = ('service','token', 'client', 'created_at')
|
list_display = ('service','token', 'client', 'created_at')
|
||||||
search_fields = ('service','token', 'client')
|
search_fields = ('service','token', 'client')
|
||||||
list_filter = ('service','token','client')
|
list_filter = ('service','token','client')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Team)
|
||||||
|
class TeamAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('first_name', 'last_name', 'position', 'department', 'is_active', 'display_order')
|
||||||
|
list_filter = ('department', 'is_active', 'show_on_about')
|
||||||
|
search_fields = ('first_name', 'last_name', 'position', 'skills')
|
||||||
|
list_editable = ('display_order', 'is_active')
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Основная информация', {
|
||||||
|
'fields': ('first_name', 'last_name', 'position', 'department')
|
||||||
|
}),
|
||||||
|
('Контактные данные', {
|
||||||
|
'fields': ('email', 'phone', 'photo'),
|
||||||
|
'classes': ('collapse',)
|
||||||
|
}),
|
||||||
|
('Профессиональная информация', {
|
||||||
|
'fields': ('bio', 'skills', 'experience_years')
|
||||||
|
}),
|
||||||
|
('Социальные сети', {
|
||||||
|
'fields': ('linkedin', 'github', 'telegram'),
|
||||||
|
'classes': ('collapse',)
|
||||||
|
}),
|
||||||
|
('Настройки отображения', {
|
||||||
|
'fields': ('is_active', 'show_on_about', 'display_order')
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
return super().get_queryset(request).order_by('display_order', 'last_name')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Career)
|
||||||
|
class CareerAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('title', 'department', 'experience_level', 'employment_type', 'status', 'is_featured', 'created_at')
|
||||||
|
list_filter = ('status', 'employment_type', 'experience_level', 'department', 'is_featured')
|
||||||
|
search_fields = ('title', 'department', 'description', 'required_skills')
|
||||||
|
list_editable = ('status', 'is_featured')
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Основная информация', {
|
||||||
|
'fields': ('title', 'department', 'location', 'employment_type', 'experience_level')
|
||||||
|
}),
|
||||||
|
('Описание вакансии', {
|
||||||
|
'fields': ('description', 'responsibilities', 'requirements', 'benefits')
|
||||||
|
}),
|
||||||
|
('Зарплата', {
|
||||||
|
'fields': ('salary_min', 'salary_max', 'salary_currency'),
|
||||||
|
'classes': ('collapse',)
|
||||||
|
}),
|
||||||
|
('Навыки', {
|
||||||
|
'fields': ('required_skills', 'preferred_skills'),
|
||||||
|
}),
|
||||||
|
('Контактная информация', {
|
||||||
|
'fields': ('contact_email', 'contact_person'),
|
||||||
|
'classes': ('collapse',)
|
||||||
|
}),
|
||||||
|
('Статус и метаданные', {
|
||||||
|
'fields': ('status', 'is_featured', 'application_deadline', 'published_at')
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
readonly_fields = ('created_at', 'updated_at')
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
return super().get_queryset(request).order_by('-is_featured', '-created_at')
|
||||||
|
|
||||||
|
def save_model(self, request, obj, form, change):
|
||||||
|
if obj.status == 'active' and not obj.published_at:
|
||||||
|
from django.utils import timezone
|
||||||
|
obj.published_at = timezone.now()
|
||||||
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
actions = ['mark_as_active', 'mark_as_paused', 'mark_as_closed']
|
||||||
|
|
||||||
|
def mark_as_active(self, request, queryset):
|
||||||
|
from django.utils import timezone
|
||||||
|
updated = queryset.update(status='active')
|
||||||
|
queryset.filter(published_at__isnull=True).update(published_at=timezone.now())
|
||||||
|
self.message_user(request, f'{updated} вакансий отмечены как активные.')
|
||||||
|
mark_as_active.short_description = "Отметить как активные"
|
||||||
|
|
||||||
|
def mark_as_paused(self, request, queryset):
|
||||||
|
updated = queryset.update(status='paused')
|
||||||
|
self.message_user(request, f'{updated} вакансий приостановлены.')
|
||||||
|
mark_as_paused.short_description = "Приостановить"
|
||||||
|
|
||||||
|
def mark_as_closed(self, request, queryset):
|
||||||
|
updated = queryset.update(status='closed')
|
||||||
|
self.message_user(request, f'{updated} вакансий закрыты.')
|
||||||
|
mark_as_closed.short_description = "Закрыть"
|
||||||
75
smartsoltech/web/migrations/0013_career_team.py
Normal file
75
smartsoltech/web/migrations/0013_career_team.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Generated by Django 5.1.1 on 2025-11-25 06:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('web', '0012_contactinfo'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Career',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(max_length=200, verbose_name='Название вакансии')),
|
||||||
|
('department', models.CharField(max_length=100, verbose_name='Отдел')),
|
||||||
|
('location', models.CharField(default='Кванджу, Южная Корея', max_length=200, verbose_name='Местоположение')),
|
||||||
|
('employment_type', models.CharField(choices=[('full_time', 'Полная занятость'), ('part_time', 'Частичная занятость'), ('contract', 'Контракт'), ('internship', 'Стажировка'), ('remote', 'Удаленная работа'), ('freelance', 'Фриланс')], default='full_time', max_length=20, verbose_name='Тип занятости')),
|
||||||
|
('experience_level', models.CharField(choices=[('junior', 'Junior (0-1 год)'), ('middle', 'Middle (2-4 года)'), ('senior', 'Senior (5+ лет)'), ('lead', 'Team Lead'), ('intern', 'Стажер')], default='middle', max_length=20, verbose_name='Уровень опыта')),
|
||||||
|
('description', models.TextField(verbose_name='Описание вакансии')),
|
||||||
|
('responsibilities', models.TextField(verbose_name='Обязанности')),
|
||||||
|
('requirements', models.TextField(verbose_name='Требования')),
|
||||||
|
('benefits', models.TextField(blank=True, verbose_name='Преимущества и условия')),
|
||||||
|
('salary_min', models.PositiveIntegerField(blank=True, null=True, verbose_name='Зарплата от (₩)')),
|
||||||
|
('salary_max', models.PositiveIntegerField(blank=True, null=True, verbose_name='Зарплата до (₩)')),
|
||||||
|
('salary_currency', models.CharField(default='KRW', max_length=10, verbose_name='Валюта')),
|
||||||
|
('required_skills', models.TextField(help_text='Разделите навыки запятыми', verbose_name='Обязательные навыки')),
|
||||||
|
('preferred_skills', models.TextField(blank=True, help_text='Разделите навыки запятыми', verbose_name='Желательные навыки')),
|
||||||
|
('status', models.CharField(choices=[('active', 'Активная'), ('paused', 'Приостановлена'), ('closed', 'Закрыта'), ('draft', 'Черновик')], default='active', max_length=20, verbose_name='Статус')),
|
||||||
|
('is_featured', models.BooleanField(default=False, verbose_name='Рекомендуемая вакансия')),
|
||||||
|
('application_deadline', models.DateField(blank=True, null=True, verbose_name='Дедлайн подачи заявок')),
|
||||||
|
('contact_email', models.EmailField(default='hr@smartsoltech.kr', max_length=254, verbose_name='Email для связи')),
|
||||||
|
('contact_person', models.CharField(blank=True, max_length=200, verbose_name='Контактное лицо')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('published_at', models.DateTimeField(blank=True, null=True, verbose_name='Дата публикации')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Вакансия',
|
||||||
|
'verbose_name_plural': 'Карьера',
|
||||||
|
'ordering': ['-is_featured', '-published_at', '-created_at'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Team',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('first_name', models.CharField(max_length=100, verbose_name='Имя')),
|
||||||
|
('last_name', models.CharField(max_length=100, verbose_name='Фамилия')),
|
||||||
|
('position', models.CharField(max_length=200, verbose_name='Должность')),
|
||||||
|
('department', models.CharField(blank=True, max_length=100, verbose_name='Отдел')),
|
||||||
|
('bio', models.TextField(blank=True, verbose_name='Биография/Описание')),
|
||||||
|
('photo', models.ImageField(blank=True, null=True, upload_to='static/img/team/', verbose_name='Фотография')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, verbose_name='Email')),
|
||||||
|
('phone', models.CharField(blank=True, max_length=20, verbose_name='Телефон')),
|
||||||
|
('linkedin', models.URLField(blank=True, verbose_name='LinkedIn')),
|
||||||
|
('github', models.URLField(blank=True, verbose_name='GitHub')),
|
||||||
|
('telegram', models.CharField(blank=True, max_length=100, verbose_name='Telegram')),
|
||||||
|
('skills', models.TextField(blank=True, help_text='Разделите навыки запятыми', verbose_name='Навыки')),
|
||||||
|
('experience_years', models.PositiveIntegerField(default=0, verbose_name='Лет опыта')),
|
||||||
|
('is_active', models.BooleanField(default=True, verbose_name='Активен')),
|
||||||
|
('display_order', models.PositiveIntegerField(default=0, verbose_name='Порядок отображения')),
|
||||||
|
('show_on_about', models.BooleanField(default=True, verbose_name='Показывать на странице О нас')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Сотрудник',
|
||||||
|
'verbose_name_plural': 'Команда',
|
||||||
|
'ordering': ['display_order', 'last_name', 'first_name'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -212,3 +212,174 @@ class Review(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Отзыв от {self.client.first_name} {self.client.last_name} for {self.service.name}"
|
return f"Отзыв от {self.client.first_name} {self.client.last_name} for {self.service.name}"
|
||||||
|
|
||||||
|
|
||||||
|
class Team(models.Model):
|
||||||
|
"""Модель для управления персоналом компании"""
|
||||||
|
first_name = models.CharField(max_length=100, verbose_name="Имя")
|
||||||
|
last_name = models.CharField(max_length=100, verbose_name="Фамилия")
|
||||||
|
position = models.CharField(max_length=200, verbose_name="Должность")
|
||||||
|
department = models.CharField(max_length=100, verbose_name="Отдел", blank=True)
|
||||||
|
bio = models.TextField(verbose_name="Биография/Описание", blank=True)
|
||||||
|
photo = models.ImageField(upload_to='static/img/team/', blank=True, null=True, verbose_name="Фотография")
|
||||||
|
email = models.EmailField(blank=True, verbose_name="Email")
|
||||||
|
phone = models.CharField(max_length=20, blank=True, verbose_name="Телефон")
|
||||||
|
|
||||||
|
# Социальные сети
|
||||||
|
linkedin = models.URLField(blank=True, verbose_name="LinkedIn")
|
||||||
|
github = models.URLField(blank=True, verbose_name="GitHub")
|
||||||
|
telegram = models.CharField(max_length=100, blank=True, verbose_name="Telegram")
|
||||||
|
|
||||||
|
# Навыки и технологии
|
||||||
|
skills = models.TextField(blank=True, verbose_name="Навыки", help_text="Разделите навыки запятыми")
|
||||||
|
experience_years = models.PositiveIntegerField(default=0, verbose_name="Лет опыта")
|
||||||
|
|
||||||
|
# Настройки отображения
|
||||||
|
is_active = models.BooleanField(default=True, verbose_name="Активен")
|
||||||
|
display_order = models.PositiveIntegerField(default=0, verbose_name="Порядок отображения")
|
||||||
|
show_on_about = models.BooleanField(default=True, verbose_name="Показывать на странице О нас")
|
||||||
|
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = 'Сотрудник'
|
||||||
|
verbose_name_plural = 'Команда'
|
||||||
|
ordering = ['display_order', 'last_name', 'first_name']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.first_name} {self.last_name} - {self.position}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_name(self):
|
||||||
|
return f"{self.first_name} {self.last_name}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def skills_list(self):
|
||||||
|
"""Возвращает список навыков"""
|
||||||
|
if self.skills:
|
||||||
|
return [skill.strip() for skill in self.skills.split(',') if skill.strip()]
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class Career(models.Model):
|
||||||
|
"""Модель для управления вакансиями и карьерными возможностями"""
|
||||||
|
|
||||||
|
EMPLOYMENT_TYPE_CHOICES = [
|
||||||
|
('full_time', 'Полная занятость'),
|
||||||
|
('part_time', 'Частичная занятость'),
|
||||||
|
('contract', 'Контракт'),
|
||||||
|
('internship', 'Стажировка'),
|
||||||
|
('remote', 'Удаленная работа'),
|
||||||
|
('freelance', 'Фриланс'),
|
||||||
|
]
|
||||||
|
|
||||||
|
EXPERIENCE_LEVEL_CHOICES = [
|
||||||
|
('junior', 'Junior (0-1 год)'),
|
||||||
|
('middle', 'Middle (2-4 года)'),
|
||||||
|
('senior', 'Senior (5+ лет)'),
|
||||||
|
('lead', 'Team Lead'),
|
||||||
|
('intern', 'Стажер'),
|
||||||
|
]
|
||||||
|
|
||||||
|
STATUS_CHOICES = [
|
||||||
|
('active', 'Активная'),
|
||||||
|
('paused', 'Приостановлена'),
|
||||||
|
('closed', 'Закрыта'),
|
||||||
|
('draft', 'Черновик'),
|
||||||
|
]
|
||||||
|
|
||||||
|
title = models.CharField(max_length=200, verbose_name="Название вакансии")
|
||||||
|
department = models.CharField(max_length=100, verbose_name="Отдел")
|
||||||
|
location = models.CharField(max_length=200, default="Кванджу, Южная Корея", verbose_name="Местоположение")
|
||||||
|
|
||||||
|
employment_type = models.CharField(
|
||||||
|
max_length=20,
|
||||||
|
choices=EMPLOYMENT_TYPE_CHOICES,
|
||||||
|
default='full_time',
|
||||||
|
verbose_name="Тип занятости"
|
||||||
|
)
|
||||||
|
|
||||||
|
experience_level = models.CharField(
|
||||||
|
max_length=20,
|
||||||
|
choices=EXPERIENCE_LEVEL_CHOICES,
|
||||||
|
default='middle',
|
||||||
|
verbose_name="Уровень опыта"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Описание вакансии
|
||||||
|
description = models.TextField(verbose_name="Описание вакансии")
|
||||||
|
responsibilities = models.TextField(verbose_name="Обязанности")
|
||||||
|
requirements = models.TextField(verbose_name="Требования")
|
||||||
|
benefits = models.TextField(blank=True, verbose_name="Преимущества и условия")
|
||||||
|
|
||||||
|
# Зарплатная вилка
|
||||||
|
salary_min = models.PositiveIntegerField(blank=True, null=True, verbose_name="Зарплата от (₩)")
|
||||||
|
salary_max = models.PositiveIntegerField(blank=True, null=True, verbose_name="Зарплата до (₩)")
|
||||||
|
salary_currency = models.CharField(max_length=10, default="KRW", verbose_name="Валюта")
|
||||||
|
|
||||||
|
# Необходимые навыки
|
||||||
|
required_skills = models.TextField(verbose_name="Обязательные навыки", help_text="Разделите навыки запятыми")
|
||||||
|
preferred_skills = models.TextField(blank=True, verbose_name="Желательные навыки", help_text="Разделите навыки запятыми")
|
||||||
|
|
||||||
|
# Статус и метаданные
|
||||||
|
status = models.CharField(
|
||||||
|
max_length=20,
|
||||||
|
choices=STATUS_CHOICES,
|
||||||
|
default='active',
|
||||||
|
verbose_name="Статус"
|
||||||
|
)
|
||||||
|
|
||||||
|
is_featured = models.BooleanField(default=False, verbose_name="Рекомендуемая вакансия")
|
||||||
|
application_deadline = models.DateField(blank=True, null=True, verbose_name="Дедлайн подачи заявок")
|
||||||
|
|
||||||
|
# Контактная информация
|
||||||
|
contact_email = models.EmailField(default="hr@smartsoltech.kr", verbose_name="Email для связи")
|
||||||
|
contact_person = models.CharField(max_length=200, blank=True, verbose_name="Контактное лицо")
|
||||||
|
|
||||||
|
# Timestamps
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
published_at = models.DateTimeField(blank=True, null=True, verbose_name="Дата публикации")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = 'Вакансия'
|
||||||
|
verbose_name_plural = 'Карьера'
|
||||||
|
ordering = ['-is_featured', '-published_at', '-created_at']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.title} ({self.get_experience_level_display()})"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def required_skills_list(self):
|
||||||
|
"""Возвращает список обязательных навыков"""
|
||||||
|
if self.required_skills:
|
||||||
|
return [skill.strip() for skill in self.required_skills.split(',') if skill.strip()]
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def preferred_skills_list(self):
|
||||||
|
"""Возвращает список желательных навыков"""
|
||||||
|
if self.preferred_skills:
|
||||||
|
return [skill.strip() for skill in self.preferred_skills.split(',') if skill.strip()]
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def salary_range(self):
|
||||||
|
"""Возвращает строку с зарплатной вилкой"""
|
||||||
|
if self.salary_min and self.salary_max:
|
||||||
|
return f"₩{self.salary_min:,} - ₩{self.salary_max:,}"
|
||||||
|
elif self.salary_min:
|
||||||
|
return f"от ₩{self.salary_min:,}"
|
||||||
|
elif self.salary_max:
|
||||||
|
return f"до ₩{self.salary_max:,}"
|
||||||
|
return "По договоренности"
|
||||||
|
|
||||||
|
def is_active_position(self):
|
||||||
|
"""Проверяет, активна ли вакансия"""
|
||||||
|
from django.utils import timezone
|
||||||
|
if self.status != 'active':
|
||||||
|
return False
|
||||||
|
if self.application_deadline and self.application_deadline < timezone.now().date():
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|||||||
637
smartsoltech/web/templates/web/career.html
Normal file
637
smartsoltech/web/templates/web/career.html
Normal file
@@ -0,0 +1,637 @@
|
|||||||
|
{% extends 'web/base_modern.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Карьера в SmartSolTech - Присоединяйтесь к нашей команде{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<section class="hero-simple bg-gradient text-white">
|
||||||
|
<div class="container-modern text-center py-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<h1 class="display-4 fw-bold mb-4">Карьера в SmartSolTech</h1>
|
||||||
|
<p class="lead opacity-90">
|
||||||
|
Развивайтесь вместе с нами в мире инновационных технологий
|
||||||
|
</p>
|
||||||
|
{% if total_positions > 0 %}
|
||||||
|
<div class="career-stats mt-4">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-number">{{ total_positions }}</div>
|
||||||
|
<div class="stat-label">Открытых позиций</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-number">{{ departments|length }}</div>
|
||||||
|
<div class="stat-label">Отделов</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-number">{{ featured_careers|length }}</div>
|
||||||
|
<div class="stat-label">Топ вакансий</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Featured Positions -->
|
||||||
|
{% if featured_careers %}
|
||||||
|
<section class="section-padding">
|
||||||
|
<div class="container-modern">
|
||||||
|
<div class="text-center mb-5">
|
||||||
|
<h2 class="display-6 fw-bold text-primary mb-3">Рекомендуемые вакансии</h2>
|
||||||
|
<p class="lead text-muted">Наиболее актуальные позиции в нашей команде</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
{% for career in featured_careers %}
|
||||||
|
<div class="col-lg-4 col-md-6">
|
||||||
|
<div class="career-card-featured">
|
||||||
|
<div class="career-header">
|
||||||
|
<div class="career-badges">
|
||||||
|
<span class="badge bg-warning text-dark">
|
||||||
|
<i class="fas fa-star me-1"></i>
|
||||||
|
Рекомендуем
|
||||||
|
</span>
|
||||||
|
<span class="badge bg-success">{{ career.get_employment_type_display }}</span>
|
||||||
|
</div>
|
||||||
|
<h3 class="career-title">{{ career.title }}</h3>
|
||||||
|
<p class="career-department">
|
||||||
|
<i class="fas fa-building me-2"></i>
|
||||||
|
{{ career.department }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="career-details">
|
||||||
|
<div class="detail-row">
|
||||||
|
<div class="detail-item">
|
||||||
|
<i class="fas fa-map-marker-alt text-primary"></i>
|
||||||
|
<span>{{ career.location }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<i class="fas fa-chart-line text-success"></i>
|
||||||
|
<span>{{ career.get_experience_level_display }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<div class="detail-item salary">
|
||||||
|
<i class="fas fa-won-sign text-warning"></i>
|
||||||
|
<span>{{ career.salary_range }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="career-description">
|
||||||
|
<p class="text-muted">{{ career.description|truncatewords:20 }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="career-requirements">
|
||||||
|
<h6 class="text-muted small mb-2">Ключевые требования:</h6>
|
||||||
|
<p class="text-muted small">{{ career.requirements|truncatewords:15 }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if career.required_skills_list %}
|
||||||
|
<div class="career-skills">
|
||||||
|
{% for skill in career.required_skills_list|slice:":5" %}
|
||||||
|
<span class="skill-tag">{{ skill }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
{% if career.required_skills_list|length > 5 %}
|
||||||
|
<span class="skill-tag more">+{{ career.required_skills_list|length|add:"-5" }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="career-footer">
|
||||||
|
{% if career.application_deadline %}
|
||||||
|
<div class="deadline-info mb-3">
|
||||||
|
<i class="fas fa-calendar-alt text-warning me-2"></i>
|
||||||
|
<small class="text-muted">Подача заявок до {{ career.application_deadline }}</small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<a href="mailto:{{ career.contact_email }}?subject=Заявка на вакансию: {{ career.title }}&body=Здравствуйте!%0A%0AМеня заинтересовала вакансия {{ career.title }} в отделе {{ career.department }}.%0A%0AОпыт работы: [укажите ваш опыт]%0AКлючевые навыки: [перечислите ваши навыки]%0A%0AПрикладываю резюме в письме.%0A%0AС уважением,[Ваше имя]"
|
||||||
|
class="btn btn-primary">
|
||||||
|
<i class="fas fa-paper-plane me-2"></i>
|
||||||
|
Откликнуться
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-outline-secondary btn-sm" onclick="shareJob('{{ career.title }}', '{{ career.department }}')">
|
||||||
|
<i class="fas fa-share me-2"></i>
|
||||||
|
Поделиться
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- All Positions -->
|
||||||
|
{% if active_careers %}
|
||||||
|
<section class="section-padding {% if not featured_careers %}pt-0{% endif %} bg-light">
|
||||||
|
<div class="container-modern">
|
||||||
|
<div class="text-center mb-5">
|
||||||
|
<h2 class="display-6 fw-bold text-primary mb-3">{% if featured_careers %}Все вакансии{% else %}Открытые вакансии{% endif %}</h2>
|
||||||
|
<p class="lead text-muted">Найдите идеальную позицию для своего развития</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Department Filter -->
|
||||||
|
{% if departments %}
|
||||||
|
<div class="filter-section mb-5">
|
||||||
|
<div class="text-center">
|
||||||
|
<h6 class="text-muted mb-3">Фильтр по отделам:</h6>
|
||||||
|
<div class="department-filters">
|
||||||
|
<button class="filter-btn active" data-department="all">Все отделы</button>
|
||||||
|
{% for dept in departments %}
|
||||||
|
<button class="filter-btn" data-department="{{ dept }}">{{ dept }}</button>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row g-4" id="careers-grid">
|
||||||
|
{% for career in active_careers %}
|
||||||
|
<div class="col-lg-6" data-department="{{ career.department }}">
|
||||||
|
<div class="career-card-compact">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="d-flex justify-content-between align-items-start">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<h4 class="career-title">{{ career.title }}</h4>
|
||||||
|
<p class="career-department text-muted mb-2">{{ career.department }}</p>
|
||||||
|
<div class="career-meta">
|
||||||
|
<span class="meta-item">
|
||||||
|
<i class="fas fa-map-marker-alt me-1"></i>
|
||||||
|
{{ career.location }}
|
||||||
|
</span>
|
||||||
|
<span class="meta-item">
|
||||||
|
<i class="fas fa-briefcase me-1"></i>
|
||||||
|
{{ career.get_employment_type_display }}
|
||||||
|
</span>
|
||||||
|
<span class="meta-item">
|
||||||
|
<i class="fas fa-chart-line me-1"></i>
|
||||||
|
{{ career.get_experience_level_display }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="position-badges">
|
||||||
|
{% if career.is_featured %}
|
||||||
|
<span class="badge bg-warning text-dark small">
|
||||||
|
<i class="fas fa-star"></i>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="career-description text-muted">{{ career.description|truncatewords:25 }}</p>
|
||||||
|
|
||||||
|
{% if career.required_skills_list %}
|
||||||
|
<div class="skills-preview mb-3">
|
||||||
|
{% for skill in career.required_skills_list|slice:":4" %}
|
||||||
|
<span class="skill-tag small">{{ skill }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
{% if career.required_skills_list|length > 4 %}
|
||||||
|
<span class="skill-tag small more">+{{ career.required_skills_list|length|add:"-4" }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div class="salary-info">
|
||||||
|
<strong class="text-success">{{ career.salary_range }}</strong>
|
||||||
|
</div>
|
||||||
|
<a href="mailto:{{ career.contact_email }}?subject=Заявка на вакансию: {{ career.title }}"
|
||||||
|
class="btn btn-primary btn-sm">
|
||||||
|
Откликнуться
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if career.application_deadline %}
|
||||||
|
<div class="card-footer">
|
||||||
|
<small class="text-muted">
|
||||||
|
<i class="fas fa-calendar-alt me-1"></i>
|
||||||
|
Подача заявок до {{ career.application_deadline }}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% else %}
|
||||||
|
<section class="section-padding text-center">
|
||||||
|
<div class="container-modern">
|
||||||
|
<div class="py-5">
|
||||||
|
<div class="mb-4">
|
||||||
|
<i class="fas fa-briefcase text-muted" style="font-size: 4rem;"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-muted">В данный момент открытых вакансий нет</h3>
|
||||||
|
<p class="text-muted mb-4">Но мы всегда рады талантливым кандидатам! Отправьте нам своё резюме.</p>
|
||||||
|
<a href="mailto:hr@smartsoltech.kr" class="btn btn-primary btn-lg">
|
||||||
|
<i class="fas fa-envelope me-2"></i>
|
||||||
|
Связаться с HR
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Join Team CTA -->
|
||||||
|
<section class="section-padding bg-gradient text-white">
|
||||||
|
<div class="container-modern text-center">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<h2 class="display-6 fw-bold mb-4">Почему выбирают SmartSolTech?</h2>
|
||||||
|
<div class="row g-4 mt-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="benefit-item">
|
||||||
|
<i class="fas fa-rocket mb-3"></i>
|
||||||
|
<h5>Инновации</h5>
|
||||||
|
<p class="small opacity-90">Работа с новейшими технологиями</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="benefit-item">
|
||||||
|
<i class="fas fa-users mb-3"></i>
|
||||||
|
<h5>Команда</h5>
|
||||||
|
<p class="small opacity-90">Дружный коллектив профессионалов</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="benefit-item">
|
||||||
|
<i class="fas fa-chart-line mb-3"></i>
|
||||||
|
<h5>Развитие</h5>
|
||||||
|
<p class="small opacity-90">Постоянное обучение и рост</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="benefit-item">
|
||||||
|
<i class="fas fa-balance-scale mb-3"></i>
|
||||||
|
<h5>Баланс</h5>
|
||||||
|
<p class="small opacity-90">Гибкий график и удаленка</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-5">
|
||||||
|
<a href="{% url 'team' %}" class="btn btn-light btn-lg me-3">
|
||||||
|
<i class="fas fa-users me-2"></i>
|
||||||
|
Наша команда
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'about' %}" class="btn btn-outline-light btn-lg">
|
||||||
|
<i class="fas fa-info-circle me-2"></i>
|
||||||
|
О компании
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_styles %}
|
||||||
|
<style>
|
||||||
|
/* Career Styles */
|
||||||
|
.hero-simple {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 350px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-stats {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-card-featured {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 30px;
|
||||||
|
transition: all 0.4s ease;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
height: 100%;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-card-featured:hover {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
|
||||||
|
border-color: #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-card-compact {
|
||||||
|
background: white;
|
||||||
|
border-radius: 15px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-card-compact:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
padding: 25px 25px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 20px 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer {
|
||||||
|
padding: 15px 25px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-top: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-badges {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-badges .badge {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #2d3748;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-department {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-item {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #6b7280;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item i {
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item.salary {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-description {
|
||||||
|
margin: 20px 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-requirements {
|
||||||
|
margin: 20px 0;
|
||||||
|
padding: 15px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 10px;
|
||||||
|
border-left: 3px solid #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-skills,
|
||||||
|
.skills-preview {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #475569;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag:hover {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag.more {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag.small {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
padding: 3px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-footer {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deadline-info {
|
||||||
|
padding: 10px;
|
||||||
|
background: #fef3c7;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.department-filters {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn {
|
||||||
|
background: white;
|
||||||
|
border: 2px solid #e2e8f0;
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 8px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #6b7280;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn:hover,
|
||||||
|
.filter-btn.active {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.position-badges {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.salary-info {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-item {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-item i {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-item h5 {
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.career-stats .row {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
margin: 10px 5px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-meta {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.department-filters {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 6px 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_scripts %}
|
||||||
|
<script>
|
||||||
|
// Department filter functionality
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const filterBtns = document.querySelectorAll('.filter-btn');
|
||||||
|
const careerCards = document.querySelectorAll('#careers-grid > div');
|
||||||
|
|
||||||
|
filterBtns.forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
// Update active button
|
||||||
|
filterBtns.forEach(b => b.classList.remove('active'));
|
||||||
|
this.classList.add('active');
|
||||||
|
|
||||||
|
const department = this.dataset.department;
|
||||||
|
|
||||||
|
careerCards.forEach(card => {
|
||||||
|
if (department === 'all' || card.dataset.department === department) {
|
||||||
|
card.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
card.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Share job functionality
|
||||||
|
function shareJob(title, department) {
|
||||||
|
if (navigator.share) {
|
||||||
|
navigator.share({
|
||||||
|
title: `Вакансия: ${title}`,
|
||||||
|
text: `Открыта вакансия "${title}" в отделе ${department} в SmartSolTech`,
|
||||||
|
url: window.location.href
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fallback - copy to clipboard
|
||||||
|
const text = `Вакансия: ${title} в ${department} - SmartSolTech\n${window.location.href}`;
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
alert('Ссылка скопирована в буфер обмена!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -442,6 +442,180 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Team Section -->
|
||||||
|
{% if team_members %}
|
||||||
|
<section class="section-padding bg-light">
|
||||||
|
<div class="container-modern">
|
||||||
|
<div class="row justify-content-center mb-5">
|
||||||
|
<div class="col-lg-8 text-center">
|
||||||
|
<h2 class="display-5 fw-bold text-primary mb-4">Наша команда</h2>
|
||||||
|
<p class="lead text-muted">
|
||||||
|
Профессионалы, которые воплощают ваши идеи в реальность
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
{% for member in team_members %}
|
||||||
|
<div class="col-lg-3 col-md-6">
|
||||||
|
<div class="team-card">
|
||||||
|
<div class="team-image-wrapper">
|
||||||
|
{% if member.photo %}
|
||||||
|
<img src="{{ member.photo.url }}" alt="{{ member.full_name }}" class="team-image">
|
||||||
|
{% else %}
|
||||||
|
<div class="team-placeholder">
|
||||||
|
<i class="fas fa-user"></i>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="team-overlay">
|
||||||
|
<div class="team-social">
|
||||||
|
{% if member.linkedin %}
|
||||||
|
<a href="{{ member.linkedin }}" target="_blank" class="social-link">
|
||||||
|
<i class="fab fa-linkedin"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.github %}
|
||||||
|
<a href="{{ member.github }}" target="_blank" class="social-link">
|
||||||
|
<i class="fab fa-github"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.telegram %}
|
||||||
|
<a href="https://t.me/{{ member.telegram|cut:'@' }}" target="_blank" class="social-link">
|
||||||
|
<i class="fab fa-telegram"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="team-info">
|
||||||
|
<h5 class="team-name">{{ member.full_name }}</h5>
|
||||||
|
<p class="team-position text-primary">{{ member.position }}</p>
|
||||||
|
{% if member.department %}
|
||||||
|
<p class="team-department text-muted small">{{ member.department }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.experience_years > 0 %}
|
||||||
|
<div class="team-experience">
|
||||||
|
<small class="text-muted">
|
||||||
|
<i class="fas fa-clock me-1"></i>
|
||||||
|
{{ member.experience_years }}+ лет опыта
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.skills_list %}
|
||||||
|
<div class="team-skills mt-2">
|
||||||
|
{% for skill in member.skills_list|slice:":3" %}
|
||||||
|
<span class="skill-tag">{{ skill }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
{% if member.skills_list|length > 3 %}
|
||||||
|
<span class="skill-tag more">+{{ member.skills_list|length|add:"-3" }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center mt-5">
|
||||||
|
<a href="{% url 'about' %}" class="btn btn-primary btn-lg">
|
||||||
|
<i class="fas fa-users me-2"></i>
|
||||||
|
Познакомиться с командой
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Career Section -->
|
||||||
|
{% if featured_careers %}
|
||||||
|
<section class="section-padding">
|
||||||
|
<div class="container-modern">
|
||||||
|
<div class="row justify-content-center mb-5">
|
||||||
|
<div class="col-lg-8 text-center">
|
||||||
|
<h2 class="display-5 fw-bold text-primary mb-4">Карьера в SmartSolTech</h2>
|
||||||
|
<p class="lead text-muted">
|
||||||
|
Присоединяйтесь к нашей команде и развивайтесь в мире технологий
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
{% for career in featured_careers %}
|
||||||
|
<div class="col-lg-4 col-md-6">
|
||||||
|
<div class="career-card">
|
||||||
|
<div class="career-header">
|
||||||
|
<div class="career-badge">
|
||||||
|
<span class="badge bg-success">{{ career.get_employment_type_display }}</span>
|
||||||
|
{% if career.is_featured %}
|
||||||
|
<span class="badge bg-warning text-dark">Рекомендуем</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<h4 class="career-title">{{ career.title }}</h4>
|
||||||
|
<p class="career-department text-muted">
|
||||||
|
<i class="fas fa-building me-1"></i>
|
||||||
|
{{ career.department }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="career-details">
|
||||||
|
<div class="detail-item">
|
||||||
|
<i class="fas fa-map-marker-alt text-primary"></i>
|
||||||
|
<span>{{ career.location }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<i class="fas fa-chart-line text-success"></i>
|
||||||
|
<span>{{ career.get_experience_level_display }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<i class="fas fa-won-sign text-warning"></i>
|
||||||
|
<span>{{ career.salary_range }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="career-description">
|
||||||
|
<p class="text-muted">{{ career.description|truncatewords:15 }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if career.required_skills_list %}
|
||||||
|
<div class="career-skills">
|
||||||
|
{% for skill in career.required_skills_list|slice:":4" %}
|
||||||
|
<span class="skill-tag small">{{ skill }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
{% if career.required_skills_list|length > 4 %}
|
||||||
|
<span class="skill-tag small more">+{{ career.required_skills_list|length|add:"-4" }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="career-footer">
|
||||||
|
{% if career.application_deadline %}
|
||||||
|
<small class="text-muted d-block mb-2">
|
||||||
|
<i class="fas fa-calendar-alt me-1"></i>
|
||||||
|
До {{ career.application_deadline }}
|
||||||
|
</small>
|
||||||
|
{% endif %}
|
||||||
|
<a href="mailto:{{ career.contact_email }}?subject=Заявка на вакансию: {{ career.title }}"
|
||||||
|
class="btn btn-primary w-100">
|
||||||
|
<i class="fas fa-paper-plane me-2"></i>
|
||||||
|
Откликнуться
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center mt-5">
|
||||||
|
<a href="{% url 'about' %}#career" class="btn btn-outline-primary btn-lg">
|
||||||
|
<i class="fas fa-briefcase me-2"></i>
|
||||||
|
Все вакансии
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_styles %}
|
{% block extra_styles %}
|
||||||
@@ -676,5 +850,254 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Team Section Styles */
|
||||||
|
.team-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.4s ease;
|
||||||
|
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-card:hover {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-image-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 250px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: transform 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(135deg, rgba(102, 126, 234, 0.9), rgba(118, 75, 162, 0.9));
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-card:hover .team-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-card:hover .team-image {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-social {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #667eea;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link:hover {
|
||||||
|
transform: scale(1.1) rotate(5deg);
|
||||||
|
color: #764ba2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-info {
|
||||||
|
padding: 25px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-name {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #2d3748;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-position {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-department {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-experience {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-skills {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag {
|
||||||
|
background: #f7fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4a5568;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag:hover {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag.more {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Career Section Styles */
|
||||||
|
.career-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 30px;
|
||||||
|
transition: all 0.4s ease;
|
||||||
|
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
height: 100%;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.12);
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-badge {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-badge .badge {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #2d3748;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-department {
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-details {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item i {
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-description {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-skills {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-skills .skill-tag.small {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
padding: 3px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-footer {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive for Team and Career */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.team-image-wrapper {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-info {
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-card {
|
||||||
|
padding: 25px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.career-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -31,6 +31,18 @@
|
|||||||
<i class="fas fa-info-circle me-2"></i>О нас
|
<i class="fas fa-info-circle me-2"></i>О нас
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link-modern {% if request.resolver_match.url_name == 'team' %}active{% endif %}"
|
||||||
|
href="{% url 'team' %}">
|
||||||
|
<i class="fas fa-users me-2"></i>Команда
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link-modern {% if request.resolver_match.url_name == 'career' %}active{% endif %}"
|
||||||
|
href="{% url 'career' %}">
|
||||||
|
<i class="fas fa-briefcase me-2"></i>Карьера
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link-modern" href="#contact">
|
<a class="nav-link-modern" href="#contact">
|
||||||
<i class="fas fa-envelope me-2"></i>Контакты
|
<i class="fas fa-envelope me-2"></i>Контакты
|
||||||
|
|||||||
@@ -31,6 +31,18 @@
|
|||||||
<i class="fas fa-info-circle me-2"></i>О нас
|
<i class="fas fa-info-circle me-2"></i>О нас
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link-modern {% if request.resolver_match.url_name == 'team' %}active{% endif %}"
|
||||||
|
href="{% url 'team' %}">
|
||||||
|
<i class="fas fa-users me-2"></i>Команда
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link-modern {% if request.resolver_match.url_name == 'career' %}active{% endif %}"
|
||||||
|
href="{% url 'career' %}">
|
||||||
|
<i class="fas fa-briefcase me-2"></i>Карьера
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link-modern" href="#contact">
|
<a class="nav-link-modern" href="#contact">
|
||||||
<i class="fas fa-envelope me-2"></i>Контакты
|
<i class="fas fa-envelope me-2"></i>Контакты
|
||||||
|
|||||||
316
smartsoltech/web/templates/web/team.html
Normal file
316
smartsoltech/web/templates/web/team.html
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
{% extends 'web/base_modern.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Наша команда - SmartSolTech{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<section class="hero-simple bg-gradient text-white">
|
||||||
|
<div class="container-modern text-center py-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<h1 class="display-4 fw-bold mb-4">Познакомьтесь с нашей командой</h1>
|
||||||
|
<p class="lead opacity-90">
|
||||||
|
Профессионалы, которые превращают идеи в инновационные технологические решения
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Team Grid Section -->
|
||||||
|
<section class="section-padding">
|
||||||
|
<div class="container-modern">
|
||||||
|
{% if team_members %}
|
||||||
|
<div class="row g-4">
|
||||||
|
{% for member in team_members %}
|
||||||
|
<div class="col-xl-3 col-lg-4 col-md-6">
|
||||||
|
<div class="team-card-detailed">
|
||||||
|
<div class="team-image-wrapper">
|
||||||
|
{% if member.photo %}
|
||||||
|
<img src="{{ member.photo.url }}" alt="{{ member.full_name }}" class="team-image">
|
||||||
|
{% else %}
|
||||||
|
<div class="team-placeholder">
|
||||||
|
<i class="fas fa-user"></i>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="team-overlay">
|
||||||
|
<div class="team-social">
|
||||||
|
{% if member.email %}
|
||||||
|
<a href="mailto:{{ member.email }}" class="social-link" title="Email">
|
||||||
|
<i class="fas fa-envelope"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.linkedin %}
|
||||||
|
<a href="{{ member.linkedin }}" target="_blank" class="social-link" title="LinkedIn">
|
||||||
|
<i class="fab fa-linkedin"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.github %}
|
||||||
|
<a href="{{ member.github }}" target="_blank" class="social-link" title="GitHub">
|
||||||
|
<i class="fab fa-github"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.telegram %}
|
||||||
|
<a href="https://t.me/{{ member.telegram|cut:'@' }}" target="_blank" class="social-link" title="Telegram">
|
||||||
|
<i class="fab fa-telegram"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.phone %}
|
||||||
|
<a href="tel:{{ member.phone }}" class="social-link" title="Телефон">
|
||||||
|
<i class="fas fa-phone"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="team-info-detailed">
|
||||||
|
<h4 class="team-name">{{ member.full_name }}</h4>
|
||||||
|
<p class="team-position text-primary">{{ member.position }}</p>
|
||||||
|
|
||||||
|
{% if member.department %}
|
||||||
|
<div class="team-department">
|
||||||
|
<i class="fas fa-building me-2 text-muted"></i>
|
||||||
|
<span class="text-muted">{{ member.department }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if member.experience_years > 0 %}
|
||||||
|
<div class="team-experience">
|
||||||
|
<i class="fas fa-clock me-2 text-muted"></i>
|
||||||
|
<span class="text-muted">{{ member.experience_years }}+ лет опыта</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if member.bio %}
|
||||||
|
<div class="team-bio mt-3">
|
||||||
|
<p class="text-muted small">{{ member.bio|truncatewords:20 }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if member.skills_list %}
|
||||||
|
<div class="team-skills mt-3">
|
||||||
|
<h6 class="text-muted small mb-2">Навыки:</h6>
|
||||||
|
<div class="skills-wrap">
|
||||||
|
{% for skill in member.skills_list %}
|
||||||
|
<span class="skill-tag">{{ skill }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="text-center py-5">
|
||||||
|
<div class="mb-4">
|
||||||
|
<i class="fas fa-users text-muted" style="font-size: 4rem;"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-muted">Команда пока не добавлена</h3>
|
||||||
|
<p class="text-muted">Мы работаем над обновлением информации о нашей команде.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Join Team CTA -->
|
||||||
|
<section class="section-padding bg-light">
|
||||||
|
<div class="container-modern text-center">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<h2 class="display-6 fw-bold mb-4">Хотите присоединиться к нашей команде?</h2>
|
||||||
|
<p class="lead text-muted mb-5">
|
||||||
|
Мы всегда ищем талантливых и мотивированных профессионалов
|
||||||
|
</p>
|
||||||
|
<div class="d-flex flex-wrap gap-3 justify-content-center">
|
||||||
|
<a href="{% url 'career' %}" class="btn btn-primary btn-lg">
|
||||||
|
<i class="fas fa-briefcase me-2"></i>
|
||||||
|
Открытые вакансии
|
||||||
|
</a>
|
||||||
|
<a href="mailto:hr@smartsoltech.kr" class="btn btn-outline-primary btn-lg">
|
||||||
|
<i class="fas fa-envelope me-2"></i>
|
||||||
|
Связаться с HR
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_styles %}
|
||||||
|
<style>
|
||||||
|
/* Team Detailed Styles */
|
||||||
|
.hero-simple {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 300px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-card-detailed {
|
||||||
|
background: white;
|
||||||
|
border-radius: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.4s ease;
|
||||||
|
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-card-detailed:hover {
|
||||||
|
transform: translateY(-15px);
|
||||||
|
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-image-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 280px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: transform 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(135deg, rgba(102, 126, 234, 0.9), rgba(118, 75, 162, 0.9));
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-card-detailed:hover .team-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-card-detailed:hover .team-image {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-social {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #667eea;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link:hover {
|
||||||
|
transform: scale(1.1) rotate(5deg);
|
||||||
|
color: #764ba2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-info-detailed {
|
||||||
|
padding: 30px 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-name {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #2d3748;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-position {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-department,
|
||||||
|
.team-experience {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-bio {
|
||||||
|
border-left: 3px solid #e2e8f0;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skills-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag {
|
||||||
|
background: #f7fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 5px 12px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4a5568;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-tag:hover {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
border-color: #667eea;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.team-image-wrapper {
|
||||||
|
height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-info-detailed {
|
||||||
|
padding: 25px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-social {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
@@ -15,6 +15,7 @@ urlpatterns = [
|
|||||||
path('blog/', views.blog_view, name='blog'),
|
path('blog/', views.blog_view, name='blog'),
|
||||||
path('news/', views.news_view, name='news'),
|
path('news/', views.news_view, name='news'),
|
||||||
path('career/', views.career_view, name='career'),
|
path('career/', views.career_view, name='career'),
|
||||||
|
path('team/', views.team_view, name='team'),
|
||||||
# path('create_order/<int:pk>/', views.create_order, name='create_order'),
|
# path('create_order/<int:pk>/', views.create_order, name='create_order'),
|
||||||
path('about/', views.about_view, name="about"),
|
path('about/', views.about_view, name="about"),
|
||||||
path('service/generate_qr_code/<int:service_id>/', views.generate_qr_code, name='generate_qr_code'),
|
path('service/generate_qr_code/<int:service_id>/', views.generate_qr_code, name='generate_qr_code'),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from django.shortcuts import render, get_object_or_404, redirect
|
from django.shortcuts import render, get_object_or_404, redirect
|
||||||
from .models import Service, Project, Client, BlogPost, Review, Order, ServiceRequest, HeroBanner, Category, ContactInfo
|
from .models import Service, Project, Client, BlogPost, Review, Order, ServiceRequest, HeroBanner, Category, ContactInfo, Team, Career
|
||||||
from django.db.models import Avg
|
from django.db.models import Avg
|
||||||
from comunication.models import TelegramSettings
|
from comunication.models import TelegramSettings
|
||||||
import qrcode
|
import qrcode
|
||||||
@@ -41,12 +41,18 @@ def home(request):
|
|||||||
latest_blog_posts = BlogPost.objects.all()[:2] # Последние статьи блога
|
latest_blog_posts = BlogPost.objects.all()[:2] # Последние статьи блога
|
||||||
reviews = Review.objects.all()[:3] # Отзывы клиентов
|
reviews = Review.objects.all()[:3] # Отзывы клиентов
|
||||||
|
|
||||||
|
# Данные для команды и карьеры
|
||||||
|
team_members = Team.objects.filter(is_active=True, show_on_about=True).order_by('display_order')[:4] # Показываем топ-4 участников команды
|
||||||
|
featured_careers = Career.objects.filter(status='active', is_featured=True).order_by('-created_at')[:3] # Топ-3 рекомендуемые вакансии
|
||||||
|
|
||||||
return render(request, 'web/home_modern.html', {
|
return render(request, 'web/home_modern.html', {
|
||||||
'services': services,
|
'services': services,
|
||||||
'hero_banners': hero_banners,
|
'hero_banners': hero_banners,
|
||||||
'latest_projects': latest_projects,
|
'latest_projects': latest_projects,
|
||||||
'latest_blog_posts': latest_blog_posts,
|
'latest_blog_posts': latest_blog_posts,
|
||||||
'reviews': reviews,
|
'reviews': reviews,
|
||||||
|
'team_members': team_members,
|
||||||
|
'featured_careers': featured_careers,
|
||||||
})
|
})
|
||||||
|
|
||||||
def service_detail(request, pk):
|
def service_detail(request, pk):
|
||||||
@@ -359,3 +365,30 @@ def check_request_status(request, request_id):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Ошибка при проверке статуса заявки {request_id}: {str(e)}")
|
logger.error(f"Ошибка при проверке статуса заявки {request_id}: {str(e)}")
|
||||||
return JsonResponse({'error': 'Ошибка сервера'}, status=500)
|
return JsonResponse({'error': 'Ошибка сервера'}, status=500)
|
||||||
|
|
||||||
|
|
||||||
|
def team_view(request):
|
||||||
|
"""Страница команды"""
|
||||||
|
team_members = Team.objects.filter(is_active=True).order_by('display_order', 'last_name')
|
||||||
|
return render(request, 'web/team.html', {
|
||||||
|
'team_members': team_members,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def career_view(request):
|
||||||
|
"""Страница карьеры"""
|
||||||
|
# Активные вакансии
|
||||||
|
active_careers = Career.objects.filter(status='active').order_by('-is_featured', '-created_at')
|
||||||
|
|
||||||
|
# Рекомендуемые вакансии
|
||||||
|
featured_careers = active_careers.filter(is_featured=True)
|
||||||
|
|
||||||
|
# Статистика
|
||||||
|
departments = Career.objects.filter(status='active').values_list('department', flat=True).distinct()
|
||||||
|
|
||||||
|
return render(request, 'web/career.html', {
|
||||||
|
'active_careers': active_careers,
|
||||||
|
'featured_careers': featured_careers,
|
||||||
|
'departments': departments,
|
||||||
|
'total_positions': active_careers.count(),
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user