day08【课程发布-课程大纲和课程发布】

1 课程大纲列表和章节管理

01-课程大纲列表显示

一、后端实现

1、定义vo

章节:ChapterVo

@Data

@ApiModel(value = "章节信息")

public class ChapterVo {

    private String id;

    private String title;

    //表示小节

    private List<VideoVo> children = new ArrayList<>();

}

小节:VideoVo

@Data

@ApiModel(value = "课时信息")

public class VideoVo {

    private String id;

    private String title;

}

2、服务层

接口

public interface EduChapterService extends IService {

    //根据课程id进行查询章节小节

    List getChapterVideoByCourseId(String courseId);

}

实现

@Service

public class EduChapterServiceImpl extends ServiceImpl implements EduChapterService {

    //在Chapter里面不能查询Video,因此需要将Video的接口注入进来

    @Autowired

    private EduVideoService videoService;


    //根据课程id进行查询章节小节

    @Override

    public List getChapterVideoByCourseId(String courseId) {

        //1 根据课程id查询课程里面的所有章节EduChapter

        QueryWrapper<EduChapter> wrapperChapter = new QueryWrapper<>();

        wrapperChapter.eq("course_id",courseId);

        List eduChapterList = baseMapper.selectList(wrapperChapter);


        //2 根据课程id查询课程里面的所有小节EduVideo

        QueryWrapper<EduVideo> wrapperVideo = new QueryWrapper<>();

        wrapperVideo.eq("course_id",courseId);

        List eduVideoList = videoService.list(wrapperVideo);


        //创建list集合,用于最终封装数据

        List finalList = new ArrayList<>();


        //3 遍历查询章节list集合进行封装

        //遍历查询章节list集合

        for (int i = 0; i < eduChapterList.size(); i++) {

            //每个章节

            EduChapter eduChapter = eduChapterList.get(i);

            //把eduChapter对象值复制到chapterVo里面

            ChapterVo chapterVo = new ChapterVo();

            BeanUtils.copyProperties(eduChapter,chapterVo);

            //把chapterVo放到最终list集合

            finalList.add(chapterVo);

            //创建集合,用于封装小节

            List videoVoList = new ArrayList<>();


            //4 遍历查询小节list集合进行封装

            for (int m = 0; m < eduVideoList.size(); m++) {

                //得到每个小节

                EduVideo eduVideo = eduVideoList.get(m);

                //判断小节的chapter_id和章节里面的id是否一样

                if (eduVideo.getChapterId().equals(eduChapter.getId())){

                    VideoVo videoVo = new VideoVo();

                    BeanUtils.copyProperties(eduVideo,videoVo);

                    videoVoList.add(videoVo);

                }

            }

            //把封装的小节list集合放到章节对象chapterVo里面

            chapterVo.setChildren(videoVoList);

        }

        return finalList;

    }

}

3、web层

@Api(description="课程章节管理")

@RestController

@RequestMapping("/eduservice/chapter")

@CrossOrigin

public class EduChapterController {

    @Autowired

    EduChapterService chapterService;

    //课程大纲列表,查询课程下的章节和小节,根据课程id进行查询章节小节

    @ApiOperation(value = "嵌套章节数据列表")

    @GetMapping("getChapterVideo/{courseId}")

    public R getChapterVideo(@ApiParam(name = "courseId", value = "课程ID", required = true)

                              @PathVariable String courseId){

        List list = chapterService.getChapterVideoByCourseId(courseId);

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

    }

}

4、Swagger测试

二、前端实现

1、定义api

chapter.js

import request from '@/utils/request'

export default{

    //1 根据课程id获取章节和小节数据列表

    getAllChapterVideo(courseId){

        return request({

            url:`/eduservice/chapter/getChapterVideo/${courseId}`,

            method:'get'

        })

    }

}

2、定义组件脚本

定义data

            courseId:'', // 所属课程

            chapterVideoList:[], // 章节嵌套课时列表

定义相关methods获取章节和课时列表

        //根据课程id查询章节和小节

        getChapterVideo(){

            chapter.getAllChapterVideo(this.courseId)

                .then(response=>{

                    this.chapterVideoList = response.data.allChapterVideo

                })

        },

获取路由的id

