Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布 -谷粒学院

谷粒学院

富文本编辑器Tinymce

一、Tinymce可视化编辑器

参考:https://panjiachen.gitee.io/vue-element-admin/#/example/create

二、组件初始化

Tinymce是一个传统javascript插件,默认不能用于Vue.js因此需要做一些特殊的整合步骤

1、复制脚本库

将脚本库复制到项目的static目录下(在vue-element-admin-master的static路径下)

2、配置html变量

在 guli-admin/build/webpack.dev.conf.js 中添加配置

使在html页面中可是使用这里定义的BASE_URL变量

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

new HtmlWebpackPlugin({
    ......,
    templateParameters: {
    	BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
    }
})

3、引入js脚本

在guli-admin/index.html 中引入js脚本

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院


三、组件引入

为了让Tinymce能用于Vue.js项目,vue-element-admin-master对Tinymce进行了封装,下面我们将它引入到我们的课程信息页面

1、复制组件

src/components/Tinymce

2、引入组件

课程信息组件中引入 Tinymce

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

//引入Tinymce富文本编辑器组件
import Tinymce from '@/components/Tinymce';

export default {
    ....
  components: { Tinymce },
}

3、组件模板

<!-- 课程简介-->
<el-form-item label="课程简介">
	<tinymce :height="300" v-model="courseInfo.description"/>
</el-form-item>

4、组件样式

在info.vue文件的最后添加如下代码,调整上传图片按钮的高度

<style scoped>
  .tinymce-container {
  line-height: 29px;
  }
</style>

5、显示效果

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

四、测试

  • 图片的base64编码

    Tinymce中的图片上传功能直接存储的是图片的base64编码,因此无需图片服务器

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 后台报错

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 修改数据库description字段类型

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 发现一级分类没有值

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 在后端8001,com.achang.eduservice.entity.vo.CourseInfoForm中添加一级分类属性

要求跟前端对应的数据名字一致,不然无法获取

    @ApiModelProperty(value = "一级分类ID")
    private String subjectParentId;

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 再次测试,成功有值,且对应id

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院


课程大纲列表功能

一、后端实现

1、创建两个实体类

章节和小节,在章节实体类使用list表示小节

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • VideoVo
@Data
public class VideoVo implements Serializable {

    private static final long serialVersionUID = 1L;

    private String id;

    private String title;

    private Boolean free;

}
  • ChapterVo
@Data
public class ChapterVo implements Serializable {

    private static final long serialVersionUID = 1L;

    private String id;

    private String title;

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

}

2、Controller

  • EduChapterController
@RestController
@RequestMapping("/eduservice/edu-chapter")
public class EduChapterController {

    @Autowired
    private EduChapterService eduChapterService;

    //获取课程大纲列表,根据课程id进行查询
    @GetMapping("/getChapterVideo/{courseId}")
    public R getChapterVideo(@PathVariable String courseId){
        List<ChapterVo> list = eduChapterService.getChapterVideoByCourseId(courseId);

        return R.ok().data("allChapterVideo",list);
    }

}

3、Service

  • service接口
public interface EduChapterService extends IService<EduChapter> {

    List<ChapterVo> getChapterVideoByCourseId(String courseId);

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

    @Autowired
    private EduVideoService eduVideoService;

    @Override
    public List<ChapterVo> getChapterVideoByCourseId(String courseId) {
        //最终要的数据列表
        ArrayList<ChapterVo> finalChapterVos = new ArrayList<>();

        //查询章节信息
        QueryWrapper<EduChapter> wrapper = new QueryWrapper<>();
        wrapper.eq("course_id",courseId);
        List<EduChapter> eduChapters = baseMapper.selectList(wrapper);

        //查询小节信息
        QueryWrapper<EduVideo> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("course_id",courseId);
        List<EduVideo> eduVideos = eduVideoService.list(wrapper1);

        //填充章节vo数据
        for (int i = 0; i < eduChapters.size(); i++) {
            EduChapter chapter = eduChapters.get(i);

            //创建章节vo对象
            ChapterVo chapterVo = new ChapterVo();
            BeanUtils.copyProperties(chapter,chapterVo);
            finalChapterVos.add(chapterVo);

            //填充课时vo对象
            ArrayList<VideoVo> finalVideoVos = new ArrayList<>();
            for (int j = 0; j < eduVideos.size(); j++) {
                EduVideo video = eduVideos.get(j);

                if (chapter.getId().equals(video.getChapterId())){
                    VideoVo videoVo = new VideoVo();
                    BeanUtils.copyProperties(video,videoVo);
                    finalVideoVos.add(videoVo);
                }
            }

            chapterVo.setChildren(finalVideoVos);

        }
        return finalChapterVos;

    }
}

