在线教育day7

任务:

  • 添加课程前端实现

  • 课程分类列表显示(树形)

  • 课程管理模块需求

  • 添加课程基本信息功能


1. 课程分类管理实现

  1. 修改路由;
    在这里插入图片描述

  2. 添加路由对应的vue页面;

    save.vue页面进行文件上传:将excel文件上传到数据库中。 用到element-ui上传组件。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  3. 测试
    在这里插入图片描述在这里插入图片描述


2. 课程列表功能(树形显示)

2.2 前端

  1. 添加路由
  2. subject.js调用后端接口
    在这里插入图片描述
  3. list.vue
<template>
  <div class="app-container">
    <el-input v-model="filterText" placeholder="Filter keyword" style="margin-bottom:30px;" />

    <el-tree
      ref="tree2"
      :data="data2"
      :props="defaultProps"
      :filter-node-method="filterNode"
      class="filter-tree"
      default-expand-all
    />

  </div>
</template>

<script>
import subject from '@/api/edu/subject'
export default {

  data() {
    return {
      filterText: '',
      data2: [],
      defaultProps: {
        children: 'children',
        label: 'title'
      }
    }
  },
  watch: {
    filterText(val) {
      this.$refs.tree2.filter(val)
    }
  },

  created(){
    this.getAllSubjectList()
  },

  methods: {
    getAllSubjectList() {
        subject.getSubjectList()
               .then(response => {
                 this.data2 = response.data.list
               })
               .error(error => {

               })
    },

    filterNode(value, data) {
      if (!value) return true
      return data.title.toLowerCase().indexOf(value.toLowerCase()) !== -1
    }
  }
}
</script>

重要代码:
在这里插入图片描述
在这里插入图片描述

这里复制的时候,把watch方法复制到methods里面去了,导致界面出现问题,排查浪费了不少时间

2.1 后端

要点在于返回特定格式数据。

  1. 建立2个实体类:分别表示一级分类和二级分类
    在这里插入图片描述
    在这里插入图片描述
  2. 建立2个实体类的关系
    在这里插入图片描述
    3. controller
    在这里插入图片描述
    4. ServiceImpl(重点)