created(){

        //获取路由的id

        //判断里面如果有参数,并且是id参数,则获取

        if(this.$route.params && this.$route.params.id){

            this.courseId = this.$route.params.id

            //根据课程id查询章节和小节

            this.getChapterVideo()

        }

    },

3、定义组件模板

简单的无样式:

    

            

                {{chapter.title}}

                

                       chapter.children" :key="video.id">

                          {{video.title}}

                      

                  

            

        

含有样式:

    

        

            v-for="chapter in chapterVideoList"

            :key="chapter.id">

            

                {{ chapter.title }}


                

                    添加课时

                    编辑

                    删除

                

            


            

            

                

                    v-for="video in chapter.children"

                    :key="video.id">

                    

                        {{ video.title }}

                        

                            编辑

                            删除

                        

                    

                

            

        

    

    

        上一步

        下一步

    

http://localhost:9528/#/course/chapter/14

4、定义样式

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

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

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

    }


02-章节管理后端接口开发

一、新增章节

web层

//新增章节

    @ApiOperation(value = "新增章节")

    @PostMapping("addChapter")

    public R addChapter(@RequestBody EduChapter eduChapter){

        chapterService.save(eduChapter);

        return R.ok();

    }

二、根据id查询

web层

//根据id查询

    @ApiOperation(value = "根据ID查询章节")

    @GetMapping("getChapterById/{id}")

    public R getChapterById(@ApiParam(name = "id", value = "章节ID", required = true)

                            @PathVariable String id){

        EduChapter eduChapter = chapterService.getById(id);

        return R.ok().data("chapter",eduChapter);

    }

三、更新

web层

    //根据ID修改章节

    @ApiOperation(value = "根据ID修改章节")

    @PostMapping("updateChapterById")

    public R updateChapterById( @ApiParam(name = "chapter", value = "章节对象", required = true)

                                @RequestBody EduChapter eduChapter){

        chapterService.updateById(eduChapter);

        return R.ok();

    }

四、删除

1、web层

    //根据ID删除章节

    //章节里面有小节需要先将小节删除

    @ApiOperation(value = "根据ID删除章节")

    @DeleteMapping("{chapterId}")

    public R deleteChapterById(@PathVariable String chapterId){

        boolean flag = chapterService.deleteChapter(chapterId);

        if (flag){

            return R.ok();

        }else {

            return R.error();

        }

    }

2、Service

EduChapterService层:接口

    //根据ID删除章节

    //章节里面有小节需要先将小节删除

    boolean deleteChapter(String chapterId);

ChapterService层:实现

    //删除章节的方法

    @Override

    public boolean deleteChapter(String chapterId) {

        //根据chapterId章节id 查询小节表,如果查询数据,不进行删除

        QueryWrapper wrapper = new QueryWrapper<>();

        wrapper.eq("chapter_id",chapterId);

        //返回的是集合,但是我们只需要判断章节里有没有小节

//        List list = videoService.list(wrapper);

        int count = videoService.count(wrapper);

        //判断

        if (count > 0 ){//查询出小节,不进行删除

            throw new GuliException(20001,"该分章节下存在视频课程,请先删除视频课程");

        }else {

            //删除章节

            int result = baseMapper.deleteById(chapterId);

            //成功 1>0 0>0

            return result>0;

        }

    }

五、Swagger测试



03-章节管理前端页面实现

一、定义api

    //添加章节 传入章节对象chapter

    addChapter(chapter){

        return request({

            url:`/eduservice/chapter/addChapter`,

            method:'post',

            data:chapter

        })

    },

    //根据ID查询章节

    getChapter(chapterId){

        return request({

            url:`/eduservice/chapter/getChapterById/${chapterId}`,

            method:'get'

        })

    },

    //修改章节

    updateChapter(chapter){

        return request({

            url:`/eduservice/chapter/updateChapterById`,

            method:'post',

            data:chapter

        })

    },

    //删除章节

    deleteChapter(chapterId){

        return request({

            url:`/eduservice/chapter/${chapterId}`,

            method:'delete'

        })

    }

二、新增章节页面功能

1、定义data数据

            dialogChapterFormVisible:false,//设置默认弹框的值false(即不显示)

            chapter:{//章节对象

                title:'',

                sort:0

            },

2、添加章节按钮

 @click="dialogChapterFormVisible = true">添加章节

3、章节表单dialog

    

        

            

                

            

            

                

            

        

        

            "dialogChapterFormVisible = false">取 消

            saveOrUpdate">确 定

        

    

