From 8518d915df9e849e7fd01846a543e81360ba9a1c Mon Sep 17 00:00:00 2001 From: gzbender Date: Thu, 1 Aug 2019 18:08:40 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86?= =?UTF-8?q?=D0=B0=20=D1=81=20=D1=86=D0=B5=D0=BD=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/serializers/content.py | 9 +++- api/v1/urls.py | 3 +- api/v1/views.py | 9 +++- apps/content/admin.py | 7 ++- .../migrations/0029_auto_20190730_2032.py | 38 +++++++++++++ apps/content/models.py | 21 ++++++++ project/templates/lilcity/packages.html | 44 +++++++++++++++ project/urls.py | 3 +- project/views.py | 12 ++++- web/src/sass/_common.sass | 54 +++++++++++++++++++ 10 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 apps/content/migrations/0029_auto_20190730_2032.py create mode 100644 project/templates/lilcity/packages.html diff --git a/api/v1/serializers/content.py b/api/v1/serializers/content.py index b2d47d15..d84e357b 100644 --- a/api/v1/serializers/content.py +++ b/api/v1/serializers/content.py @@ -4,7 +4,7 @@ from django.conf import settings from apps.content.models import ( Banner, Content, Image, Text, ImageText, Video, - Gallery, GalleryImage, ImageObject, FAQ) + Gallery, GalleryImage, ImageObject, FAQ, Package) from . import Base64ImageField @@ -268,3 +268,10 @@ class FAQSerializer(serializers.ModelSerializer): class Meta: model = FAQ fields = '__all__' + + +class PackageSerializer(serializers.ModelSerializer): + + class Meta: + model = Package + fields = '__all__' diff --git a/api/v1/urls.py b/api/v1/urls.py index 08434dfc..f5158356 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -19,7 +19,7 @@ from .views import ( SchoolScheduleViewSet, LiveLessonViewSet, PaymentViewSet, ObjectCommentsViewSet, ContestViewSet, ContestWorkViewSet, NotifiedAboutBonuses, - AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet, BonusesViewSet) + AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet, BonusesViewSet, PackageViewSet) router = DefaultRouter() router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests') @@ -48,6 +48,7 @@ router.register(r'users', UserViewSet, base_name='users') router.register(r'user-gallery', UserGalleryViewSet, base_name='user-gallery') router.register(r'contests', ContestViewSet, base_name='contests') router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works') +router.register(r'packages', PackageViewSet, base_name='packages') # router.register(r'configs', ConfigViewSet, base_name='configs') diff --git a/api/v1/views.py b/api/v1/views.py index 4bde8660..ecebf9a0 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -30,7 +30,7 @@ from .serializers.content import ( VideoSerializer, VideoCreateSerializer, GallerySerializer, GalleryImageSerializer, GalleryImageCreateSerializer, - ImageObjectSerializer, FAQSerializer, + ImageObjectSerializer, FAQSerializer, PackageSerializer, ) from .serializers.school import ( SchoolScheduleSerializer, @@ -65,7 +65,7 @@ from apps.config.models import Config from apps.content.models import ( Banner, Image, Text, ImageText, Video, Gallery, GalleryImage, ImageObject, - Contest, ContestWork, FAQ) + Contest, ContestWork, FAQ, Package) from apps.payment.models import ( AuthorBalance, Payment, CoursePayment, SchoolPayment, UserBonus, @@ -774,3 +774,8 @@ class NotifiedAboutBonuses(views.APIView): b.save() return Response({'status': 'ok'}) + +class PackageViewSet(ExtendedModelViewSet): + queryset = Package.objects.all() + serializer_class = PackageSerializer + permission_classes = (IsAdmin,) diff --git a/apps/content/admin.py b/apps/content/admin.py index a407d671..07d86380 100644 --- a/apps/content/admin.py +++ b/apps/content/admin.py @@ -8,7 +8,7 @@ from polymorphic.admin import ( from apps.content.models import ( Banner, Content, Image, Text, ImageText, Video, Gallery, GalleryImage, ImageObject, - Contest, ContestWork, FAQ, + Contest, ContestWork, FAQ, Package, ) @@ -99,3 +99,8 @@ class ContestWorkAdmin(admin.ModelAdmin): @admin.register(FAQ) class FAQAdmin(admin.ModelAdmin): base_model = FAQ + + +@admin.register(Package) +class PackageAdmin(admin.ModelAdmin): + base_model = Package diff --git a/apps/content/migrations/0029_auto_20190730_2032.py b/apps/content/migrations/0029_auto_20190730_2032.py new file mode 100644 index 00000000..645e97e2 --- /dev/null +++ b/apps/content/migrations/0029_auto_20190730_2032.py @@ -0,0 +1,38 @@ +# Generated by Django 2.0.7 on 2019-07-30 20:32 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0028_auto_20190726_0106'), + ] + + operations = [ + migrations.CreateModel( + name='Package', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('price', models.DecimalField(decimal_places=2, max_digits=10)), + ('high_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)), + ('description', models.TextField(db_index=True, default='', verbose_name='Описание')), + ('duration', models.PositiveSmallIntegerField()), + ('options', models.TextField(db_index=True, default='', verbose_name='Описание')), + ], + options={ + 'ordering': ('duration',), + }, + ), + migrations.AlterField( + model_name='banner', + name='main_banner', + field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(choices=[(1, 'Главная'), (2, 'Курсы'), (3, 'Школа'), (4, 'Пакеты')]), blank=True, default=[], size=None), + ), + migrations.AlterField( + model_name='banner', + name='pages', + field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(choices=[(1, 'Главная'), (2, 'Курсы'), (3, 'Школа'), (4, 'Пакеты')]), blank=True, default=[], size=None), + ), + ] diff --git a/apps/content/models.py b/apps/content/models.py index 101ffe7e..045bcafa 100644 --- a/apps/content/models.py +++ b/apps/content/models.py @@ -146,11 +146,13 @@ class Banner(models.Model): PAGE_INDEX = 1 PAGE_COURSES = 2 PAGE_SCHOOL = 3 + PAGE_PACKAGES = 4 PAGE_CHOICES = ( (PAGE_INDEX, 'Главная'), (PAGE_COURSES, 'Курсы'), (PAGE_SCHOOL, 'Школа'), + (PAGE_PACKAGES, 'Пакеты') ) text = models.TextField(blank=True, default='') @@ -241,3 +243,22 @@ class ContestWork(models.Model): class FAQ(models.Model): question = models.TextField(max_length=1000,) answer = models.TextField(max_length=1000,) + + +class Package(models.Model): + price = models.DecimalField(max_digits=10, decimal_places=2,) + high_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) + description = models.TextField( + 'Описание', default='', db_index=True + ) + duration = models.PositiveSmallIntegerField() + options = models.TextField( + 'Опции', default='', db_index=True + ) + + class Meta: + ordering = ('duration',) + + @property + def options_html(self): + return ''.join(map(lambda x: '

