尚硅谷在线教育七:尚硅谷在线教育项目课程管理相关的开发

1.项目介绍

1.1.项目流程介绍

在这里插入图片描述

1.2项目涉及的一些表

edu_course 课程表:存储课程基本信息
edu_course_description 课程简介表 存储课程简介信息
edu_chapter 课程章节表 存储课程章节信息
edu_video 课程小结表 存储章节里面的小结信息
edu_teacher 讲师表
edu_subject 分类表

表之间的关系
在这里插入图片描述

2 编辑课程基本信息

注意问题

  1. 创建VO实体类用于表单数据的封装
  2. 表单提交的数据添加到数据库,对两张表进行添加(课程表和课程描述表)
  3. 把讲师和分类使用下来列表展示
    课程分类做成二级联动的效果

2.1创建VO类封装表单提交的数据

在vo下创建CourseInfoVo类

@Data
@ApiModel(value = "课程基本信息", description = "编辑课程基本信息的表单对象")
public class CourseInfoVo {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "课程ID")
    private String id;

    @ApiModelProperty(value = "课程讲师ID")
    private String teacherId;

    @ApiModelProperty(value = "课程专业ID")
    private String subjectId;

    @ApiModelProperty(value = "课程标题")
    private String title;

    @ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
    private BigDecimal price;

    @ApiModelProperty(value = "总课时")
     private Integer lessonNum;

    @ApiModelProperty(value = "课程封面图片路径")
    private String cover;

    @ApiModelProperty(value = "课程简介")
    private String description;
}

2.2 Conroller层

@RestController
@RequestMapping("/eduservice/course")
@Api(tags = "课程相关的接口")
public class EduCourseController {

    @Autowired
    private EduCourseService eduCourseService;

    @ApiOperation("添加课程信息")
    @PostMapping("/addCourseInfo")
    public Res addCourseInfo(@RequestBody CourseInfoVo courseInfoVo)
    {
        eduCourseService.saveCourseInfo(courseInfoVo);

        return Res.ok();
    }
}

2.3service层

@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {

    @Autowired
    private EduCourseMapper eduCourseMapper;

    @Autowired
    private EduCourseDescriptionMapper courseDescriptionMapper;

    @Override
    public void saveCourseInfo(CourseInfoVo courseInfoVo) {
        ///1.向课程表中添加课程基本信息
        EduCourse eduCourse = new EduCourse();
        //进行对象装换
        BeanUtils.copyProperties(courseInfoVo,eduCourse);
//        int insert = eduCourseMapper.insert(eduCourse);
        int insert = baseMapper.insert(eduCourse);
        if(insert<0)
        {
            throw  new GuliException(20001,"添加课程信息失败");
        }
        String id = eduCourse.getId();
        //向课程描述表中加数据
        EduCourseDescription eduCourseDescription = new EduCourseDescription();
        eduCourseDescription.setDescription(courseInfoVo.getDescription());
        eduCourseDescription.setId(id);
        courseDescriptionMapper.insert(eduCourseDescription);
    }
}

2.4 编辑课程基本信息

2.4.1添加路由

在route/index.js下添加路由信息
在这里插入图片描述

 {
    path: '/course',
    component: Layout,
    redirect: '/course/list',
    name: '课程管理',
    meta: { title: '课程管理', icon: 'example' },
    children: [
      {
        path: 'list',
        name: '课程列表',
        component: () => import('@/views/edu/course/list'),
        meta: { title: '课程列表', icon: 'table' }
      },
      {
        path: 'info',
        name: '添加课程',
        component: () => import('@/views/edu/course/info'),
        meta: { title: '添加课程', icon: 'tree' }
      },
      {
        path: 'info/:id',
        name: '编辑课程基本信息',
        component: () => import('@/views/edu/course/info'),
        meta: { title: '编辑课程基本信息', icon: 'tree' },
        hidden: true
      },
      {
        path: 'chapter/:id',
        name: '编辑课程大纲',
        component: () => import('@/views/edu/course/chapter'),
        meta: { title: '编辑课程大纲', icon: 'tree' },
        hidden: true
      },
      {
        path: 'publish/:id',
        name: '发布课程',
        component: () => import('@/views/edu/course/publish'),
        meta: { title: '发布课程', icon: 'tree' },
        hidden: true
      }   
    ]
  },

2.4.2 根据路由信息创建响应的文件

在src/views/edu下创建文件夹course,并在course文件夹下分别创建名为chapter.vue,info.vue,list.vue,publish.vue
在这里插入图片描述

2.4.3编写表单页面,实现接口调用

views/edu/course/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 -->
  <!-- 课程讲师 TODO -->
  <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.descriptions" 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="next">保存并下一步</el-button> -->
  </el-form-item>
</el-form>

    <el-form label-width="120px">
      <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'
export default {
  data() {
    return {
      saveBtnDisabled: false, // 保存按钮是否禁用,
      courseInfo:{}
    }
  },
  created() {
    console.log('info created')
  },
  methods: {
    saveOrUpdate() {
      course.addCourseInfo(this.courseInfo)
      .then(response=>{
           //提示信息
            this.$message({
                        type: 'success',
                        message: '添加课程信息成功!'
                    });
            //路由跳转
             this.$router.push({ path: '/course/chapter/1' })        
      })
      
      //跳转到第二步
    //   this.$router.push({ path: '/course/chapter/1' })
    }
  }
}
</script>

由于添加课程id需要课程id,需要返回id
在这里插入图片描述
servic返回课程id
在这里插入图片描述
前端info.vue更改
在这里插入图片描述

2.4.4讲师下拉列表的显示

效果如下:
在这里插入图片描述
在添加课程的时候有讲师下拉列表

  1. 在api/edu/course下添加路由
   getListTeacher(){
        return request({
            url:"/eduservice/teacher/findAll",
            menubar:"get"
        })
    }
  1. 在views/edu/course/info.vue中添加下拉列表模块

<!-- 课程讲师 -->
<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>

并添加响应的数据和方法
在这里插入图片描述

2.4.5分类显示

首次进入页面显示所有的一级分类,二级分类为空,选择某个一级分类后,显示一级分类里面对应的二级分类
views/edu/course/info添加分类显示代码
在这里插入图片描述
data添加一级分类和二级
在这里插入图片描述
对应的方法
在这里插入图片描述

2.4.6添加课程信息前端完善添加封面

组件
在这里插入图片描述
方法
在这里插入图片描述

