Mooc项目开发笔记(十三):课程章节显示前后端实现、课程基本信息回显、课程基本信息更新实现

一、课程章节列表显示后端实现

1、创建章节和小节vo类

/**
 * 章节和小节的vo类
 */
@Data
@ApiModel("章节和小节的vo类")
public class ChapterVo {

    private String id;
    private String title;

    //如果是章节用于存放其包含小节
    //如果是小节则为空
    private List<ChapterVo> children = null;
}

2、服务层

接口

public interface EduChapterService extends IService<EduChapter> {
    List<ChapterVo> getChapterByCourseId(String courseId);
}

实现

@Service
public class EduChapterServiceImpl extends ServiceImpl<EduChapterMapper, EduChapter> implements EduChapterService {

    @Autowired
    private EduVideoMapper videoMapper;

    /**
     * 根据课程id获取课程包含的章节和小节信息
     * 并以ChapterVo的形式作为结果集返回
     * @param courseId
     * @return
     */
    @Override
    public List<ChapterVo> getChapterByCourseId(String courseId) {
        //用于存放章节和小节列表(树状)
        List<ChapterVo> res = new ArrayList<>();

        //根据课程id插入课程所有的章节
        QueryWrapper<EduChapter> chapterWrapper = new QueryWrapper<>();
        chapterWrapper.eq("course_id", courseId);
        List<EduChapter> chapters = baseMapper.selectList(chapterWrapper);

        //根绝课程id查询出该课程所有小节
        QueryWrapper<EduVideo> videoWrapper = new QueryWrapper<>();
        chapterWrapper.eq("course_id", courseId);
        List<EduVideo> videos = videoMapper.selectList(videoWrapper);

        for (EduChapter chapter : chapters) {
            ChapterVo chapterVo = new ChapterVo();
            BeanUtils.copyProperties(chapter, chapterVo);

            //为章节创建children列表
            chapterVo.setChildren(new ArrayList<>());
            String chapterId = chapterVo.getId();
            //遍历所有小节,将与chapterVo对应的小节存入children列表中
            for (EduVideo video : videos) {
                if (chapterId != null && chapterId.equals(video.getChapterId())){
                    ChapterVo videoVo = new ChapterVo();
                    BeanUtils.copyProperties(video, videoVo);
                    chapterVo.getChildren().add(videoVo);
                }
            }

            //将章节存入结果集中
            res.add(chapterVo);
        }

        return res;
    }
}

3、controller层

@RestController
@RequestMapping("/eduservice/chapter")
@CrossOrigin
@Api("课程章节管理")
public class EduChapterController {

    @Autowired
    private EduChapterService chapterService;

    @ApiOperation("根绝课程id获取其对应的章节和小节")
    @GetMapping("list/{courseId}")
    public R getCourseChapter(
            @PathVariable("courseId") String courseId) {
        List<ChapterVo> list = chapterService.getChapterByCourseId(courseId);
        return R.ok().data("list", list);
    }
}

4、测试

打开swagger,找到接口输入课程id,点击执行
在这里插入图片描述

二、课程章节列表显示前端实现

1、定义api

scr/api/edu下创建chapter.js,内容如下:

import request from '@/utils/request'

//表示导出,别的文件可以使用
export default {

    /**
     * 添加课程信息
     */
    getCourseChapter(courseId){
        return request({
            url: `/eduservice/chapter/list/${courseId}`,
            method: 'get',
          })
    },
}

2、定义组件脚本

定义data

courseId: '', // 所属课程
chapterNestedList: [] // 章节嵌套课时列表

methods中添加方法

  methods: {
    //根据课程id获取章节和小节信息
    getCourseChapter(){
      chapterApi.getCourseChapter(this.courseId)
            .then(response => {
              this.chapterNestedList = response.data.list
            })
    },
        ...//其他方法
  }

created中调用上述方法

  created() {
    //根据路由获取url中的id值
    if(this.$route.params && this.$route.params.id){
      this.courseId = this.$route.params.id
      //根据课程id获取章节和小节信息
      this.getCourseChapter()
    }
  },

3、定义组件模板

<el-button type="text">添加章节</el-button>
<!-- 章节 -->
<ul class="chanpterList">
    <li
        v-for="chapter in chapterNestedList"
        :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>

4、定义样式

将样式的定义放在页面的最后

scope表示这里定义的样式只在当前页面范围内生效,不会污染到其他的页面

<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>

5、效果

在这里插入图片描述

三、课程信息回显实现

1、业务层

接口:CourseService.java

CourseInfoVo getCourseInfoById(String id);

实现:CourseServiceImpl.java

    /**
     * 根据课程id获取课程基本信息和课程描述信息
     * 并封装到CourseInfoVo中
     * @param id
     * @return
     */
    @Override
    public CourseInfoVo getCourseInfoById(String id) {
        CourseInfoVo courseInfo = new CourseInfoVo();

        //从数据库获取课程基本信息
        EduCourse eduCourse = baseMapper.selectById(id);
        //将基本信息赋值给courseInfo
        BeanUtils.copyProperties(eduCourse, courseInfo);

        //从数据库获取课程描述信息,描述信息id和课程信息一致
        EduCourseDescription description = descriptionService.getById(id);
        courseInfo.setDescription(description.getDescription());

        return courseInfo;
    }

2、controller层

    @ApiOperation(value = "根据id获取课程基本信息")
    @GetMapping("{id}")
    public R getCourseById(@PathVariable String id) {
        //根据id获取课程基本信息,包括课程描述信息
        CourseInfoVo course = courseService.getCourseInfoById(id);
        return R.ok().data("course", course);
    }

后端实现之后,接下来实现前端的内容

