feat: добавлены модели AboutPage и FooterSettings с админ-панелью и интеграцией скриптов

This commit is contained in:
2025-11-24 09:18:22 +09:00
parent ee3a1bf846
commit 3cea013a8e
9 changed files with 558 additions and 17 deletions

View File

@@ -72,6 +72,7 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'web.context_processors.footer_settings', # Custom context processor
], ],
}, },
}, },

View File

@@ -1,5 +1,8 @@
from django.contrib import admin from django.contrib import admin
from .models import Service, Project, Client, Order, Review, BlogPost, Category, ServiceRequest from .models import (
Service, Project, Client, Order, Review, BlogPost,
Category, ServiceRequest, AboutPage, FooterSettings
)
from .forms import ProjectForm from .forms import ProjectForm
@admin.register(Service) @admin.register(Service)
@@ -45,4 +48,105 @@ 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(AboutPage)
class AboutPageAdmin(admin.ModelAdmin):
list_display = ('hero_title', 'is_active', 'updated_at')
list_filter = ('is_active', 'updated_at')
search_fields = ('hero_title', 'mission_title', 'vision_title')
fieldsets = (
('Hero секция', {
'fields': ('hero_badge', 'hero_title', 'hero_description')
}),
('Статистика', {
'fields': ('stat_projects', 'stat_clients', 'stat_years', 'stat_support')
}),
('Миссия', {
'fields': (
'mission_badge', 'mission_title', 'mission_description',
'mission_point_1_title', 'mission_point_1_text',
'mission_point_2_title', 'mission_point_2_text',
'mission_point_3_title', 'mission_point_3_text',
)
}),
('Видение', {
'fields': ('vision_badge', 'vision_title', 'vision_description')
}),
('Навыки', {
'fields': (
'skill_1_name', 'skill_1_percent',
'skill_2_name', 'skill_2_percent',
'skill_3_name', 'skill_3_percent',
'skill_4_name', 'skill_4_percent',
)
}),
('Команда', {
'fields': ('team_badge', 'team_title', 'team_description')
}),
('Ценности', {
'fields': (
'values_badge', 'values_title',
'value_1_icon', 'value_1_title', 'value_1_text',
'value_2_icon', 'value_2_title', 'value_2_text',
'value_3_icon', 'value_3_title', 'value_3_text',
'value_4_icon', 'value_4_title', 'value_4_text',
)
}),
('Контакты', {
'fields': ('contact_title', 'contact_description')
}),
('Настройки', {
'fields': ('is_active',)
}),
)
def has_add_permission(self, request):
return not AboutPage.objects.filter(is_active=True).exists()
@admin.register(FooterSettings)
class FooterSettingsAdmin(admin.ModelAdmin):
list_display = ('company_name', 'email', 'is_active', 'updated_at')
list_filter = ('is_active', 'updated_at')
search_fields = ('company_name', 'email')
fieldsets = (
('Информация о компании', {
'fields': ('company_name', 'company_description', 'company_logo_icon')
}),
('Социальные сети', {
'fields': ('telegram_url', 'instagram_url', 'linkedin_url', 'github_url', 'facebook_url', 'twitter_url'),
'classes': ('collapse',)
}),
('Контактная информация', {
'fields': ('email', 'phone', 'address')
}),
('Меню футера', {
'fields': (
'show_services_menu', 'services_title',
'show_company_menu', 'company_menu_title'
),
'classes': ('collapse',)
}),
('Copyright', {
'fields': ('copyright_text',)
}),
('Интеграция скриптов', {
'fields': ('google_analytics', 'google_adsense', 'yandex_metrika', 'facebook_pixel'),
'description': 'Вставьте коды аналитики без тегов <script></script>',
'classes': ('collapse',)
}),
('Дополнительные скрипты', {
'fields': ('custom_head_scripts', 'custom_body_scripts'),
'description': 'Вставьте дополнительные скрипты С тегами <script></script>',
'classes': ('collapse',)
}),
('Настройки', {
'fields': ('is_active',)
}),
)
def has_add_permission(self, request):
return not FooterSettings.objects.filter(is_active=True).exists()