2.4.7富文本编辑器

  1. 复杂文本编辑器相关的组件到文件目录里面
    在这里插入图片描述
    在这里插入图片描述
  2. 在 guli-admin/build/webpack.dev.conf.js 中添加配置
    在这里插入图片描述
  3. 找到index.html引入js文件
<script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>
<script src=<%= BASE_URL %>/tinymce4.7.5/langs/zh_CN.js></script>

在这里插入图片描述
4. info.vue使用文本编辑器组件
在这里插入图片描述
进行替换
在这里插入图片描述
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 subjectNestedList"
      :key="subject.id"
      :label="subject.title"
      :value="subject.id"/>
  </el-select>
  
<!-- 二级分类 -->
<el-select v-model="courseInfo.subjectId" placeholder="二级分类">
  <el-option
    v-for="subject in subSubjectList"
    :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="课程简介">
    <tinymce :height="300" v-model="courseInfo.description"/>
</el-form-item>
 <!-- <el-form-item label="课程简介">
    <el-input v-model="courseInfo.descriptions" placeholder=" " />
  </el-form-item> -->

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

<!-- 课程封面-->
<el-form-item label="课程封面">
  <el-upload
    :show-file-list="false"
    :on-success="handleAvatarSuccess"
    :before-upload="beforeAvatarUpload"
    :action="BASE_API+'/eduoss/fileoss'"
    class="avatar-uploader">
    <img :src="courseInfo.cover">
  </el-upload>
</el-form-item>

  <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="next">保存并下一步</el-button> -->
  </el-form-item>
</el-form>

    <el-form label-width="120px">
      <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'
import Tinymce from '@/components/Tinymce' //引入组件
export default {
   components: {  //声明组件
     Tinymce
      },
  data() {
    return {
      saveBtnDisabled: false, // 保存按钮是否禁用,
      courseInfo:{
        subjectId:' ',
        cover:'/static/01.jpg'
      },
      BASE_API: process.env.BASE_API,
      teacherList:[],
      subjectNestedList: [],//一级分类列表
      subSubjectList: []//二级分类列表
    }
  },
  created() {
    // console.log('info created')
    this.getTeacherList()
    this.getOneSubject()
  },
  methods: {
    //点击某个一级分类,触发change 显示对应的二级分类
    subjectLevelOneChanged(value)//value就是一级分类id
    {
      //遍历所有分类 包括一级和二级
      for(let i = 0; i <this.subjectNestedList.length;i++)
      {
        //当前一级分类的id和显示数据的一级分类id一致
        if(value === this.subjectNestedList[i].id)
       {
         //得到对应的二级分类
         this.subSubjectList=this.subjectNestedList[i].children;
         //把二级分类id值情况
       this.courseInfo.subjectId=' '
       }
      }
  

    },
    //上传之前
    beforeAvatarUpload(file)
    {
      const isJPG = file.type === 'image/jpeg'
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 格式!')
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!')
      }
      return isJPG && isLt2M

    },
    //上传封面成功
    handleAvatarSuccess(res,file){
        this.courseInfo.cover=res.data.url
    },
    getOneSubject(){
      subject.getSubjectList()
      .then(response =>{
        this.subjectNestedList=response.data.list

      }

      )
    },
        getTeacherList(){
       course.getListTeacher()
       .then(respones=>{
         this.teacherList=respones.data.teacherList
       })
    },
    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' })
    }
  }
}
</script>
<style scoped>
.tinymce-container {
  line-height: 29px;
}
</style>

2.5编辑课程大纲后台

  1. 创建两个实体类,章节和小节,章节里面使用list表示小节
    在domian包下建一个名为chapter的包,chapter包下建两个名为ChapterVO和VideoVo的实体类
    VideoVo
import lombok.Data;

@Data
//小节实体类
public class VideoVo {
    private String id;

    private String title;
}

chapterVo

import java.util.ArrayList;
import java.util.List;

@Data
public class ChapterVo {
    private String id;

    private String title;

    //表示小结
    private List<VideoVo> children=new ArrayList<>();
}

  1. controller层
@RestController
@RequestMapping("/eduservice/chapter")
@Api(tags = "课程章节管理")
@CrossOrigin
public class EduChapterController {

    @Autowired
    private EduChapterService eduChapterService;

    //根据课程id查到课程章节信息
    @ApiOperation("得到所有的章节信息")
    @GetMapping("/getChapterView/{courseId}")
    public Res getChapterView(@PathVariable String courseId)
    {
     List<ChapterVo> chapterVoList= eduChapterService.getCourseInfoById(courseId);
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("chapterList",chapterVoList);
        return Res.ok().data(hashMap);
    }
}
  1. service层
    @Autowired
    private EduChapterMapper eduChapterMapper;

    @Autowired
    private EduVideoMapper eduVideoMapper;

    //根据课程id查到课程章节信息
    @Override
    public List<ChapterVo> getCourseInfoById(String courseId) {

        //根据课程id查找所的章节信息
        QueryWrapper<EduChapter> eduChapterQueryWrapper = new QueryWrapper<>();
        eduChapterQueryWrapper.eq("course_id",courseId);
        List<EduChapter> eduChapterList = eduChapterMapper.selectList(eduChapterQueryWrapper);
        //查找课程id查找所有的小节信息
        QueryWrapper<EduVideo> eduVideoQueryWrapper = new QueryWrapper<>();
        eduVideoQueryWrapper.eq("course_id",courseId);
        List<EduVideo> videoList = eduVideoMapper.selectList(eduVideoQueryWrapper);
        //存放所有的章节信息
        ArrayList<ChapterVo> chapterVoArrayList = new ArrayList<>();
        //变量所有章节信息
        for(EduChapter eduChapter:eduChapterList)
        {
            ChapterVo chapterVo = new ChapterVo();
            BeanUtils.copyProperties(eduChapter,chapterVo);
            String id = eduChapter.getId();
            //存储;对应章节的所有小节信息
            ArrayList<VideoVo> videoVoArrayList = new ArrayList<>();
            //获取所有小节信息
            for(EduVideo eduVideo:videoList)
            {
                //小节的章节id和章节id一致
                if(id.equals(eduVideo.getChapterId()))
                {
                    VideoVo videoVo = new VideoVo();
                    BeanUtils.copyProperties(eduVideo,videoVo);
                    videoVoArrayList.add(videoVo);
                }
            }
            chapterVo.setChildren(videoVoArrayList);
            chapterVoArrayList.add(chapterVo);
        }
      return chapterVoArrayList;
    }

3. 编辑课程大纲

3.1编辑课程大纲前端

3.1.1 创建路由信息