4、测试


二、前端实现

1、定义api

chapter.js

import request from '@/utils/request' //引入已经封装好的axios 和 拦截器

export default{
    //根据课程id获取章节和小节数据列表
    getChapterVideoByCourseId(courseId){
        return request({
            url:`/eduservice/edu-chapter/getChapterVideo/${courseId}`,
            method: 'get',
        })
    },
}

2、引入api脚本方法

import chapter from '@/api/teacher/chapter.js';

3、定义方法、变量、created()调用

export default {
  data() {
    return {
      courseId:'',
      chapterVideoList:[],
      ....
    };
  },
  methods: {
    //根据课程id查询对应的课程章节和小结
    getChapterVideoByCourseId(){
        chapter.getChapterVideoByCourseId(this.courseId)
          .then(resp=>{
            this.chapterVideoList =  resp.data.allChapterVideo
          })
    },
	...
  },
  created() {
    //获取路由里的id值
    if(this.$route.params && this.$route.params.id){
      this.courseId = this.¥route.params.id
    }
    //根据课程id查询对应的课程章节和小结
    this.getChapterVideoByCourseId();
  },
};
</script>

4、组件模版

    <ul>
      <li v-for="chapter in chapterVideoList" :key="chapter.id">
        <p>
          {{ chapter.title }}
          <span>
            <el-button type="text">添加课时</el-button>
            <el-button style="" type="text">编辑</el-button>
            <el-button type="text">删除</el-button>
          </span>
        </p>

        <ul>
          <li v-for="video in chapter.children" :key="video.id">
            {{ video.title }}
          </li>
        </ul>
      </li>
      <li>
        <!-- 视频 -->
        <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>

课程修改功能

一、后端接口实现

1、根据课程id查询课程基本信息

  • EduCourseController
    //根据课程id查询课程基本信息
    @GetMapping("/getCourseInfoById/{courseId}")
    public R getCourseInfoById(@PathVariable String courseId){
        CourseInfoForm courseInfoForm = eduCourseService.getCourseInfo(courseId);
        return R.ok().data("courseInfoForm",courseInfoForm);
    }
  • EduCourseService
    //根据课程id查询课程基本信息
    CourseInfoForm getCourseInfo(String courseId);

  • EduCourseServiceImpl
//课程描述注入
@Autowired
private EduCourseDescriptionService eduCourseDescriptionService;

@Override
public CourseInfoForm getCourseInfo(String courseId) {
    //查询课程表
    EduCourse eduCourse = baseMapper.selectById(courseId);
    CourseInfoForm courseInfoForm = new CourseInfoForm();
    BeanUtils.copyProperties(eduCourse,courseInfoForm);

    //查询简介表
    EduCourseDescription courseDescription = eduCourseDescriptionService.getById(courseId);
    courseInfoForm.setDescription(courseDescription.getDescription());

    return courseInfoForm;
}

2、修改课程信息

  • EduCourseController
//修改课程信息
@PostMapping("/updateCourseInfo")
public R updateCourseInfo(@RequestBody CourseInfoForm courseInfoForm){
    eduCourseService.updateCourseInfo(courseInfoForm);
    return R.ok();
}
  • EduCourseService
//修改课程信息
void updateCourseInfo(CourseInfoForm courseInfoForm);
  • EduCourseServiceImpl
