Merge branch 'dev' of gitlab.com:lilcity/backend into dev

remotes/origin/hasaccess
Ivlev Denis 8 years ago
commit 5b98faaa5d
  1. 4
      project/templates/lilcity/edit_index.html
  2. 5
      web/package-lock.json
  3. 1
      web/package.json
  4. 113
      web/src/components/CourseRedactor.vue
  5. 10
      web/src/js/course-redactor.js
  6. 7
      web/src/js/modules/api.js

@ -46,13 +46,13 @@
</button>
<a class="header__logo logo" href="/"></a>
<div class="header__actions">
<div class="header__status">СОХРАНЕНО</div>
<div id="course-redactor__saving-status" class="header__status"></div>
<button class="header__btn btn btn_icon">
<svg class="icon icon-eye">
<use xlink:href="{% static 'img/sprite.svg' %}#icon-eye"></use>
</svg>
</button>
<button class="header__btn btn">ОПУБЛИКОВАТЬ</button>
<button id="course-redactor__publish-button" class="header__btn btn">ОПУБЛИКОВАТЬ</button>
</div>
{% if request.user.is_authenticated %}
<div class="header__login">

@ -7041,6 +7041,11 @@
"lodash._bindcallback": "3.0.1"
}
},
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",

@ -58,6 +58,7 @@
"history": "^4.7.2",
"ilyabirman-likely": "^2.3.0",
"jquery": "^3.3.1",
"lodash.debounce": "^4.0.8",
"moment": "^2.20.1",
"owl.carousel": "^2.2.0",
"slugify": "^1.2.9",