4、添加章节methods

        //添加章节

        saveOrUpdate(){

            chapter.addChapter(this.chapter)

                .then(response=>{

                    //关闭弹框

                    this.dialogChapterFormVisible = false

                    //提示信息

                    this.$message({

                        type:'success',

                        message:'添加章节成功'

                    });

                    //刷新页面  即把所有数据再查询一次

                    this.getChapterVideo()

                })

        },

执行了全局异常处理:说明后端代码有问题了

错误原因:chapter对象的实体类中有courseId没有值

        //添加章节

        saveOrUpdate(){

            //设置课程id到chapter对象里面

            //因为chapter对象的实体类中有courseId

            this.chapter.courseId = this.courseId

            chapter.addChapter(this.chapter)

                .then(response=>{

                    //关闭弹框

                    this.dialogChapterFormVisible = false

                    //提示信息

                    this.$message({

                        type:'success',

                        message:'添加章节成功'

                    });

                    //刷新页面 即把所有数据再查询一次

                    this.getChapterVideo()

                })

        },



问题:

解决方案:每次弹框的时候把表单数据清空

   @click="dialogChapterFormVisible = true">添加章节

把添加章节中的值写到一个方法里面:

@click="openChapterDialog()">添加章节

通过方法进行弹框操作:

        //弹出添加章节页面

        openChapterDialog(){

            //弹框

            this.dialogChapterFormVisible = true

            //表单数据清空

            this.chapter.title =''

            this.chapter.sort = 0            

        },

三、修改章节信息

1、编辑章节按钮

            v-for="chapter in chapterVideoList"

            :key="chapter.id">

            

                {{ chapter.title }}                

                

                    添加课时

                    

                    

                     @click="openEditChapter(chapter.id)">编辑

                    删除

                

            

2、定义编辑方法

        //修改章节弹框、数据回显

        //方法中需要章节id,如chapterId

        openEditChapter(chapterId){

            //弹框

            this.dialogChapterFormVisible = true

            //调用接口

            chapter.getChapter(chapterId)

                .then(response=>{

                    this.chapter = response.data.chapter

                })

        },

3、定义更新方法

         //修改章节 与添加章节差不多

        updateChapter(){

            //设置课程id到chapter对象里面

            //因为chapter对象的实体类中有courseId

            this.chapter.courseId = this.courseId

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

            }

        },

四、删除章节

1、按钮

removeChapter(chapter.id)">删除

2、定义删除方法

        //删除章节

        removeChapter(chapterId){

            this.$confirm('此操作将删除章节, 是否继续?', '提示', {

                    confirmButtonText: '确定',

                    cancelButtonText: '取消',

                    type: 'warning'

                }).then(() => {//点击确定,执行then方法

                    //调用删除的方法

                    chapter.deleteChapter(chapterId)

                        .then(response=>{//删除成功            

                        //提示信息

                        this.$message({

                            type: 'success',

                            message: '删除成功!'

                        })

                        //刷新页面 即把所有数据再查询一次

                        this.getChapterVideo()             

                    })

                })//点击取消,执行catch方法

        },



2 课时(小节)管理

01-课时管理后端开发

EduVideoController.java

@RestController

@RequestMapping("/eduservice/video")

@CrossOrigin

public class EduVideoController {

    @Autowired

    private EduVideoService eduVideoService;


    //添加小节

    @ApiOperation(value = "添加小节")

    @PostMapping("addVideo")

    public R addVideo(@ApiParam(name = "videoForm", value = "课时对象", required = true)

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

    }


    //根据id查询

    @ApiOperation(value = "根据ID查询小节")

    @GetMapping("getVideoById/{id}")

    public R getVideoById(String id){

        EduVideo eduVideo = eduVideoService.getById(id);

        return R.ok().data("video",eduVideo);

    }


    //修改小节

    @PostMapping("updateVideo")

    public R updateVideo(@RequestBody EduVideo eduVideo){

        eduVideoService.updateById(eduVideo);

        return R.ok();

    }

}

openVideo(chapter.id)">添加小节

添加和修改课时表单:课时表单dialog

    

    

        

            

                video.title"/>

            

            

                video.sort" :min="0" controls-position="right"/>

            

            

                video.free">

                    免费

                    默认

                

            

            

                

            

        

        

            取 消

            确 定

        

    