@Override
public void updateCourseInfo(CourseInfoForm courseInfoForm) {
    //1、修改课程表
    EduCourse eduCourse = new EduCourse();
    BeanUtils.copyProperties(courseInfoForm,eduCourse);
    int update = baseMapper.updateById(eduCourse);
    if (update <= 0){
        throw new AchangException(20001,"修改课程信息失败");
    }

    //2、修改描述信息
    EduCourseDescription eduCourseDescription = new EduCourseDescription();
    eduCourseDescription.setDescription(courseInfoForm.getDescription());
    eduCourseDescription.setId(courseInfoForm.getId());
    eduCourseDescriptionService.updateById(eduCourseDescription);
}

二、前端实现

  • 定义api方法

guli-admin\src\api\teacher\course.js

    //根据课程id 查询课程基本信息
    getCourseInfoById(courseId){
        return request({
            url:`/eduservice/edu-course/getCourseInfoById/${courseId}`,
            method: 'get',
        })
    },
    //修改课程信息
    updateCourseInfo(courseInfoForm){
        return request({
            url:"/eduservice/edu-course/updateCourseInfo",
            method: 'post',
            data: courseInfoForm,
        })
    }
  • 修改chapter页面跳转路径

guli-admin\src\views\edu\course\chapter.vue

    //跳转到上一步
    previous() {
      this.$router.push({ path: "/course/info/"+this.courseId});
    },
    next() {
      //跳转到第三步
      this.$router.push({ path: "/course/publish/"+this.courseId});
    }
  • info页面 created()
created() {
    //判断路径中是否有课程id
    if (this.$route.params && this.$route.params.id) {
        this.courseId = this.$route.params.id;
        //根据课程id 查询课程基本信息
        this.getCourseInfo()
    },
        ....
}
  • info页面 methods
methods: {
    //获取课程信息
    getCourseInfo() {
        course.getCourseInfoById(this.courseId).then((resp) => {
            this.courseInfo = resp.data.courseInfoForm
        })
    },
        ....
}
  • info页面 data
  data() {
    return {
		...
      courseId: "",
    };
  }
  • 测试

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 上面问题,二级分类中的数据显示出现了问题
  created() {
    //判断路径中是否有课程id
    if (this.$route.params && this.$route.params.id) {
      this.courseId = this.$route.params.id;
      //根据课程id 查询课程基本信息
      this.getCourseInfo();
    } else {
      //初始化所有讲师
      this.getListTeacher();
      //初始化一级分类
      this.getOneSubject();
    }
  }
    //获取课程信息
    getCourseInfo() {
      course.getCourseInfoById(this.courseId).then((resp) => {
        this.courseInfo = resp.data.courseInfoForm;
        //查询所有分类,包含一级和二级所有
        subject.getSubjectList().then((resp) => {
          //获取所有一级分类
          this.subjectOneLists = resp.data.list;

          //把所有一级分类数组进行遍历
          for (var i = 0; i < this.subjectOneLists.length; i++) {
            //获取每个一级分类
            var oneSubject = this.subjectOneLists[i];
            //比较当前courseInfo里面的一级分类id和所有的一级分类id是否一样
            if (this.courseInfo.subjectParentId == oneSubject.id) {
              //获取一级分类中所有的二级分类
              this.subjectTwoLists = oneSubject.children;
            }
          }
        });
        //初始化所有讲师
        this.getListTeacher();
      });
    }
  • 出现一个bug,就是回显数据后,再单击添加课程,数据还在,按理应该是清空数据

添加监听器,监听路由,如果路由变化,就将courseInfo的数据清空

  watch: {
    $route(to, from) {
      //路由变化方式,当路由发送变化,方法就执行
      console.log("watch $route");
      this.courseInfo={}
    },
  }
  • 实现修改功能