View File

@@ -0,0 +1,13 @@
from .models import FooterSettings
def footer_settings(request):
"""Context processor для настроек футера"""
try:
footer = FooterSettings.objects.filter(is_active=True).first()
except:
footer = None
return {
'footer_settings': footer
}

View File

@@ -0,0 +1,112 @@
from django.core.management.base import BaseCommand
from web.models import AboutPage, FooterSettings
class Command(BaseCommand):
help = 'Создает начальные данные для страницы О нас и Footer'
def handle(self, *args, **options):
# Создать About Page
if not AboutPage.objects.exists():
AboutPage.objects.create(
hero_badge='🚀 О нас',
hero_title='Мы создаем <span class="text-gradient">цифровое будущее</span>',
hero_description='SmartSolTech - это команда профессионалов, которые превращают идеи в инновационные IT-решения. Мы помогаем бизнесу расти и развиваться в цифровую эпоху.',
stat_projects=50,
stat_clients=30,
stat_years=3,
stat_support='24/7',
mission_badge='🎯 Наша миссия',
mission_title='Делаем технологии <span class="text-gradient">доступными</span>',
mission_description='Мы верим, что каждый бизнес заслуживает доступа к современным технологиям. Наша миссия — демократизировать IT-решения и помочь компаниям любого размера достичь цифрового совершенства.',
mission_point_1_title='Инновационные решения',
mission_point_1_text='Используем передовые технологии для создания уникальных продуктов',
mission_point_2_title='Клиентоориентированность',
mission_point_2_text='Фокусируемся на потребностях и целях каждого клиента',
mission_point_3_title='Непрерывное развитие',
mission_point_3_text='Постоянно совершенствуем наши навыки и знания',
vision_badge='🔮 Наше видение',
vision_title='Будущее начинается <span class="text-gradient">сегодня</span>',
vision_description='Мы стремимся стать ведущей IT-компанией в Корее, известной своими инновационными решениями, высоким качеством сервиса и способностью трансформировать бизнес-идеи в успешные цифровые продукты.',
skill_1_name='Веб-разработка',
skill_1_percent=95,
skill_2_name='Мобильная разработка',
skill_2_percent=90,
skill_3_name='UI/UX Дизайн',
skill_3_percent=85,
skill_4_name='DevOps',
skill_4_percent=80,
team_badge='👥 Команда',
team_title='Познакомьтесь с <span class="text-gradient">нашей командой</span>',
team_description='Талантливые профессионалы, которые воплощают ваши идеи в реальность',
values_badge='💎 Наши ценности',
values_title='Что нами <span class="text-gradient">движет</span>',
value_1_icon='fa-lightbulb',
value_1_title='Инновации',
value_1_text='Мы постоянно ищем новые решения и подходы',
value_2_icon='fa-handshake',
value_2_title='Партнерство',
value_2_text='Строим долгосрочные отношения с клиентами',
value_3_icon='fa-chart-line',
value_3_title='Результат',
value_3_text='Фокусируемся на достижении целей клиента',
value_4_icon='fa-shield-alt',
value_4_title='Надежность',
value_4_text='Гарантируем качество и безопасность',
contact_title='Готовы начать проект?',
contact_description='Свяжитесь с нами сегодня, и мы поможем воплотить ваши идеи в жизнь',
is_active=True
)
self.stdout.write(self.style.SUCCESS('✅ AboutPage создана'))
else:
self.stdout.write(self.style.WARNING('⚠️ AboutPage уже существует'))
# Создать Footer Settings
if not FooterSettings.objects.exists():
FooterSettings.objects.create(
company_name='SmartSolTech',
company_description='Мы создаем инновационные IT-решения, которые помогают бизнесу расти и развиваться в цифровую эпоху.',
company_logo_icon='fa-code',
telegram_url='https://t.me/smartsoltech',
instagram_url='https://instagram.com/smartsoltech',
linkedin_url='https://linkedin.com/company/smartsoltech',
github_url='https://github.com/smartsoltech',
email='info@smartsoltech.kr',
phone='+82-10-XXXX-XXXX',
address='Seoul, South Korea',
show_services_menu=True,
services_title='Услуги',
show_company_menu=True,
company_menu_title='Компания',
copyright_text='© 2025 SmartSolTech. Все права защищены.',
is_active=True
)
self.stdout.write(self.style.SUCCESS('✅ FooterSettings созданы'))
else:
self.stdout.write(self.style.WARNING('⚠️ FooterSettings уже существуют'))
self.stdout.write(self.style.SUCCESS('\n✨ Готово! Данные созданы успешно'))

