[TOC]

image.png

静态路由和动态路由:顶部栏固定的链接跳转时静态路由;点击心仪讲师实现具体信息页面显示是动态路由

名师列表

后端

  1. 后端接口controller

    1. 分页条件查,且每页显示8条讲师记录,且是热门讲师
    2. 此分页条件查区别于之前的课程页面,此处未使用element-ui组件

      @Api(description = "讲师管理前端")
      @RestController
      @RequestMapping("/eduservice/teacherfront")
      @CrossOrigin
      public class TeacherFrontController {
      
      @Autowired
      private EduTeacherService teacherService;
      
      @Autowired
      private EduCourseService courseService;
      
      @ApiOperation(value = "分页查询所有讲师")
      @PostMapping("getTeacherFrontList/{page}/{limit}")
      public R getTeacherFrontList(@PathVariable long page,@PathVariable long limit) {
        Page<EduTeacher> pageTeacher = new Page<>(page, limit);
        Map<String,Object> map = teacherService.getTeacherFrontList(pageTeacher);
        //返回封装的数据
        return R.ok().data(map);
      }
      }
      
  2. 实现接口中的方法

    @Override
    public Map<String, Object> getTeacherFrontList(Page<EduTeacher> pageParam) {
     QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
     wrapper.orderByDesc("id");
     baseMapper.selectPage(pageParam,wrapper);
    
     List<EduTeacher> records = pageParam.getRecords();
     long current = pageParam.getCurrent();
     long pages = pageParam.getPages();
     long size = pageParam.getSize();
     long total = pageParam.getTotal();
     boolean hasNext = pageParam.hasNext();//下一页
     boolean hasPrevious = pageParam.hasPrevious();//上一页
    
     //把分页数据获取出来,放到map集合
     Map<String,Object> map = new HashMap<>();
     map.put("items",records);
     map.put("pages",pages);
     map.put("current",current);
     map.put("size",size);
     map.put("total",total);
     map.put("hasNext",hasNext);
     map.put("hasPrevious",hasPrevious);
    
     return map;
    }
    

    前端

  3. 前端接口teacher.js ```javascript import request from ‘@/utils/request’

export default { //查询讲师信息方法 getTeacherList(page,limit) { return request({ url: /eduservice/teacherfront/getTeacherFrontList/${page}/${limit}, method: ‘post’ }) }, }


2. 讲师页面调用api获取数据
```javascript
<script>
import teacherApi from '@/api/teacher'

export default {
  //异步调用,调用一次
  //params: 相当于之前 this.$route.params.id  等价  params.id
  asyncData({ params, error }) {
    return teacherApi.getTeacherList(1,8).then(response => {
          //this.data = response.data.data
          return { data: response.data.data }
       })
  },
  methods:{
    //分页切换的方法
    //参数是页码数
    gotoPage(page) {
      teacherApi.getTeacherList(page,8)
        .then(response => {
          this.data = response.data.data
        })
    }
  }
};
</script>
  1. 分页展示和页面展示 ```java ========================页面展示=================

      没有相关数据,小编正在努力整理中…

    ========================分页展示=================

    <a

    :class="{undisable: !data.hasPrevious}"
    href="#"
    title="首页"
    @click.prevent="gotoPage(1)">首页</a>
    

    <a

    :class="{undisable: !data.hasPrevious}"
    href="#"
    title="前一页"
    @click.prevent="gotoPage(data.current-1)">&lt;</a>
    

    <a

    v-for="page in data.pages"
    :key="page"
    :class="{current: data.current == page, undisable: data.current == page}"
    :title="'第'+page+'页'"
    href="#"
    @click.prevent="gotoPage(page)">{{ page }}</a>
    

    <a

    :class="{undisable: !data.hasNext}"
    href="#"
    title="后一页"
    @click.prevent="gotoPage(data.current+1)">&gt;</a>
    

    <a

    :class="{undisable: !data.hasNext}"
    href="#"
    title="末页"
    @click.prevent="gotoPage(data.pages)">末页</a>
    

<a name="Z21BI"></a>
# 名师详情
<a name="dfxfp"></a>
## 后端
```java
@ApiOperation(value = "讲师详情功能")
 @GetMapping("getTeacherFrontInfo/{teacherId}")
 public R getTeacherFrontInfo(@PathVariable String teacherId) {
     //根据讲师id 查询讲师基本信息
     EduTeacher teacher = teacherService.getById(teacherId);

     //根据讲师id 查询课程基本信息
     QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();
     wrapper.eq("teacher_id",teacherId);
     List<EduCourse> courseList = courseService.list(wrapper);

     return R.ok().data("teacher",teacher).data("courseList",courseList);
 }

