luffy-(12)
内容概览
- 课程详情页接口
- 课程列表前端
- 课程详情前端
- 搜索导航栏
- 搜索后台接口
- 搜索前端页面
课程详情页接口
1 课程详情接口
2 课程章节接口---> 章节下有课时-查询所有章节接口,带按课程id号过滤的功能-http://127.0.0.1:8000/api/v1/course/chapter/?course=2
views.py
class CourseChapterView(GenericViewSet, CommonListModelMixin):queryset = CourseChapter.objects.all().filter(is_delete=False, is_show=True).order_by('orders')serializer_class = CourseChapterSerializerfilter_backends = [DjangoFilterBackend]filterset_fields = ['course']
serializer
class CourseSectionSerializer(serializers.ModelSerializer):class Meta:model = CourseSectionfields = '__all__'class CourseChapterSerializer(serializers.ModelSerializer):# 一个章节下,有很多课时,课时是多条,子序列化的时候,一定不要忘了many=Truecoursesections = CourseSectionSerializer(many=True)class Meta:model = CourseChapterfields = ['id', 'chapter', 'name', 'summary','coursesections'] # 在章节表中设置了 related_name='coursechapters' 所以可以通过coursesections反向查询到章节
urls.py
router.register('chapter', CourseChapterView, 'chapter')
课程列表前端
<template><div class="course"><Header></Header><div class="main"><!-- 筛选条件 --><div class="condition"><ul class="cate-list"><li class="title">课程分类:</li><li :class="filter.course_category==0?'this':''" @click="filter.course_category=0">全部</li><li :class="filter.course_category==category.id?'this':''" v-for="category in category_list"@click="filter.course_category=category.id" :key="category.name">{{ category.name }}</li></ul><div class="ordering"><ul><li class="title">筛 选:</li><li class="default" :class="(filter.ordering=='id' || filter.ordering=='-id')?'this':''"@click="filter.ordering='orders'">默认</li><li class="hot" :class="(filter.ordering=='students' || filter.ordering=='-students')?'this':''"@click="filter.ordering=(filter.ordering=='-students'?'students':'-students')">人气</li><li class="price":class="filter.ordering=='price'?'price_up this':(filter.ordering=='-price'?'price_down this':'')"@click="filter.ordering=(filter.ordering=='-price'?'price':'-price')">价格</li></ul><p class="condition-result">共{{ course_total }}个课程</p></div></div><!-- 课程列表 --><div class="course-list"><div class="course-item" v-for="course in course_list" :key="course.name"><div class="course-image"><img :src="course.course_img" alt=""></div><div class="course-info"><h3><router-link :to="'/course/detail/'+course.id">{{ course.name }}</router-link><span><img src="@/assets/img/avatar1.svg" alt="">{{ course.students }}人已加入学习</span></h3><p class="teather-info">{{ course.teacher.name }} {{ course.teacher.title }} {{ course.teacher.signature }}<spanv-if="course.sections>course.pub_sections">共{{ course.sections }}课时/已更新{{course.pub_sections}}课时</span><span v-else>共{{ course.sections }}课时/更新完成</span></p><ul class="section-list"><li v-for="(section, key) in course.section_list" :key="section.name"><spanclass="section-title">0{{ key + 1 }} | {{ section.name }}</span><span class="free" v-if="section.free_trail">免费</span></li></ul><div class="pay-box"><span class="discount-price">¥{{ course.price }}元</span><span class="buy-now">立即购买</span></div></div></div></div><div class="course_pagination block"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page.sync="filter.page":page-sizes="[2, 3, 5, 10]":page-size="filter.size"layout="sizes, prev, pager, next":total="course_total"></el-pagination></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/Header"
import Footer from "@/components/Footer"export default {name: "Course",data() {return {category_list: [], // 课程分类列表course_list: [], // 课程列表course_total: 0, // 当前课程的总数量filter: {course_category: 0, // 当前用户选择的课程分类,刚进入页面默认为全部,值为0ordering: "orders", // 数据的排序方式,默认值是orders,表示对于id进行降序排列size: 2, // 单页数据量page: 1,}}},created() {this.get_category();this.get_course();},components: {Header,Footer,},watch: {"filter.course_category": function () {this.filter.page = 1;this.get_course();},"filter.ordering": function () {this.get_course();},"filter.size": function () {this.get_course();},"filter.page": function () {this.get_course();}},methods: {handleSizeChange(val) {// 每页数据量发生变化时执行的方法this.filter.page = 1;this.filter.size = val;},handleCurrentChange(val) {// 页码发生变化时执行的方法this.filter.page = val;},get_category() {// 获取课程分类信息this.$axios.get(`${this.$settings.BASE_URL}course/category/`).then(response => {this.category_list = response.data.result;}).catch(() => {this.$message({message: "获取课程分类信息有误,请联系客服工作人员",})})},get_course() {// 排序let filters = {ordering: this.filter.ordering, // 排序};// 判决是否进行分类课程的展示if (this.filter.course_category > 0) {filters.course_category = this.filter.course_category;}// 设置单页数据量if (this.filter.size > 0) {filters.size = this.filter.size;} else {filters.size = 5;}// 设置当前页码if (this.filter.page > 1) {filters.page = this.filter.page;} else {filters.page = 1;}// 构造出查询数据//filters:{ordering:orders,page:1,size:5,course_category:0}// 获取课程列表信息this.$axios.get(`${this.$settings.BASE_URL}course/list/`, {params: filters}).then(response => {// console.log(response.data);this.course_list = response.data.result.results;this.course_total = response.data.result.count;console.log(this.course_list);}).catch(() => {this.$message({message: "获取课程信息有误,请联系客服工作人员"})})}}
}
</script><style scoped>
.course {background: #f6f6f6;
}.course .main {width: 1100px;margin: 35px auto 0;
}.course .condition {margin-bottom: 35px;padding: 25px 30px 25px 20px;background: #fff;border-radius: 4px;box-shadow: 0 2px 4px 0 #f0f0f0;
}.course .cate-list {border-bottom: 1px solid #333;border-bottom-color: rgba(51, 51, 51, .05);padding-bottom: 18px;margin-bottom: 17px;
}.course .cate-list::after {content: "";display: block;clear: both;
}.course .cate-list li {float: left;font-size: 16px;padding: 6px 15px;line-height: 16px;margin-left: 14px;position: relative;transition: all .3s ease;cursor: pointer;color: #4a4a4a;border: 1px solid transparent; /* transparent 透明 */
}.course .cate-list .title {color: #888;margin-left: 0;letter-spacing: .36px;padding: 0;line-height: 28px;
}.course .cate-list .this {color: #ffc210;border: 1px solid #ffc210 !important;border-radius: 30px;
}.course .ordering::after {content: "";display: block;clear: both;
}.course .ordering ul {float: left;
}.course .ordering ul::after {content: "";display: block;clear: both;
}.course .ordering .condition-result {float: right;font-size: 14px;color: #9b9b9b;line-height: 28px;
}.course .ordering ul li {float: left;padding: 6px 15px;line-height: 16px;margin-left: 14px;position: relative;transition: all .3s ease;cursor: pointer;color: #4a4a4a;
}.course .ordering .title {font-size: 16px;color: #888;letter-spacing: .36px;margin-left: 0;padding: 0;line-height: 28px;
}.course .ordering .this {color: #ffc210;
}.course .ordering .price {position: relative;
}.course .ordering .price::before,
.course .ordering .price::after {cursor: pointer;content: "";display: block;width: 0px;height: 0px;border: 5px solid transparent;position: absolute;right: 0;
}.course .ordering .price::before {border-bottom: 5px solid #aaa;margin-bottom: 2px;top: 2px;
}.course .ordering .price::after {border-top: 5px solid #aaa;bottom: 2px;
}.course .ordering .price_up::before {border-bottom-color: #ffc210;
}.course .ordering .price_down::after {border-top-color: #ffc210;
}.course .course-item:hover {box-shadow: 4px 6px 16px rgba(0, 0, 0, .5);
}.course .course-item {width: 1100px;background: #fff;padding: 20px 30px 20px 20px;margin-bottom: 35px;border-radius: 2px;cursor: pointer;box-shadow: 2px 3px 16px rgba(0, 0, 0, .1);/* css3.0 过渡动画 hover 事件操作 */transition: all .2s ease;
}.course .course-item::after {content: "";display: block;clear: both;
}/* 顶级元素 父级元素 当前元素{} */
.course .course-item .course-image {float: left;width: 423px;height: 210px;margin-right: 30px;
}.course .course-item .course-image img {max-width: 100%;max-height: 210px;
}.course .course-item .course-info {float: left;width: 596px;
}.course-item .course-info h3 a {font-size: 26px;color: #333;font-weight: normal;margin-bottom: 8px;
}.course-item .course-info h3 span {font-size: 14px;color: #9b9b9b;float: right;margin-top: 14px;
}.course-item .course-info h3 span img {width: 11px;height: auto;margin-right: 7px;
}.course-item .course-info .teather-info {font-size: 14px;color: #9b9b9b;margin-bottom: 14px;padding-bottom: 14px;border-bottom: 1px solid #333;border-bottom-color: rgba(51, 51, 51, .05);
}.course-item .course-info .teather-info span {float: right;
}.course-item .section-list::after {content: "";display: block;clear: both;
}.course-item .section-list li {float: left;width: 44%;font-size: 14px;color: #666;padding-left: 22px;/* background: url("路径") 是否平铺 x轴位置 y轴位置 */background: url("/src/assets/img/play-icon-gray.svg") no-repeat left 4px;margin-bottom: 15px;
}.course-item .section-list li .section-title {/* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */text-overflow: ellipsis;overflow: hidden;white-space: nowrap;display: inline-block;max-width: 200px;
}.course-item .section-list li:hover {background-image: url("/src/assets/img/play-icon-yellow.svg");color: #ffc210;
}.course-item .section-list li .free {width: 34px;height: 20px;color: #fd7b4d;vertical-align: super;margin-left: 10px;border: 1px solid #fd7b4d;border-radius: 2px;text-align: center;font-size: 13px;white-space: nowrap;
}.course-item .section-list li:hover .free {color: #ffc210;border-color: #ffc210;
}.course-item {position: relative;
}.course-item .pay-box {position: absolute;bottom: 20px;width: 600px;
}.course-item .pay-box::after {content: "";display: block;clear: both;
}.course-item .pay-box .discount-type {padding: 6px 10px;font-size: 16px;color: #fff;text-align: center;margin-right: 8px;background: #fa6240;border: 1px solid #fa6240;border-radius: 10px 0 10px 0;float: left;
}.course-item .pay-box .discount-price {font-size: 24px;color: #fa6240;float: left;
}.course-item .pay-box .original-price {text-decoration: line-through;font-size: 14px;color: #9b9b9b;margin-left: 10px;float: left;margin-top: 10px;
}.course-item .pay-box .buy-now {width: 120px;height: 38px;background: transparent;color: #fa6240;font-size: 16px;border: 1px solid #fd7b4d;border-radius: 3px;transition: all .2s ease-in-out;float: right;text-align: center;line-height: 38px;position: absolute;right: 0;bottom: 5px;
}.course-item .pay-box .buy-now:hover {color: #fff;background: #ffc210;border: 1px solid #ffc210;
}.course .course_pagination {margin-bottom: 60px;text-align: center;
}
</style>
课程详情前端
课程详情页前端
router/index.js
import CourseDetail from "@/views/CourseDetail";Vue.use(VueRouter)const routes = [{path: '/course/detail/:id',name: 'detail',component: CourseDetail},
]
CourseDetail.vue
<template><div class="detail"><Header/><div class="main"><div class="course-info"><div class="wrap-left"><videoPlayer class="video-player vjs-custom-skin"ref="videoPlayer":playsinline="true":options="playerOptions"@play="onPlayerPlay($event)"@pause="onPlayerPause($event)"></videoPlayer></div><div class="wrap-right"><h3 class="course-name">{{ course_info.name }}</h3><p class="data">{{ course_info.students }}人在学 课程总时长:{{course_info.sections}}课时/{{ course_info.pub_sections }}小时 难度:{{ course_info.level_name }}</p><div class="sale-time"><p class="sale-type">价格 <span class="original_price">¥{{ course_info.price }}</span></p><p class="expire"></p></div><div class="buy"><div class="buy-btn"><button class="buy-now">立即购买</button><button class="free">免费试学</button></div><!--<div class="add-cart" @click="add_cart(course_info.id)">--><!--<img src="@/assets/img/cart-yellow.svg" alt="">加入购物车--><!--</div>--></div></div></div><div class="course-tab"><ul class="tab-list"><li :class="tabIndex==1?'active':''" @click="tabIndex=1">详情介绍</li><li :class="tabIndex==2?'active':''" @click="tabIndex=2">课程章节 <span :class="tabIndex!=2?'free':''">(试学)</span></li><li :class="tabIndex==3?'active':''" @click="tabIndex=3">用户评论</li><li :class="tabIndex==4?'active':''" @click="tabIndex=4">常见问题</li></ul></div><div class="course-content"><div class="course-tab-list"><div class="tab-item" v-if="tabIndex==1"><div class="course-brief" v-html="course_info.brief"></div></div><div class="tab-item" v-if="tabIndex==2"><div class="tab-item-title"><p class="chapter">课程章节</p><p class="chapter-length">共{{ course_chapters.length }}章 {{ course_info.sections }}个课时</p></div><div class="chapter-item" v-for="chapter in course_chapters" :key="chapter.name"><p class="chapter-title"><img src="@/assets/img/enum.svg"alt="">第{{ chapter.chapter }}章·{{ chapter.name }}</p><ul class="section-list"><li class="section-item" v-for="section in chapter.coursesections" :key="section.name"><p class="name"><span class="index">{{ chapter.chapter }}-{{ section.orders }}</span>{{ section.name }}<span class="free" v-if="section.free_trail">免费</span></p><p class="time">{{ section.duration }} <img src="@/assets/img/chapter-player.svg"></p><button class="try" v-if="section.free_trail">立即试学</button><button class="try" v-else>立即购买</button></li></ul></div></div><div class="tab-item" v-if="tabIndex==3">用户评论</div><div class="tab-item" v-if="tabIndex==4">常见问题</div></div><div class="course-side"><div class="teacher-info"><h4 class="side-title"><span>授课老师</span></h4><div class="teacher-content"><div class="cont1"><img :src="course_info.teacher.image"><div class="name"><p class="teacher-name">{{ course_info.teacher.name }}{{ course_info.teacher.title }}</p><p class="teacher-title">{{ course_info.teacher.signature }}</p></div></div><p class="narrative">{{ course_info.teacher.brief }}</p></div></div></div></div></div><Footer/></div>
</template><script>
import Header from "@/components/Header"
import Footer from "@/components/Footer"// 加载组件
import {videoPlayer} from 'vue-video-player';export default {name: "Detail",data() {return {tabIndex: 2, // 当前选项卡显示的下标course_id: 0, // 当前课程信息的IDcourse_info: {teacher: {},}, // 课程信息course_chapters: [], // 课程的章节课时列表playerOptions: {playbackRates: [0.5, 1.0, 1.5, 2.0], // 可选的播放速度preload: 'auto',aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")sources: [{ // 播放资源和资源格式type: "video/mp4",src: "https://video.pearvideo.com/mp4/adshort/20210310/cont-1722801-15627881_adpkg-ad_hd.mp4" //你的视频地址(必填)}],}}},created() {this.get_course_id();this.get_course_data();this.get_chapter();},methods: {onPlayerPlay() {// 当视频播放时,执行的方法console.log('视频开始播放')},onPlayerPause() {// 当视频暂停播放时,执行的方法console.log('视频暂停,可以打开广告了')},get_course_id() {// 获取地址栏上面的课程IDthis.course_id = this.$route.params.idif (this.course_id < 1) {let _this = this;_this.$alert("对不起,当前视频不存在!", "警告", {callback() {_this.$router.go(-1);}});}},get_course_data() {// ajax请求课程信息this.$axios.get(`${this.$settings.BASE_URL}course/list/${this.course_id}/`).then(response => {this.course_info = response.data;console.log(this.course_info)}).catch(() => {this.$message({message: "对不起,访问页面出错!请联系客服工作人员!"});})},get_chapter() {// 获取当前课程对应的章节课时信息this.$axios.get(`${this.$settings.BASE_URL}course/chapter/`, {params: {"course": this.course_id,}}).then(response => {this.course_chapters = response.data.result;}).catch(error => {console.log(error.response);})},},components: {Header,Footer,videoPlayer, // 注册组件}
}
</script><style scoped>
.main {background: #fff;padding-top: 30px;
}.course-info {width: 1200px;margin: 0 auto;overflow: hidden;
}.wrap-left {float: left;width: 690px;height: 388px;background-color: #000;
}.wrap-right {float: left;position: relative;height: 388px;
}.course-name {font-size: 20px;color: #333;padding: 10px 23px;letter-spacing: .45px;
}.data {padding-left: 23px;padding-right: 23px;padding-bottom: 16px;font-size: 14px;color: #9b9b9b;
}.sale-time {width: 464px;background: #fa6240;font-size: 14px;color: #4a4a4a;padding: 10px 23px;overflow: hidden;
}.sale-type {font-size: 16px;color: #fff;letter-spacing: .36px;float: left;
}.sale-time .expire {font-size: 14px;color: #fff;float: right;
}.sale-time .expire .second {width: 24px;display: inline-block;background: #fafafa;color: #5e5e5e;padding: 6px 0;text-align: center;
}.course-price {background: #fff;font-size: 14px;color: #4a4a4a;padding: 5px 23px;
}.discount {font-size: 26px;color: #fa6240;margin-left: 10px;display: inline-block;margin-bottom: -5px;
}.original {font-size: 14px;color: #9b9b9b;margin-left: 10px;text-decoration: line-through;
}.buy {width: 464px;padding: 0px 23px;position: absolute;left: 0;bottom: 20px;overflow: hidden;
}.buy .buy-btn {float: left;
}.buy .buy-now {width: 125px;height: 40px;border: 0;background: #ffc210;border-radius: 4px;color: #fff;cursor: pointer;margin-right: 15px;outline: none;
}.buy .free {width: 125px;height: 40px;border-radius: 4px;cursor: pointer;margin-right: 15px;background: #fff;color: #ffc210;border: 1px solid #ffc210;
}.add-cart {float: right;font-size: 14px;color: #ffc210;text-align: center;cursor: pointer;margin-top: 10px;
}.add-cart img {width: 20px;height: 18px;margin-right: 7px;vertical-align: middle;
}.course-tab {width: 100%;background: #fff;margin-bottom: 30px;box-shadow: 0 2px 4px 0 #f0f0f0;}.course-tab .tab-list {width: 1200px;margin: auto;color: #4a4a4a;overflow: hidden;
}.tab-list li {float: left;margin-right: 15px;padding: 26px 20px 16px;font-size: 17px;cursor: pointer;
}.tab-list .active {color: #ffc210;border-bottom: 2px solid #ffc210;
}.tab-list .free {color: #fb7c55;
}.course-content {width: 1200px;margin: 0 auto;background: #FAFAFA;overflow: hidden;padding-bottom: 40px;
}.course-tab-list {width: 880px;height: auto;padding: 20px;background: #fff;float: left;box-sizing: border-box;overflow: hidden;position: relative;box-shadow: 0 2px 4px 0 #f0f0f0;
}.tab-item {width: 880px;background: #fff;padding-bottom: 20px;box-shadow: 0 2px 4px 0 #f0f0f0;
}.tab-item-title {justify-content: space-between;padding: 25px 20px 11px;border-radius: 4px;margin-bottom: 20px;border-bottom: 1px solid #333;border-bottom-color: rgba(51, 51, 51, .05);overflow: hidden;
}.chapter {font-size: 17px;color: #4a4a4a;float: left;
}.chapter-length {float: right;font-size: 14px;color: #9b9b9b;letter-spacing: .19px;
}.chapter-title {font-size: 16px;color: #4a4a4a;letter-spacing: .26px;padding: 12px;background: #eee;border-radius: 2px;display: -ms-flexbox;display: flex;-ms-flex-align: center;align-items: center;
}.chapter-title img {width: 18px;height: 18px;margin-right: 7px;vertical-align: middle;
}.section-list {padding: 0 20px;
}.section-list .section-item {padding: 15px 20px 15px 36px;cursor: pointer;justify-content: space-between;position: relative;overflow: hidden;
}.section-item .name {font-size: 14px;color: #666;float: left;
}.section-item .index {margin-right: 5px;
}.section-item .free {font-size: 12px;color: #fff;letter-spacing: .19px;background: #ffc210;border-radius: 100px;padding: 1px 9px;margin-left: 10px;
}.section-item .time {font-size: 14px;color: #666;letter-spacing: .23px;opacity: 1;transition: all .15s ease-in-out;float: right;
}.section-item .time img {width: 18px;height: 18px;margin-left: 15px;vertical-align: text-bottom;
}.section-item .try {width: 86px;height: 28px;background: #ffc210;border-radius: 4px;font-size: 14px;color: #fff;position: absolute;right: 20px;top: 10px;opacity: 0;transition: all .2s ease-in-out;cursor: pointer;outline: none;border: none;
}.section-item:hover {background: #fcf7ef;box-shadow: 0 0 0 0 #f3f3f3;
}.section-item:hover .name {color: #333;
}.section-item:hover .try {opacity: 1;
}.course-side {width: 300px;height: auto;margin-left: 20px;float: right;
}.teacher-info {background: #fff;margin-bottom: 20px;box-shadow: 0 2px 4px 0 #f0f0f0;
}.side-title {font-weight: normal;font-size: 17px;color: #4a4a4a;padding: 18px 14px;border-bottom: 1px solid #333;border-bottom-color: rgba(51, 51, 51, .05);
}.side-title span {display: inline-block;border-left: 2px solid #ffc210;padding-left: 12px;
}.teacher-content {padding: 30px 20px;box-sizing: border-box;
}.teacher-content .cont1 {margin-bottom: 12px;overflow: hidden;
}.teacher-content .cont1 img {width: 54px;height: 54px;margin-right: 12px;float: left;
}.teacher-content .cont1 .name {float: right;
}.teacher-content .cont1 .teacher-name {width: 188px;font-size: 16px;color: #4a4a4a;padding-bottom: 4px;
}.teacher-content .cont1 .teacher-title {width: 188px;font-size: 13px;color: #9b9b9b;white-space: nowrap;
}.teacher-content .narrative {font-size: 14px;color: #666;line-height: 24px;
}
</style>
视频播放器
# 前端使用视频播放器:cnpm install vue-video-player@5 -S
main.js
import 'video.js/dist/video-js.css'
import 'vue-video-player/src/custom-theme.css'
import VideoPlayer from 'vue-video-player'Vue.use(VideoPlayer);
视频的配置参数
export default {data() {return {playerOptions: {playbackRates: [0.5, 1.0, 1.5, 2.0], // 可选的播放速度autoplay: false, // 如果为true,浏览器准备好时开始回放。muted: false, // 默认情况下将会消除任何音频。loop: false, // 是否视频一结束就重新开始。preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)language: 'zh-CN',aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。sources: [{type: "video/mp4", // 类型 type: "application/x-mpegURL"直播流src: '' // url地址}],poster: '', // 封面地址notSupportedMessage: '此视频暂无法播放,请稍后再试', // 允许覆盖Video.js无法播放媒体源时显示的默认信息。controlBar: {timeDivider: true, // 当前时间和持续时间的分隔符durationDisplay: true, // 显示持续时间remainingTimeDisplay: false, // 是否显示剩余时间功能fullscreenToggle: true // 是否显示全屏按钮}}}}
}
如果用不了,使用这个:vue-core-video-player
视频托管
# 课程视频,比较多,如果传到自己服务器放到media文件夹#文件存储服务器-ceph-fastdfs-go-fastdfs-MinIO-第三方存储
# 阿里oss:
# 第三方七牛云:-上海公司-技术驱动型公司:ceo 许式伟 -国内第一批使用go语言的,全线go语言 -go+ 语言 -七牛云:-注册账号-创建空间(桶)-上传文件:-1 直接上传-2 使用代码上传-python:sdk-前端上传:js代码案例
# 公司内部存储:fastdfshttps://zhuanlan.zhihu.com/p/372286804# MinIO-部署完:http://docs.minio.org.cn/docs/master/minio-docker-quickstart-guide-web管理页面:类似于七牛云-python的sdk上传
搜索导航栏
添加在顶部组件中
Header.vue
<template><div class="header"><div class="slogan"><p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p></div><div class="nav"><ul class="left-part"><li class="logo"><router-link to="/"><img src="../assets/img/head-logo.svg" alt=""></router-link></li><li class="ele"><span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span></li><li class="ele"><span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span></li><li class="ele"><span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span></li></ul><div class="right-part"><!-- 通过用户名判断当前是否登录--><div v-if="!this.username"><span @click="put_login">登录</span><span class="line">|</span><span @click="put_register">注册</span></div><div v-else><span @click="put_login">{{ username }}</span><span class="line">|</span><!-- 给注销绑定点击事件--><span @click="logout">注销</span></div><Login v-if="is_login" @close="close_login" @go="put_register"></Login><Register v-if="is_register" @close="close_register" @go="put_login"></Register></div><form class="search"><div class="tips" v-if="is_search_tip && !search_word"><span @click="search_action('Python')">Python</span><span @click="search_action('Linux')">Linux</span></div><input type="text" :placeholder="search_placeholder" @focus="on_search" @blur="off_search"v-model="search_word"><button type="button" class="glyphicon glyphicon-search" @click="search_action(search_word)"></button></form></div></div></template><script>
import Login from "@/components/Login";
import Register from "@/components/Register";export default {name: "Header",data() {return {url_path: sessionStorage.url_path || '/',is_login: false,is_register: false,username: '',// 搜索导航栏is_search_tip: true,search_placeholder: '',search_word: ''}},methods: {goPage(url_path) {// 已经是当前路由就没有必要重新跳转if (this.url_path !== url_path) {// 传入的参数,如果不等于当前路径,就跳转this.$router.push(url_path)}sessionStorage.url_path = url_path;},goLogin() {this.loginShow = true},put_login() {this.is_login = true;this.is_register = false;},put_register() {this.is_login = false;this.is_register = true;},close_login() {this.is_login = false;this.username = this.$cookies.get('username')},close_register() {this.is_register = false;},logout() {this.$cookies.remove('username')this.$cookies.remove('token')this.$cookies.remove('icon')this.username = ''},// 搜索导航栏search_action(search_word) {if (!search_word) {this.$message('请输入要搜索的内容');return}if (search_word !== this.$route.query.word) {this.$router.push(`/course/search?word=${search_word}`);}this.search_word = '';},on_search() {this.search_placeholder = '请输入想搜索的课程';this.is_search_tip = false;},off_search() {this.search_placeholder = '';this.is_search_tip = true;},},created() {sessionStorage.url_path = this.$route.paththis.url_path = this.$route.paththis.username = this.$cookies.get('username') // 创建页面时检查cookies中是否有用户名},components: {Login,Register}
}
</script><style scoped>
.header {background-color: white;box-shadow: 0 0 5px 0 #aaa;
}.header:after {content: "";display: block;clear: both;
}.slogan {background-color: #eee;height: 40px;
}.slogan p {width: 1200px;margin: 0 auto;color: #aaa;font-size: 13px;line-height: 40px;
}.nav {background-color: white;user-select: none;width: 1200px;margin: 0 auto;}.nav ul {padding: 15px 0;float: left;
}.nav ul:after {clear: both;content: '';display: block;
}.nav ul li {float: left;
}.logo {margin-right: 20px;
}.ele {margin: 0 20px;
}.ele span {display: block;font: 15px/36px '微软雅黑';border-bottom: 2px solid transparent;cursor: pointer;
}.ele span:hover {border-bottom-color: orange;
}.ele span.active {color: orange;border-bottom-color: orange;
}.right-part {float: right;
}.right-part .line {margin: 0 10px;
}.right-part span {line-height: 68px;cursor: pointer;
}/*搜索导航栏*/.search {float: right;position: relative;margin-top: 22px;margin-right: 10px;
}.search input, .search button {border: none;outline: none;background-color: white;
}.search input {border-bottom: 1px solid #eeeeee;
}.search input:focus {border-bottom-color: orange;
}.search input:focus + button {color: orange;
}.search .tips {position: absolute;bottom: 3px;left: 0;
}.search .tips span {border-radius: 11px;background-color: #eee;line-height: 22px;display: inline-block;padding: 0 7px;margin-right: 3px;cursor: pointer;color: #aaa;font-size: 14px;}.search .tips span:hover {color: orange;
}</style>
搜索后台接口
urls.py
router.register('search', CourseSearchView, 'search')
views.py
class CourseSearchView(GenericViewSet, ListModelMixin):queryset = Course.objects.all().filter(is_delete=False, is_show=True).order_by('orders')serializer_class = CourseSerializerpagination_class = CommonPageNumPaginationfilter_backends = [OrderingFilter, SearchFilter]ordering_fields = ['orders', 'price', 'students']search_fields = ['name']# 这样只能够搜索实战课"""
需要将三种课程都查询出来需要重写list方法
手动查询出另外两张表的结果,在添加到Response中"""
搜索前端页面
router/index.js
{path: '/course/search',name: 'search',component: Search},
Search.vue
<template><div class="course"><Header></Header><div class="main"><!-- 筛选条件 --><!-- 课程列表 --><div class="course-list"><div class="course-item" v-for="course in course_list" :key="course.name"><div class="course-image"><img :src="course.course_img" alt=""></div><div class="course-info"><h3><router-link :to="'/course/detail/'+course.id">{{ course.name }}</router-link><span><img src="@/assets/img/avatar1.svg" alt="">{{ course.students }}人已加入学习</span></h3><p class="teather-info">{{ course.teacher.name }} {{ course.teacher.title }} {{ course.teacher.signature }}<spanv-if="course.sections>course.pub_sections">共{{ course.sections }}课时/已更新{{course.pub_sections}}课时</span><span v-else>共{{ course.sections }}课时/更新完成</span></p><ul class="section-list"><li v-for="(section, key) in course.section_list" :key="section.name"><spanclass="section-title">0{{ key + 1 }} | {{ section.name }}</span><span class="free" v-if="section.free_trail">免费</span></li></ul><div class="pay-box"><span class="discount-price">¥{{ course.price }}元</span><span class="buy-now">立即购买</span></div></div></div></div><div class="course_pagination block"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page.sync="filter.page":page-sizes="[2, 3, 5, 10]":page-size="filter.size"layout="sizes, prev, pager, next":total="course_total"></el-pagination></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/Header"
import Footer from "@/components/Footer"export default {name: "Course",data() {return {course_list: [], // 课程列表course_total: 0, // 当前课程的总数量filter: {course_category: 0, // 当前用户选择的课程分类,刚进入页面默认为全部,值为0ordering: "orders", // 数据的排序方式,默认值是orders,表示对于id进行降序排列size: 2, // 单页数据量page: 1,search: '',}}},created() {this.get_course();},components: {Header,Footer,},watch: {// 查询条件修改时重新查询课程"$route.query"() {this.get_course()},"filter.size": function () {this.get_course();},"filter.page": function () {this.get_course();}},methods: {handleSizeChange(val) {// 每页数据量发生变化时执行的方法this.filter.page = 1;this.filter.size = val;},handleCurrentChange(val) {// 页码发生变化时执行的方法this.filter.page = val;},get_category() {// 获取课程分类信息this.$axios.get(`${this.$settings.BASE_URL}course/category/`, {params: this.filter}).then(response => {this.category_list = response.data.result;}).catch(() => {this.$message({message: "获取课程分类信息有误,请联系客服工作人员",})})},get_course() {// 获取搜索的关键字this.filter.search = this.$route.query.word || this.$route.query.wd;// 排序let filters = {ordering: this.filter.ordering, // 排序};// 设置单页数据量if (this.filter.size > 0) {filters.size = this.filter.size;} else {filters.size = 5;}// 设置当前页码if (this.filter.page > 1) {filters.page = this.filter.page;} else {filters.page = 1;}// 构造出查询数据//filters:{ordering:orders,page:1,size:5,course_category:0}// 获取课程列表信息this.$axios.get(`${this.$settings.BASE_URL}course/search/`, {params: this.filter}).then(response => {// console.log(response.data);this.course_list = response.data.results;this.course_total = response.data.count;console.log(this.course_list);}).catch(() => {this.$message({message: "获取课程信息有误,请联系客服工作人员"})})}}
}
</script><style scoped>
.course {background: #f6f6f6;
}.course .main {width: 1100px;margin: 35px auto 0;
}.course .condition {margin-bottom: 35px;padding: 25px 30px 25px 20px;background: #fff;border-radius: 4px;box-shadow: 0 2px 4px 0 #f0f0f0;
}.course .cate-list {border-bottom: 1px solid #333;border-bottom-color: rgba(51, 51, 51, .05);padding-bottom: 18px;margin-bottom: 17px;
}.course .cate-list::after {content: "";display: block;clear: both;
}.course .cate-list li {float: left;font-size: 16px;padding: 6px 15px;line-height: 16px;margin-left: 14px;position: relative;transition: all .3s ease;cursor: pointer;color: #4a4a4a;border: 1px solid transparent; /* transparent 透明 */
}.course .cate-list .title {color: #888;margin-left: 0;letter-spacing: .36px;padding: 0;line-height: 28px;
}.course .cate-list .this {color: #ffc210;border: 1px solid #ffc210 !important;border-radius: 30px;
}.course .ordering::after {content: "";display: block;clear: both;
}.course .ordering ul {float: left;
}.course .ordering ul::after {content: "";display: block;clear: both;
}.course .ordering .condition-result {float: right;font-size: 14px;color: #9b9b9b;line-height: 28px;
}.course .ordering ul li {float: left;padding: 6px 15px;line-height: 16px;margin-left: 14px;position: relative;transition: all .3s ease;cursor: pointer;color: #4a4a4a;
}.course .ordering .title {font-size: 16px;color: #888;letter-spacing: .36px;margin-left: 0;padding: 0;line-height: 28px;
}.course .ordering .this {color: #ffc210;
}.course .ordering .price {position: relative;
}.course .ordering .price::before,
.course .ordering .price::after {cursor: pointer;content: "";display: block;width: 0px;height: 0px;border: 5px solid transparent;position: absolute;right: 0;
}.course .ordering .price::before {border-bottom: 5px solid #aaa;margin-bottom: 2px;top: 2px;
}.course .ordering .price::after {border-top: 5px solid #aaa;bottom: 2px;
}.course .ordering .price_up::before {border-bottom-color: #ffc210;
}.course .ordering .price_down::after {border-top-color: #ffc210;
}.course .course-item:hover {box-shadow: 4px 6px 16px rgba(0, 0, 0, .5);
}.course .course-item {width: 1100px;background: #fff;padding: 20px 30px 20px 20px;margin-bottom: 35px;border-radius: 2px;cursor: pointer;box-shadow: 2px 3px 16px rgba(0, 0, 0, .1);/* css3.0 过渡动画 hover 事件操作 */transition: all .2s ease;
}.course .course-item::after {content: "";display: block;clear: both;
}/* 顶级元素 父级元素 当前元素{} */
.course .course-item .course-image {float: left;width: 423px;height: 210px;margin-right: 30px;
}.course .course-item .course-image img {max-width: 100%;max-height: 210px;
}.course .course-item .course-info {float: left;width: 596px;
}.course-item .course-info h3 a {font-size: 26px;color: #333;font-weight: normal;margin-bottom: 8px;
}.course-item .course-info h3 span {font-size: 14px;color: #9b9b9b;float: right;margin-top: 14px;
}.course-item .course-info h3 span img {width: 11px;height: auto;margin-right: 7px;
}.course-item .course-info .teather-info {font-size: 14px;color: #9b9b9b;margin-bottom: 14px;padding-bottom: 14px;border-bottom: 1px solid #333;border-bottom-color: rgba(51, 51, 51, .05);
}.course-item .course-info .teather-info span {float: right;
}.course-item .section-list::after {content: "";display: block;clear: both;
}.course-item .section-list li {float: left;width: 44%;font-size: 14px;color: #666;padding-left: 22px;/* background: url("路径") 是否平铺 x轴位置 y轴位置 */background: url("/src/assets/img/play-icon-gray.svg") no-repeat left 4px;margin-bottom: 15px;
}.course-item .section-list li .section-title {/* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */text-overflow: ellipsis;overflow: hidden;white-space: nowrap;display: inline-block;max-width: 200px;
}.course-item .section-list li:hover {background-image: url("/src/assets/img/play-icon-yellow.svg");color: #ffc210;
}.course-item .section-list li .free {width: 34px;height: 20px;color: #fd7b4d;vertical-align: super;margin-left: 10px;border: 1px solid #fd7b4d;border-radius: 2px;text-align: center;font-size: 13px;white-space: nowrap;
}.course-item .section-list li:hover .free {color: #ffc210;border-color: #ffc210;
}.course-item {position: relative;
}.course-item .pay-box {position: absolute;bottom: 20px;width: 600px;
}.course-item .pay-box::after {content: "";display: block;clear: both;
}.course-item .pay-box .discount-type {padding: 6px 10px;font-size: 16px;color: #fff;text-align: center;margin-right: 8px;background: #fa6240;border: 1px solid #fa6240;border-radius: 10px 0 10px 0;float: left;
}.course-item .pay-box .discount-price {font-size: 24px;color: #fa6240;float: left;
}.course-item .pay-box .original-price {text-decoration: line-through;font-size: 14px;color: #9b9b9b;margin-left: 10px;float: left;margin-top: 10px;
}.course-item .pay-box .buy-now {width: 120px;height: 38px;background: transparent;color: #fa6240;font-size: 16px;border: 1px solid #fd7b4d;border-radius: 3px;transition: all .2s ease-in-out;float: right;text-align: center;line-height: 38px;position: absolute;right: 0;bottom: 5px;
}.course-item .pay-box .buy-now:hover {color: #fff;background: #ffc210;border: 1px solid #ffc210;
}.course .course_pagination {margin-bottom: 60px;text-align: center;
}
</style>
luffy-(12)相关推荐
- 系统启动没有声音,音量控制图标不能正常显示,但realplayer能正常播放
最近碰到了一个问题,任务栏的音量显示图标突然不能正常显示(卸载程序造成),造成计算机启动.注销等 没有声音,swf文件播放不正常,为此很是苦恼了一下,在网上查了一些资料,都是一些陈词烂调,比如 1.到 ...
- ACM POJ 2723 Get Luffy Out(2-SAT入门)
题目链接:http://poj.org/problem?id=2723 [题目大意] 有2n把钥匙,分成2组,给你每组的钥匙信息,并且每组的钥匙只能用一个. 有m个门,每个门有2个锁,只要打开一个锁这 ...
- 路飞学城之 luffy(1)
目录 路飞学城之 luffy(1) 一.内容 二.内容大纲 小结 三.内容大纲 小结 四.内容大纲 自定义模态框 componses/Login.vue componses/Header.vue vu ...
- swig error : Unrecognized option -doxygen Ubuntu 安装 swig-3.0.12
1. 下载 下载地址:https://sourceforge.net/projects/swig/ 2. 安装 tar -xzvf swig-3.0.12.tar.gzcd swig-3.0.12# ...
- 1-2 用Python编写【房价预测】模型----paddle
课程>我的课程>百度架构师手把手教深度学习>1-2 用Python编写[房价预测]模型> 1-2 用Python编写[房价预测]模型 paddle初级教程第一章 第二节 王然( ...
- 【CV】吴恩达机器学习课程笔记 | 第1-2章
本系列文章如果没有特殊说明,正文内容均解释的是文字上方的图片 机器学习 | Coursera 吴恩达机器学习系列课程_bilibili 目录 1 介绍 1-3 监督学习 1-4 无监督学习 2 单变量 ...
- mysql效率优化_MySQL性能优化的最佳12条经验
数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我 们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据库时 ...
- 网站项目必备——12款白富美型 jQuery 图片轮播插件
转自:http://www.cnblogs.com/lhb25/archive/2013/01/06/jquery-image-carousel-effect.html 图片轮播是网站中的常用功能,用 ...
- 写代码:使用while循环实现输出1,2,3,4,5,7,8,9,11,12
# 使用while循环实现输出1,2,3,4,5,7,8,9,11,12 number = 1while number <= 12:if number == 6 or number == 10: ...
- Oracle 12c(12.1.0.5) oem agent silent install(静默安装agent)
注释: 文章来自oracle support 文档 ID 1360083.1,静默安装agent采用的是把OMS服务端(即oem server端)的agent用压缩包download,远程传到agen ...
最新文章
- 暴力枚举 UVA 725 Division
- golang 判断 两个slice 是否相等
- only one element tensors can be converted to Python scalars
- python算法与数据结构-数据结构中二叉树的介绍
- 支付宝的一些小问题,注意事项等等,等用得时候在来写写
- elementUI响应式布局@media:基于断点的隐藏类
- 快速软件开发 学习笔记 之六
- DeepMind深度学习高级课程,视频已全部放出
- 汇编指令对应的机器码_汇编语言输出“welcome to you!”
- Linux手机研发要过五大难关
- 手机号空号检测的几点建议
- 联想微型计算机Q150,联想Q150E电脑安装攻略
- 宗宁:企业微博品牌榜的新时代意义
- 如何做gif动图?手把手教你在线制作动图
- STM32不能进入睡眠模式
- 怎么把知网CAJ转换成可复制文字的PDF文件
- 医学图像分割常用的评价指标
- Task Office for Mac(GTD办公软件)
- vue3中scrollTop不生效的问题
- 51单片机,时钟频率,机器周期,与执行指令的时间
热门文章
- Ubuntu 16.04 LTS 初体验
- 让我们旋转跳跃不停歇~~~当3D打印遇上八音盒!(二)
- 【机器学习】为什么机器学习难于应用
- 软件测试实习生 带人计划 Plan for Training Inten
- office之word开启参考线对齐
- IT招聘惨淡季?求职者无offer,招聘者无简历
- 经典boost手机背光电路调试分析
- pr零基础晋升笔记(学习复习用)
- 2017南开秋奥鹏作业计算机,南开17秋学期《DirectX程序设计》在线作业(资料)...
- mysql使得df和du不一致_df和du显示的磁盘空间使用情况不一致的原因及处理