guli-admin\src\views\edu\course\info.vue

    //添加课程
    saveCourse() {
      course.addCourseInfo(this.courseInfo).then((resp) => {
        this.$message({
          message: "添加课程信息成功",
          type: "success",
        });
        //跳转到第二步,并带着这个课程生成的id
        this.$router.push({ path: "/course/chapter/" + resp.data.courseId });
      });
    },

    //修改课程
    updateCourse() {
      course.updateCourseInfo(this.courseInfo).then((resp) => {
        this.$message({
          message: "修改课程信息成功",
          type: "success",
        });
        //跳转到第二步,并带着这个课程生成的id
        this.$router.push({ path: "/course/chapter/" + this.courseId });
      });
    },
	
    //判断是修改还是新增
    saveOrUpdate() {
      //判断courseInfo中是否有id值
      if (this.courseInfo.id) {
        //有id值,为修改
        this.updateCourse();
      } else {
        //没id值,为添加
        this.saveCourse();
      }
    }

课程章节添加修改删除功能

一、后端接口实现

  • controller
    //添加章节
    @PostMapping("addChapter")
    public R addChapter(@RequestBody EduChapter eduChapter){
        eduChapterService.save(eduChapter);
        return R.ok();
    }

    //根据章节id查询
    @GetMapping("getChapter/{chapterId}")
    public R getChapter(@PathVariable String chapterId){
        EduChapter eduChapter = eduChapterService.getById(chapterId);
        return R.ok().data("chapter",eduChapter);
    }

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

    //删除章节
    @DeleteMapping("deleteById/{chapterId}")
    public R deleteById(@PathVariable String chapterId){
        boolean flag = eduChapterService.deleteChapter(chapterId);
        if (flag){
            return R.ok();
        }else {
            return R.error();
        }

    }
  • service
boolean deleteChapter(String chapterId);
  • serviceImpl
    //删除章节的方法
    @Override
    public boolean deleteChapter(String chapterId) {
        //根据chapter章节id 查询查询小节表,如果查询有数据,则不删除
        QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();
        wrapper.eq("chapter_id",chapterId);
        int count = eduVideoService.count(wrapper);
        //判断
        if (count>0){
            //能查询出来小节,不进行删除
            throw new AchangException(20001,"还有小节数据,不能删除");
        }else {
            //不能查询出小节,进行删除
            int delete = baseMapper.deleteById(chapterId);
            return delete>0;
        }
    }

二、前端页面实现

  • 定义api
    //添加章节
    addChapter(chapter) {
        return request({
            url: `/eduservice/edu-chapter/addChapter`,
            method: `post`,
            data: chapter
        })
    },
    //根据id查询章节
    updateChapterById(chapterID) {
        return request({
            url: `/eduservice/edu-chapter/getChapter/${chapterID}`,
            method: `get`,
        })
    },
    //修改章节
    updateChapter(chapter) {
        return request({
            url: `/eduservice/edu-chapter/updateChapter`,
            method: `post`,
            data: chapter
        })
    },
    //删除章节
    deleteById(chapterID) {
        return request({
            url: `/eduservice/edu-chapter/deleteById/${chapterID}`,
            method: `delete`,
        })
    }
  • 引入api
import chapter from "@/api/teacher/chapter.js";
  • 【添加课程】前端实现

    Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

methods: {
	//添加章节
    saveChapter() {
      //设置课程id到chapter对象中
      this.chapter.courseId = this.courseId
      chapter.addChapter(this.chapter).then((resp) => {
        //关闭弹框
        this.dialogChapterFormVisible = false;
        //提示信息
        this.$message({
          message: "添加章节成功",
          type: "success",
        });
        //刷新页面
        this.getChapterVideoByCourseId()
      });
    },
    saveOrUpdate() {
          this.saveChapter()
        }
}
  • 设置com.achang.eduservice.entity.EduChapter的创建时间和更新时间自动增添

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 测试新增章节功能是否优先

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 设置弹出表单时,清空数据

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

    //弹出添加章节表单
    openChapterDialog(){
       //清空之前的数据
        this.chapter={}
        //显示弹框
        this.dialogChapterFormVisible = true
    }
  • 【修改功能】实现