@ -1,5 +1,5 @@
<template>
<div>
<div id="lilcity__course-redactor" v-on:course_publish="onCoursePublish">
<div v-if="!courseLoading">
<form v-if="viewSection !== 'lessons-edit'" @submit.prevent="onSubmit">
<div class="info">
@ -21,12 +21,15 @@
</div>
</div>
<div class="info__title">
<div class="info__field field field_info">
<div class="info__field field field_info"
v-bind:class="{ error: ($v.course.title.$dirty || showErrors) && $v.course.title.$invalid }">
<div class="field__label">НАЗВАНИЕ КУРСА</div>
<div class="field__wrap">
<textarea class="field__textarea field__textarea_lg"
rows="1"
title="Название курса"
v-autosize="course.title"
@input="$v.course.title.$touch()"
v-model="course.title"></textarea>
</div>
</div>
@ -39,16 +42,18 @@
placeholder="Выберите категорию"/>
</div>
</div>
<div class="info__field field field_info">
<div class="info__field field field_info"
v-bind:class="{ error: ($v.course.duration.$dirty || showErrors) && $v.course.duration.$invalid }">
<div class="field__label field__label_gray">ПРОДОЛЖИТЕЛЬНОСТЬ</div>
<div class="field__wrap">
<input type="text" class="field__input" v-model.number="course.duration">
<input type="text" class="field__input" v-model.number="course.duration"
@input="$v.course.duration.$touch()">
</div>
</div>
<div class="info__field field field_info">
<div class="field__label field__label_gray">СТОИМОСТЬ</div>
<div class="field__wrap">
<input type="text" class="field__input" v-model="displayPrice" :disabled="!course.is_paid">
<input type="text" class="field__input" v-model.number="displayPrice" :disabled="!course.is_paid">
</div>
</div>
</div>
@ -116,12 +121,14 @@
<div class="section__center center">
<div class="kit">
<div class="kit__section">
<div class="kit__field field">
<div class="kit__field field"
v-bind:class="{ error: ($v.course.short_description.$dirty || showErrors) && $v.course.short_description.$invalid }">
<div class="field__wrap">
<textarea type="text"
class="field__input"
<textarea class="field__input"
rows="1"
placeholder="Кратко о курсе"
v-autosize="course.short_description"
@input="$v.course.short_description.$touch()"
v-model="course.short_description"></textarea>
</div>
</div>
@ -179,11 +186,11 @@
<block-add v-on:added="onBlockAdded"/>
<div class="kit__foot">
<!--<div class="kit__foot">
<button type="submit" class="kit__submit btn btn_md" v-bind:class="{ loading: courseSaving }">
Сохранить
</button>
</div>
</div>-->
</div>
<div v-if="viewSection === 'lessons'" class="kit__body">
<div class="lessons__title title">Содержание курса</div>
@ -243,6 +250,8 @@
import LessonRedactor from "./LessonRedactor";
import {api} from "../js/modules/api";
import BlockAdd from "./blocks/BlockAdd";
import debounce from 'lodash.debounce';
import {required, minValue, numeric } from 'vuelidate/lib/validators'
export default {
name: "course-redactor",
@ -315,9 +324,31 @@
'value': '18:00',
}
],
showErrors: false,
savingTimeout: null,
categoryOptions: []
}
},
validations: {
course: {
title: {
required
},
short_description: {
required
},
duration: {
required,
numeric,
minValue: minValue(1)
},
category: {
required,
numeric,
minValue: minValue(1)
}
},
},
methods: {
onCoverImageSelected(event) {
let file = event.target.files[0];
@ -386,6 +417,7 @@
content: [],
};
this.viewSection = 'lessons-edit';
window.scrollTo(0, 0);
},
onSubmit() {
this.courseSaving = true;
@ -425,29 +457,62 @@
goToLessons() {
this.viewSection = 'lessons';
},
loadCourse(courseId) {
loadCourseDraft() {
this.courseLoading = true;
api.loadCourse(courseId, this.accessToken)
api.getCourseDraft(this.accessToken)
.then((response) => {
this.courseLoading = false;
this.course = api.convertCourseJson(response.data);
this.lessons = response.data.lessons.map((lessonJson) => {
return api.convertLessonJson(lessonJson);
});
})
.catch((err) => {
this.courseLoading = false;
console.log('error course loading', err);
});
},
loadLessons(courseId) {
api.getCourseLessons(courseId, this.accessToken)
loadCourse() {
this.courseLoading = true;
api.loadCourse(this.courseId, this.accessToken)
.then((response) => {
this.lessons = response.data.results.map((lessonJson) => {
this.courseLoading = false;
this.course = api.convertCourseJson(response.data);
this.lessons = response.data.lessons.map((lessonJson) => {
return api.convertLessonJson(lessonJson);
});
})
.catch((err) => {
this.courseLoading = false;
console.log('error course loading', err);
});
}
},
loadLessons(courseId) {
},
onCoursePublish() {
console.log('publish course');
},
saveCourseDraft: debounce(function (newValue, oldValue) {
if (!oldValue.id) {
return;
}
this.courseSaving = true;
clearTimeout(this.savingTimeout);
document.getElementById('course-redactor__saving-status').innerText = 'СОХРАНЕНИЕ';
api.saveCourse(this.course, this.accessToken)
.then((response) => {
this.courseSaving = false;
document.getElementById('course-redactor__saving-status').innerText = 'СОХРАНЕНО';
this.savingTimeout = setTimeout(() => {
document.getElementById('course-redactor__saving-status').innerText = '';
}, 2000);
// this.course = api.convertCourseJson(response.data);
})
.catch((err) => {
this.courseSaving = false;
});
}, 2000)
},
mounted() {
api.getCategories(this.accessToken)
@ -464,8 +529,9 @@
});
if (this.courseId) {
this.loadCourse(this.courseId);
this.loadLessons(this.courseId);
this.loadCourse()
} else {
this.loadCourseDraft();
}
},
computed: {
@ -500,7 +566,16 @@
courseFullUrl() {
let suffix = this.course.url ? this.course.url : 'ваша_ссылка';
return `https://lil.city/course/${suffix}`;
}
},
},
watch: {
'course': {
handler: function (newValue, oldValue) {
this.saveCourseDraft(newValue, oldValue);
},
deep: true,
},
},
components: {
BlockAdd,

@ -1,7 +1,9 @@
import Vue from 'vue'
import VueAutosize from 'vue-autosize'
import Vuelidate from 'vuelidate'
import 'babel-polyfill'
import CourseRedactor from '../components/CourseRedactor.vue'
import $ from 'jquery';
if (process.env.NODE_ENV === 'development') {
// Enable vue-devtools
@ -9,10 +11,18 @@ if (process.env.NODE_ENV === 'development') {
}
Vue.use(VueAutosize);
Vue.use(Vuelidate);
let app = new Vue({
el: '#lilcity-vue-app',
components: {
'course-redactor': CourseRedactor,
}
});
$(document).ready(function () {
$('#course-redactor__publish-button').on('click', function () {
let event = new Event('course_publish');
document.getElementById('lilcity__course-redactor').dispatchEvent(event);
});
});

@ -372,4 +372,11 @@ export const api = {
}
});
},
getCourseDraft: (accessToken) => {
return axios.get('/api/v1/courses/draft/', {
headers: {
'Authorization': `Token ${accessToken}`,
}
});
}
};
Loading…
Cancel
Save