Yajun Gakuen_8th Heaven

eighth day

1. Add the basic information of the course to improve

(1) Integrated text editor

2. Curriculum management

(1) Course outline list display

(2) Chapter addition, modification and deletion

(3) Subsection addition, modification and deletion

3. Course information confirmation

(1) Write sql statement to achieve

Course release

Course Introduction Adding a Rich Text Editor

Skip it, I choose to use text, the method of configuring rich text in the new version is different

Course Syllabus List Function

Create two entity classes, chapter, summary,

code part

Class Vo

ChapterVo.java

package com.lkw.eduservice.entity.chapter;

import lombok.Data;

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

@Data
public class ChapterVo {
    
    
    private String id;
    private String title;
    private List<VideoVo> children = new ArrayList<>();
}

VideoVo.java

package com.lkw.eduservice.entity.chapter;

import lombok.Data;

@Data
public class VideoVo {
    
    
    private String id;
    private String title;
    private String videoSourceId;
}

Controller

EduChapterController.java

package com.lkw.eduservice.controller;

import com.lkw.commonutils.R;
import com.lkw.eduservice.entity.EduChapter;
import com.lkw.eduservice.entity.chapter.ChapterVo;
import com.lkw.eduservice.service.EduChapterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@CrossOrigin
@RequestMapping("/eduservice/chapter")
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 chapterById = chapterService.getById(chapterId);
        return R.ok().data("chapter", chapterById);
    }


    //修改课程章节
    @PostMapping("updateChapter")
    public R updateChapter(@RequestBody EduChapter eduChapter) {
    
    
        chapterService.updateById(eduChapter);
        return R.ok();
    }

    //删除课程章节
    @DeleteMapping("{chapterId}")
    public R deleteChapter(@PathVariable String chapterId) {
    
    
        boolean result = chapterService.deleteChapterById(chapterId);
        if (result) {
    
    
            return R.ok();
        } else {
    
    
            return R.error();
        }
    }

}

Service

EduChapterService

package com.lkw.eduservice.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lkw.eduservice.entity.EduChapter;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lkw.eduservice.entity.EduVideo;
import com.lkw.eduservice.entity.chapter.ChapterVo;
import com.lkw.servicebase.exceptionhandler.GuliException;

import java.util.List;

/**
* @author 
* @description 针对表【edu_chapter(课程)】的数据库操作Service
* @createDate 2022-10-07 16:40:12
*/
public interface EduChapterService extends IService<EduChapter> {
    
    

    List<ChapterVo> getChapterVideoByCourseId(String courseId);

    boolean deleteChapterById(String chapterId);

    void removeChapterByCourseId(String courseId) ;
}

Impl

EduChapterServiceImpl