data

            // video对象的定义

            video:{

                title:'',

                sort:0,

                free:0,

                videoSourceId:''

            },

dialogVideoFormVisible:false

methods

         //添加小节弹框方法

        openVideo(chapterId){

            this.dialogVideoFormVisible = true

        },

测试:

http://localhost:9528/#/course/chapter/1281130194916139010

定义api

创建video.js

参考course.js 

import request from '@/utils/request'

export default{

    //添加小节

    addVideo(video){

        return request({

            url:`/eduservice/video/addVideo`,

            method:'post',

            data:video

        })

    },

    //根据ID查询小节

    getVideo(id){

        return request({

            url:`/eduservice/video/deleteVideo/${id}`,

            method:'get'

        })

    },

    //修改小节

    updateVideo(video){

        return request({

            url:`/eduservice/video/updateVideo`,

            method:'post',

            data:video

        })

    },

    //删除小节

    deleteVideo(id){

        return request({

            url:`/eduservice/chapter/deleteVideo/${id}`,

            method:'delete'

        })

    }

}

引入到chapter.vue

import video from'@/api/edu/video'

添加小节的时候需要课程id和章节id:

        //添加小节弹框方法

        openVideo(chapterId){

            //弹框

            this.dialogVideoFormVisible = true

            //添加小节的时候需要课程id和章节id

            //设置章节id

            this.video.chapterId = chapterId

            //设置课程id

            this.video.courseId = this.courseId

        },

添加小节方法:

        //添加小节

        addVideo(){

            video.addVideo(this.video)

                .then(response=>{

                    //关闭弹框

                    this.dialogVideoFormVisible = false

                    //提示信息

                    this.$message({

                        type:'success',

                        message:'添加小节成功'

                    });

                    //刷新页面 即把所有数据再查询一次

                    this.getChapterVideo()

                })

        },

       saveOrUpdateVideo(){

            this.addVideo()

        },

测试:

清空表单数据:

      //添加小节弹框方法

        openVideo(chapterId){

            //弹框

            this.dialogVideoFormVisible = true

            //添加小节的时候需要课程id和章节id

            //设置章节id

            this.video.chapterId = chapterId

            //设置课程id

            this.video.courseId = this.courseId

            //表单数据清空

            this.video.title = ''

            this.video.sort = 0

            this.video.free = 0

            this.videoSourceId = ''

        },

编辑:

openEditVideo(video.id)">编辑


        //小节弹框、数据回显

        //方法中需要小节id

        openEditVideo(videoId){

            //弹框

            this.dialogVideoFormVisible = true

            //调用接口

            video.getVideo(videoId)

                .then(response=>{

                    this.video = response.data.video

                })

        },

解决是否免费不回显问题:

修改与实体类里面对应:将所有free改为isFree

解决添加小节表单的是否免费没有默认值问题:


02-课时管理前端开发

删除课时

1、按钮

  @click="removeVideo(video.id)">删除

2、定义删除方法

         //删除小节

        removeVideo(videoId){

            this.$confirm('此操作将删除小节, 是否继续?', '提示', {

                    confirmButtonText: '确定',

                    cancelButtonText: '取消',

                    type: 'warning'

                }).then(() => {//点击确定,执行then方法

                    //调用删除的方法

                    video.deleteVideo(videoId)

                        .then(response=>{//删除成功            

                        //提示信息

                        this.$message({

                            type: 'success',

                            message: '删除成功!'

                        })

                        //刷新页面 即把所有数据再查询一次

                        this.getChapterVideo()             

                    })

                })//点击取消,执行catch方法

        },

http://localhost:9528/#/course/chapter/1281130194916139010



3 课程最终发布

http://localhost:9528/#/course/publish/1281130194916139010

    可以根据课程id查询。

    把课程信息最终显示进行确认,但是需要查询多张表

    方法一:可以使用封装的方式,比如章节小节,一级二级分类。

          但是现在不太合适因为表比较多。

        在实际中,当查询的表比较多,或者要写一些复杂的查询操作,一般建议手写sql语句实现。