@Service
public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {

    //添加课程分类
    @Override
    public void saveSubject(MultipartFile file, EduSubjectService eduSubjectService) {
        try{
            //得到文件的输入流
            InputStream in = file.getInputStream();
            //调用方法进行读取
            EasyExcel.read(in, SubjectData.class, new SubjectExcelListener(eduSubjectService)).sheet().doRead();

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //课程分类列表(树形)
    @Override
    public List<OneSubject> getAllOneTwoSubject() {

        //1. 从edu_subject表中查询出所有的一级分类:parent_id = '0'
        QueryWrapper<EduSubject> wrapperOne = new QueryWrapper<>();
        wrapperOne.eq("parent_id", '0');
        List<EduSubject> oneSubjectList = baseMapper.selectList(wrapperOne);
        System.out.println("一级目录:"+oneSubjectList.size());

        //2.edu_subject表中查询出所有的二级分类: parent_id != '0'
        QueryWrapper<EduSubject> wrapperTwo = new QueryWrapper<>();
        wrapperTwo.ne("parent_id", '0');
        List<EduSubject> twoSubjectList = baseMapper.selectList(wrapperTwo);

        //3.创建集合,用来返回最终的数据
        List<OneSubject> finalSubjectList = new ArrayList<>();

        /******************************** 4.封装一级分类 ***************************/
        //将 oneSubjectList(即List<EduSubject>)  ----->  转换成List<OneSubject>
        for(int i = 0; i < oneSubjectList.size(); i++){

            //得到每个oneSubjectList对象
            EduSubject eduSubject = oneSubjectList.get(i);
            //将eduSubject的值获取出来,放到OneSubject对象里面
            OneSubject oneSubject = new OneSubject();

            //oneSubject.setId(eduSubject.getId());
            //oneSubject.setTitle(eduSubject.getId());
            /** 用spring中的工具类进行复制**/
            BeanUtils.copyProperties(eduSubject, oneSubject);

            /********************************** 5.封装二级分类 **********************/
            List<TwoSubject> twoFinalSubjectList = new ArrayList<>();
            for (int j = 0; j < twoSubjectList.size(); j++) {
                //获取每个二级分类
                EduSubject subject = twoSubjectList.get(j);
                if(subject.getParentId().equals(oneSubject.getId())){
                    TwoSubject twoSubject = new TwoSubject();
                    BeanUtils.copyProperties(subject, twoSubject);
                    twoFinalSubjectList.add(twoSubject);
                }
            }
            //把所有的二级分类放到一级分类中
            oneSubject.setChildren(twoFinalSubjectList);

            //添加到List<OneSubject>中
            finalSubjectList.add(oneSubject);
        }

        return finalSubjectList;
    }
}

重要步骤
在这里插入图片描述
注意方法返回值为List< OneSubject >

在这里插入图片描述
在这里插入图片描述
测试:
在这里插入图片描述
测试:
在这里插入图片描述


3. 课程管理模块概述

3.1 课程管理需求

在这里插入图片描述

3.2 课程管理涉及到的表

在这里插入图片描述


3.3 注意事项

在这里插入图片描述


4 课程添加模块

4.1 后端

  1. 自动生成Service,Controller,Entity。
  2. 创建Vo类,用于封装表单提交的数据—因为表单中包含几种对应的实体类。
  3. Controller中添加课程。
    在这里插入图片描述
  4. Service进行实际的课程信息第实际添加::1. 课程表添加信息;2. 课程描述表添加信息。
    在这里插入图片描述

Bug: 添加信息后,课程表和课程描述表信息相互独立,没有联系。
解决: 将课程描述表的id设置为课程表的id

具体做法:

1. 修改主键生成策略:
在这里插入图片描述
2. 修改Service

在这里插入图片描述

4.2 前端

1. 添加路由
在这里插入图片描述

  1. 添加课程的页面: info.vue,chapter.vue,publish.vue
  2. js调用后台接口
    在这里插入图片描述
  3. publish.vue中调用接口

bug: 添加课程后,紧接着跳转到添加章节页面,根据课程id添加章节,所以要把课程id传过去,所以在添加课程的后台接口中要返回课程id
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


下拉列表显示所有讲师

前端调用后端接口,前端用Element-ui实现,后端查询所有讲师接口前面已经写好。
在这里插入图片描述
二级联动添加二级课程分类

用下拉列表实现。

  • 第一次进入页面,显示所有一级列表,二级列表为空。

  • 当选中某一个一级列表时,显示一级列表对应的二级列表。

实现:后台在做一级分类和二级分类时已经提供了1个接口,可以返回所有的一级分类,而返回的一级分类的实体类中包含一个成员:二级分类,所以我们这里可以不用写接口,直接调用之前写好的接口就可以。

已经写好的接口:
在这里插入图片描述
info.vue

<template>

  <div class="app-container">

    <h2 style="text-align: center;">发布新课程</h2>

    <el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="填写课程基本信息"/>
      <el-step title="创建课程大纲"/>
      <el-step title="最终发布"/>
    </el-steps>

<el-form label-width="120px">

  <el-form-item label="课程标题">
    <el-input v-model="courseInfo.title" placeholder=" 示例:机器学习项目课:从基础到搭建项目视频课程。专业名称注意大小写"/>
  </el-form-item>

  <!-- 所属分类 TODO -->
   <el-form-item label="课程分类">
  <el-select
    v-model="courseInfo.subjectParentId"
    placeholder="一级分类" @change="subjectLevelOneChanged">
    <el-option
      v-for="subject in subjectOneList"
      :key="subject.id"
      :label="subject.title"
      :value="subject.id"/>
  </el-select>

  <!-- 二级分类 -->
<el-select v-model="courseInfo.subjectId" placeholder="二级分类">
  <el-option
    v-for="subject in subjectTwoList"
    :key="subject.id"
    :label="subject.title"
    :value="subject.id"/>
</el-select>
</el-form-item>

  <!-- 课程讲师 TODO -->
  <!-- 课程讲师 -->
<el-form-item label="课程讲师">
  <el-select
    v-model="courseInfo.teacherId"
    placeholder="请选择">
    <el-option
      v-for="teacher in teacherList"
      :key="teacher.id"
      :label="teacher.name"
      :value="teacher.id"/>
  </el-select>
</el-form-item>

  <el-form-item label="总课时">
    <el-input-number :min="0" v-model="courseInfo.lessonNum" controls-position="right" placeholder="请填写课程的总课时数"/>
  </el-form-item>

  <!-- 课程简介 TODO -->
  <el-form-item label="课程简介">
    <el-input v-model="courseInfo.description" placeholder=""/>
  </el-form-item>

  <!-- 课程封面 TODO -->

  <el-form-item label="课程价格">
    <el-input-number :min="0" v-model="courseInfo.price" controls-position="right" placeholder="免费课程请设置为0元"/></el-form-item>

  <el-form-item>
    <el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存并下一步</el-button>
  </el-form-item>
</el-form>
  </div>
</template>


<script>
import course from '@/api/edu/course'
import subject from '@/api/edu/subject'
export default {
  data() {
    return {
      saveBtnDisabled: false,  
      courseInfo:{
          title: '',
          subjectId:'',//二级分类id
          subjectParentId:'',//一级分类id
          teacherId: '', 
          lessonNum: 0,
          description: '',
          cover: '',
          price: 0
      },
      //封装所有讲师数据
      teacherList:[],
      //一级分类列表
      subjectOneList:[],
      //二级分类列表
      subjectTwoList:[]
    }
  },

  created() {
    //初始化所有讲师
    this.getListTeacher()
    //初始化一级分类
    this.getOneSubject()
  },

  methods: {
    //点击某个一级分类,会触发change时间,会显示对应的二级分类
    subjectLevelOneChanged(value){
        //value为一级分类的id值,事件发生时,会自动传过来id值,不同自己在上面中写个参数传递id值
        //alert(value)
        //遍历所有的一级分类,如果选中的id=一级id,直接获取到当前一级分类的子分类(二级分类列表)
        for(var i = 0; i < this.subjectOneList.length; i++){
            var oneSubject = this.subjectOneList[i]
            if(oneSubject.id === value){
                //从一级分类中获取所有的二级分类
                this.subjectTwoList = oneSubject.children
            }
        }
    },

    //查询所有的一级分类
    getOneSubject(){
        console.log("dfsfds")
        subject.getSubjectList()
               .then(response => {
                    this.subjectOneList = response.data.list
                })
                 
    },


    saveOrUpdate() {
      course.addCourseInfo(this.courseInfo)
            .then(response =>{
                //提示添加成功
                    this.$message({
                        type: 'success',
                        message: '添加课程信息成功!'
                    })
                //跳转到添加章节页面
                this.$router.push({path:'/course/chapter/' + response.data.courseId})
            })
       
      this.$router.push({ path: '/course/chapter/1' })
    },
    
    //查询所有讲师
    getListTeacher(){
        course.getListTeacher()
              .then(response =>{
                    this.teacherList = response.data.item
              })
               
    }
  }
}
</script>
  • 在info.vue中加入下拉列表:
    在这里插入图片描述
    - 重要代码
    在这里插入图片描述
    测试:
    在这里插入图片描述
    bug:比如选择了前端开发,然后选Vue;再选择后端开发,Vue还在,应该清除。

在这里插入图片描述
原因:Vue双向绑定设置了之后,以后不会清空;

解决方法:每次选择一级列表触发事件方法时,在事件方法里面清空二级事件的id值。
在这里插入图片描述


课程封面上传

上传到阿里云OSS,前面上传图像时接口已经写好,这里直接用。这里主要是修改前端。


(完)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值