package com.lkw.eduservice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lkw.eduservice.entity.EduChapter;
import com.lkw.eduservice.entity.EduVideo;
import com.lkw.eduservice.entity.chapter.ChapterVo;
import com.lkw.eduservice.entity.chapter.VideoVo;
import com.lkw.eduservice.service.EduChapterService;
import com.lkw.eduservice.mapper.EduChapterMapper;
import com.lkw.eduservice.service.EduVideoService;
import com.lkw.servicebase.exceptionhandler.GuliException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
* @author 李可文
* @description 针对表【edu_chapter(课程)】的数据库操作Service实现
* @createDate 2022-10-07 16:40:12
*/
@Service
public class EduChapterServiceImpl extends ServiceImpl<EduChapterMapper, EduChapter>
    implements EduChapterService {
    
    

    @Autowired
    private EduVideoService eduVideoService;

    @Override
    public List<ChapterVo>  getChapterVideoByCourseId(String courseId) {
    
    
        //1根据课程id查询课程里面所有的章节
        QueryWrapper<EduChapter> chapterQueryWrapper = new QueryWrapper<>();
        chapterQueryWrapper.eq("course_id", courseId);
        List<EduChapter> eduChapterList = baseMapper.selectList(chapterQueryWrapper);
        //2根据课程id查询课程里面所有的小节
        QueryWrapper<EduVideo> videoQueryWrapper = new QueryWrapper<>();
        videoQueryWrapper.eq("course_id", courseId);
        List<EduVideo> eduVideoList = eduVideoService.list(videoQueryWrapper);
        //创建list集合进行最终封装
        ArrayList<ChapterVo> finalList = new ArrayList<>();
        //3遍历查询章节list集合进行封装
        for (int i = 0; i < eduChapterList.size(); i++) {
    
    
            EduChapter eduChapter = eduChapterList.get(i);
            ChapterVo chapterVo = new ChapterVo();
            BeanUtils.copyProperties(eduChapter, chapterVo);
            finalList.add(chapterVo);

            ArrayList<VideoVo> finalVideoVoList = new ArrayList<>();
            //4遍历查询小节list集合进行封装
            for (int j = 0; j < eduVideoList.size(); j++) {
    
    
                EduVideo eduVideo = eduVideoList.get(j);
                if (eduVideo.getChapterId().equals(chapterVo.getId())) {
    
    
                    VideoVo videoVo = new VideoVo();
                    BeanUtils.copyProperties(eduVideo, videoVo);
                    finalVideoVoList.add(videoVo);
                }
            }

            chapterVo.setChildren(finalVideoVoList);
        }


        return finalList;
    }

    //删除章节的方法
    @Override
    public boolean deleteChapterById(String chapterId) {
    
    
        //根据章节id,如果有小节数据则不能删除
        QueryWrapper<EduVideo> eduVideoWrapper = new QueryWrapper<>();
        eduVideoWrapper.eq("chapter_id", chapterId);
        int count =(int) eduVideoService.count(eduVideoWrapper);
        if (count > 0) {
    
    
            //有小节
            throw new GuliException(20001, "有小节,无法删除");
        }
        int i = baseMapper.deleteById(chapterId);

        return i > 0;
    }

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


}





Stocking brother test:

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-7kWUGlaC-1667554945363)(md%E5%9B%BE%E7%89%87/image-20221009171113755.png )]

front end

src\api\chapter\chapter.js

import request from '@/utils/request'


export default{
    
    

 
    //根据课程id获取章节和小节数据列表
    getAllChapterVideo(courseId){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/getChapterVideo/'+courseId,
            method: 'get'
        })
    } 
}

chapter.view

<template>
<div class="app-container">
    <h2 style="text-align: center;">发布新课程</h2>
<el-steps :active="2" finish-status="success">
  <el-step title="填写课程基本信息"></el-step>
  <el-step title="创建课程大纲"></el-step>
  <el-step title="最终发布"></el-step>
</el-steps>


    <!-- 章节 -->
    <ul class="chanpterList">
      <li
        v-for="chapter in chapterVideoList"
        :key="chapter.id">
        <p>
          {
   
   { chapter.title }}
        </p>
        <!-- 视频 -->

        <ul class="chanpterList videoList">
          <li
            v-for="video in chapter.children"
            :key="video.id">
            <p>{
   
   {video.title}}
            </p>
          </li>
        </ul>
      </li>
    </ul>

  <div>
    <el-button @click="previous">上一步</el-button>
    <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
  </div>
</div>
</template>

<script>




import chapter from '@/api/chapter/chapter'

  export default {
    data() {
      return {
        courseId: '',
        chapterVideoList:[],
        saveBtnDisabled:false
      }
    },

    methods: {
      //根据课程id查询课程章节小节
      getChapterVideo(){
        chapter.getAllChapterVideo(this.courseId)
        .then(response=>{
          this.chapterVideoList=response.data.allChapterVideo
        })
      },

      previous(){ 
          this.$router.push({path:'/course/info/1'})
      },
        next(){
          //跳转到第三步
          this.$router.push({path:'/course/publish/1'})
      },
      init(){
        if(this.$route.params&&this.$route.params.id){
          this.courseId=this.$route.params.id
          //根据课程id查询章节和小节
          this.getChapterVideo()
        }
      }


    },

    created(){
      this.init();
    }
  }
</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>