View File

@@ -0,0 +1,106 @@
# Generated by Django 5.1.1 on 2025-11-24 00:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0009_alter_servicerequest_options_and_more'),
]
operations = [
migrations.CreateModel(
name='AboutPage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hero_badge', models.CharField(default='🚀 О нас', max_length=100, verbose_name='Hero Badge')),
('hero_title', models.CharField(default='Мы создаем цифровое будущее', max_length=200, verbose_name='Заголовок Hero')),
('hero_description', models.TextField(default='SmartSolTech - это команда профессионалов...', verbose_name='Описание Hero')),
('stat_projects', models.IntegerField(default=50, verbose_name='Количество проектов')),
('stat_clients', models.IntegerField(default=30, verbose_name='Количество клиентов')),
('stat_years', models.IntegerField(default=3, verbose_name='Лет опыта')),
('stat_support', models.CharField(default='24/7', max_length=50, verbose_name='Поддержка')),
('mission_badge', models.CharField(default='🎯 Наша миссия', max_length=100, verbose_name='Mission Badge')),
('mission_title', models.CharField(default='Делаем технологии доступными', max_length=200, verbose_name='Заголовок миссии')),
('mission_description', models.TextField(verbose_name='Описание миссии')),
('mission_point_1_title', models.CharField(default='Инновационные решения', max_length=200, verbose_name='Пункт миссии 1')),
('mission_point_1_text', models.TextField(default='Используем передовые технологии...', verbose_name='Текст пункта 1')),
('mission_point_2_title', models.CharField(default='Клиентоориентированность', max_length=200, verbose_name='Пункт миссии 2')),
('mission_point_2_text', models.TextField(default='Фокусируемся на потребностях...', verbose_name='Текст пункта 2')),
('mission_point_3_title', models.CharField(default='Непрерывное развитие', max_length=200, verbose_name='Пункт миссии 3')),
('mission_point_3_text', models.TextField(default='Постоянно совершенствуем...', verbose_name='Текст пункта 3')),
('vision_badge', models.CharField(default='🔮 Наше видение', max_length=100, verbose_name='Vision Badge')),
('vision_title', models.CharField(default='Будущее начинается сегодня', max_length=200, verbose_name='Заголовок видения')),
('vision_description', models.TextField(verbose_name='Описание видения')),
('skill_1_name', models.CharField(default='Веб-разработка', max_length=100, verbose_name='Навык 1')),
('skill_1_percent', models.IntegerField(default=95, verbose_name='Процент навыка 1')),
('skill_2_name', models.CharField(default='Мобильная разработка', max_length=100, verbose_name='Навык 2')),
('skill_2_percent', models.IntegerField(default=90, verbose_name='Процент навыка 2')),
('skill_3_name', models.CharField(default='UI/UX Дизайн', max_length=100, verbose_name='Навык 3')),
('skill_3_percent', models.IntegerField(default=85, verbose_name='Процент навыка 3')),
('skill_4_name', models.CharField(default='DevOps', max_length=100, verbose_name='Навык 4')),
('skill_4_percent', models.IntegerField(default=80, verbose_name='Процент навыка 4')),
('team_badge', models.CharField(default='👥 Команда', max_length=100, verbose_name='Team Badge')),
('team_title', models.CharField(default='Познакомьтесь с нашей командой', max_length=200, verbose_name='Заголовок команды')),
('team_description', models.TextField(default='Талантливые профессионалы...', verbose_name='Описание команды')),
('values_badge', models.CharField(default='💎 Наши ценности', max_length=100, verbose_name='Values Badge')),
('values_title', models.CharField(default='Что нами движет', max_length=200, verbose_name='Заголовок ценностей')),
('value_1_icon', models.CharField(default='fa-lightbulb', max_length=50, verbose_name='Иконка ценности 1')),
('value_1_title', models.CharField(default='Инновации', max_length=100, verbose_name='Ценность 1')),
('value_1_text', models.TextField(default='Мы постоянно ищем новые решения...', verbose_name='Текст ценности 1')),
('value_2_icon', models.CharField(default='fa-handshake', max_length=50, verbose_name='Иконка ценности 2')),
('value_2_title', models.CharField(default='Партнерство', max_length=100, verbose_name='Ценность 2')),
('value_2_text', models.TextField(default='Строим долгосрочные отношения...', verbose_name='Текст ценности 2')),
('value_3_icon', models.CharField(default='fa-chart-line', max_length=50, verbose_name='Иконка ценности 3')),
('value_3_title', models.CharField(default='Результат', max_length=100, verbose_name='Ценность 3')),
('value_3_text', models.TextField(default='Фокусируемся на достижении целей...', verbose_name='Текст ценности 3')),
('value_4_icon', models.CharField(default='fa-shield-alt', max_length=50, verbose_name='Иконка ценности 4')),
('value_4_title', models.CharField(default='Надежность', max_length=100, verbose_name='Ценность 4')),
('value_4_text', models.TextField(default='Гарантируем качество и безопасность...', verbose_name='Текст ценности 4')),
('contact_title', models.CharField(default='Готовы начать проект?', max_length=200, verbose_name='Заголовок контактов')),
('contact_description', models.TextField(default='Свяжитесь с нами сегодня...', verbose_name='Описание контактов')),
('is_active', models.BooleanField(default=True, verbose_name='Активна')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Обновлено')),
],
options={
'verbose_name': 'Страница О нас',
'verbose_name_plural': 'Страницы О нас',
},
),
migrations.CreateModel(
name='FooterSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('company_name', models.CharField(default='SmartSolTech', max_length=100, verbose_name='Название компании')),
('company_description', models.TextField(default='Мы создаем инновационные IT-решения, которые помогают бизнесу расти...', verbose_name='Описание компании')),
('company_logo_icon', models.CharField(default='fa-code', max_length=50, verbose_name='Иконка компании')),
('telegram_url', models.URLField(blank=True, verbose_name='Telegram URL')),
('instagram_url', models.URLField(blank=True, verbose_name='Instagram URL')),
('linkedin_url', models.URLField(blank=True, verbose_name='LinkedIn URL')),
('github_url', models.URLField(blank=True, verbose_name='GitHub URL')),
('facebook_url', models.URLField(blank=True, verbose_name='Facebook URL')),
('twitter_url', models.URLField(blank=True, verbose_name='Twitter URL')),
('email', models.EmailField(default='info@smartsoltech.kr', max_length=254, verbose_name='Email')),
('phone', models.CharField(default='+82-10-XXXX-XXXX', max_length=50, verbose_name='Телефон')),
('address', models.TextField(default='Seoul, South Korea', verbose_name='Адрес')),
('show_services_menu', models.BooleanField(default=True, verbose_name='Показывать меню услуг')),
('services_title', models.CharField(default='Услуги', max_length=100, verbose_name='Заголовок меню услуг')),
('show_company_menu', models.BooleanField(default=True, verbose_name='Показывать меню компании')),
('company_menu_title', models.CharField(default='Компания', max_length=100, verbose_name='Заголовок меню компании')),
('copyright_text', models.CharField(default='© 2025 SmartSolTech. Все права защищены.', max_length=200, verbose_name='Текст Copyright')),
('google_analytics', models.TextField(blank=True, help_text='Вставьте код Google Analytics (без тегов <script>)', verbose_name='Google Analytics')),
('google_adsense', models.TextField(blank=True, help_text='Вставьте код Google AdSense (без тегов <script>)', verbose_name='Google AdSense')),
('yandex_metrika', models.TextField(blank=True, help_text='Вставьте код Яндекс Метрики (без тегов <script>)', verbose_name='Яндекс Метрика')),
('facebook_pixel', models.TextField(blank=True, help_text='Вставьте код Facebook Pixel (без тегов <script>)', verbose_name='Facebook Pixel')),
('custom_head_scripts', models.TextField(blank=True, help_text='Дополнительные скрипты для вставки в <head> (с тегами <script>)', verbose_name='Скрипты в <head>')),
('custom_body_scripts', models.TextField(blank=True, help_text='Дополнительные скрипты для вставки перед закрывающим </body> (с тегами <script>)', verbose_name='Скрипты перед </body>')),
('is_active', models.BooleanField(default=True, verbose_name='Активно')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Обновлено')),
],
options={
'verbose_name': 'Настройки футера',
'verbose_name_plural': 'Настройки футера',
},
),
]

