remotes/origin/hotfix/LIL-661
gzbender 8 years ago
parent 0ad60238a9
commit 876cefab66
  1. 21
      apps/content/templates/content/contest.html
  2. 8
      apps/content/views.py
  3. 2
      project/templates/blocks/lil_store_js.html
  4. 2
      project/templates/blocks/popup_auth.html
  5. 3
      project/urls.py
  6. 183
      web/src/components/UploadContestWork.vue
  7. 0
      web/src/components/blocks/ContestWork.vue
  8. 4
      web/src/components/blocks/Image.vue
  9. 23
      web/src/js/app.js
  10. 5
      web/webpack.config.js

@ -2,19 +2,21 @@
{% block content %} {% block content %}
<div class="main main_default"> <upload-contest-work contest-id="{{ contest.id }}"></upload-contest-work>
<div class="main main_default" {% if contest.cover %}style="background-image: url({{ contest.cover.image.url }});"{% endif %}>
<div class="main__center center"> <div class="main__center center">
<div class="main__title"> <div class="main__title">
<span class="main__bold">Lil School</span> — первая образовательная онлайн-платформа креативного мышления для детей {{ contest.title }}
</div> </div>
<div class="main__subtitle"> <div class="main__subtitle">
Приглашаем вас на месяц открытых дверей в Lil School {{ contest.description }}
</div> </div>
<div class="main__actions"> <div class="main__actions">
<a class="main__btn btn btn_white" href="#">Загрузить свою работу</a> <a class="main__btn btn btn_white" href="#" data-show-upload-contest-work>Загрузить свою работу</a>
</div> </div>
</div> </div>
</div> </div>
<div style="text-align: center;">
{% for content in contest.content.all %} {% for content in contest.content.all %}
{% with template="content/blocks/"|add:content.ctype|add:".html" %} {% with template="content/blocks/"|add:content.ctype|add:".html" %}
@ -25,20 +27,21 @@
<div class="section"> <div class="section">
<div class="section__center center"> <div class="section__center center">
<a id="gallery" name="gallery"> <a id="gallery" name="gallery">
<div class="title title_center">Галерея</div> <div class="title title_center">Галлерея</div>
</a> </a>
<div class="text"> <div class="text">
<p>Тысячи шедевров уже созданы благодаря Lil School. Более 10000 работ можно
<a target="_blank" href='{{ config.SERVICE_INSTAGRAM_URL }}'>увидеть</a> в Инстаграм</p>
<img class="text__curve text__curve_three" src="{% static 'img/curve-3.svg' %}">
</div> </div>
<div class="gallery"> <div class="gallery">
<div class="gallery__grid"> <div class="gallery__grid">
{% for contest_work in contest_works %} {% for contest_work in contest_works %}
{% include '' %} {% include 'content/blocks/contest_work.html' %}
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
{% endblock content %} {% endblock content %}
{% block foot %}
{% endblock foot %}

@ -1,7 +1,7 @@
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.generic import TemplateView from django.views.generic import TemplateView, DetailView
from apps.content.models import Contest from apps.content.models import Contest
@ -22,3 +22,9 @@ class ContestEditView(TemplateView):
context = super().get_context_data() context = super().get_context_data()
context['object'] = self.object context['object'] = self.object
return context return context
class ContestView(DetailView):
model = Contest
context_object_name = 'contest'
template_name = 'content/contest.html'

