element vue springboot
1. 添加一级章节按钮
1.1. 后端 - 章节表insertChapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   | package com.online.edu.eduservice.controller;
 
  import com.online.edu.common.R; import com.online.edu.eduservice.entity.EduChapter; import com.online.edu.eduservice.entity.query.QueryChapter; import com.online.edu.eduservice.service.EduChapterService; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;
  import java.util.List;
  @RestController @RequestMapping("/eduservice/edu-chapter") @CrossOrigin public class EduChapterController {
      @Autowired     EduChapterService eduChapterService;
      @ApiOperation("添加章节")     @PostMapping("/insertChapter")     public R insert(@ApiParam("章节") @RequestBody EduChapter eduChapter){         boolean flag = eduChapterService.save(eduChapter);         if(flag){             return R.ok().message("章节添加成功").data("chapterId",eduChapter.getId());         }else{             return R.error().message("章节添加失败");         }     } }
   | 
 
1.2. 前端 - chapter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | import request from '@/utils/request'
  const base = '/eduservice/edu-chapter'
  export default{
      insertChapter(chapterObj){         return request({             url : `${base}/insertChapter`,             method:'post',             data:chapterObj         })     } }
   | 
 
1.3. 前端 - el-dialog标签-实现增加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
   | <el-button  type="primary" round @click="insertChapter">      添加一级分类 </el-button>
  <!-- 章节表 --> <el-dialog title="添加章节" :visible.sync="chapterFormVisible" :show-close="false">   <el-form :model="chapterObj">       <el-form-item label="章节名称" :label-width="formLabelWidth">           <el-input v-model="chapterObj.title" autocomplete="off"></el-input>       </el-form-item>       <el-form-item label="章节排序" :label-width="formLabelWidth">           <el-tooltip content="数值越高排在越先" placement="right" effect="light">               <el-input-number :min="0" v-model="chapterObj.sort" />           </el-tooltip>       </el-form-item>   </el-form>   <div slot="footer" class="dialog-footer">       <el-button @click="cancel">取 消</el-button>       <el-button type="primary" @click="saveOrUpdateChapter">确 定</el-button>   </div> </el-dialog>
  <script>   import chapter from '@/api/edu/chapter'      data(){         return{             chapterObj:{                 id:'',                 courseId:'',                 title: '',                 sort: 0             },             formLabelWidth: '120px',             chapterFormVisible:false,             courseId: '',         }     },     created(){         //路径中的id值         this.courseId = this.$route.params.id         this.chapterObj.courseId=this.courseId     },     methods{       	//添加一级章节         insertChapter(){             this.chapterFormVisible=true         },         //章节取消按钮         cancel(){             this.chapterFormVisible = false             this.chapterObj.title=''             this.chapterObj.sort =0         },         //通过章节id判断进行的操作         saveOrUpdateChapter(){           if(this.chapterObj.id){
            }else{               //插入               chapter.insertChapter(this.chapterObj).then(response=>{               this.dialogFormVisible=false               this.chapterObj.id=response.data.chapterId                 this.$message({                   type:'success',                   message:response.message                   })               }).catch(response=>{                   this.$message({                       type: 'error',                       message: response.message                   })               })           }       }      }
  </script>
   | 
 
1.4. 最终实现

2. 显示章节
2.1. 后端 - QueryChapter类
得到所有的章节和所属章节下的课时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | package com.online.edu.eduservice.entity.query;
  import com.online.edu.eduservice.entity.EduVideo; import io.swagger.annotations.ApiParam; import lombok.Data;
  import java.util.ArrayList; import java.util.List;
  @Data public class QueryChapter {
      @ApiParam("章节ID")     private String id;
      @ApiParam("章节名称")     private String title;
      @ApiParam("章节下视频")     private List<EduVideo> children = new ArrayList<>(); }
   | 
 
2.2. 后端 - selectAllInfo(courseId) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   |  @Override public List<QueryChapter> selectAllInfo(String id){
      List<QueryChapter> chapters = new ArrayList<>();
           QueryWrapper<EduChapter> queryWrapper = new QueryWrapper<>();     queryWrapper.eq("course_id",id);          queryWrapper.orderByDesc("sort");     List<EduChapter> eduChapters = baseMapper.selectList(queryWrapper);
           for(EduChapter chapter:eduChapters){         QueryChapter queryChapter = new QueryChapter();         queryChapter.setId(chapter.getId());         queryChapter.setTitle(chapter.getTitle());
       	          QueryWrapper<EduVideo> videoWrapper = new QueryWrapper<>();         videoWrapper.eq("chapter_id",chapter.getId());         videoWrapper.orderByDesc("sort");         List<EduVideo> videos = eduVideoService.selectAll(videoWrapper);
          queryChapter.setChildren(videos);
          chapters.add(queryChapter);     }
      return chapters; }
 
  | 
 
2.3. 后端 - deleteWrapper - EduVideo
1 2 3 4 5
   | @Override public List<EduVideo> selectAll(QueryWrapper<EduVideo> queryWrapper){
       return baseMapper.selectList(queryWrapper); }
   | 
 
2.4. 后端 - 控制器方法-listChapter
1 2 3 4 5 6 7
   | @ApiOperation("根据课程ID查询所有章节") @GetMapping("/listChapter/{id}") public R listChapter(@ApiParam("课程ID")@PathVariable String id){     List<QueryChapter> lists = eduChapterService.selectAllInfo(id);
      return R.ok().data("chapterList",lists); }
  | 
 
2.5. 前端 - chapter.js
1 2 3 4 5 6
   | getChapterList(id){     return request({         url: `${base}/listChapter/`+id,         method:'get'     }) }
  | 
 
2.6. 前端 - chapter.vue
v-for 显示所有章节及课时 
样式来自 https://element.eleme.cn/#/zh-CN/component/button
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
   | <ul class="chapterList">     <li v-for="chapter in chapterList" :key="chapter.id">         <p>             <strong>{{chapter.title}}</strong>             <span class="acts">                 <el-tooltip content="添加课时" placement="top" effect="light">                     <el-button type="success" icon="el-icon-plus" circle v-on:click="insertVideo(chapter.id)"></el-button>                 </el-tooltip>                 <el-tooltip content="修改信息" placement="top" effect="light">                     <el-button type="primary" icon="el-icon-edit" circle @click="updateChapter(chapter.id)"></el-button>                 </el-tooltip>                  <el-tooltip content="删除章节及课时" placement="top" effect="light">                     <el-button type="danger" icon="el-icon-delete" circle @click="deleteChapter(chapter.id)"></el-button>                  </el-tooltip>             </span>                               </p>         <ul class="chapterList videoList">             <li v-for="video in chapter.children" :key="video.id">                  <p>{{video.title}}                     <span class="acts">                         <el-button type="text" @click="updateVideo(video.id)">编辑</el-button>                         <el-button type="text" @click="deleteVideo(video.id)">删除</el-button>                     </span>                 </p>             </li>         </ul>     </li> </ul>
  <script>   import chapter from '@/api/edu/chapter'   data(){     return{       coursId:'',       chapterList:[]     }   }   created(){     this.getChapterList(this.courseId)   },   methods{       //所有章节及课时       getChapterList(id){           chapter.getChapterList(id).then(response=>{               this.chapterList=response.data.chapterList           }).catch()       }   } </script>
  <!-- 样式 --> <style scoped> .chapterList{     position: relative;     list-style: none;     padding-right: 0px;     margin-right: 100px; } .chapterList li{     position: relative; }
   .chanpterList p{     padding-right: 50px; }  .chapterList strong{     font-size: 17px; }  .chapterList .acts {     float: right;     font-size: 14px;     justify-content: space-between; }
  .videoList{     padding-left: 0px;     margin-left:50px ; }
  .videoList p{     padding-left: 10px;     border-bottom: 2px dotted #DDD; }  </style>
   | 
 
2.7. 最终样式

3. 更新章节
3.1. 后端-controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | @ApiOperation("根据ID查询章节") @GetMapping("/selectChapterById/{id}") public R selectById(@ApiParam("章节ID") @PathVariable String id){     EduChapter chapter = eduChapterService.getById(id);     if (chapter!=null){         return R.ok().data("items",chapter);     }else{         return R.error().message("查询失败");     } }
  @ApiOperation("根据ID更新章节") @PostMapping("/updateChapter") public R update(@ApiParam("章节信息") @RequestBody EduChapter eduChapter){     boolean flag = eduChapterService.updateById(eduChapter);     if (flag){         return R.ok().message("更新成功");     }else{         return R.error().message("更新失败");     } }
  | 
 
3.2. 前端-chapter.js
1 2 3 4 5 6 7 8 9 10 11 12 13
   | updateChapter(chapterObj){     return request({         url : `${base}/updateChapter`,         method:'post',         data:chapterObj     }) }, getChapterById(id){     return request({         url: `${base}/selectChapterById/`+id,         method:'get'     }) }
  | 
 
3.3. 前端-chapter.vue
点击添加按钮显示输入框 , 按钮点击传递章节id v-on:click="updateChapter(chapter.id)
点击确认按钮提交数据 @click="saveOrUpdateChapter"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
   | <script>   saveOrUpdateChapter(){     //如果是插入,章节id是不存在的     if(this.chapterObj.id){         chapter.updateChapter(this.chapterObj).then(response=>{             this.$message({                 type:'success',                 message: response.message             })             //刷新页面             this.getChapterList(this.courseId)             //关闭框             this.chapterFormVisible=false         }).catch(response=>{             this.$message({                 type:'error',                 message:response.message             })         })     }  },    //更新章节按钮   updateChapter(id){       this.chapterObj.id = id       this.chapterFormVisible=true       //根据id得到数据       this.getchapterById(id)   }, 		//根据id查询章节     getchapterById(id){         chapter.getChapterById(id).then(response=>{             this.chapterObj=response.data.items         }).catch(response=>{             this.$message({                 type:'error',                 message:response.message             })         })
      }
 
  </script>
   | 
 
4. 删除章节
4.1. 后端-删除章节及课时
1 2 3 4 5 6 7 8 9 10
   | @Override public boolean deleteById(String id) {          QueryWrapper<EduVideo> queryWrapper = new QueryWrapper<>();     queryWrapper.eq("chapter_id",id);     eduVideoService.deleteWrapper(queryWrapper);
      int flag = baseMapper.deleteById(id);     return flag>0; }
   | 
 
4.2. 后端-controller
1 2 3 4 5 6 7 8 9 10
   | @ApiOperation("删除章节") @DeleteMapping("/deleteChapterById/{id}") public R deleteById(@ApiParam("章节ID")@PathVariable String id) {     boolean flag = eduChapterService.deleteById(id);     if (flag) {         return R.ok().message("章节修改成功");     } else {         return R.error().message("章节修改失败");     } }
  | 
 
4.3. 前端- chapter.js
1 2 3 4 5 6
   | deleteChapterById(id){     return request({         url:`${base}/deleteChapterById/`+id,         method:'delete'     }) }
  | 
 
4.4. 前端 - chapter.vue
点击编辑按钮@click="updateChapter(chapter.id)"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
   | <script>     //删除章节按钮     deleteChapter(id){         this.$confirm('此操作将永久删除章节及课时信息, 是否继续?', '提示', {             confirmButtonText: '确定',             cancelButtonText: '取消',             type: 'warning'         })         .then(() => {             //return 后then方法才会执行             return chapter.deleteChapterById(id)         })         .then(response => {             //重新所有分类             this.getChapterList(this.courseId)             this.$message({                 type: 'success',                 message: response.message             })
          }).catch(response => {             //判断错误操作类别             //console.log(response)             if(response === 'cancel'){                 this.$message({                     type: 'info',                     message: '已取消删除'                 })              } else{                 this.$message({                     type: 'error',                     message: response.message                 })              }                 })     } </script>
   | 
 
5. 添加课时
5.1. 后端-EduVideoServiceImpl
1 2 3 4 5
   | @Override public boolean insert(EduVideo video) {   int flag=baseMapper.insert(video);   return flag>0; }
   | 
 
5.2. 后端-controller
1 2 3 4 5 6 7 8 9 10
   | @ApiOperation("删除视频信息") @DeleteMapping("/deleteVideoById/{id}") public R deleteVideo(@ApiParam("视频ID")@PathVariable String id) {     boolean flag = eduVideoService.deleteById(id);     if (flag) {         return R.ok().message("删除视频成功");     } else {         return R.error().message("删除视频失败");     } }
  | 
 
5.3. 前端-video.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | import request from '@/utils/request'
  const base ='/eduservice/edu-video'
  export default{      insertVideo(videoObj){         return request({             url:`${base}/insertVideo`,             method:'post',             data:videoObj         })     } }
   | 
 
5.4. 前端-chapter.vue
videoFormVisible 控制表单的显示 , 当点击添加按钮,this.videoFormVisible=true 使表单显示
@click="saveOrUpdateVideo" 控制添加or更新课时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
   | <!-- 课时表 --> <el-dialog title="添加课时" :visible.sync="videoFormVisible" :show-close="false">     <el-form :model="videoObj">         <el-form-item label="视频名称" :label-width="formLabelWidth">             <el-input v-model="videoObj.title"/>         </el-form-item>         <el-form-item label="视频时长" :label-width="formLabelWidth">             <el-tooltip content="按0.02秒递增" placement="right" effect="light">                 <el-input-number v-model="videoObj.duration" :min="0" :precision="2"              controls-position="right" step="0.02" placeholder="00:00"/> 秒             </el-tooltip>         </el-form-item>         <el-form-item label="视频排名" :label-width="formLabelWidth">              <el-tooltip content="数值越高排在越先" placement="right" effect="light">                 <el-input-number v-model="videoObj.sort" :min="0" />              </el-tooltip>         </el-form-item>         <el-form-item label="是否可以试听" :label-width="formLabelWidth">             <el-radio v-model="videoObj.isFree" :label="false"> 可以</el-radio>             <el-radio v-model="videoObj.isFree" :label="true"> 不可以</el-radio>         </el-form-item>     </el-form>     <div slot="footer" class="dialog-footer">             <el-button @click="videoCancel">取 消</el-button>             <el-button type="primary" @click="saveOrUpdateVideo">确 定</el-button>         </div> </el-dialog>
  <script>   import video from '@/api/edu/video'   data(){     return{       videoObj:{           id:'',           chapterId: "",           courseId: "",           duration: '',           isFree: false,           size: 0,           sort: 0,           title: ""       },       videoFormVisible:false,        }   }   //根据章节ID添加课时按钮   insertVideo(id){       this.videoFormVisible=true       this.videoObj.chapterId=id   },     //视频确定按钮事件判断     saveOrUpdateVideo(){         if(this.videoObj.id){
          }else{             console.log(this.videoObj)             video.insertVideo(this.videoObj).then(response=>{                 this.videoFormVisible=false                 this.videoObj.id=response.data.videoId                 this.$message(({                     type:'success',                     message:response.message                 }))                 this.getChapterList(this.courseId)             }).catch(response=>{                 this.$message(({                     type:'error',                     message:response.message                 }))
              })         }         //console.log(this.videoObj)     } </script>
   | 
 
5.5. 最终显示

6. 更新课时
6.1. 后端-controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | @ApiOperation("根据ID查询视频信息") @GetMapping("/selectVideoById/{id}") public R selectVideoById(@ApiParam("视频ID")@PathVariable String id) {     EduVideo video = eduVideoService.getById(id);     if (video != null) {         return R.ok().data("items",video);     } else {         return R.error().message("查询视频失败");     } }
  @ApiOperation("更新视频信息") @PostMapping("/updateVideo") public R updateVideo(@ApiParam("视频信息")@RequestBody EduVideo video) {     boolean flag = eduVideoService.updateById(video);     if (flag) {         return R.ok().message("更新视频成功");     } else {         return R.error().message("更新视频失败");     } }
  | 
 
6.2. 前端 - video.js
1 2 3 4 5 6 7 8 9 10 11 12 13
   | selectVideoById(id){     return request({         url:`${base}/selectVideoById/`+id,         method:'get'             }) }, updateVideo(videoObj){     return request({         url:`${base}/updateVideo`,         method:'post',         data:videoObj     }) }
  | 
 
6.3. 前端 -chapter.vue
点击编辑 @click="updateVideo(video.id)" 显示表单,查询id对应video表数据
@click="saveOrUpdateVideo" 确定按钮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | <script>   updateVideo(id){       this.videoFormVisible=true       this.videoObj.id = id       this.getVideoById(id)   },   getVideoById(id){       video.selectVideoById(id).then(response=>{           this.videoObj=response.data.items       })   }     //视频确定按钮事件判断     saveOrUpdateVideo(){       if(this.videoObj.id){           video.updateVideo(this.videoObj).then(response=>{               this.$message({                   type:'success',                   message: response.message               })               this.getChapterList(this.courseId)               this.videoFormVisible=false           }).catch(response=>{               this.$message({                   type:'error',                   message:response.message               })           })       }else{       }     }
  </script>
   | 
 
7. 删除课时
7.1. 后端-controller
采用basemapper中的方法
1 2 3 4 5 6 7 8 9 10
   | @ApiOperation("删除视频信息") @DeleteMapping("/deleteVideoById/{id}") public R deleteVideo(@ApiParam("视频ID")@PathVariable String id) {     boolean flag = eduVideoService.deleteById(id);     if (flag) {         return R.ok().message("删除视频成功");     } else {         return R.error().message("删除视频失败");     } }
  | 
 
7.2. 后端-EduVideoServiceImpl
1 2 3 4
   | public boolean deleteById(String id){     int flag = baseMapper.deleteById(id);     return flag>0; }
  | 
 
7.3. 前端 - video.js
1 2 3 4 5 6
   | deleteVideoById(id){     return request({         url: `${base}/deleteVideoById/`+id,         method:'delete'     }) }
  | 
 
7.4. 前端 - chapter.vue
根据 @click="deleteVideo(video.id)" 删除 操作,传递的是课时的id,根据课时id删除课时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
   | <script>    deleteVideo(id){       this.$confirm('此操作将永久删除课时信息, 是否继续?', '提示', {           confirmButtonText: '确定',           cancelButtonText: '取消',           type: 'warning'       })       .then(() => {           //return 后then方法才会执行           return video.deleteVideoById(id)       })       .then(response => {           //重新所有分类           this.getChapterList(this.courseId)           this.$message({               type: 'success',               message: response.message           })
        }).catch(response => {           //判断错误操作类别           //console.log(response)           if(response === 'cancel'){               this.$message({                   type: 'info',                   message: '已取消删除'               })            } else{               this.$message({                   type: 'error',                   message: response.message               })            }               })
    }
  </script>
   | 
 
7.5. 最终显示

8. 传递课程id参数
@click="primary" 返回到上一步
@click="next" 保存并下一步
1 2 3 4 5 6 7 8 9 10 11 12 13
   | <script>   next(){       this.$router.push({           path:"/course/publish/"+this.courseId       })   },   primary(){       this.$router.push({           path:'/course/info/'+this.courseId       })   }
  </script>
   |