内容概览

  • 课程详情页接口
  • 课程列表前端
  • 课程详情前端
  • 搜索导航栏
  • 搜索后台接口
  • 搜索前端页面

课程详情页接口

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">筛&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;选:</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 }}人在学&nbsp;&nbsp;&nbsp;&nbsp;课程总时长:{{course_info.sections}}课时/{{ course_info.pub_sections }}小时&nbsp;&nbsp;&nbsp;&nbsp;难度:{{ 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)相关推荐

  1. 系统启动没有声音,音量控制图标不能正常显示,但realplayer能正常播放

    最近碰到了一个问题,任务栏的音量显示图标突然不能正常显示(卸载程序造成),造成计算机启动.注销等 没有声音,swf文件播放不正常,为此很是苦恼了一下,在网上查了一些资料,都是一些陈词烂调,比如 1.到 ...

  2. ACM POJ 2723 Get Luffy Out(2-SAT入门)

    题目链接:http://poj.org/problem?id=2723 [题目大意] 有2n把钥匙,分成2组,给你每组的钥匙信息,并且每组的钥匙只能用一个. 有m个门,每个门有2个锁,只要打开一个锁这 ...

  3. 路飞学城之 luffy(1)

    目录 路飞学城之 luffy(1) 一.内容 二.内容大纲 小结 三.内容大纲 小结 四.内容大纲 自定义模态框 componses/Login.vue componses/Header.vue vu ...

  4. 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# ...

  5. 1-2 用Python编写【房价预测】模型----paddle

    课程>我的课程>百度架构师手把手教深度学习>1-2 用Python编写[房价预测]模型> 1-2 用Python编写[房价预测]模型 paddle初级教程第一章 第二节 王然( ...

  6. 【CV】吴恩达机器学习课程笔记 | 第1-2章

    本系列文章如果没有特殊说明,正文内容均解释的是文字上方的图片 机器学习 | Coursera 吴恩达机器学习系列课程_bilibili 目录 1 介绍 1-3 监督学习 1-4 无监督学习 2 单变量 ...

  7. mysql效率优化_MySQL性能优化的最佳12条经验

    数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我 们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据库时 ...

  8. 网站项目必备——12款白富美型 jQuery 图片轮播插件

    转自:http://www.cnblogs.com/lhb25/archive/2013/01/06/jquery-image-carousel-effect.html 图片轮播是网站中的常用功能,用 ...

  9. 写代码:使用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: ...

  10. Oracle 12c(12.1.0.5) oem agent silent install(静默安装agent)

    注释: 文章来自oracle support 文档 ID 1360083.1,静默安装agent采用的是把OMS服务端(即oem server端)的agent用压缩包download,远程传到agen ...

最新文章

  1. 暴力枚举 UVA 725 Division
  2. golang 判断 两个slice 是否相等
  3. only one element tensors can be converted to Python scalars
  4. python算法与数据结构-数据结构中二叉树的介绍
  5. 支付宝的一些小问题,注意事项等等,等用得时候在来写写
  6. elementUI响应式布局@media:基于断点的隐藏类
  7. 快速软件开发 学习笔记 之六
  8. DeepMind深度学习高级课程,视频已全部放出
  9. 汇编指令对应的机器码_汇编语言输出“welcome to you!”
  10. Linux手机研发要过五大难关
  11. 手机号空号检测的几点建议
  12. 联想微型计算机Q150,联想Q150E电脑安装攻略
  13. 宗宁:企业微博品牌榜的新时代意义
  14. 如何做gif动图?手把手教你在线制作动图
  15. STM32不能进入睡眠模式
  16. 怎么把知网CAJ转换成可复制文字的PDF文件
  17. 医学图像分割常用的评价指标
  18. Task Office for Mac(GTD办公软件)
  19. vue3中scrollTop不生效的问题
  20. 51单片机,时钟频率,机器周期,与执行指令的时间

热门文章

  1. Ubuntu 16.04 LTS 初体验
  2. 让我们旋转跳跃不停歇~~~当3D打印遇上八音盒!(二)
  3. 【机器学习】为什么机器学习难于应用
  4. 软件测试实习生 带人计划 Plan for Training Inten
  5. office之word开启参考线对齐
  6. IT招聘惨淡季?求职者无offer,招聘者无简历
  7. 经典boost手机背光电路调试分析
  8. pr零基础晋升笔记(学习复习用)
  9. 2017南开秋奥鹏作业计算机,南开17秋学期《DirectX程序设计》在线作业(资料)...
  10. mysql使得df和du不一致_df和du显示的磁盘空间使用情况不一致的原因及处理