%s

' % x, self.options.split('\n'))) diff --git a/project/templates/lilcity/packages.html b/project/templates/lilcity/packages.html new file mode 100644 index 00000000..35f85ed8 --- /dev/null +++ b/project/templates/lilcity/packages.html @@ -0,0 +1,44 @@ +{% extends "templates/lilcity/index.html" %} +{% load static %} +{% load ruplural from plural %} + +{% block content %} +
+
+
+ {% for package in packages %} +
+
+ {% if package.duration == 12 %} + 1 год + {% else %} + {{ package.duration }} {{ package.duration|ruplural:"месяц,месяца,месяцев" }} + {% endif %} +
+
{{ package.description }}
+
+ {{ package.price|floatformat }}р + {% if package.high_price %} +
 {{ package.high_price|floatformat }}р 
+ {% endif %} +
+
+ Включает +
{{ package.options_html|safe }}
+
+ +
+ {% endfor %} +
+
+
+{% endblock content %} diff --git a/project/urls.py b/project/urls.py index 9d5266c8..a5fab3da 100644 --- a/project/urls.py +++ b/project/urls.py @@ -37,7 +37,7 @@ from apps.payment.views import ( SchoolBuyView, GiftCertificatesView, GiftCertificateBuyView, GiftCertificateBuySuccessView, GiftCertificateGetView, DrawingCampBuyView) -from .views import AboutView, IndexView, SchoolSchedulesView, LinksView +from .views import AboutView, IndexView, SchoolSchedulesView, LinksView, PackagesView # TODO trim slash in the end urlpatterns = [ @@ -103,6 +103,7 @@ urlpatterns = [ path('gift-certificate//get', GiftCertificateGetView.as_view(), name='gift-certificate-get'), path('faq', FAQView.as_view(), name='faq'), path('links', LinksView.as_view(), name='links'), + path('packages', PackagesView.as_view(), name='packages'), ] diff --git a/project/views.py b/project/views.py index 4eac0b91..9273d2c2 100644 --- a/project/views.py +++ b/project/views.py @@ -11,7 +11,7 @@ from paymentwall.pingback import Pingback from apps.course.models import Course from apps.school.models import SchoolSchedule from apps.payment.models import SchoolPayment, UserGiftCertificate, Payment, DrawingCampPayment -from apps.content.models import Banner +from apps.content.models import Banner, Package User = get_user_model() @@ -142,3 +142,13 @@ class SchoolSchedulesView(TemplateView): class LinksView(TemplateView): template_name = 'templates/lilcity/links.html' + + +class PackagesView(TemplateView): + template_name = 'templates/lilcity/packages.html' + + def get_context_data(self): + context = super().get_context_data() + context['packages'] = Package.objects.all()[:4] + context['banners'] = Banner.get_for_page(Banner.PAGE_PACKAGES)[:1] + return context diff --git a/web/src/sass/_common.sass b/web/src/sass/_common.sass index da710681..fe39fcba 100755 --- a/web/src/sass/_common.sass +++ b/web/src/sass/_common.sass @@ -4837,3 +4837,57 @@ a padding-top: 80px min-height: 200px padding-bottom: 60px + +.packages + display: flex + overflow-x: auto + background: white + padding: 30px + margin: -50px + +.package + border-radius: 10px + box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.1) + margin-right: 20px + padding: 20px + width: calc(25% - 20px) + display: flex + flex-direction: column + text-align: center + + &__btn + width: 100% + + &__title + font-size: 14px + text-align: center + margin-top: 20px + font-family: 'ProximaNova-Regular', sans-serif + + &__desc + font-size: 13px + height: 35px + + &__price + font-size: 40px + margin: 20px 0 40px + + &__high-price + text-decoration: line-through + font-size: 15px + color: #9b9b9b + height: 15px + margin-bottom: -15px + + &__options + padding: 30px 0 + border-image-source: linear-gradient(to right, #ffe2eb, #d8f5f5) + border-image-slice: 1 + border-top: 1px solid + text-align: left + font-size: 12px + line-height: 18px + flex: 1 + + & p + margin-top: 6px