谷粒学苑_第八天

八日目

1.コースの基本情報を追加して改善する

(1) 統合テキストエディタ

2. カリキュラム管理

(1) コース概要一覧表示

(2) 章の追加、修正、削除

(3) 小節の追加、修正および削除

3. コース情報確認

(1) 実現するSQL文を書く

コースリリース

コース紹介 リッチ テキスト エディターの追加

スキップします。テキストの使用を選択します。新しいバージョンではリッチ テキストの設定方法が異なります

科目シラバス一覧機能

2 つのエンティティ クラス、章、概要、

コード部分

クラス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;
}

コントローラ

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();
        }
    }

}

サービス

EduChapterサービス

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) ;
}

実装

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);
    }


}





ストッキング兄弟テスト:

[外部リンクの画像転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-7kWUGlaC-1667554945363)(md%E5%9B%BE%E7%89% 87/画像-20221009171113755.png )]

フロントエンド

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'
        })
    } 
}

チャプタービュー

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

フロントエンドのテスト

コースIDを変更

後部

EduCourseの場合

コントローラ

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();
    }


}

サービス

少し

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);
    }

}


ストッキングブラザーテスト

少し

フロントエンド

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
        })
    } ,


}

chapter.vue add id の 2 つのジャンプ メソッド

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

ID を取得するコードを追加し、クエリを取得します。

    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 メソッド:

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

403 エラーがクロスドメインであるか、間違ったパスが見つからない

プルダウンしてエコーします。

最下層、保存された ID を使用して、同じオプションの同じ表示を持つすべてのオプションの ID を比較します。同じ表示 ID を持っていません。

追加または変更するメソッド

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

            })
        },

コース管理

フロントエンド

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

追加 編集 削除 章

後部

前に書いた

フロントエンド

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'
        })
    }
}

追加表示をクリア

データエコーを追加し、削除ボタンを編集します

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

効果:
ここに画像の説明を挿入

測定操作

当分の間、フロントエンドは更新操作を実装していません

後部

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();
    }
}

フロントエンド

チャプタービュー

<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'
        })
    }

}

コース情報確認

手動の SQL フォームを使用する

内部結合: クエリ関連の結合

左外部結合、

右外部結合

vo オブジェクトを定義する

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);
    }

サーバ

    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>

先生のミスもあるかもしれませんが(私がミスしたわけではありません)

xml は静的リソースであるため、

読み込み時に Maven が静的リソースを読み込まない場合がある

//解決策 1: xml などのリソースをターゲットに手動でコピーする

//解決策 2: pom.xml または application.properties 内
ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/m0_52070517/article/details/127693643