//修改章节
    updateChapter() {
      //设置课程id到chapter对象中
      this.chapter.courseId = this.courseId;
      chapter.updateChapter(this.chapter).then((resp) => {
        //关闭弹框
        this.dialogChapterFormVisible = false;
        //提示信息
        this.$message({
          message: "修改章节成功",
          type: "success",
        });
        //刷新页面
        this.getChapterVideoByCourseId();
      });
    }
    saveOrUpdate() {
      if (this.chapter.id) {
        //修改章节
        this.updateChapter();
      } else {
        //新增章节
        this.saveChapter();
      }
    }

  • 【删除功能】实现

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

    //删除章节
    removeById(chapterId) {
      this.$confirm("此操作将永久删除章节信息, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        //点击确定,执行then方法
        chapter.deleteById(chapterId).then((resp) => {
          //删除成功
          //提示信息
          this.$message({
            type: "success",
            message: "删除成功!",
          });
          //刷新页面
          this.getChapterVideoByCourseId();
        });
      });
    }

课程章节小节功能

一、后端接口实现

  • com.achang.eduservice.controller.EduVideoController
@RestController
@RequestMapping("/eduservice/edu-video")
@CrossOrigin //解决跨域问题
public class EduVideoController {

    @Autowired
    private EduVideoService eduVideoService;

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


    //删除小节
    // TODO 后面这个方法需要完善,删除小节的时候,同时也要把视频删除
    @DeleteMapping("/deleteVideo/{id}")
    public R deleteVideo(@PathVariable String id){
        eduVideoService.removeById(id);
        return R.ok();
    }

    //修改小节
    @PostMapping("/updateVideo")
    public R updateVideo(@RequestBody EduVideo eduVideo){
        eduVideoService.updateById(eduVideo);
        return R.ok();
    }

    //根据小节id查询
    @GetMapping("/getVideoById/{videoId}")
    public R getVideoById(@PathVariable String videoId){
        EduVideo eduVideo = eduVideoService.getById(videoId);
        return R.ok().data("video",eduVideo);
    }


}

二、前端实现

  • 页面搭建

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

<!--添加小节表单-->
    <!-- 添加和修改课时表单 -->
    <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(video.id)"
          >确 定</el-button
        >
      </div>
    </el-dialog>
  • api

guli-admin\src\api\teacher\video.js

import request from '@/utils/request' //引入已经封装好的axios 和 拦截器

export default {
    //添加小节
    addVideo(video) {
        return request({
            url: `/eduservice/edu-video/addVideo`,
            method: `post`,
            data: video
        })
    },
    //根据id查询小节
    getVideoById(videoId) {
        return request({
            url: `/eduservice/edu-video/getVideoById/${videoId}`,
            method: `get`,
        })
    },
    //修改小节
    updateVideo(video) {
        return request({
            url: `/eduservice/edu-video/updateVideo`,
            method: `post`,
            data: video
        })
    },
    //删除小节
    deleteById(videoId) {
        return request({
            url: `/eduservice/edu-video/deleteVideo/${videoId}`,
            method: `delete`,
        })
    },
}
  • 引入api
