学院项目day08_课程章节的实现
一、后端接口的实现
1.1、章节接口的实现
1.1.1、web层
@RestController @RequestMapping("/eduservice/chapter") @CrossOrigin public class EduChapterController { @Autowired private EduChapterService chapterService; //课程大纲列表,根据课程id进行查询 @GetMapping("getChapterVideo/{courseId}") public R getChapterVideo(@PathVariable String courseId) { List<ChapterVo> list = chapterService.getChapterVideoByCourseId(courseId); return R.ok().data("allChapterVideo",list); } //添加章节 @PostMapping("addChapter") public R addChapter(@RequestBody EduChapter eduChapter) { chapterService.save(eduChapter); return R.ok(); } //根据章节id查询 @GetMapping("getChapterInfo/{chapterId}") public R getChapterInfo(@PathVariable String chapterId) { EduChapter eduChapter = chapterService.getById(chapterId); return R.ok().data("chapter",eduChapter); } //修改章节 @PostMapping("updateChapter") public R updateChapter(@RequestBody EduChapter eduChapter) { chapterService.updateById(eduChapter); return R.ok(); } //删除的方法 @DeleteMapping("{chapterId}") public R deleteChapter(@PathVariable String chapterId) { boolean flag = chapterService.deleteChapter(chapterId); if(flag) { return R.ok(); } else { return R.error(); } } }
1.1.2、service层的实现
@Service public class EduChapterServiceImpl extends ServiceImpl<EduChapterMapper, EduChapter> implements EduChapterService { @Autowired private EduVideoService videoService;//注入小节service //课程大纲列表,根据课程id进行查询 @Override public List<ChapterVo> getChapterVideoByCourseId(String courseId) { //1 根据课程id查询课程里面所有的章节 QueryWrapper<EduChapter> wrapperChapter = new QueryWrapper<>(); wrapperChapter.eq("course_id",courseId); List<EduChapter> eduChapterList = baseMapper.selectList(wrapperChapter); //2 根据课程id查询课程里面所有的小节 QueryWrapper<EduVideo> wrapperVideo = new QueryWrapper<>(); wrapperVideo.eq("course_id",courseId); List<EduVideo> eduVideoList = videoService.list(wrapperVideo); //创建list集合,用于最终封装数据 List<ChapterVo> finalList = new ArrayList<>(); //3 遍历查询章节list集合进行封装 //遍历查询章节list集合 for (int i = 0; i < eduChapterList.size(); i++) { //每个章节 EduChapter eduChapter = eduChapterList.get(i); //eduChapter对象值复制到ChapterVo里面 ChapterVo chapterVo = new ChapterVo(); BeanUtils.copyProperties(eduChapter,chapterVo); //把chapterVo放到最终list集合 finalList.add(chapterVo); //创建集合,用于封装章节的小节 List<VideoVo> videoList = new ArrayList<>(); //4 遍历查询小节list集合,进行封装 for (int m = 0; m < eduVideoList.size(); m++) { //得到每个小节 EduVideo eduVideo = eduVideoList.get(m); //判断:小节里面chapterid和章节里面id是否一样 if(eduVideo.getChapterId().equals(eduChapter.getId())) { //进行封装 VideoVo videoVo = new VideoVo(); BeanUtils.copyProperties(eduVideo,videoVo); //放到小节封装集合 videoList.add(videoVo); } } //把封装之后小节list集合,放到章节对象里面 chapterVo.setChildren(videoList); } return finalList; } ////删除章节的方法 @Override public boolean deleteChapter(String chapterId) { //根据chapterid章节id 查询小节表,如果查询数据,不进行删除 QueryWrapper<EduVideo> wrapper = new QueryWrapper<>(); wrapper.eq("chapter_id",chapterId); int count = videoService.count(wrapper); //判断 if(count >0) {//查询出小节,不进行删除 throw new GuliException(20001,"不能删除"); } else { //不能查询数据,进行删除 //删除章节 int result = baseMapper.deleteById(chapterId); //成功 1>0 0>0 return result>0; } } }
1.2、小节接口实现
1.2.1、web层
@RestController @RequestMapping("/eduservice/video") @CrossOrigin public class EduVideoController { @Autowired private EduVideoService videoService; //添加小节 @PostMapping("addVideo") public R addVideo(@RequestBody EduVideo eduVideo) { videoService.save(eduVideo); return R.ok(); } //删除小节 // TODO 后面这个方法需要完善:删除小节时候,同时把里面视频删除 @DeleteMapping("{id}") public R deleteVideo(@PathVariable String id) { videoService.removeById(id); return R.ok(); } }
二、前端的实现
src/api/chapter.js
import request from '@/utils/request' export default { //1 根据课程id获取章节和小节数据列表 getAllChapterVideo(courseId) { return request({ url: '/eduservice/chapter/getChapterVideo/'+courseId, method: 'get' }) }, //添加章节 addChapter(chapter) { return request({ url: '/eduservice/chapter/addChapter', method: 'post', data: chapter }) }, //根据id查询章节 getChapter(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/'+chapterId, method: 'delete' }) }, }
src\views\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> <el-button type="text" @click="openChapterDialog()">添加章节</el-button> <!-- 章节 --> <ul class="chanpterList"> <li v-for="chapter in chapterVideoList" :key="chapter.id"> <p> {{ chapter.title }} <span class="acts"> <el-button style="" type="text" @click="openVideo(chapter.id)">添加小节</el-button> <el-button style="" type="text" @click="openEditChatper(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 style="" type="text">编辑</el-button> <el-button type="text" @click="removeVideo(video.id)">删除</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> </div> </template> <script> import chapter from '@/api/edu/chapter' import video from '@/api/edu/video' export default { data() { return { saveBtnDisabled:false, courseId:'',//课程id chapterVideoList:[], chapter:{ //封装章节数据 title: '', sort: 0 }, video: { title: '', sort: 0, free: 0, videoSourceId: '' }, dialogChapterFormVisible:false,//章节弹框 dialogVideoFormVisible:false //小节弹框 } }, created() { //获取路由的id值 if(this.$route.params && this.$route.params.id) { this.courseId = this.$route.params.id //根据课程id查询章节和小节 this.getChapterVideo() } }, methods:{ //==============================小节操作==================================== //删除小节 removeVideo(id) { this.$confirm('此操作将删除小节, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { //点击确定,执行then方法 //调用删除的方法 video.deleteVideo(id) .then(response =>{//删除成功 //提示信息 this.$message({ type: 'success', message: '删除小节成功!' }); //刷新页面 this.getChapterVideo() }) }) //点击取消,执行catch方法 }, //添加小节弹框的方法 openVideo(chapterId) { //弹框 this.dialogVideoFormVisible = true //设置章节id this.video.chapterId = chapterId }, //添加小节 addVideo() { //设置课程id this.video.courseId = this.courseId video.addVideo(this.video) .then(response => { //关闭弹框 this.dialogVideoFormVisible = false //提示 this.$message({ type: 'success', message: '添加小节成功!' }); //刷新页面 this.getChapterVideo() }) }, saveOrUpdateVideo() { this.addVideo() }, //==============================章节操作==================================== //删除章节 removeChapter(chapterId) { this.$confirm('此操作将删除章节, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { //点击确定,执行then方法 //调用删除的方法 chapter.deleteChapter(chapterId) .then(response =>{//删除成功 //提示信息 this.$message({ type: 'success', message: '删除成功!' }); //刷新页面 this.getChapterVideo() }) }) //点击取消,执行catch方法 }, //修改章节弹框数据回显 openEditChatper(chapterId) { //弹框 this.dialogChapterFormVisible = true //调用接口 chapter.getChapter(chapterId) .then(response => { this.chapter = response.data.chapter }) }, //弹出添加章节页面 openChapterDialog() { //弹框 this.dialogChapterFormVisible = true //表单数据清空 this.chapter.title = '' this.chapter.sort = 0 }, //添加章节 addChapter() { //设置课程id到chapter对象里面 this.chapter.courseId = this.courseId chapter.addChapter(this.chapter) .then(response => { //关闭弹框 this.dialogChapterFormVisible = false //提示 this.$message({ type: 'success', message: '添加章节成功!' }); //刷新页面 this.getChapterVideo() }) }, //修改章节的方法 updateChapter() { chapter.updateChapter(this.chapter) .then(response => { //关闭弹框 this.dialogChapterFormVisible = false //提示 this.$message({ type: 'success', message: '修改章节成功!' }); //刷新页面 this.getChapterVideo() }) }, saveOrUpdate() { if(!this.chapter.id) { this.addChapter() } else { this.updateChapter() } }, //根据课程id查询章节和小节 getChapterVideo() { chapter.getAllChapterVideo(this.courseId) .then(response => { this.chapterVideoList = response.data.allChapterVideo }) }, previous() { this.$router.push({path:'/course/info/'+this.courseId}) }, 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>
遇到的问题
1、在前端页面当中,遇到点击“编辑”按钮没反应(无法出现弹框)的问题,查询得知:将样式里的chanpterList p{ 的 float: left;注释掉即可。
2、在后端接口里写修改章节的web层用的是PutMaping方式,但是前端js文件里定义的是Post方式,因此修改一下后端接口如下:
//修改章节 @PostMapping("updateChapter") public R updateChapter(@RequestBody EduChapter eduChapter) { chapterService.updateById(eduChapter); return R.ok(); }
3、前端中要设置:
//设置课程id到chapter对象里面 this.chapter.courseId = this.courseId
因为在数据库里面courseId 的值