Front-end testing

modify course id

rear end

For EduCourse

controller

package com.lkw.eduservice.controller;

import com.lkw.commonutils.R;
import com.lkw.eduservice.entity.vo.CourseInfoVo;
import com.lkw.eduservice.service.EduCourseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@CrossOrigin
@RequestMapping("/eduservice/course")
public class EduCourseController {
    
    



    @Autowired
    private EduCourseService courseService;
    //添加课程基本信息的方法
    @PostMapping("addCourseInfo")
    public R addCourseInfo(@RequestBody CourseInfoVo courseInfoVo){
    
    

        String id=courseService.saveCourseInfo(courseInfoVo);
        return R.ok().data("courseId",id);
    }


    @GetMapping("getCourseInfo/{courseId}")
    public R getCourseInfo(@PathVariable String courseId){
    
    
        CourseInfoVo courseInfoVo=courseService.getCourseInfo(courseId);
        return R.ok().data("courseInfoVo",courseInfoVo);
    }


    @PostMapping("updateCourseInfo")
    public R updateCourseInfo(@RequestBody CourseInfoVo courseInfoVo){
    
    


        courseService.updateCourseInfo(courseInfoVo);
        return R.ok();
    }


}

Service

slightly

impl

package com.lkw.eduservice.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lkw.eduservice.entity.EduCourse;
import com.lkw.eduservice.entity.EduCourseDescription;
import com.lkw.eduservice.entity.vo.CourseInfoVo;
import com.lkw.eduservice.service.EduCourseDescriptionService;
import com.lkw.eduservice.service.EduCourseService;
import com.lkw.eduservice.mapper.EduCourseMapper;
import com.lkw.servicebase.exceptionhandler.GuliException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* @author 李可文
* @description 针对表【edu_course(课程)】的数据库操作Service实现
* @createDate 2022-10-06 15:55:48
*/
@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse>
    implements EduCourseService{
    
    



    @Autowired
    private EduCourseDescriptionService courseDescriptionService;

    @Override
    public String saveCourseInfo(CourseInfoVo courseInfoVo) {
    
    

        //Vo转换成entity类
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseInfoVo,eduCourse );

        int insert = baseMapper.insert(eduCourse);
        if(insert<=0){
    
    
            //添加失败
            throw new GuliException(20001,"添加课程失败");
        }
        //添加成功获取id
        String cid = eduCourse.getId();

        //课程描述
        EduCourseDescription courseDescription = new EduCourseDescription();
        courseDescription.setDescription(courseInfoVo.getDescription());
        courseDescription.setId(cid);
        courseDescriptionService.save(courseDescription);

        return cid;
    }

    //根据课程id查询课程基本信息
    @Override
    public CourseInfoVo getCourseInfo(String courseId) {
    
    
        EduCourse eduCourse = baseMapper.selectById(courseId);
        CourseInfoVo courseInfoVo = new CourseInfoVo();
        BeanUtils.copyProperties(eduCourse,courseInfoVo);
        //查询描述表
        EduCourseDescription courseDescription = courseDescriptionService.getById(courseId);
        courseInfoVo.setDescription(courseDescription.getDescription());

        return courseInfoVo;
    }


    @Override
    public void updateCourseInfo(CourseInfoVo courseInfoVo) {
    
    
        //1 修改课程表
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseInfoVo, eduCourse);
        int update = baseMapper.updateById(eduCourse);
        if (update == 0) {
    
    
            throw new GuliException(20001, "修改课程信息失败");
        }

        //2 修改描述表
        EduCourseDescription description = new EduCourseDescription();
        description.setId(courseInfoVo.getId());
        description.setDescription(courseInfoVo.getDescription());
        courseDescriptionService.updateById(description);
    }

}


stockings brother test

slightly

front end

api

course.js

import request from '@/utils/request'


