Compare commits
2 Commits
c1616ac542
...
9839389fc9
| Author | SHA1 | Date | |
|---|---|---|---|
| 9839389fc9 | |||
| ec01a2ae10 |
@@ -1,5 +1,5 @@
|
||||
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
|
||||
|
||||
@admin.register(ContactInfo)
|
||||
@@ -87,4 +87,96 @@ class CategoryAdmin(admin.ModelAdmin):
|
||||
class ServiceRequestAdmin(admin.ModelAdmin):
|
||||
list_display = ('service','token', 'client', 'created_at')
|
||||
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):
|
||||
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>
|
||||
</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 %}
|
||||
|
||||
{% block extra_styles %}
|
||||
@@ -676,5 +850,254 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
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>
|
||||
{% endblock %}
|
||||
@@ -31,6 +31,18 @@
|
||||
<i class="fas fa-info-circle me-2"></i>О нас
|
||||
</a>
|
||||
</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">
|
||||
<a class="nav-link-modern" href="#contact">
|
||||
<i class="fas fa-envelope me-2"></i>Контакты
|
||||
|
||||
@@ -31,6 +31,18 @@
|
||||
<i class="fas fa-info-circle me-2"></i>О нас
|
||||
</a>
|
||||
</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">
|
||||
<a class="nav-link-modern" href="#contact">
|
||||
<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('news/', views.news_view, name='news'),
|
||||
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('about/', views.about_view, name="about"),
|
||||
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 .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 comunication.models import TelegramSettings
|
||||
import qrcode
|
||||
@@ -41,12 +41,18 @@ def home(request):
|
||||
latest_blog_posts = BlogPost.objects.all()[:2] # Последние статьи блога
|
||||
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', {
|
||||
'services': services,
|
||||
'hero_banners': hero_banners,
|
||||
'latest_projects': latest_projects,
|
||||
'latest_blog_posts': latest_blog_posts,
|
||||
'reviews': reviews,
|
||||
'team_members': team_members,
|
||||
'featured_careers': featured_careers,
|
||||
})
|
||||
|
||||
def service_detail(request, pk):
|
||||
@@ -359,3 +365,30 @@ def check_request_status(request, request_id):
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при проверке статуса заявки {request_id}: {str(e)}")
|
||||
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