在src/api/edu下创建chapter.js
在这里插入图片描述

import request from '@/utils/request'

export default{
    getChapterVideo(courseId){
        return request({
            url:`/eduservice/chapter/${courseId}`,
            method:"get"
        })
    }

}    

edu/course/chapter.vue

<template>
  <div class="app-container">
    <h2 style="text-align: center;">发布新课程</h2>
    <el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="填写课程基本信息"/>
      <el-step title="创建课程大纲"/>
      <el-step title="提交审核"/>
    </el-steps>
    <!-- 章节 -->
<ul class="chanpterList">
    <li
        v-for="chapter in chapterVideoList"
        :key="chapter.id">
        <p>
            {{ chapter.title }}
            <span class="acts">
                <el-button type="text">添加课时</el-button>
                <el-button style="" type="text">编辑</el-button>
                <el-button type="text">删除</el-button>
            </span>
        </p>
        <!-- 视频 -->
        <ul class="chanpterList videoList">
            <li
                v-for="video in chapter.children"
                :key="video.id">
                <p>{{ video.title }}
                    <span class="acts">
                        <el-button type="text">编辑</el-button>
                        <el-button type="text">删除</el-button>
                    </span>
                </p>
            </li>
        </ul>
    </li>
</ul>
<div>
    <el-button @click="previous">上一步</el-button>
    <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
</div>

    <!-- <el-form label-width="120px">
      <el-form-item>
        <el-button @click="previous">上一步</el-button>
        <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
      </el-form-item>
    </el-form> -->
  </div>
</template>
<script>
import chapter from '@/api/edu/chapter.js'
export default {
  data() {
    return {
      saveBtnDisabled: false, // 保存按钮是否禁用
      chapterVideoList:[],
      courseId:' '
    }
  },
  created() {
    if(this.$route.params && this.$route.params.id)
    {
      this.courseId = this.$route.params.id
      //根据id查询所有的章节和小节
      this.getChapterVideos()
    }
  },
  methods: {
    //根据ID查询章节和小结
    getChapterVideos() {
        chapter.getChapterVideo(this.courseId)
        .then(response=>{
          // alter("1")
              this.chapterVideoList=response.data.chapterList
        })
    },
    previous() {
      console.log('previous')
      this.$router.push({ path: '/course/info/1' })
    },
    next() {
      console.log('next')
      this.$router.push({ path: '/course/publish/1' })
    }
  }
}
</script>
<style scoped>
.chanpterList{
    position: relative;
    list-style: none;
    margin: 0;
    padding: 0;
}
.chanpterList li{
  position: relative;
}
.chanpterList p{
  float: left;
  font-size: 20px;
  margin: 10px 0;
  padding: 10px;
  height: 70px;
  line-height: 50px;
  width: 100%;
  border: 1px solid #DDD;
}
.chanpterList .acts {
    float: right;
    font-size: 14px;
}
.videoList{
  padding-left: 50px;
}
.videoList p{
  float: left;
  font-size: 14px;
  margin: 10px 0;
  padding: 10px;
  height: 50px;
  line-height: 30px;
  width: 100%;
  border: 1px dotted #DDD;
}
</style>

3.1.2修改课程基本信息

达到要求
在填写第二步时,点击上一步,把课程基本信息进行回显
在数据回显页面点击保存后,数据进行保存并更新数据库
后台
在EduCourseController.java中定义根据id查询课程信息和修改课程信息的接口

 @ApiOperation("根据ID查询课程基本信息")
    @GetMapping("/getCourseInfo/{id}")
    public Res  getCourseInfoById(@PathVariable String id)
    {
       CourseInfoVo courseInfoVo=eduCourseService.getCourseInfoById(id);
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("courseInfo",courseInfoVo);
        return Res.ok().data(hashMap);
    }

    @ApiOperation("修改课程信息")
    @PostMapping("/updateCourseInfo")
    public Res updateCourseInfo(@RequestBody CourseInfoVo courseInfoVo)
    {
        eduCourseService.updateCourseInfo(courseInfoVo);
        return Res.ok();
    }

在EduCourseServiceImpl中进行实现

   @Override
    public CourseInfoVo getCourseInfoById(String id) {
        CourseInfoVo courseInfoVo = new CourseInfoVo();
        //查询课程表
        EduCourse eduCourse = eduCourseMapper.selectById(id);
        BeanUtils.copyProperties(eduCourse,courseInfoVo);
        //查询描述表
        EduCourseDescription eduCourseDescription = courseDescriptionMapper.selectById(id);
        BeanUtils.copyProperties(eduCourseDescription,courseInfoVo);
        return courseInfoVo;
    }

    //修改课程信息
    @Override
    public void updateCourseInfo(CourseInfoVo courseInfoVo) {
        //修改课程表
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseInfoVo,eduCourse);
        eduCourseMapper.updateById(eduCourse);
        //修改描述表
        EduCourseDescription eduCourseDescription = new EduCourseDescription();
        BeanUtils.copyProperties(courseInfoVo,eduCourseDescription);
        courseDescriptionMapper.updateById(eduCourseDescription);
    }

3.2课程章节的添加、修改和删除

  1. 点击添加按钮 添加章节
  2. 点击添加章节按钮,弹出添加弹框,输入章节信息,点击保存按钮进行添加

3.2.1前端部分

添加按钮以及弹框

<el-button type="text" @click="dialogChapterFormVisible=true">添加章节</el-button>
<!-- 添加和修改章节表单 -->
<el-dialog :visible.sync="dialogChapterFormVisible" title="添加章节">
    <el-form :model="chapter" label-width="120px">
        <el-form-item label="章节标题">
            <el-input v-model="chapter.title"/>
        </el-form-item>
        <el-form-item label="章节排序">
            <el-input-number v-model="chapter.sort" :min="0" controls-position="right"/>
        </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
        <el-button @click="dialogChapterFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveOrUpdate">确 定</el-button>
    </div>
</el-dialog>

以及添加两个字段
在这里插入图片描述

3.2.2章节信息的相关后台代码