export default{
    
    

    //添加课程信息
    addCourseInfo(courseInfo){
    
    
        return request({
    
    
            url: `http://localhost:8001/eduservice/course/addCourseInfo`,
            method: 'post',
            data: courseInfo
        })


    },

    //查询所有讲师
    getListTeacher(){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/teacher/findAll',
            method: 'get'
        })
    } ,

    //根据课程id查询课程基本信息

    getCourseInfoId(id){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/course/getCourseInfo/'+id,
            method: 'get'
        })
    } ,
    //根据课程id查询课程基本信息

    updateCourseInfoId(courseInfo){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/course/updateCourseInfo/',
            method: 'post',
            data: courseInfo
        })
    } ,


}

The two jump methods of chapter.vue add id

      previous(){ 
          this.$router.push({path:'/course/info/'+this.courseId})
      },
        next(){
          //跳转到第三步
          this.$router.push({path:'/course/publish/'+this.courseId})
      },
info.vue data echo

created Add the code to get the id, and get the query:

    created(){
        //获取id
          if(this.$route.params&&this.$route.params.id){
          this.courseId=this.$route.params.id
          console.log(this.courseId)
          this.getInfo()
          this.getListTeacher()
          }else{

            this.getListTeacher()
            this.getOneSubject()
          }
    }

getInfo method:

 getInfo(){
            course.getCourseInfoId(this.courseId)
            .then(response=>{
                this.courseInfo=response.data.courseInfoVo
            })
            subject.getSubjectList()
            .then(response=>{
                this.subjectOneList=response.data.list
                //遍历一级分类
                for(var i=0;i<this.subjectOneList.length;i++){
                    var oneSubject=this.subjectOneList[i]
                    if(this.courseInfo.subjectParentId==oneSubject.id){
                        //获取一级分类的所有二级分类
                        this.subjectTwoList=oneSubject.children
                    }
                }
            })
        }

The 403 error is cross-domain, or the wrong path cannot be found

Pull down to echo:

Bottom layer, use the stored id and compare the ids of all options that have the same display for the same option, that do not have the same display id

Methods to add or modify

        updateCourse(){
            course.updateCourseInfoId(this.courseInfo)
            .then(response=>{
                
                //提示
                this.$message({
                    type: 'success', 
                    message: '修改课程信息成功'
                })

            //跳转到第二步
            this.$router.push({path:'/course/chapter/'+this.courseId})

            })
            
        },

        saveOrUpdate(){
            if(!this.courseInfo.id){
                //添加
                this.addCourse()
            }else{
                this.updateCourse()
            }

        },


        addCourse(){

            course.addCourseInfo(this.courseInfo)
            .then(response=>{
                //提示
                this.$message({
                    type: 'success', 
                    message: '添加课程信息成功'
                })

            //跳转到第二步
            this.$router.push({path:'/course/chapter/'+response.data.courseId})

            })
        },

course management

front end

<!-- 添加和修改章节表单 -->
<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>

add edit delete chapter

rear end

written earlier

front end

api:

import request from '@/utils/request'

export default{
    
    
    //根据课程id获取章节和小节数据列表
    getAllChapterVideo(courseId){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/getChapterVideo/'+courseId,
            method: 'get'
        })
    } ,
    //添加章节
    addChapter(chapter){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/addChapter',
            method: 'post',
            data: chaper
        })
    } ,
    //根据id查询章节
    getChapter(chapterId){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/getChapterInfo/'+chapterId,
            method: 'get'
        })
    },
    //修改章节
    updateChapter(chaper){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/updateChapter',
            method: 'post',
            data: chaper
        })
    },
    //删除
    deleteChapter(chapterId){
    
     
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/'+chapterId,
            method: 'delete'
        })
    }
}

clear add display

Add data echo, and edit delete button

<template>
<div class="app-container">
    <h2 style="text-align: center;">发布新课程</h2>
<el-steps :active="2" finish-status="success">
  <el-step title="填写课程基本信息"></el-step>
  <el-step title="创建课程大纲"></el-step>
  <el-step title="最终发布"></el-step>
</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 type="text" @click="removeChapter(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}}
            </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>


</div>
</template>

<script>