3、定义api

api/edu/course.js中添加如下内容

    /**
     * 根据课程id获取课程基本信息和课程描述信息
     */
    getCourseInfoById(id){
        return request({
            url: `/eduservice/course/${id}`,
            method: 'get',
          })
    },

4、修改chapter.vue中的跳转路径

    previous() {
      console.log('previous')
      this.$router.push({ path: '/course/info/'+this.courseId })
    },

    next() {
      console.log('next')
      this.$router.push({ path: '/course/publish/'+this.courseId })
    }

5、定义data

在course.vue中

  data() {
    return {
      ...
      courseId: '', //修改时路径中传来的课程id
      ...
    }
  }

6、编写方法

在course.vue中

  methods: {
    //根据课程id获取课程信息
    getCourseInfo(id){
        courseApi.getCourseInfoById(id)
            .then(response => {
                this.courseInfo = response.data.course
            })
    },
    ...
  }

7、初始化时调用方法

在course.vue中

  created() {
    //根据路由获取url中的id值
    if(this.$route.params && this.$route.params.id){
        this.courseId = this.$route.params.id
        this.getCourseInfo(this.courseId)
    }

    this.getAllTeacherList()
    this.getAllSubjectrList()
  },

8、测试

在这里插入图片描述

四、解决级联下拉菜单回显问题

可以看到上面的测试中课程的二级类编显示是id而不是名称,所以我们需要进行解决

1、修改init方法

将 this.initSubjectList()移至else

  created() {
    //根据路由获取url中的id值
    if(this.$route.params && this.$route.params.id){ //修改
        this.courseId = this.$route.params.id
        this.getCourseInfo(this.courseId)
    } else{ //添加
        this.getAllSubjectrList()
    }
    //获取讲师列表
    this.getAllTeacherList()
  },

2、修改getCourseInfo方法

    //根据课程id获取课程信息
    getCourseInfo(id){
        courseApi.getCourseInfoById(id)
            .then(response => {
                this.courseInfo = response.data.course
                //调用接口获取所有的课程分类信息
                subjectApi.getAllSubject()
                    .then(response => {
                        debugger
                        this.subjectParentList = response.data.list
                        //对一级分类进行遍历找到其中courseId与this.courseId相等的一级分类
                        //并将其中包含的二级分类信息赋值为this.subSubjidectList
                        for (let i = 0; i < this.subjectParentList.length; i++) {
                            if (this.subjectParentList[i].id === this.courseInfo.subjectParentId) {
                            this.subSubjectList = this.subjectParentList[i].children
                            }
                        }
                    })
            })
    },

3、效果

在这里插入图片描述

五、课程信息的更新实现

1、业务层

接口:CourseService.java

void updateCourseInfo(CourseInfoVo course);

实现:CourseServiceImpl.java

    /**
     * 更新课程基本信息和描述信息
     * @param courseInfo
     */
    @Override
    public void updateCourseInfo(CourseInfoVo courseInfo) {
        //创建并赋值EduCourse对象
        EduCourse course = new EduCourse();
        BeanUtils.copyProperties(courseInfo, course);
        //更新数据库
        int update1 = baseMapper.updateById(course);
        if (update1 == 0) {
            throw new CustomException(20001, "修改课程基本信息失败");
        }
        //创建并赋值EduCourseDescription对象
        EduCourseDescription description = new EduCourseDescription();
        description.setId(courseInfo.getId());
        description.setDescription(courseInfo.getDescription());
        description.setGmtModified(new Date());
        //更新数据库
        boolean update2 = descriptionService.updateById(description);
        if (!update2) {
            throw new CustomException(20001, "修改课程描述信息失败");
        }
    }

2、controller层

    @ApiOperation(value = "根据课程基本信息,包括课程描述信息")
    @PostMapping("update")
    public R updateCourse(@RequestBody CourseInfoVo course) {
        courseService.updateCourseInfo(course);
        return R.ok();
    }

后端实现之后,接下来实现前端的内容

3、定义api

api/edu/course.js中添加如下内容

   /**
     * 更新课程基本信息和描述信息
     */
    updateCourseInfo(courseInfo){
        return request({
            url: `/eduservice/course/update`,
            method: 'post',
            data:courseInfo
          })
    },

4、组件js

将之前的next方法修改为下面的内容

    //添加或者修改课程信息
    next() {
        //更新时会从接口查询出courseInfo,其中会包括id
        if(this.courseInfo.id){ //修改
            this.updateCourse()
        } else {
            this.addCourse()
        }
    },

    //修改课程信息
    updateCourse(){
        courseApi.updateCourseInfo(this.courseInfo)
            .then(response => {
                this.$message({
                    type: 'success',
                    message: '修改课程信息成功'
                })
                this.$router.push({ path: '/course/chapter/'+this.courseId })
            })
            .catch(error => {
                this.saveBtnDisabled = false
                console.log(error)
            }) //请求失败
    },

    //添加课程信息
    addCourse(){
        console.log('next')
        this.saveBtnDisabled = true
        courseApi.addCourseInfo(this.courseInfo)
                .then(response=>{
                    this.$message({
                        type: 'success',
                        message: '添加课程信息成功'
                    })
                    this.$router.push({ path: '/course/chapter/'+response.data.id })
                })
                .catch(error => {
                    this.saveBtnDisabled = false
                    console.log(error)
                }) //请求失败
    }

5、测试

首先在表单中输入信息并点击保存下一步

在这里插入图片描述

之后点击上一步,再次修改表单内容表单

在这里插入图片描述

点击保存并下一步,提示修改课程信息成功

在这里插入图片描述

查看数据库中已经修改成功

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章