feat: добавлена современная страница деталей услуги с портфолио и отзывами

This commit is contained in:
2025-11-24 09:05:48 +09:00
parent faa02b79c0
commit ee3a1bf846
20 changed files with 1260 additions and 53 deletions

View File

@@ -1,9 +1,11 @@
from django.shortcuts import render, get_object_or_404, redirect
from .models import Service, Project, Client, BlogPost, Review, Order, ServiceRequest
from .models import Service, Project, Client, BlogPost, Review, Order, ServiceRequest, Category
from django.db.models import Avg
from comunication.models import TelegramSettings
import qrcode
import os
import io
import base64
from django.conf import settings
import uuid
from django.utils.http import urlsafe_base64_encode
@@ -42,7 +44,7 @@ def service_detail(request, pk):
average_rating = service.reviews.aggregate(Avg('rating'))['rating__avg'] or 0
total_reviews = service.reviews.count()
reviews = service.reviews.all()
return render(request, 'web/service_detail.html', {
return render(request, 'web/service_detail_modern.html', {
'service': service,
'projects_in_category': projects_in_category,
'average_rating': average_rating,
@@ -63,8 +65,26 @@ def blog_post_detail(request, pk):
return render(request, 'web/blog_post_detail.html', {'blog_post': blog_post})
def services_view(request):
services = Service.objects.all()
return render(request, 'web/services_modern.html', {'services': services})
# Получаем выбранную категорию из GET параметра
category_id = request.GET.get('category')
# Получаем все категории для фильтров
categories = Category.objects.all()
# Фильтруем услуги по категории, если выбрана
if category_id:
services = Service.objects.filter(category_id=category_id)
selected_category = Category.objects.filter(id=category_id).first()
else:
services = Service.objects.all()
selected_category = None
context = {
'services': services,
'categories': categories,
'selected_category': selected_category,
}
return render(request, 'web/services_modern.html', context)
def about_view(request):
return render(request, 'web/about_modern.html')
@@ -191,19 +211,32 @@ def generate_qr_code(request, service_id):
)
logger.info(f"Создана новая заявка: {service_request.id} для клиента: {client.email}")
# Генерация ссылки и QR-кода для Telegram
# Получаем настройки Telegram бота из БД
telegram_settings = get_object_or_404(TelegramSettings, pk=1)
registration_link = f'https://t.me/{telegram_settings.bot_name}?start=request_{service_request.id}_token_{urlsafe_base64_encode(force_bytes(token))}'
qr = qrcode.make(registration_link)
qr_code_dir = os.path.join(settings.STATICFILES_DIRS[0], 'qr_codes')
qr_code_path = os.path.join(qr_code_dir, f"request_{service_request.id}.png")
external_qr_link = f'static/qr_codes/request_{service_request.id}.png'
if not os.path.exists(qr_code_dir):
os.makedirs(qr_code_dir)
qr.save(qr_code_path)
bot_username = telegram_settings.bot_name
# Генерация ссылки для Telegram
registration_link = f'https://t.me/{bot_username}?start=request_{service_request.id}_token_{urlsafe_base64_encode(force_bytes(token))}'
# Генерируем QR-код в памяти (без сохранения на диск)
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data(registration_link)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
# Конвертируем изображение в base64
buffer = io.BytesIO()
img.save(buffer, format='PNG')
qr_code_base64 = base64.b64encode(buffer.getvalue()).decode()
qr_code_data_url = f'data:image/png;base64,{qr_code_base64}'
logger.info(f"QR-код сгенерирован в памяти для заявки {service_request.id}")
except IntegrityError as e:
logger.error(f"Ошибка целостности данных при создании пользователя или клиента: {str(e)}")
@@ -214,7 +247,7 @@ def generate_qr_code(request, service_id):
return JsonResponse({
'registration_link': registration_link,
'qr_code_url': f"/{external_qr_link}",
'qr_code_url': qr_code_data_url,
'service_request_id': service_request.id,
'client_email': client_email,
'client_phone': client_phone,