@ -1,5 +1,7 @@
{% load static %}
<script> <script>
window.LIL_STORE = { window.LIL_STORE = {
staticUrl: '{% static "" %}',
accessToken: '{{ request.user.auth_token }}', accessToken: '{{ request.user.auth_token }}',
user: { user: {
id: '{{ request.user.id }}', id: '{{ request.user.id }}',

@ -3,7 +3,7 @@
<div class="popup__wrap js-popup-wrap"> <div class="popup__wrap js-popup-wrap">
<button class="popup__close js-popup-close"> <button class="popup__close js-popup-close">
<svg class="icon icon-close"> <svg class="icon icon-close">
<use xlink:href={% static "img/sprite.svg" %}#icon-close></use> <use xlink:href="{% static 'img/sprite.svg' %}#icon-close"></use>
</svg> </svg>
</button> </button>
<div class="popup__body"> <div class="popup__body">

@ -18,7 +18,7 @@ from django.contrib import admin
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.urls import path, include from django.urls import path, include
from apps.content.views import ContestEditView from apps.content.views import ContestEditView, ContestView
from apps.course.views import ( from apps.course.views import (
CoursesView, likes, coursecomment, CoursesView, likes, coursecomment,
CourseView, LessonView, SearchView, CourseView, LessonView, SearchView,
@ -85,6 +85,7 @@ urlpatterns = [
path('test', TemplateView.as_view(template_name='templates/lilcity/test.html'), name='test'), path('test', TemplateView.as_view(template_name='templates/lilcity/test.html'), name='test'),
path('contest/create', ContestEditView.as_view(), name='contest_create'), path('contest/create', ContestEditView.as_view(), name='contest_create'),
path('contest/<int:pk>/edit', ContestEditView.as_view(), name='contest_edit'), path('contest/<int:pk>/edit', ContestEditView.as_view(), name='contest_edit'),
path('contest/<int:pk>/', ContestView.as_view(), name='contest'),
] ]

@ -0,0 +1,183 @@
<template>
<div ref="popup" class="upload-contest-work popup">
<div class="popup__wrap popup__wrap_md">
<button class="popup__close" @click.prevent="hide">
<svg class="icon icon-close">
<use v-bind="{'xlink:href': $root.store.staticUrl + 'img/sprite.svg' + '#icon-close' }"></use>
</svg>
</button>
<div class="popup__body">
<form class="form">
<div class="title">
Чтобы принять участие<br>в конкурсе, заполните поля<br>и прикрепите изображение
</div>
<div class="field"
v-bind:class="{ error: $v.contestWork.child_full_name.$dirty && $v.contestWork.child_full_name.$invalid }">
<div class="field__label">ИМЯ И ФАМИЛИЯ РЕБЕНКА</div>
<div class="field__wrap">
<input class="field__input" type="text" v-model="contestWork.child_full_name">
</div>
<div class="field__error"></div>
</div>
<div class="field"
v-bind:class="{ error: $v.contestWork.age.$dirty && $v.contestWork.age.$invalid }">
<div class="field__label">ВОЗРАСТ</div>
<div class="field__wrap">
<input class="field__input" type="number" v-model="contestWork.age" style="width: 100px;">
</div>
<div class="field__error"></div>
</div>
<div class="field">
<lil-image :image-id.sync="contestWork.imageId" :image-url.sync="contestWork.imageUrl"
v-on:update:imageId="onUpdateImageId" :access-token="$root.store.accessToken" />
</div>
<div class="field" style="text-align: center;">
<button class="btn btn_light" tabindex="3" @click="save">Отправить на конкурс</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import {api} from "../js/modules/api";
import LilImage from './blocks/Image';
import {showNotification} from "../js/modules/notification";
import {required, minValue, numeric, url } from 'vuelidate/lib/validators';
import $ from 'jquery';
export default {
name: 'upload-contest-work',
props: ['contestId'],
data() {
return {
fields: {
image: "Изображение",
child_full_name: "Имя и фамилия ребенка",
age: 'Возраст',
},
contestWork: {
contest: this.contestId,
image: null,
imageId: null,
imageUrl: '',
child_full_name: '',
age: '',
}
}
},
validations() {
return {
contestWork: {
image: {
required
},
child_full_name: {
required
},
age: {
required, numeric
},
},
};
},
mounted() {
$('[data-show-upload-contest-work]').click(() => {
this.clear();
this.show();
});
},
methods: {
clear() {
Object.assign(this.$data, this.$options.data.apply(this))
},
onUpdateImageId(imageId) {
this.contestWork.image = imageId;
},
show() {
const $popup = $(this.$refs.popup)
$('body').addClass('no-scroll');
$popup.addClass('visible');
setTimeout(() => {
$popup.addClass('open');
}, 300);
},
hide() {
const $popup = $(this.$refs.popup)
$('body').removeClass('no-scroll');
$popup.removeClass('visible');
setTimeout(() => {
$popup.removeClass('open');
}, 300);
},
validate() {
if (this.$v.contestWork.$invalid) {
for(let i in this.$v.contestWork) {
if(this.$v.contestWork[i].$invalid) {
showNotification("error", "Ошибка валидации поля " + this.fields[i]);
}
}
return false;
}
return true;
},
save() {
if(! this.validate()) {
return;
}
let data = this.contestWork;
data.contest = this.contestId;
data.user = this.$root.store.user.id;
const request = api.post(`/api/v1/contest_works/`, data, {
headers: {
'Authorization': `Token ${this.$root.store.accessToken}`,
}
});
request.then((response) => {
if(response.data.id){
this.$emit('add:contestWork', response.data);
this.hide();
}
});
}
},
components: {
'lil-image': LilImage,
}
}
</script>
<style lang="scss">
.upload-contest-work {
.popup__wrap {
padding: 35px 35px 0;
}
.title {
text-align: center; font-size: 24px;
}
.kit__photo {
height: 400px;
}
.kit__photo.has-image {
border: none;
}
.kit__photo-image {
max-height: 400px;
height: auto;
width: auto;
}
.kit__file {
bottom: 0;
}
}
</style>

@ -1,5 +1,5 @@
<template> <template>
<div class="kit__photo"> <div class="kit__photo" :class="{ 'has-image': !! imageUrl }">
<svg class="icon icon-add-plus" v-if="!imageUrl"> <svg class="icon icon-add-plus" v-if="!imageUrl">
<use xlink:href="/static/img/sprite.svg#icon-add-plus"></use> <use xlink:href="/static/img/sprite.svg#icon-add-plus"></use>
</svg> </svg>
@ -51,4 +51,4 @@
display: block; display: block;
object-fit: contain; object-fit: contain;
} }
</style> </style>

@ -17,3 +17,26 @@ import "./modules/notification";
import "./modules/mixpanel"; import "./modules/mixpanel";
import "../sass/app.sass"; import "../sass/app.sass";
import Vue from 'vue';
import Vuelidate from 'vuelidate';
import UploadContestWork from '../components/UploadContestWork.vue';
Vue.use(Vuelidate);
if (process.env.NODE_ENV === 'development') {
// Enable vue-devtools
Vue.config.devtools = true;
}
const app = new Vue({
el: '#lilcity-vue-app',
data() {
return {
store: window.LIL_STORE,
}
},
components: {
'upload-contest-work': UploadContestWork,
}
});

@ -9,6 +9,7 @@ module.exports = {
entry: { entry: {
app: "./src/js/app.js", app: "./src/js/app.js",
courseRedactor: "./src/js/course-redactor.js", courseRedactor: "./src/js/course-redactor.js",
contestRedactor: "./src/js/contest-redactor.js",
mixpanel: "./src/js/third_party/mixpanel-2-latest.js", mixpanel: "./src/js/third_party/mixpanel-2-latest.js",
sprite: glob('./src/icons/*.svg'), sprite: glob('./src/icons/*.svg'),
images: glob('./src/img/*'), images: glob('./src/img/*'),
@ -116,6 +117,10 @@ module.exports = {
}, },
watch: NODE_ENV === 'development', watch: NODE_ENV === 'development',
watchOptions: {
ignored: 'node_modules',
poll: 2000,
},
devtool: NODE_ENV === 'development' ? 'source-map' : false devtool: NODE_ENV === 'development' ? 'source-map' : false
}; };

Loading…
Cancel
Save