前端

  1. 前端api

    //根据讲师id查询详情
    getTeacherInfo(id) {
    return request({
     url: `/eduservice/teacherfront/getTeacherFrontInfo/${id}`,
     method: 'get'
    })
    }
    
  2. 讲师详情页调用数据: pages/teacher/_id.vue ```javascript

    
    3. 讲师详情页面
    ```vue
    <!-- 讲师基本信息 -->
    <section class="fl t-infor-box c-desc-content">
      <div class="mt20 ml20">
        <section class="t-infor-pic">
          <img :src="teacher.avatar">
        </section>
        <h3 class="hLh30">
          <span class="fsize24 c-333">{{teacher.name}}&nbsp;
            {{ teacher.level===1?'高级讲师':'首席讲师' }}
          </span>
        </h3>
        <section class="mt10">
          <span class="t-tag-bg">{{teacher.intro}}</span>
        </section>
        <section class="t-infor-txt">
          <p
            class="mt20">{{teacher.career}}</p>
        </section>
        <div class="clear"></div>
      </div>
    </section>
    
    
    <!-- /无数据提示 开始-->
    <section class="no-data-wrap" v-if="courseList.length==0">
      <em class="icon30 no-data-ico">&nbsp;</em>
      <span class="c-666 fsize14 ml10 vam">没有相关数据,小编正在努力整理中...</span>
    </section>
    <!-- /无数据提示 结束-->
    
    
    <!-- 当前讲师课程列表-->
    <article class="comm-course-list">
      <ul class="of">
        <li v-for="course in courseList" :key="course.id">
          <div class="cc-l-wrap">
            <section class="course-img">
              <img :src="course.cover" class="img-responsive" >
              <div class="cc-mask">
                <a href="#" title="开始学习" target="_blank" class="comm-btn c-btn-1">开始学习</a>
              </div>
            </section>
            <h3 class="hLh30 txtOf mt10">
              <a href="#" :title="course.title" target="_blank" class="course-title fsize18 c-333">{{course.title}}</a>
            </h3>
          </div>
        </li>
    
      </ul>
      <div class="clear"></div>
    </article>
    

    课程列表

    后端

    1. 后端vo类 ```java @Data public class CourseFrontVo implements Serializable {

      private static final long serialVersionUID = 1L;

      @ApiModelProperty(value = “课程名称”) private String title;

      @ApiModelProperty(value = “讲师id”) private String teacherId;

      @ApiModelProperty(value = “一级类别id”) private String subjectParentId;

      @ApiModelProperty(value = “二级类别id”) private String subjectId;

      @ApiModelProperty(value = “销量排序”) private String buyCountSort;

      @ApiModelProperty(value = “最新时间排序”) private String gmtCreateSort;

      @ApiModelProperty(value = “价格排序”) private String priceSort;

    }

    
    2. service接口及实现类
    ```java
    public interface EduCourseService extends IService<EduCourse> {
        ......
    
        //前台多条件分页查询
        Map<String, Object> getCourseFrontInfo(Page<EduCourse> pageCourse, CourseFrontVo courseFrontVo);
    
    }
    
    @Service
    public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {
    
        //前台多条件分页查询
        @Override
        public Map<String, Object> getCourseFrontInfo(Page<EduCourse> pageCourse, CourseFrontVo courseFrontVo) {
    
            String title = null;
            String subjectId = null;
            String subjectParentId = null;
            String gmtCreateSort = null;
            String buyCountSort = null;
            String priceSort = null;
            String teacherId = null;
    
            if (!StringUtils.isEmpty(courseFrontVo)){
                title = courseFrontVo.getTitle();
                subjectId = courseFrontVo.getSubjectId();
                subjectParentId = courseFrontVo.getSubjectParentId();
                gmtCreateSort = courseFrontVo.getGmtCreateSort();
                buyCountSort = courseFrontVo.getBuyCountSort();
                priceSort = courseFrontVo.getPriceSort();
                teacherId = courseFrontVo.getTeacherId();
            }
    
    
            QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();
            //判断条件值是否为空,不为空拼接条件
            if (!StringUtils.isEmpty(subjectParentId)){//一级分类
                wrapper.eq("subject_parent_id",subjectParentId);
            }
            if (!StringUtils.isEmpty(subjectId)){//二级分类
                wrapper.eq("subject_id",subjectId);
            }
            if (!StringUtils.isEmpty(buyCountSort)){//关注度
                wrapper.orderByDesc("buy_count");
            }
            if (!StringUtils.isEmpty(priceSort)){//价格
                wrapper.orderByDesc("price");
            }
            if (!StringUtils.isEmpty(gmtCreateSort)){//最新,创建时间
                wrapper.orderByDesc("gmt_create");
            }
    
    
            baseMapper.selectPage(pageCourse, wrapper);
    
            long total = pageCourse.getTotal();//总记录数
            List<EduCourse> courseList = pageCourse.getRecords();//数据集合
            long size = pageCourse.getSize();//每页记录数
            long current = pageCourse.getCurrent();//当前页
            long pages = pageCourse.getPages();//总页数
            boolean hasPrevious = pageCourse.hasPrevious();//是否有上一页
            boolean hasNext = pageCourse.hasNext();//是否有下一页
    
            HashMap<String, Object> map = new HashMap<>();
            map.put("total",total);
            map.put("list",courseList);
            map.put("size",size);
            map.put("current",current);
            map.put("pages",pages);
            map.put("hasPrevious",hasPrevious);
            map.put("hasNext",hasNext);
    
            return map;
        }
    }
    

    前端

    1. 前端api api/course.js ```javascript import request from ‘@/utils/request’

    export default{ //前台多条件分页查询 getConditionPage(page,limit,searchObj){ return request({ url: /eduservice/courseFront/getConditionPage/${page}/${limit}, method: ‘post’, data: searchObj }) }, //查询所有分类(一级分类、二级分类)的方法 getAllSubject(){ return request({ url: /eduservice/edu-subject/getAllSubject, method: ‘get’ }) } }

    
    2. pages/course/index.vue
    ```javascript
    <script>
        import courseApi from "@/api/course";
    export default {
        data() {
            return {
                page: 1, //当前页
                data: {}, //课程列表
                subjectNestedList: [], // 一级分类列表
                subSubjectList: [], // 二级分类列表
                searchObj: {}, // 查询表单对象
                oneIndex: -1,
                twoIndex: -1,
                buyCountSort: "",
                gmtCreateSort: "",
                priceSort: "",
            };
        },
        methods: {
            //根据价格进行排序
            searchPrice(){
                //设置对应变量值,为了样式生效
                this.buyCountSort=''
                this.gmtCreateSort=''
                this.priceSort='1'
    
                //把值赋值到searchObj中
                this.searchObj.buyCountSort = this.buyCountSort
                this.searchObj.priceSort = this.priceSort
                this.searchObj.gmtCreateSort = this.gmtCreateSort
    
                //调用方法查询
                this.gotoPage(1)
            },
            //根据最新进行排序
            searchGmtCreate(){
                //设置对应变量值,为了样式生效
                this.buyCountSort=''
                this.gmtCreateSort='1'
                this.priceSort=''
    
                //把值赋值到searchObj中
                this.searchObj.buyCountSort = this.buyCountSort
                this.searchObj.priceSort = this.priceSort
                this.searchObj.gmtCreateSort = this.gmtCreateSort
    
                //调用方法查询
                this.gotoPage(1)
            },
            //根据销量排序
            searchBuyCount(){
                //设置对应变量值,为了样式生效
                this.buyCountSort='1'
                this.gmtCreateSort=''
                this.priceSort=''
    
                //把值赋值到searchObj中
                this.searchObj.buyCountSort = this.buyCountSort
                this.searchObj.priceSort = this.priceSort
                this.searchObj.gmtCreateSort = this.gmtCreateSort
    
                //调用方法查询
                this.gotoPage(1)
    
            },
            //课程第一次查询
            initCourseFirst() {
                courseApi.getConditionPage(1, 8, this.searchObj).then((resp) => {
                    this.data = resp.data.data;
                });
            },
            //查询所有一级分类
            initSubject() {
                courseApi.getAllSubject().then((resp) => {
                    this.subjectNestedList = resp.data.data.list;
                    // this.subSubjectList = resp.data.data.list.children
                });
            },
            //分页切换方法
            gotoPage(page) {
                courseApi.getConditionPage(page, 8, this.searchObj).then((resp) => {
                    this.data = resp.data.data;
                });
            },
            //点击某个一级分类,查询对应的二级分类
            seacherOne(subjectParentId, index) {
                //把传递来的index赋值给ondex,为了active样式生效
                // this.oneIndex = index
                // this.twoIndex = -1
                // this.searchObj.subjectId=''
                // this.subSubjectList=[]
    
                //把一级分类点击的id值,赋值给searchObj
                this.searchObj.subjectParentId = subjectParentId;
                //点击某个一级分类进行条件查询
                this.gotoPage(1);
    
                //拿着点击的一级分类id 和 所有一级分类id进行比较
                //如果id相同,从那个一级分类中获取他的二级分类
                for (let i = 0; i < this.subjectNestedList.length; i++) {
                    //获取每个一级分类
                    var oneSubject = this.subjectNestedList[i];
                    //比较id是否相同
                    if (oneSubject.id == subjectParentId) {
                        this.subSubjectList = oneSubject.children;
                    }
                }
            },
            //点击某个二级分类实现查询
            searchTwo(subjectId, index) {
                //把index赋值,为了样式生效
                this.twoIndex = index;
                //把二级分类点击id值,赋给searchObj
                this.searchObj.subjectId = subjectId;
                //点击某个二级分类进行调节查询
                this.gotoPage(1);
            },
        },
        created() {
            //课程第一次查询
            this.initCourseFirst();
            //一级分类显示
            this.initSubject();
        },
    };
    </script>
    <style scoped>
        .active {
            background: #bdbdbd;
        }
    .hide {
        display: none;
    }
    .show {
        display: block;
    }
    </style>
    
    1. index.vue页面
      <template>
      <div id="aCoursesList" class="bg-fa of">
       <!-- /课程列表 开始 -->
       <section class="container">
         <header class="comm-title">
           <h2 class="fl tac">
             <span class="c-333">全部课程</span>
           </h2>
         </header>
         <section class="c-sort-box">
           <section class="c-s-dl">
             <dl>
               <dt>
                 <span class="c-999 fsize14">课程类别</span>
               </dt>
               <dd class="c-s-dl-li">
                 <ul class="clearfix">
                   <li>
                     <a title="全部" href="#">全部</a>
                   </li>
                   <li
                     v-for="subjectNested in subjectNestedList"
                     :key="subjectNested.id"
                   >
                     <a
                       :title="subjectNested.title"
                       @click="seacherOne(subjectNested.id, index)"
                       href="#"
                       >{{ subjectNested.title }}</a
                     >
                   </li>
                 </ul>
               </dd>
             </dl>
             <dl>
               <dt>
                 <span class="c-999 fsize14"></span>
               </dt>
               <dd class="c-s-dl-li">
                 <ul class="clearfix">
                   <li v-for="subject in subSubjectList" :key="subject.id">
                     <a
                       :title="subject.title"
                       @click="searchTwo(subject.id, index)"
                       href="#"
                       >{{ subject.title }}</a
                     >
                   </li>
                 </ul>
               </dd>
             </dl>
             <div class="clear"></div>
           </section>
           <div class="js-wrap">
             <section class="fr">
               <span class="c-ccc">
                 <i class="c-master f-fM">1</i>/
                 <i class="c-666 f-fM">1</i>
               </span>
             </section>
             <section class="fl">
               <ol class="js-tap clearfix">
                 <li :class="{ 'current bg-orange': buyCountSort != '' }">
                   <a
                     title="销量"
                     href="javascript:void(0);"
                     @click="searchBuyCount()"
                     >销量
                     <span :class="{ hide: buyCountSort == '' }">↓</span>
                   </a>
                 </li>
                 <li :class="{ 'current bg-orange': gmtCreateSort != '' }">
                   <a
                     title="最新"
                     href="javascript:void(0);"
                     @click="searchGmtCreate()"
                     >最新
                     <span :class="{ hide: gmtCreateSort == '' }">↓</span>
                   </a>
                 </li>
                 <li :class="{ 'current bg-orange': priceSort != '' }">
                   <a
                     title="价格"
                     href="javascript:void(0);"
                     @click="searchPrice()"
                     >价格&nbsp;
                     <span :class="{ hide: priceSort == '' }">↓</span>
                   </a>
                 </li>
               </ol>
             </section>
           </div>
           <div class="mt40">
             <!-- /无数据提示 开始-->
             <section class="no-data-wrap" v-if="data.total == 0">
               <em class="icon30 no-data-ico">&nbsp;</em>
               <span class="c-666 fsize14 ml10 vam"
                 >没有相关数据,小编正在努力整理 中...</span
               >
             </section>
             <!-- /无数据提示 结束-->
             <article class="comm-course-list" v-if="data.total > 0">
               <ul class="of" id="bna">
                 <li v-for="item in data.list" :key="item.id">
                   <div class="cc-l-wrap">
                     <section class="course-img">
                       <img
                         :src="item.cover"
                         class="img-responsive"
                         :alt="item.title"
                       />
                       <div class="cc-mask">
                         <a
                           href="/course/1"
                           title="开始学习"
                           class="comm-btn c- btn-1"
                           >开始学习</a
                         >
                       </div>
                     </section>
                     <h3 class="hLh30 txtOf mt10">
                       <a
                         href="/course/1"
                         :title="item.title"
                         class="course-title fsize18 c-333"
                         >{{ item.title }}</a
                       >
                     </h3>
                     <section class="mt10 hLh20 of">
                       <span
                         class="fr jgTag bg-green"
                         v-if="Number(item.price) === 0"
                       >
                         <i class="c-fff fsize12 f-fA">免费</i>
                       </span>
                       <span class="fl jgAttr c-ccc f-fA">
                         <i class="c-999 f-fA">9634人学习</i>
                         |
                         <i class="c-999 f-fA">9634评论</i>
                       </span>
                     </section>
                   </div>
                 </li>
               </ul>
               <div class="clear"></div>
             </article>
           </div>
           <!-- 公共分页 开始 -->
           <div>
             <div class="paging">
               <!-- undisable这个class是否存在,取决于数据属性hasPrevious -->
               <a
                 :class="{ undisable: !data.hasPrevious }"
                 href="#"
                 title="首页"
                 @click.prevent="gotoPage(1)"
                 >首</a
               >
               <a
                 :class="{ undisable: !data.hasPrevious }"
                 href="#"
                 title="前一页"
                 @click.prevent="gotoPage(data.current - 1)"
                 >&lt;</a
               >
               <a
                 v-for="page in data.pages"
                 :key="page"
                 :class="{
                   current: data.current == page,
                   undisable: data.current == page,
                 }"
                 :title="'第' + page + '页'"
                 href="#"
                 @click.prevent="gotoPage(page)"
                 >{{ page }}</a
               >
               <a
                 :class="{ undisable: !data.hasNext }"
                 href="#"
                 title="后一页"
                 @click.prevent="gotoPage(data.current + 1)"
                 >&gt;</a
               >
               <a
                 :class="{ undisable: !data.hasNext }"
                 href="#"
                 title="末页"
                 @click.prevent="gotoPage(data.pages)"
                 >末</a
               >
               <div class="clear" />
             </div>
           </div>
           <!-- 公共分页 结束 -->
         </section>
       </section>
       <!-- /课程列表 结束 -->
      </div>
      </template>
      

    03 讲师详情功能.png04 课程列表功能.png05 课程详情功能.png06 整合阿里云播放器.png