controller层

 //添加章节
    @PostMapping("addchapter")
    @ApiOperation("添加章节信息")
    public Res saveChapter(@RequestBody EduChapter eduChapter)
    {
        eduChapterService.save(eduChapter);
        return Res.ok();
    }

    //根据章节id查询
    @GetMapping("/getChapterInfo/{chapterId}")
    @ApiOperation("根据id查询章节信息")
    public Res  getChapterInfoById(@PathVariable("chapterId") String chapterId)
    {
        EduChapter byId = eduChapterService.getById(chapterId);
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("chapter",byId);
        return Res.ok().data(hashMap);
    }
    //修改章节信息
    @PostMapping("/updateChapter")
    @ApiOperation("修改章节信息")
    public Res updateChapter(@RequestBody EduChapter eduChapter)
    {
        eduChapterService.updateById(eduChapter);
        return Res.ok();
    }
    //删除章节信息
    @DeleteMapping("/deleteChapter/{chapterId}")
    @ApiOperation("删除章节信息")
    public Res deleteChapter(@PathVariable String chapterId)
    {
        boolean deleteChapter = eduChapterService.deleteChapter(chapterId);
        return Res.ok();
    }

service层

   //删除章节
    @Override
    public boolean deleteChapter(String chapterId) {
            //根据章节id查询小节,如果删除到数据进行删除
        QueryWrapper<EduVideo> eduVideoQueryWrapper = new QueryWrapper<>();
        eduVideoQueryWrapper.eq("chapter_id",chapterId);
        Integer count = eduVideoMapper.selectCount(eduVideoQueryWrapper);
        //判断
        if(count>0)//查询出小节,不进行删除
        {
                   throw new GuliException(20001,"不能进行删除");
        }
        else {
            int deleteById = eduVideoMapper.deleteById(chapterId);
            return deleteById>0;
        }
    }

前端代码
chapter.vue代码汇总

<template>
  <div class="app-container">
    <h2 style="text-align: center;">发布新课程</h2>
    <el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="填写课程基本信息"/>
      <el-step title="创建课程大纲"/>
      <el-step title="提交审核"/>
    </el-steps>
<el-button type="text" @click="openChapterDiglog()">添加章节</el-button>
    <!-- 章节 -->
<!-- 章节 -->
<ul class="chanpterList">
    <li
        v-for="chapter in chapterVideoList"
        :key="chapter.id">
        <p>
            {{ chapter.title }}
            <span class="acts">
                <el-button type="text">添加课时</el-button>
                <el-button style="" type="text" @click="openEditChapter(chapter.id)">编辑</el-button>
                <el-button type="text" @click="removechapter(chapter.id)">删除</el-button>
            </span>
        </p>
        <!-- 视频 -->
        <ul class="chanpterList videoList">
            <li
                v-for="video in chapter.children"
                :key="video.id">
                <p>{{ video.title }}
                    <span class="acts">
                        <el-button type="text">编辑</el-button>
                        <el-button type="text">删除</el-button>
                    </span>
                </p>
            </li>
        </ul>
    </li>
</ul>
<div>
    <el-button @click="previous">上一步</el-button>
    <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
</div>

<!-- 添加和修改章节表单 -->
<el-dialog :visible.sync="dialogChapterFormVisible" title="添加章节">
    <el-form :model="chapter" label-width="120px">
        <el-form-item label="章节标题">
            <el-input v-model="chapter.title"/>
        </el-form-item>
        <el-form-item label="章节排序">
            <el-input-number v-model="chapter.sort" :min="0" controls-position="right"/>
        </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
        <el-button @click="dialogChapterFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveOrUpdate">确 定</el-button>
    </div>
</el-dialog>

    <!-- <el-form label-width="120px">
      <el-form-item>
        <el-button @click="previous">上一步</el-button>
        <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
      </el-form-item>
    </el-form> -->
  </div>