import chapter from '@/api/chapter/chapter'

  export default {
    data() {
      return {
        courseId: '',
        chapterVideoList:[],
        saveBtnDisabled:false,
        chapter:{//封装章节数据
        title:'',
        sort:0,
        courseId:''
        },
        dialogChapterFormVisible:false//章节弹框
      }
    },

    methods: {
      //删除章节
      removeChapter(chapterId){
        this.$confirm('此操作将删除章节,是否继续?','提示',{
          confirmButtonText:'确定',
          cancelButtonText:'取消',
          type:'warning'
          }).then(()=>{
            //点击确定执行then
            chapter.deleteChapter(chapterId)
            .then(response=>{
              //删除成功
              //提示信息
              this.$message({
                type:'success',
                message:'删除成功              '
              })
              this.getChapterVideo()
            })
          })
      },
            
  

      //弹框数据回显
      openEditChapter(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(){
        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})
      },
      init(){
        
        if(this.$route.params&&this.$route.params.id){
          this.courseId=this.$route.params.id
          //根据课程id查询章节和小节
          this.getChapterVideo()
        }
      }


    },

    created(){
      this.init();
    }
  }
</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>

Effect:
insert image description here

Measure operation

The front end has not implemented the update operation for the time being

rear end

package com.lkw.eduservice.controller;

import com.lkw.commonutils.R;
import com.lkw.eduservice.entity.EduVideo;
import com.lkw.eduservice.service.EduVideoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@CrossOrigin
@RequestMapping("/eduservice/video")
public class EduVideoController {
    
    
    @Autowired
    private EduVideoService videoService;

    //添加小节
    @PostMapping("addVideo")
    public R addVideo(@RequestBody EduVideo eduVideo){
    
    
        videoService.save(eduVideo);
        return R.ok();
    }

    @PostMapping("updateVideo")
    public R updateVideo(@RequestBody EduVideo eduVideo){
    
    
        videoService.updateById(eduVideo);
        return R.ok();
    }


    //删除小节
    //需要完善,删小节时,把视频删除
    @DeleteMapping("{id}")
    public R deleteVideo(@PathVariable String id){
    
    
        videoService.removeById(id);
        return R.ok();
    }
}

front end

chapter.view

<template>
<div class="app-container">
    <h2 style="text-align: center;">发布新课程</h2>
<el-steps :active="2" finish-status="success">
  <el-step title="填写课程基本信息"></el-step>
  <el-step title="创建课程大纲"></el-step>
  <el-step title="最终发布"></el-step>
</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 type="text" @click="openVideo(chapter.id);  chapterId = 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 style="" type="text" @click="openVideo(chapter.id); chapterId = chapter.id">编辑</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="上传视频" >
          
        </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/chapter/chapter'
import video from '@/api/video/video'

  export default {
    data() {
      return {
        saveBtnDisabled:false,
        courseId: '',
        chapterVideoList:[],
        
        chapter:{//封装章节数据
        title:'',
        sort:0,
        courseId:''
        },
        video:{
          title:'',
          sort: 0,
          free: 0,
          videoSourceId:'',
          courseId: '',
          chapterId: ''
       
        },
        dialogChapterFormVisible:false,//章节弹框
        dialogVideoFormVisible:false,//小节弹框
        saveVideoBtnDisabled:false
      }
    },

    methods: {
      小节操作

      removeVideo(id){
        this.$confirm('此操作将删除章节,是否继续?','提示',{
          confirmButtonText:'确定',
          cancelButtonText:'取消',
          type:'warning'
          }).then(()=>{
            //点击确定执行then
            video.deleteVideo(id)
            .then(response=>{
              //删除成功
              //提示信息
              this.$message({
                type:'success',
                message:'删除成功'
              })
              this.getChapterVideo()
            })
          })

      },
      //添加小结id
      openVideo(chapterId){
        //弹框
        this.dialogVideoFormVisible=true
        //设置章节id
        this.video.chapterId=chapterId
      },
      //添加小节
      addVideo(){
        //设置课程id
        this.video.courseId=this.courseId
        this.video.chapterId=this.chapterId
       
        video.addVideo(this.video)
        .then(response=>{
          //关闭弹框
          this.dialogVideoFormVisible=false
          //提示
          this.$message({
            type:'success',
            message:'添加小节成功'

          })         
          //刷新
          this.getChapterVideo()

        })
      },
      //添加小节
    saveOrUpdateVideo(){
      console.log(this.video)
      if(this.video.id){
          //添加
        this.addVideo()
        }else{
        this.addVideo()//updateVideo()
        //修改
        }
    },




      //章节操作
      //删除章节
      removeChapter(chapterId){
        this.$confirm('此操作将删除章节,是否继续?','提示',{
          confirmButtonText:'确定',
          cancelButtonText:'取消',
          type:'warning'
          }).then(()=>{
            //点击确定执行then
            chapter.deleteChapter(chapterId)
            .then(response=>{
              //删除成功
              //提示信息
              this.$message({
                type:'success',
                message:'删除成功              '
              })
              this.getChapterVideo()
            })
          })
      },
            
  

      //弹框数据回显
      openEditChapter(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(){
        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})
      },
      init(){
        
        if(this.$route.params&&this.$route.params.id){
          this.courseId=this.$route.params.id
          //根据课程id查询章节和小节
          this.getChapterVideo()
        }
      }


    },

    created(){
      this.init();
    }
  }