View File

@@ -153,3 +153,191 @@ 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 AboutPage(models.Model):
"""Модель для страницы 'О нас' - все данные управляются из админки"""
# Hero Section
hero_badge = models.CharField(max_length=100, default='🚀 О нас', verbose_name='Hero Badge')
hero_title = models.CharField(max_length=200, default='Мы создаем цифровое будущее', verbose_name='Заголовок Hero')
hero_description = models.TextField(default='SmartSolTech - это команда профессионалов...', verbose_name='Описание Hero')
# Statistics
stat_projects = models.IntegerField(default=50, verbose_name='Количество проектов')
stat_clients = models.IntegerField(default=30, verbose_name='Количество клиентов')
stat_years = models.IntegerField(default=3, verbose_name='Лет опыта')
stat_support = models.CharField(max_length=50, default='24/7', verbose_name='Поддержка')
# Mission Section
mission_badge = models.CharField(max_length=100, default='🎯 Наша миссия', verbose_name='Mission Badge')
mission_title = models.CharField(max_length=200, default='Делаем технологии доступными', verbose_name='Заголовок миссии')
mission_description = models.TextField(verbose_name='Описание миссии')
mission_point_1_title = models.CharField(max_length=200, default='Инновационные решения', verbose_name='Пункт миссии 1')
mission_point_1_text = models.TextField(default='Используем передовые технологии...', verbose_name='Текст пункта 1')
mission_point_2_title = models.CharField(max_length=200, default='Клиентоориентированность', verbose_name='Пункт миссии 2')
mission_point_2_text = models.TextField(default='Фокусируемся на потребностях...', verbose_name='Текст пункта 2')
mission_point_3_title = models.CharField(max_length=200, default='Непрерывное развитие', verbose_name='Пункт миссии 3')
mission_point_3_text = models.TextField(default='Постоянно совершенствуем...', verbose_name='Текст пункта 3')
# Vision Section
vision_badge = models.CharField(max_length=100, default='🔮 Наше видение', verbose_name='Vision Badge')
vision_title = models.CharField(max_length=200, default='Будущее начинается сегодня', verbose_name='Заголовок видения')
vision_description = models.TextField(verbose_name='Описание видения')
# Skills
skill_1_name = models.CharField(max_length=100, default='Веб-разработка', verbose_name='Навык 1')
skill_1_percent = models.IntegerField(default=95, verbose_name='Процент навыка 1')
skill_2_name = models.CharField(max_length=100, default='Мобильная разработка', verbose_name='Навык 2')
skill_2_percent = models.IntegerField(default=90, verbose_name='Процент навыка 2')
skill_3_name = models.CharField(max_length=100, default='UI/UX Дизайн', verbose_name='Навык 3')
skill_3_percent = models.IntegerField(default=85, verbose_name='Процент навыка 3')
skill_4_name = models.CharField(max_length=100, default='DevOps', verbose_name='Навык 4')
skill_4_percent = models.IntegerField(default=80, verbose_name='Процент навыка 4')
# Team Section
team_badge = models.CharField(max_length=100, default='👥 Команда', verbose_name='Team Badge')
team_title = models.CharField(max_length=200, default='Познакомьтесь с нашей командой', verbose_name='Заголовок команды')
team_description = models.TextField(default='Талантливые профессионалы...', verbose_name='Описание команды')
# Values Section
values_badge = models.CharField(max_length=100, default='💎 Наши ценности', verbose_name='Values Badge')
values_title = models.CharField(max_length=200, default='Что нами движет', verbose_name='Заголовок ценностей')
value_1_icon = models.CharField(max_length=50, default='fa-lightbulb', verbose_name='Иконка ценности 1')
value_1_title = models.CharField(max_length=100, default='Инновации', verbose_name='Ценность 1')
value_1_text = models.TextField(default='Мы постоянно ищем новые решения...', verbose_name='Текст ценности 1')
value_2_icon = models.CharField(max_length=50, default='fa-handshake', verbose_name='Иконка ценности 2')
value_2_title = models.CharField(max_length=100, default='Партнерство', verbose_name='Ценность 2')
value_2_text = models.TextField(default='Строим долгосрочные отношения...', verbose_name='Текст ценности 2')
value_3_icon = models.CharField(max_length=50, default='fa-chart-line', verbose_name='Иконка ценности 3')
value_3_title = models.CharField(max_length=100, default='Результат', verbose_name='Ценность 3')
value_3_text = models.TextField(default='Фокусируемся на достижении целей...', verbose_name='Текст ценности 3')
value_4_icon = models.CharField(max_length=50, default='fa-shield-alt', verbose_name='Иконка ценности 4')
value_4_title = models.CharField(max_length=100, default='Надежность', verbose_name='Ценность 4')
value_4_text = models.TextField(default='Гарантируем качество и безопасность...', verbose_name='Текст ценности 4')
# Contact Section
contact_title = models.CharField(max_length=200, default='Готовы начать проект?', verbose_name='Заголовок контактов')
contact_description = models.TextField(default='Свяжитесь с нами сегодня...', verbose_name='Описание контактов')
# Meta
is_active = models.BooleanField(default=True, verbose_name='Активна')
updated_at = models.DateTimeField(auto_now=True, verbose_name='Обновлено')
class Meta:
verbose_name = 'Страница О нас'
verbose_name_plural = 'Страницы О нас'
def __str__(self):
return f"О нас (обновлено: {self.updated_at.strftime('%d.%m.%Y')})"
def save(self, *args, **kwargs):
# Оставляем только одну активную запись
if self.is_active:
AboutPage.objects.exclude(pk=self.pk).update(is_active=False)
super().save(*args, **kwargs)
class FooterSettings(models.Model):
"""Настройки футера - все данные управляются из админки"""
# Company Info
company_name = models.CharField(max_length=100, default='SmartSolTech', verbose_name='Название компании')
company_description = models.TextField(
default='Мы создаем инновационные IT-решения, которые помогают бизнесу расти...',
verbose_name='Описание компании'
)
company_logo_icon = models.CharField(max_length=50, default='fa-code', verbose_name='Иконка компании')
# Social Links
telegram_url = models.URLField(blank=True, verbose_name='Telegram URL')
instagram_url = models.URLField(blank=True, verbose_name='Instagram URL')
linkedin_url = models.URLField(blank=True, verbose_name='LinkedIn URL')
github_url = models.URLField(blank=True, verbose_name='GitHub URL')
facebook_url = models.URLField(blank=True, verbose_name='Facebook URL')
twitter_url = models.URLField(blank=True, verbose_name='Twitter URL')
# Contact Info
email = models.EmailField(default='info@smartsoltech.kr', verbose_name='Email')
phone = models.CharField(max_length=50, default='+82-10-XXXX-XXXX', verbose_name='Телефон')
address = models.TextField(default='Seoul, South Korea', verbose_name='Адрес')
# Services Links (for footer menu)
show_services_menu = models.BooleanField(default=True, verbose_name='Показывать меню услуг')
services_title = models.CharField(max_length=100, default='Услуги', verbose_name='Заголовок меню услуг')
# Company Links (for footer menu)
show_company_menu = models.BooleanField(default=True, verbose_name='Показывать меню компании')
company_menu_title = models.CharField(max_length=100, default='Компания', verbose_name='Заголовок меню компании')
# Copyright
copyright_text = models.CharField(
max_length=200,
default='© 2025 SmartSolTech. Все права защищены.',
verbose_name='Текст Copyright'
)
# Integration Scripts
google_analytics = models.TextField(
blank=True,
verbose_name='Google Analytics',
help_text='Вставьте код Google Analytics (без тегов <script>)'
)
google_adsense = models.TextField(
blank=True,
verbose_name='Google AdSense',
help_text='Вставьте код Google AdSense (без тегов <script>)'
)
yandex_metrika = models.TextField(
blank=True,
verbose_name='Яндекс Метрика',
help_text='Вставьте код Яндекс Метрики (без тегов <script>)'
)
facebook_pixel = models.TextField(
blank=True,
verbose_name='Facebook Pixel',
help_text='Вставьте код Facebook Pixel (без тегов <script>)'
)
custom_head_scripts = models.TextField(
blank=True,
verbose_name='Скрипты в <head>',
help_text='Дополнительные скрипты для вставки в <head> (с тегами <script>)'
)
custom_body_scripts = models.TextField(
blank=True,
verbose_name='Скрипты перед </body>',
help_text='Дополнительные скрипты для вставки перед закрывающим </body> (с тегами <script>)'
)
# Meta
is_active = models.BooleanField(default=True, verbose_name='Активно')
updated_at = models.DateTimeField(auto_now=True, verbose_name='Обновлено')
class Meta:
verbose_name = 'Настройки футера'
verbose_name_plural = 'Настройки футера'
def __str__(self):
return f"Футер (обновлено: {self.updated_at.strftime('%d.%m.%Y')})"
def save(self, *args, **kwargs):
# Оставляем только одну активную запись
if self.is_active:
FooterSettings.objects.exclude(pk=self.pk).update(is_active=False)
super().save(*args, **kwargs)