</template>
<script>
import chapter1 from '@/api/edu/chapter.js'
export default {
  data() {
    return {
      saveBtnDisabled: false, // 保存按钮是否禁用
      chapterVideoList:[],
      courseId:' ',
      dialogChapterFormVisible:false,
      chapter:{//章节信息
          title:'',
          sort:0,
          ju:0
      }
    }
  },
  created() {
    if(this.$route.params && this.$route.params.id)
    {
      this.courseId = this.$route.params.id
      //根据id查询所有的章节和小节
      this.getChapterVideos()
    }
  },
  methods: {
    //修改章节弹框数据回显
    openEditChapter(chapterId)
    {
         //弹框
         this.dialogChapterFormVisible=true
         //调用接口
         chapter1.getChapterById(chapterId)
         .then(response=>{
           this.chapter=response.data.chapter
           this.chapter.ju=1
         })
    },
    //弹出添加章节
    openChapterDiglog(){
         //弹框
         this.dialogChapterFormVisible=true
         //表单数据清空
         this.chapter.title=' '
         this.chapter.sort=0
         this.chapter.ju=2
         this.chapter.id=' '
    },
    saveOrUpdate(){
     if(this.chapter.ju==2)
     {
       this.addChapter()
     }
     else{
       this.updateChapter()
     }
    },
    //修改章节信息
    updateChapter(){
       chapter1.updateChapter(this.chapter)
      .then(response=>{
        //关闭弹框
        this.dialogChapterFormVisible=false
        //提示
        this.$message({
          type: "success",
          message:"修改章节成功"
        })
        //刷新页面
        this.getChapterVideos()
      })

    },
    //添加章节信息
    addChapter(){
        //设置课程id
      this.chapter.courseId=this.courseId
      chapter1.addChapter(this.chapter)
      .then(response=>{
        //关闭弹框
        this.dialogChapterFormVisible=false
        //提示
        this.$message({
          type: "success",
          message:"添加章节成功"
        })
        //刷新页面
        this.getChapterVideos()
      })
    },
    //根据ID查询章节和小结
    getChapterVideos() {
        chapter1.getChapterVideo(this.courseId)
        .then(response=>{
         
              this.chapterVideoList=response.data.chapterList
        })
    },
    //删除章节
    removechapter(chapterId){
       this.$confirm('此操作将永久删除该章节的记录, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                    })
                    .then(() => { //点击确定执行then方法
                        //调用删除方法
                  
                        chapter1.deleteChapter(chapterId)
                        .then(response=>{  //删除成功
                        this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                    this.getChapterVideos()
                        })
                        //回到列表页面
                        this.getChapterVideos()
                    })


    },
    previous() {
      console.log('previous')
      this.$router.push({ path: '/course/info/'+this.courseId })
    },
    next() {
      console.log('next')
      this.$router.push({ path: '/course/publish/'+this.courseId})
    }
  }
}
</script>
<style scoped>
.chanpterList{
    position: relative;
    list-style: none;
    margin: 0;
    padding: 0;
}
.chanpterList li{
  position: relative;
}
.chanpterList p{
  float: left;
  font-size: 20px;
  margin: 10px 0;
  padding: 10px;
  height: 70px;
  line-height: 50px;
  width: 100%;
  border: 1px solid #DDD;
}
.chanpterList .acts {
    float: right;
    font-size: 14px;
}
.videoList{
  padding-left: 50px;
}
.videoList p{
  float: left;
  font-size: 14px;
  margin: 10px 0;
  padding: 10px;
  height: 50px;
  line-height: 30px;
  width: 100%;
  border: 1px dotted #DDD;
}
</style>

chapter.js

import request from '@/utils/request'

export default{

    //得到课程信息
    getChapterVideo(courseId){
        return request({
            url:`/eduservice/chapter/getChapterView/${courseId}`,
            method:"get"
        })
    },
    //添加章节信息
    addChapter(chapter){
        return request({
            url:"/eduservice/chapter//addchapter",
            method:"POST",
            data:chapter
        })
    },
    getChapterById(chapterId){
        return request({
            url:`/eduservice/chapter/getChapterInfo/${chapterId}`,
            method:"GET"
        })
    },
    //修改章节
    updateChapter(chapter)
    {
       return request({
           url:"/eduservice/chapter/updateChapter",
           method:"post",
           data:chapter
       })
    },
    //删除章节信息
    deleteChapter(chapterId)
    {
        return request({
            url:`/eduservice/chapter/deleteChapter/${chapterId}`,
            method:"delete"
        })
    }

}    

3.3章节中的小节信息增加、修改和删除

3.3.1后台

controller层
EduVideoController

@RestController
@RequestMapping("/eduservice/video")
@CrossOrigin
public class EduVideoController {

    @Autowired
    private EduVideoService eduVideoService;

    //添加小节信息
    @PostMapping("/addVideo")
    public Res addVideo(@RequestBody EduVideo eduVideo)
    {
        eduVideoService.save(eduVideo);
        return Res.ok();
    }

    //删除小节信息
    //TOOO 后面此方法需要完善 删除小节的时候同时删除里面的视频
    @DeleteMapping("{id}")
    public Res deleteVideo(@PathVariable("id") String id)
    {
        eduVideoService.removeById(id);
        return Res.ok();
    }
     //修改小节信息
    @PostMapping("/updateVideo")
    public Res updateVideo(@RequestBody EduVideo eduVideo)
    {
        eduVideoService.updateById(eduVideo);
        return Res.ok();
    }
    //通过id查询小节信息
    @GetMapping("/getVideo/{id}")
    public Res getVideo(@PathVariable("id") String id)
    {
        EduVideo eduVideo = eduVideoService.getById(id);
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("video",eduVideo);
        return Res.ok().data(hashMap);
    }
}

3.3.2前端

小节信息的路由信息
在src/api/edu下创建一个video.vue并填入相应的路由信息
在这里插入图片描述

import request from '@/utils/request'

export default{

    //添加小节
    addVideo(video)
    {
        return request({
            url: "/eduservice/video/addVideo",
            method: 'POST',
            data:video
        })
    },
    //修改小节
    updateVideo(video) {
        return request({
            url:"/eduservice/video/updateVideo",
            method: 'POST',
            data:video
        })
    },
    //删除小节
    deleteVideo(id){
        return request({
            url:"/eduservice/video/"+id,
            method:"delete"
        })
    },
    //通过id查询小节信息
    getVideoById(id) {
        return request({
            url:"/eduservice/video/getVideo/"+id,
            method:"get"
        })
    }
}

在chapter.vue中添加响应的data
在这里插入图片描述
添加小节信息的相关函数

    //==========添加小节的操作=========================
       openEditVideo(id)
    {
         //弹框
         this.dialogVideoFormVisible=true
         //调用接口
          video1.getVideoById(id)
          .then(response =>{
            this.video=response.data.video
             this.video.ju=1
          })
        // this.dialogChapterFormVisible=true
    },
             //添加小节的弹框
             openVideo(chapterId)
             {
                this.video.title='',
                this.video.sort=0,
                this.video.free==0,
                this.video.videoSourceId=''
                 //弹框
                 this.dialogVideoFormVisible=true
                    //设置章节id
                    this.video.chapterId=chapterId
             },
             //添加小节信息
            addVideo()
            {
                //设置课程id
                this.video.courseId=this.courseId
                this.video.id=""
                video1.addVideo(this.video)
                .then(response=>{
                    //关闭弹框
                    this.dialogVideoFormVisible=false
                    //提示信息
                    this.$message({
                        type:"success",
                        message:"添加小节成功"
                    });
                    this.getChapterVideos() 
                })
                this.getChapterVideos()
            },
          updateVideo(){
              video1.updateVideo(this.video)
              .then(response=>{
                 //关闭弹框
                    this.dialogVideoFormVisible=false
                    //提示信息
                    this.$message({
                        type:"success",
                        message:"修改小节成功"
                    });
                    this.getChapterVideos() 
              })
          },
         saveOrUpdateVideo()
         {
           if(this.video.ju==1)
           this.updateVideo()
           else
             this.addVideo()
             this.video.ju=0
         },
         //删除小节
         removeVideo(id) {
          this.$confirm('此操作将永久删除该小节的记录, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                    })
                    .then(() => { //点击确定执行then方法
                        //调用删除方法
                  
                        video1.deleteVideo(id)
                        .then(response=>{  //删除成功
                        this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                    this.getChapterVideos()
                        })
                        //回到列表页面
                        this.getChapterVideos()
                    })
         },    

chapter.vue的总体代码

<template>
  <div class="app-container">
    <h2 style="text-align: center;">发布新课程</h2>
    <el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="填写课程基本信息"/>
      <el-step title="创建课程大纲"/>
      <el-step title="提交审核"/>
    </el-steps>
<el-button type="text" @click="openChapterDiglog()">添加章节</el-button>
    <!-- 章节 -->
<!-- 章节 -->
<ul class="chanpterList">
    <li
        v-for="chapter in chapterVideoList"
        :key="chapter.id">
        <p>
            {{ chapter.title }}
            <span class="acts">
                <el-button type="text" @click="openVideo(chapter.id)">添加课时</el-button>
                <el-button style="" type="text" @click="openEditChapter(chapter.id)">编辑</el-button>
                <el-button type="text" @click="removechapter(chapter.id)">删除</el-button>
            </span>
        </p>
        <!-- 视频 -->
        <ul class="chanpterList videoList">
            <li
                v-for="video in chapter.children"
                :key="video.id">
                <p>{{ video.title }}
                    <span class="acts">
                        <el-button type="text"  @click="openEditVideo(video.id)">编辑</el-button>
                        <el-button type="text" @click="removeVideo(video.id)">删1除</el-button>
                    </span>
                </p>
            </li>
        </ul>
    </li>
</ul>
<div>
    <el-button @click="previous">上一步</el-button>
    <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
</div>

<!-- 添加和修改章节表单 -->
<el-dialog :visible.sync="dialogChapterFormVisible" title="添加章节">
    <el-form :model="chapter" label-width="120px">
        <el-form-item label="章节标题">
            <el-input v-model="chapter.title"/>
        </el-form-item>
        <el-form-item label="章节排序">
            <el-input-number v-model="chapter.sort" :min="0" controls-position="right"/>
        </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
        <el-button @click="dialogChapterFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveOrUpdate">确 定</el-button>
    </div>
</el-dialog>
<!-- 添加和修改课时表单 -->
<el-dialog :visible.sync="dialogVideoFormVisible" title="添加课时">
  <el-form :model="video" label-width="120px">
    <el-form-item label="课时标题">
      <el-input v-model="video.title"/>
    </el-form-item>
    <el-form-item label="课时排序">
      <el-input-number v-model="video.sort" :min="0" controls-position="right"/>
    </el-form-item>
    <el-form-item label="是否免费">
      <el-radio-group v-model="video.free">
        <el-radio :label="true">免费</el-radio>
        <el-radio :label="false">默认</el-radio>
      </el-radio-group>
    </el-form-item>
    <el-form-item label="上传视频">
      <!-- TODO -->
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button @click="dialogVideoFormVisible = false">取 消</el-button>
    <el-button :disabled="saveVideoBtnDisabled" type="primary" @click="saveOrUpdateVideo">确 定</el-button>
  </div>
</el-dialog>

    <!-- <el-form label-width="120px">
      <el-form-item>
        <el-button @click="previous">上一步</el-button>
        <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
      </el-form-item>
    </el-form> -->
  </div>
</template>
<script>
import chapter1 from '@/api/edu/chapter.js'
import video1 from '@/api/edu/video.js'
export default {
  data() {
    return {
      saveBtnDisabled: false, // 保存按钮是否禁用
      chapterVideoList:[],
      courseId:' ',
      dialogChapterFormVisible:false,//章节弹框
      dialogVideoFormVisible:false,//小节弹框
      chapter:{//章节信息
          title:'',
          sort:0,
          ju:0
      },
      video:{
           title: '',
           sort: 0,
           free: 0,
           videoSourceId: '',
           ju:0,
           id:''
      }
    }
  },
  created() {
    if(this.$route.params && this.$route.params.id)
    {
      this.courseId = this.$route.params.id
      //根据id查询所有的章节和小节
      this.getChapterVideos()
    }
  },
  methods: {
      //==========添加小节的操作=========================
       openEditVideo(id)
    {
         //弹框
         this.dialogVideoFormVisible=true
         //调用接口
          video1.getVideoById(id)
          .then(response =>{
            this.video=response.data.video
             this.video.ju=1
          })
        // this.dialogChapterFormVisible=true
    },
             //添加小节的弹框
             openVideo(chapterId)
             {
                this.video.title='',
                this.video.sort=0,
                this.video.free==0,
                this.video.videoSourceId=''
                 //弹框
                 this.dialogVideoFormVisible=true
                    //设置章节id
                    this.video.chapterId=chapterId
             },
             //添加小节信息
            addVideo()
            {
                //设置课程id
                this.video.courseId=this.courseId
                this.video.id=""
                video1.addVideo(this.video)
                .then(response=>{
                    //关闭弹框
                    this.dialogVideoFormVisible=false
                    //提示信息
                    this.$message({
                        type:"success",
                        message:"添加小节成功"
                    });
                    this.getChapterVideos() 
                })
                this.getChapterVideos()
            },
          updateVideo(){
              video1.updateVideo(this.video)
              .then(response=>{
                 //关闭弹框
                    this.dialogVideoFormVisible=false
                    //提示信息
                    this.$message({
                        type:"success",
                        message:"修改小节成功"
                    });
                    this.getChapterVideos() 
              })
          },
         saveOrUpdateVideo()
         {
           if(this.video.ju==1)
           this.updateVideo()
           else
             this.addVideo()
             this.video.ju=0
         },
         //删除小节
         removeVideo(id) {
          this.$confirm('此操作将永久删除该小节的记录, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                    })
                    .then(() => { //点击确定执行then方法
                        //调用删除方法
                  
                        video1.deleteVideo(id)
                        .then(response=>{  //删除成功
                        this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                    this.getChapterVideos()
                        })
                        //回到列表页面
                        this.getChapterVideos()
                    })
         },    
      //==========添加章节的操作====================
    //修改章节弹框数据回显
    openEditChapter(chapterId)
    {
         //弹框
         this.dialogChapterFormVisible=true
         //调用接口
         chapter1.getChapterById(chapterId)
         .then(response=>{
           this.chapter=response.data.chapter
           this.chapter.ju=1
         })
    },
    //弹出添加章节
    openChapterDiglog(){
         //弹框
         this.dialogChapterFormVisible=true
         //表单数据清空
         this.chapter.title=' '
         this.chapter.sort=0
         this.chapter.ju=2
         this.chapter.id=' '
    },
    saveOrUpdate(){
     if(this.chapter.ju==2)
     {
       this.addChapter()
     }
     else{
       this.updateChapter()
     }
    },
    //修改章节信息
    updateChapter(){
       chapter1.updateChapter(this.chapter)
      .then(response=>{
        //关闭弹框
        this.dialogChapterFormVisible=false
        //提示
        this.$message({
          type: "success",
          message:"修改章节成功"
        })
        //刷新页面
        this.getChapterVideos()
      })

    },
    //添加章节信息
    addChapter(){
        //设置课程id
      this.chapter.courseId=this.courseId
      chapter1.addChapter(this.chapter)
      .then(response=>{
        //关闭弹框
        this.dialogChapterFormVisible=false
        //提示
        this.$message({
          type: "success",
          message:"添加章节成功"
        })
        //刷新页面
        this.getChapterVideos()
      })
    },
    //根据ID查询章节和小结
    getChapterVideos() {
        chapter1.getChapterVideo(this.courseId)
        .then(response=>{
         
              this.chapterVideoList=response.data.chapterList
        })
    },
    //删除章节
    removechapter(chapterId){
       this.$confirm('此操作将永久删除该章节的记录, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                    })
                    .then(() => { //点击确定执行then方法
                        //调用删除方法
                  
                        chapter1.deleteChapter(chapterId)
                        .then(response=>{  //删除成功
                        this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                    this.getChapterVideos()
                        })
                        //回到列表页面
                        this.getChapterVideos()
                    })
    },
    previous() {
      console.log('previous')
      this.$router.push({ path: '/course/info/'+this.courseId })
    },
    next() {
      console.log('next')
      this.$router.push({ path: '/course/publish/'+this.courseId})
    }
  }
}
</script>
<style scoped>
.chanpterList{
    position: relative;
    list-style: none;
    margin: 0;
    padding: 0;
}
.chanpterList li{
  position: relative;
}
.chanpterList p{
  float: left;
  font-size: 20px;
  margin: 10px 0;
  padding: 10px;
  height: 70px;
  line-height: 50px;
  width: 100%;
  border: 1px solid #DDD;
}
.chanpterList .acts {
    float: right;
    font-size: 14px;
}
.videoList{
  padding-left: 50px;
}
.videoList p{
  float: left;
  font-size: 14px;
  margin: 10px 0;
  padding: 10px;
  height: 50px;
  line-height: 30px;
  width: 100%;
  border: 1px dotted #DDD;
}
</style>

3.4课程最终发布信息确认

3.4.1 后台

  1. 在eduSubjectController添加查询发布信息的接口
    @GetMapping("/getAllSubject")
    @ApiOperation("得到所有课程的分类信息")
    public Res getAllSubject()
    {
      List<OneSubject> list= eduSubjectService.getOneTwoSubject();
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("list",list);
        return Res.ok().data(hashMap);
    }
  1. 实现查询发布信息的接口
   @Override
    public List<CoursePublishVo> getCoursePublish(String id) {
        return eduCourseMapper.getCoursePublishInfo(id);
    }
  1. mapper层实现发布信息的查询
  @Select("select ec.id,ec.title,ec.price,ec.lesson_num,et.name as teacherName,es1.title as subjectLevelOne ,es2.title as subjectLevelTwo,ec.cover from edu_course ec " +
            "LEFT JOIN edu_course_description ed on ec.id=ed.id " +
            "LEFT JOIN edu_teacher et on ec.teacher_id=et.id " +
            "LEFT JOIN edu_subject es1 on ec.subject_id=es1.id " +
            "LEFT JOIN edu_subject es2 on ec.subject_parent_id=es2.id where ec.id=#{id}")
    public List<CoursePublishVo> getCoursePublishInfo(String id);

3.4.2前端实现

  1. 在api/edu/course.js中添加路由信息
getpublishCourses() {
      course1.getPublishCourseInfo(this.courseId)
      .then(response =>{
        console.log(response)
        this.coursePublish=response.data.coursePublish[0]
      })
    }
  1. views/edu/course/publish.vue
<template>
  <div class="app-container">

   <h2 style="text-align: center;">发布新课程</h2>
    <el-steps :active="3" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="填写课程基本信息"/>
      <el-step title="创建课程大纲"/>
      <el-step title="发布课程"/>
    </el-steps>
    <div class="ccInfo">
      <img :src="coursePublish.cover">
      <div class="main">
        <h2>{{ coursePublish.title }}</h2>
        <p class="gray"><span>{{ coursePublish.lessonNum }}课时</span></p>
        <p><span>所属分类:{{ coursePublish.subjectLevelOne }}{{ coursePublish.subjectLevelTwo }}</span></p>
        <p>课程讲师:{{ coursePublish.teacherName }}</p>
        <h3 class="red">{{ coursePublish.price }}</h3>
      </div>
    </div>
    <div>
      <el-button @click="previous">返回修改</el-button>
      <el-button :disabled="saveBtnDisabled" type="primary" @click="publish">发布课程</el-button>
    </div>
  </div>
</template>
<script>
import course1 from '@/api/edu/course' 
export default {
  data() {
    return {
      saveBtnDisabled: false ,// 保存按钮是否禁用
      courseId:'',
      coursePublish:{}
    }
  },
  created() {
    if(this.$route.params && this.$route.params.id)
    {
      this.courseId=this.$route.params.id;
      //通过id查询发布信息
      this.getpublishCourses()
    }
  },
  methods: {
    previous() {
      console.log('previous')
      this.$router.push({ path: '/course/chapter/1' })
    },
    publish() {
      console.log('publish')
      this.$router.push({ path: '/course/list' })
    },
    getpublishCourses() {
      course1.getPublishCourseInfo(this.courseId)
      .then(response =>{
        console.log(response)
        this.coursePublish=response.data.coursePublish[0]
      })
    }
  }
}
</script>
<style scoped>
.ccInfo {
    background: #f5f5f5;
    padding: 20px;
    overflow: hidden;
    border: 1px dashed #DDD;
    margin-bottom: 40px;
    position: relative;
}
.ccInfo img {
    background: #d6d6d6;
    width: 500px;
    height: 278px;
    display: block;
    float: left;
    border: none;
}
.ccInfo .main {
    margin-left: 520px;
}
.ccInfo .main h2 {
    font-size: 28px;
    margin-bottom: 30px;
    line-height: 1;
    font-weight: normal;
}
.ccInfo .main p {
    margin-bottom: 10px;
    word-wrap: break-word;
    line-height: 24px;
    max-height: 48px;
    overflow: hidden;
}
.ccInfo .main p {
    margin-bottom: 10px;
    word-wrap: break-word;
    line-height: 24px;
    max-height: 48px;
    overflow: hidden;
}
.ccInfo .main h3 {
    left: 540px;
    bottom: 20px;
    line-height: 1;
    font-size: 28px;
    color: #d32f24;
    font-weight: normal;
    position: absolute;
}
</style>

3.4.3 课程最终发布

在这里插入图片描述

修改课程的static为normal已发布

  //课程最终发布,修改课程状态
    @PostMapping("/publishCourse/{id}")
    @ApiOperation("修改课程状态")
    public Res publishCourse(@PathVariable("id") String id)
    {
        EduCourse eduCourse = new EduCourse();
        eduCourse.setId(id);
        eduCourse.setStatus("Normal");
        eduCourseService.updateById(eduCourse);
        return Res.ok();
    }

3.5课程列表的显示和课程信息的相关操作

3.5.1前端

  1. api/edu/course.js中添加相关的路由信息
//获得课程列表
  getCourseInfo(current,limit,courseQuery)
     {
         return request({
            url:`/eduservice/course/getCourseList/${current}/${limit}`,
            method:"post",
            data:courseQuery
         })
     },
    //根据id删除课程信息
     deleteCourseInfo(id)
     {
         return request({
             url:`/eduservice/course/${id}`,
             method:'delete'
         })
     } 
  1. 在course/list.vue
<template>
    <div class="app-container">
        课程列表
 <!--查询表单-->
    <el-form :inline="true" class="demo-form-inline">
      <el-form-item>
        <el-input v-model="courseQuery.title" placeholder="课程名称"/>
     </el-form-item>
      <el-form-item>
        <el-select v-model="courseQuery.level" clearable placeholder="课程状态">
          <el-option :value="Normal" label="已发布"/>
          <el-option :value="Draft" label="未发布"/>
        </el-select>
      </el-form-item>
      <el-button type="primary" icon="el-icon-search" @click="getTeacherList()">查询</el-button>
      <el-button type="default" @click="resetData()">清空</el-button>
    </el-form>

         <!-- 表格 -->
    <el-table
     :data="list"
      element-loading-text="数据加载中"
      border
      fit
      highlight-current-row>
      <el-table-column
        label="序号"
        width="70"
        align="center">
        <template slot-scope="scope">
          {{ (page - 1) * limit + scope.$index + 1 }}
        </template>
      </el-table-column>
      <el-table-column prop="title" label="课程标题" width="80" />
      <el-table-column label="课程状态" width="80">
        <template slot-scope="scope">
          {{ scope.row.level===Normal?'已发布':'未发布' }}
        </template>
      </el-table-column>
      <el-table-column prop="lessonNum" label="课时数" />
      <el-table-column prop="gmtCreate" label="添加时间" width="160"/>
      <el-table-column prop="viewCount" label="浏览数量" width="60" />
      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
          <router-link :to="'/course/info/'+scope.row.id">
            <el-button type="primary" size="mini" icon="el-icon-edit" @click="updataCourse(scope.row.id)">编辑课程信息</el-button>
          </router-link>
          <router-link :to="'/course/chapter/'+scope.row.id">
            <el-button type="primary" size="mini" icon="el-icon-edit">编辑课程大纲</el-button>
          </router-link>
          <el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(scope.row.id)">删除课程信息</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
  <el-pagination    
      :current-page="page" 
      :page-size="limit"
      :total="total"
      style="padding: 30px 0; text-align: center;"
      layout="total, prev, pager, next, jumper"
      @current-change="getTeacherList"
    />
    
    </div>
</template>
<script>
// 引入调用teacher.js的文件
import course from '@/api/edu/course'
export default {
    //写核心代码的位置
    
    data() {//定义变量以及初始值
          return{
          list:null,
          page:1,
          limit:5,
          total:0,
          courseQuery:{} //通过v-module会将属性自动传过来
        
          }

    },
    created() {//页面渲染之前执行,一般调用methods定义的方法
          this.getTeacherList()
    },
    methods:{//创建具体的方法。调用teacher.js定义的方法
            //讲师列表
            getTeacherList(page=1){
                this.page=page
                course.getCourseInfo(this.page,this.limit,this.courseQuery)
                .then(respons=>{//请求失败
                console.log("请求成功")
                console.log(respons)
                this.list=respons.data.record
                this.total=respons.data.total
                console.log(this.list)
                console.log(this.total)
                })
                .catch(err=>{//请求成功
                console.log("请求失败")
                    console.log(err)
                })
            },
            resetData(){//清空方法  1.查询所有数据 2.清空表单数据
            //清空表单数据
            this.courseQuery={}
            //查询所有数据
            this.getTeacherList()
            },
            removeDataById(id)
            {
               this.$confirm('此操作将永久删除该课程的记录, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                    })
                    .then(() => { //点击确定执行then方法
                        //调用删除方法
                        course.deleteCourseInfo(id)
                        .then(response=>{  //删除成功
                        this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                     this.getTeacherList()
                        })
                        //回到列表页面
                         this.getTeacherList()
                    })
            }
     }
 }
</script>

3.5.2后端

eduCourseController.java

    //TODO 完善田间查询带分页
    @PostMapping("/getCourseList/{current}/{limit}")
    @ApiOperation("获取课程列表信息")
    public Res getCourseList(@PathVariable int current,@PathVariable int limit,@RequestBody(required = false) EduCourse eduCourse)
    {
        System.out.println(current);
        System.out.println(limit);
//        System.out.println();
        Page<EduCourse> page = new Page<>(current, limit);
        QueryWrapper<EduCourse> queryWrapper = new QueryWrapper<>();
        if(!StringUtils.isEmpty(eduCourse.getTitle()))
        {
            queryWrapper.eq("title",eduCourse.getTitle());
        }
        if(!StringUtils.isEmpty(eduCourse.getStatus()))
        {
            queryWrapper.eq("status",eduCourse.getStatus());
        }
        queryWrapper.orderByDesc("gmt_create");
        eduCourseService.page(page, queryWrapper);
        //总记录数
        long total = page.getTotal();
        //数据的集合
        List<EduCourse> pageRecords = page.getRecords();
        System.out.println(pageRecords);
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("total",total);
        hashMap.put("record",pageRecords);
        return Res.ok().data(hashMap);
        
    }
     //删除课程
    @DeleteMapping("{courseId}")
    public Res deleteCourse(@PathVariable String courseId)
    {
        //根据id删除小节信息
        eduCourseService.deleteCourse(courseId);
        return Res.ok();


    }

EduCourseServiceImpl.java

 //删除课程信息
    @Override
    public void deleteCourse(String courseId) {
       //根据课程id删除小节
        eduVideoService.deleteVideoByCourseId(courseId);
        //根据课程id删除章节
        eduChapterService.deleteChapterBuCourseId(courseId);
        //根据课程id删除描述
        eduCourseDescriptionService.getById(courseId);
        //根据课程id删除课程本身
        int i = baseMapper.deleteById(courseId);
        if(i==0)
        {
            throw new GuliException(20001,"删除失败");
        }
    }

EduVideoServiceImpl.java

  @Override
    public void deleteVideoByCourseId(String courseId) {
        QueryWrapper<EduVideo> eduVideoQueryWrapper = new QueryWrapper<>();
        eduVideoQueryWrapper.eq("course_id",courseId);
        baseMapper.delete(eduVideoQueryWrapper);
    }

EduChapterServiceImpl.java

 @Override
    public void deleteChapterBuCourseId(String courseId) {
        QueryWrapper<EduChapter> chapterQueryWrapper = new QueryWrapper<>();
        chapterQueryWrapper.eq("course_id",courseId);
        baseMapper.delete(chapterQueryWrapper);
    }

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值