在线教育网站搭建七课程大纲填写

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
//根据courseId查询章节和视频
@Override
public List<QueryChapter> selectAllInfo(String id){

List<QueryChapter> chapters = new ArrayList<>();

//根据course_id 查询所有章节
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());

//根据章节ID查询所有视频
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>
本文结束  感谢您的阅读