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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZD6URoQQ-1614611373296)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301115058890.png)]

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

3、引入js脚本

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bLiP9QVt-1614611373302)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301115540528.png)]


三、组件引入

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

1、复制组件

src/components/Tinymce

2、引入组件

课程信息组件中引入 Tinymce

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wKsmmxSr-1614611373308)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301115937921.png)]

//引入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、显示效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ww9iCrar-1614611373314)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301125720949.png)]

四、测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-muCkUiWd-1614611373321)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301130036443.png)]

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajB8FDia-1614611373330)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301122147362.png)]

在这里插入图片描述

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

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

在这里插入图片描述

在这里插入图片描述


课程大纲列表功能

一、后端实现

1、创建两个实体类

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

在这里插入图片描述

@Data
public class VideoVo implements Serializable {

    private static final long serialVersionUID = 1L;

    private String id;

    private String title;

    private Boolean free;

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

@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

public interface EduChapterService extends IService<EduChapter> {

    List<ChapterVo> getChapterVideoByCourseId(String courseId);

}
@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查询课程基本信息

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

//课程描述注入
@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、修改课程信息

//修改课程信息
@PostMapping("/updateCourseInfo")
public R updateCourseInfo(@RequestBody CourseInfoForm courseInfoForm){
    eduCourseService.updateCourseInfo(courseInfoForm);
    return R.ok();
}
//修改课程信息
void updateCourseInfo(CourseInfoForm courseInfoForm);
@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);
}

二、前端实现

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

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});
    }
created() {
    //判断路径中是否有课程id
    if (this.$route.params && this.$route.params.id) {
        this.courseId = this.$route.params.id;
        //根据课程id 查询课程基本信息
        this.getCourseInfo()
    },
        ....
}
methods: {
    //获取课程信息
    getCourseInfo() {
        course.getCourseInfoById(this.courseId).then((resp) => {
            this.courseInfo = resp.data.courseInfoForm
        })
    },
        ....
}
  data() {
    return {
		...
      courseId: "",
    };
  }

在这里插入图片描述

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

添加监听器,监听路由,如果路由变化,就将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();
      }
    }

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

一、后端接口实现

    //添加章节
    @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();
        }

    }
boolean deleteChapter(String chapterId);
    //删除章节的方法
    @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;
        }
    }

二、前端页面实现

    //添加章节
    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`,
        })
    }
import chapter from "@/api/teacher/chapter.js";
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()
        }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSQ1jeQ8-1614611373373)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301193058647.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-haSaK6wy-1614611373374)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301193140747.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zEe86p2C-1614611373375)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301193809829.png)]

    //弹出添加章节表单
    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();
      }
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TS94m8kw-1614611373377)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301201936160.png)]

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

课程章节小节功能

一、后端接口实现

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


}

二、前端实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tE45zGri-1614611373379)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301210837755.png)]

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PydDrQmx-1614611373381)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301211614154.png)]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MClVIf1z-1614611373382)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301213128067.png)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ypmselu5-1614611373384)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301214211583.png)]

    //修改小节表单回显
    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();
      });
    },

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2L2Oos8t-1614611373386)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301220516228.png)]


课程最终发布

一、后端实现

@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>
@Component
public interface EduCourseMapper extends BaseMapper<EduCourse> {  
    public CoursePublishVo getPublishCourseInfo(String courseId);
}
    根据课程id查询课程确认信息
    public CoursePublishVo getPublishCourseInfo(String courseId);
    //根据课程id查询课程确认信息
    @Override
    public CoursePublishVo getPublishCourseInfo(String courseId) {
        return eduCourseMapper.getPublishCourseInfo(courseId);
    }
    //根据课程id查询课程确认信息
    @GetMapping("/getpublishCourseInfo/{id}")
    public R getpublishCourseInfo(@PathVariable String id){
        CoursePublishVo publishCourseInfo = eduCourseService.getPublishCourseInfo(id);
        return R.ok().data("publishCourse",publishCourseInfo);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yjqfo99p-1614611373388)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301225614464.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-07skounZ-1614611373390)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301230028092.png)]

#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/achang/eduservice/mapper/xml/*.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iExDrqrh-1614611373391)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210301230137703.png)]


二、前端实现

…明天继续

标签:chapter,文本编辑,return,courseId,修改,课程,video,id
来源: https://blog.csdn.net/qq_43284469/article/details/114274115