View File

@@ -9,14 +9,13 @@
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col-lg-6"> <div class="col-lg-6">
<span class="badge bg-gradient text-white mb-3 px-3 py-2 rounded-pill"> <span class="badge bg-gradient text-white mb-3 px-3 py-2 rounded-pill">
🚀 О нас {{ about.hero_badge|default:"🚀 О нас" }}
</span> </span>
<h1 class="display-4 fw-bold mb-4"> <h1 class="display-4 fw-bold mb-4">
Мы создаем <span class="text-gradient">цифровое будущее</span> {{ about.hero_title|default:"Мы создаем цифровое будущее"|safe }}
</h1> </h1>
<p class="lead text-muted mb-4"> <p class="lead text-muted mb-4">
SmartSolTech - это команда профессионалов, которые превращают идеи в инновационные IT-решения. {{ about.hero_description|default:"SmartSolTech - это команда профессионалов..." }}
Мы помогаем бизнесу расти и развиваться в цифровую эпоху.
</p> </p>
<div class="d-flex flex-wrap gap-3"> <div class="d-flex flex-wrap gap-3">
<a href="#team" class="btn btn-primary-modern"> <a href="#team" class="btn btn-primary-modern">
@@ -40,7 +39,7 @@
<div class="stat-icon bg-primary rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;"> <div class="stat-icon bg-primary rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;">
<i class="fas fa-code text-white fa-2x"></i> <i class="fas fa-code text-white fa-2x"></i>
</div> </div>
<h3 class="text-gradient fw-bold">50+</h3> <h3 class="text-gradient fw-bold">{{ about.stat_projects|default:"50" }}+</h3>
<p class="mb-0 text-muted">Проектов</p> <p class="mb-0 text-muted">Проектов</p>
</div> </div>
</div> </div>
@@ -49,7 +48,7 @@
<div class="stat-icon bg-success rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;"> <div class="stat-icon bg-success rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;">
<i class="fas fa-users text-white fa-2x"></i> <i class="fas fa-users text-white fa-2x"></i>
</div> </div>
<h3 class="text-gradient fw-bold">30+</h3> <h3 class="text-gradient fw-bold">{{ about.stat_clients|default:"30" }}+</h3>
<p class="mb-0 text-muted">Клиентов</p> <p class="mb-0 text-muted">Клиентов</p>
</div> </div>
</div> </div>
@@ -58,7 +57,7 @@
<div class="stat-icon bg-warning rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;"> <div class="stat-icon bg-warning rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;">
<i class="fas fa-award text-white fa-2x"></i> <i class="fas fa-award text-white fa-2x"></i>
</div> </div>
<h3 class="text-gradient fw-bold">3+</h3> <h3 class="text-gradient fw-bold">{{ about.stat_years|default:"3" }}+</h3>
<p class="mb-0 text-muted">Лет опыта</p> <p class="mb-0 text-muted">Лет опыта</p>
</div> </div>
</div> </div>
@@ -67,7 +66,7 @@
<div class="stat-icon bg-info rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;"> <div class="stat-icon bg-info rounded-3 mb-3 mx-auto" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;">
<i class="fas fa-rocket text-white fa-2x"></i> <i class="fas fa-rocket text-white fa-2x"></i>
</div> </div>
<h3 class="text-gradient fw-bold">24/7</h3> <h3 class="text-gradient fw-bold">{{ about.stat_support|default:"24/7" }}</h3>
<p class="mb-0 text-muted">Поддержка</p> <p class="mb-0 text-muted">Поддержка</p>
</div> </div>
</div> </div>
@@ -87,15 +86,13 @@
<div class="col-lg-6"> <div class="col-lg-6">
<div class="pe-lg-4"> <div class="pe-lg-4">
<span class="badge bg-primary text-white mb-3 px-3 py-2 rounded-pill"> <span class="badge bg-primary text-white mb-3 px-3 py-2 rounded-pill">
🎯 Наша миссия {{ about.mission_badge|default:"🎯 Наша миссия" }}
</span> </span>
<h2 class="display-6 fw-bold mb-4"> <h2 class="display-6 fw-bold mb-4">
Делаем технологии <span class="text-gradient">доступными</span> {{ about.mission_title|default:"Делаем технологии доступными"|safe }}
</h2> </h2>
<p class="text-muted mb-4"> <p class="text-muted mb-4">
Мы верим, что каждый бизнес заслуживает доступа к современным технологиям. {{ about.mission_description|default:"Мы верим, что каждый бизнес заслуживает..." }}
Наша миссия — демократизировать IT-решения и помочь компаниям любого размера
достичь цифрового совершенства.
</p> </p>
<div class="mission-points"> <div class="mission-points">
<div class="d-flex align-items-start mb-3"> <div class="d-flex align-items-start mb-3">