import video from "@/api/teacher/video.js";
  • 方法定义
    //添加小节弹框的方法
    openEditVideo(chapterId) {
      //清空之前的数据
      this.video = {};
      //显示弹框
      this.dialogVideoFormVisible = true;
      //设置章节id
      this.video.chapterId = chapterId;
    },
  • 添加方法
    //添加小节
    addVideo() {
      //设置课程id
      this.video.courseId = this.courseId;
      video.addVideo(this.video).then((resp) => {
        //关闭弹框
        this.dialogVideoFormVisible = false;
        //提示信息
        this.$message({
          message: "添加小节成功",
          type: "success",
        });
        //刷新页面
        this.getChapterVideoByCourseId();
      });
    },
  • 给EduVideo,entity对象添加自动插入时间和修改时间

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 测试通过

  • 【删除小节】功能

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

    //删除小节
    removeVideo(videoId) {
      this.$confirm("此操作将永久删除小节信息, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        //点击确定,执行then方法
        video.deleteById(videoId).then((resp) => {
          //删除成功
          //提示信息
          this.$message({
            type: "success",
            message: "删除成功!",
          });
          //刷新页面
          this.getChapterVideoByCourseId();
        });
      });
    },

  • 【小节修改】功能

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

    //修改小节表单回显
    getVideoById(videoId) {
      //弹出小节弹窗
      this.dialogVideoFormVisible = true;
      video.getVideoById(videoId).then((resp) => {
        this.video = resp.data.video;
      });
    },
  • 【小节修改】功能
    //小节修改
    updateVideorById(videoId) {
      //设置小节id到video对象中
      this.video.id = videoId;
      video.updateVideo(this.video).then((resp) => {
        //关闭弹框
        this.dialogVideoFormVisible = false;
        //提示信息
        this.$message({
          message: "修改小节成功",
          type: "success",
        });
        //刷新页面
        this.getChapterVideoByCourseId();
      });
    },
  • 测试

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院


课程最终发布

一、后端实现

  • com.achang.eduservice.entity.vo.CoursePublishVo
@Data
public class CoursePublishVo implements Serializable {

    private static final long serialVersionUID = 1L;

    private String id;//课程id
    
    private String title; //课程名称

    private String cover; //封面

    private Integer lessonNum;//课时数

    private String subjectLevelOne;//一级分类

    private String subjectLevelTwo;//二级分类

    private String teacherName;//讲师名称

    private String price;//价格 ,只用于显示

}
  • 数据访问层

接口:EduCourseMapper

public interface EduCourseMapper extends BaseMapper<EduCourse> {
    public CoursePublishVo getPublishCourseInfo(String courseId);
}

实现:EduCourseMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.achang.eduservice.mapper.EduCourseMapper">

    <select id="getPublishCourseInfo"    resultType="com.achang.eduservice.entity.vo.CoursePublishVo">
        SELECT
            ec.id,
            ec.title,
            ec.cover,
            ec.lesson_num AS lessonNum,
            ec.price,
            s1.title AS subjectLevelOne,
            s2.title AS subjectLevelTwo,
            t.name AS teacherName
        FROM
            edu_course ec
                LEFT JOIN edu_teacher t ON ec.id = t.id
                LEFT JOIN edu_subject s1 ON ec.subject_parent_id = s1.id
                LEFT JOIN edu_subject s2 ON ec.id = s2.id
        WHERE
            ec.id = #{id}
    </select>
</mapper>
  • EduCourseMapper接口
@Component
public interface EduCourseMapper extends BaseMapper<EduCourse> {  
    public CoursePublishVo getPublishCourseInfo(String courseId);
}
  • EduCourseService接口
    根据课程id查询课程确认信息
    public CoursePublishVo getPublishCourseInfo(String courseId);
  • EduCourseServiceImpl
    //根据课程id查询课程确认信息
    @Override
    public CoursePublishVo getPublishCourseInfo(String courseId) {
        return eduCourseMapper.getPublishCourseInfo(courseId);
    }
  • EduCourseController
    //根据课程id查询课程确认信息
    @GetMapping("/getpublishCourseInfo/{id}")
    public R getpublishCourseInfo(@PathVariable String id){
        CoursePublishVo publishCourseInfo = eduCourseService.getPublishCourseInfo(id);
        return R.ok().data("publishCourse",publishCourseInfo);
    }
  • 测试,访问:http://localhost:8801/swagger-ui.html

  • 报错

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • 原因、解决方式

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院

  • application.properties下指定xml文件夹
#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/achang/eduservice/mapper/xml/*.xml
  • 再次测试,成功

Day207.富文本编辑器、课程大纲列表、课程修改、课程章节添加修改、课程小节CRUD、课程最终发布   -谷粒学院


二、前端实现

…明天继续

上一篇:《C++ primer》chapter 5:语句


下一篇:Chapter 2 (Discrete Random Variables): Joint PMFs of Multiple Random Variables (多个随机变量的联合分布列)