страница с ценами

remotes/origin/feature/packages-page-1-08-19
gzbender 7 years ago
parent e2c46af6a2
commit 8518d915df
  1. 9
      api/v1/serializers/content.py
  2. 3
      api/v1/urls.py
  3. 9
      api/v1/views.py
  4. 7
      apps/content/admin.py
  5. 38
      apps/content/migrations/0029_auto_20190730_2032.py
  6. 21
      apps/content/models.py
  7. 44
      project/templates/lilcity/packages.html
  8. 3
      project/urls.py
  9. 12
      project/views.py
  10. 54
      web/src/sass/_common.sass

@ -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__'

@ -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')

@ -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,)

@ -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

@ -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),
),
]

@ -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: '<p>%s</p>' % x, self.options.split('\n')))

@ -0,0 +1,44 @@
{% extends "templates/lilcity/index.html" %}
{% load static %}
{% load ruplural from plural %}
{% block content %}
<div class="section">
<div class="section__center center">
<div class="packages">
{% for package in packages %}
<div class="package">
<div class="package__title subtitle">
{% if package.duration == 12 %}
<b>1</b>&nbsp;год
{% else %}
<b>{{ package.duration }}</b>&nbsp;{{ package.duration|ruplural:"месяц,месяца,месяцев" }}
{% endif %}
</div>
<div class="package__desc">{{ package.description }}</div>
<div class="package__price">
{{ package.price|floatformat }}р
{% if package.high_price %}
<div class="package__high-price">&nbsp;{{ package.high_price|floatformat }}р&nbsp;</div>
{% endif %}
</div>
<div class="package__options">
<b>Включает</b>
<div>{{ package.options_html|safe }}</div>
</div>
<div>
<a href="#" class="package__btn btn {% if forloop.counter == 2 %}btn_light{% endif %}"
{% if forloop.counter == 1 %}
style="background-image: linear-gradient(104deg, #f8f8f8, #fff2f2)"
{% endif %}
{% if forloop.counter == 4 %}
style="background-image: linear-gradient(to bottom, #ffe790, #f9d055 45%, #f9c155); padding: 12px 9px;"
{% endif %}
>{% if forloop.counter == 4 %}Вступить в Lil-Клуб{% else %}Купить{% endif %}</a>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}

@ -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/<str:slug>/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'),
]

@ -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

@ -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

Loading…
Cancel
Save