View File

@@ -36,6 +36,25 @@
<!-- Force unblock script - загружается ПЕРВЫМ для предотвращения блокировки --> <!-- Force unblock script - загружается ПЕРВЫМ для предотвращения блокировки -->
<script src="{% static 'assets/js/force-unblock.js' %}"></script> <script src="{% static 'assets/js/force-unblock.js' %}"></script>
<!-- Integration Scripts from Footer Settings -->
{% if footer_settings %}
{% if footer_settings.google_analytics %}
<script>
{{ footer_settings.google_analytics|safe }}
</script>
{% endif %}
{% if footer_settings.yandex_metrika %}
<script>
{{ footer_settings.yandex_metrika|safe }}
</script>
{% endif %}
{% if footer_settings.custom_head_scripts %}
{{ footer_settings.custom_head_scripts|safe }}
{% endif %}
{% endif %}
{% block extra_head %}{% endblock %} {% block extra_head %}{% endblock %}
</head> </head>
<body> <body>

View File

@@ -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, Category from .models import Service, Project, Client, BlogPost, Review, Order, ServiceRequest, Category, AboutPage, FooterSettings
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
@@ -87,7 +87,8 @@ def services_view(request):
return render(request, 'web/services_modern.html', context) return render(request, 'web/services_modern.html', context)
def about_view(request): def about_view(request):
return render(request, 'web/about_modern.html') about_page = AboutPage.objects.filter(is_active=True).first()
return render(request, 'web/about_modern.html', {'about': about_page})
def create_service_request(request, service_id): def create_service_request(request, service_id):
if request.method == 'POST': if request.method == 'POST':