</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{
    
    

 
    //根据课程id获取章节和小节数据列表
    getAllChapterVideo(courseId){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/getChapterVideo/'+courseId,
            method: 'get'
        })
    } ,
    //添加章节
    addChapter(chapter){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/addChapter',
            method: 'post',
            data: chapter
        })
    } ,
    //根据id查询章节
    getChapter(chapterId){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/getChapterInfo/'+chapterId,
            method: 'get'
        })
    },
    //修改章节
    updateChapter(chaper){
    
    
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/updateChapter',
            method: 'post',
            data: chaper
        })
    },
    //删除
    deleteChapter(chapterId){
    
     
        return request({
    
    
            url: 'http://localhost:8001/eduservice/chapter/'+chapterId,
            method: 'delete'
        })
    }

}

Course Information Confirmation

Use manual sql form

Inner join: Query related joins

left outer join,

right outer join

define a vo object

package com.lkw.eduservice.entity.vo;

import lombok.Data;

import java.io.Serializable;

@Data
public class CoursePublishVo implements Serializable {
    
    
    private String id;
    private String title;
    private String cover;
    private Integer lessonNum;
    private String subjectLevelOne;
    private String subjectLevelTwo;
    private String teacherName;
    private String price;//只用于显示
}

impl

    @Override
    public CoursePublishVo publishCourseInfo(String id) {
    
    
        //调用mapper
        return baseMapper.getPublishCourseInfo(id);
    }

server

    CoursePublishVo publishCourseInfo(String id);

mapper.xml

  <select id="getPublishCourseInfo" resultType="com.lkw.eduservice.entity.vo.CoursePublishVo">/*方法名,返回值类型*//*resultMap也是定义*/
    SELECT ec.id,ec.title,ec.price,ec.lesson_num AS lessonNum,ec.cover,
           et.`name` AS teacherName,
           es1.title AS subjectLevelOne,
           es2.title AS subjectLevelTwo
    from edu_course ec LEFT OUTER JOIN edu_course_description ecd ON ec.id=ecd.id
                       LEFT OUTER JOIN edu_teacher et ON ec.teacher_id=et.id
                       LEFT OUTER JOIN edu_subject es1 ON ec.subject_parent_id=es1.id
                       LEFT OUTER JOIN edu_subject es2 ON ec.subject_id=es2.id
    WHERE ec.id=#{courseId}
    </select>

There may be a teacher's mistake (but I didn't make this mistake)

Because xml is a static resource,

Maven may not load static resources when loading

//Solution 1: Manually copy resources such as xml to target

//Solution 2: In pom.xml or application.properties
insert image description here

insert image description here

insert image description here

Guess you like

Origin blog.csdn.net/m0_52070517/article/details/127693643