多表连接查询

    内连接:查询两张表有关联的数据,比如下表只能查询出前两条数据,运维没有关联,因此查询不出来

    左外连接(LEFT OUTER JOIN,OUTER可省略):左边表所有数据都查出来,右边表只查关联

    右外连接:右边表所有数据都查出来,左边表只查关联

         一般用的比较多的是内连接和左外连接。

        本案例中,特点:课程中课程没有简介,即简介为空;可能也没有分类,也没有讲师。所以使用内连接不太合适。因此使用左外连接比较合适。

         左外连接查询课程简介、课程讲师:

        课程分类:特点有两个ID(一个一级分类,一个二级分类),但是一级分类、二级分类都保存在edu_subject表中,如果一张表中有多个字段都同时关联同一张表,可以查询多次,可以先使用一级分类ID查询表关联出来,再使用二级分类ID查询关联出来,即查询两次。

根据课程id进行查询:

测试:

SELECT *

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 = es1.id

WHERE ec.id='1281130194916139010'

mapper:

        mapper中有接口和接口有对应的配置文件,在接口中可以定义方法,在配置文件中写sql语句。

        在配置文件中编写sql语句:

            在接口中编方法,根据课程id查询课程基本信息方法,这个方法需要编写一个返回对象(之前定义的对象都不太合适),专门进行封装。

02-课程最终发布后端

一、根据id查询课程发布信息

1、定义vo

CoursePublishVo

@Data

public class CoursePublishVo {

    private String id;

    private String title;

    private String cover;

    private Integer lessonNum;

    private String subjectLevelOne;

    private String subjectLevelTwo;

    private String teacherName;

    private String price;//只用于显示

}

2、数据访问层

在接口EduCourseMapper.java中编方法

public interface EduCourseMapper extends BaseMapper {

    public CoursePublishVo getPublishCourseInfo(String courseId);

}

实现:EduCourseMapper.xml编写sql语句

        可通过select标签进行查询,属性一:id值为mapper接口中的方法名称,属性二:resultType返回值类型需要为包和类型的全路径。

        在select中编写sql语句,进行修改,需要与实体类进行对应:

        课程id是需要传递过来的,法一:where ec.id=#{courseId} 法二:where ec.id=${courseId},但是我们一般不用$,因为$表示字符串拼接,会产生sql注入问题。

   

3、web层

    //根据ID获取课程发布信息

    @ApiOperation(value = "根据ID获取课程发布信息")

    @GetMapping("getPublishCourseInfo/{courseId}")

    public R getPublishCourseInfo(@PathVariable String courseId){

        CoursePublishVo coursePublishVo = courseService.getPublishCourseInfo(courseId);

        return R.ok().data("publish",coursePublishVo);

    }

4、业务层

接口:

    //根据ID获取课程发布信息

    CoursePublishVo getPublishCourseInfo(String courseId);

实现:

    @Override

    public CoursePublishVo getPublishCourseInfo(String courseId) {

        return baseMapper.getPublishCourseInfo(courseId);

    }

        //调用mapper,在impl实现类中调用方法,可以使用baseMapper也可以写this,但是调用我们自己写的mapper,就必须写baseMapper才能调到。

        通过controller调service,然后service用baseMapper调mapper中的方法,方法会最终执行到sql语句,得到数据。

测试:报告异常“执行了全局异常处理”

BinDing : 数据绑定异常。

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.atguigu.eduservice.mapper.EduCourseMapper.getPublishCourseInfo

导致这个错误的两个原因:一 看mapper中的方法名......是否写错;二 由于maven默认的加载机制造成的问题,maven加载时候,把java文件夹里面. java类型文件进行编译,如果其他类型文件,不会加载。

问题分析:

        dao层编译后只有class文件,没有mapper.xml,因为maven工程在默认情况下src/main/java目录下的所有资源文件是不发布到target目录下的,

解决方案:

1、在guli_edu的pom中配置如下节点

 **/*.xml

*表示加载的是一级目录

**表示多级目录,在xml前面有很多级目录

       

           

                src/main/java

               

                    **/*.xml

               

                false

           

       

   

2、在Spring Boot配置文件中添加配置(service_edu的application.properties)

#配置mapper xml文件的路径

mybatis-plus.mapper-locations=classpath:com/atguigu/eduservice/mapper/xml/*.xml

classpath表示类路径:src里面的内容

重新启动,在swagger中测试:

courseId:1281130194916139010


01-课程最终发布前端

一、前端代码

发布页面课程信息显示:

1、定义api

分析这个页面一共有两个远程方法:一个是根据课程id获取课程基本预览信息,第二个是发布课程

/api/edu/course.js

//发布课程

    getPublicCourseInfo(courseId){

        return request({

            url:`/eduservice/course/getPublishCourseInfo/${courseId}`,

            method:'get'

        })

    }

2、定义数据模型

/edu/course/publish.vue

 data(){

        return {

            saveBtnDisabled: false, // 保存按钮是否禁用

            courseId:'',// 所属课程

            coursePublish:{}

        }

    },

3、组件方法定义

在publish.vue中引入js文件

import course from '@/api/edu/course'

得到路由中的id值:

created(){

      if(this.$route.params && this.$route.params.id){

        this.courseId = this.$route.params.id

      }

    },

调用接口中的方法:

created(){

      if(this.$route.params && this.$route.params.id){

        this.courseId = this.$route.params.id

        // 根据id获取课程基本信息

        this.getCoursePublishId()

      }

    },

编写获取数据的方法:

 //根据课程id查询

        getCoursePublishId(){

          course.getPublicCourseInfo(this.courseId)

            .then(response=>{

              this.coursePublish = response.data.publish

            })

        }

4、组件模板

    把内容在页面中进行显示,获取publishCourse对象里面的值,通过{{}}。

    

      coursePublish.cover">

      

        

{{ coursePublish.title }}

        共{{ coursePublish.lessonNum }}课时

        

所属分类:{{ coursePublish.subjectLevelOne }} — {{ coursePublish.subjectLevelTwo }}

        

课程讲师:{{ coursePublish.teacherName }}

        ¥{{ coursePublish.price }}

      

    

    <div>

              返回修改

              发布课程

    div>

5、css样式

.ccInfo {

    background: #f5f5f5;

    padding: 20px;

    overflow: hidden;

    border: 1px dashed #DDD;

    margin-bottom: 40px;

    position: relative;

}

.ccInfo img {

    background: #d6d6d6;

    width: 500px;

    height: 278px;

    display: block;

    float: left;

    border: none;

}

.ccInfo .main {

    margin-left: 520px;

}

.ccInfo .main h2 {

    font-size: 28px;

    margin-bottom: 30px;

    line-height: 1;

    font-weight: normal;

}

.ccInfo .main p {

    margin-bottom: 10px;

    word-wrap: break-word;

    line-height: 24px;

    max-height: 48px;

    overflow: hidden;

}

.ccInfo .main p {

    margin-bottom: 10px;

    word-wrap: break-word;

    line-height: 24px;

    max-height: 48px;

    overflow: hidden;

}

.ccInfo .main h3 {

    left: 540px;

    bottom: 20px;

    line-height: 1;

    font-size: 28px;

    color: #d32f24;

    font-weight: normal;

    position: absolute;

}

http://localhost:9528/#/course/publish/1281130194916139010


发布课程(修改课程状态):

一、根据id发布课程

1、web层

//根据id发布课程

    //课程最终发布

    //修改课程状态

    @ApiOperation(value = "根据id发布课程")

    @PostMapping("publishCourse/{courseId}")

    public R publishCourse(@PathVariable String courseId){

        EduCourse eduCourse = new EduCourse();

        eduCourse.setId(courseId);

        eduCourse.setStatus("Normal");//设置课程发布状态

        courseService.updateById(eduCourse);

        return R.ok();

    }

二、前端

1、定义api

分析这个页面一共有两个远程方法:一个是根基课程id获取课程基本预览信息,第二个是发布课程

/api/edu/course.js

 //课程最终发布

    publicCourseInfo(courseId){

        return request({

            url:`/eduservice/course/publishCourse/${courseId}`,

            method:'post'

        })

    }

2、组件方法定义

发布课程的点击事件

publish(){

              this.$confirm('发布课程, 是否继续?', '提示', {

                    confirmButtonText: '继续',

                    cancelButtonText: '取消',

                    type: 'warning'

                }).then(() => {//点击继续,执行then方法

                    course.publicCourseInfo(this.courseId)

                      .then(response=>{

                        //提示信息

                        this.$message({

                            type: 'success',

                            message: '发布成功!'

                        })

                        //跳转到第二步

                        this.$router.push({path:'/course/list'})

                      })                  

                })//点击取消,执行catch方法

        },

测试:

你可能感兴趣的:(day08【课程发布-课程大纲和课程发布】)