Skip to main content

一、后端实现

1、定义vo

ChapterVo

package com.guli.edu.vo;
@ApiModel(value = "章节信息")
@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

package com.guli.edu.vo;
@ApiModel(value = "课时信息")
@Data
public class VideoVo implements Serializable {

private static final long serialVersionUID = 1L;

private String id;
private String title;
private Boolean free;
}

2、服务层

接口

package com.guli.edu.service;
public interface ChapterService extends IService<Chapter> {
List<ChapterVo> nestedList(String courseId);
}

实现

package com.guli.edu.service.impl;

@Service
public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> implements ChapterService {

@Autowired
private VideoService videoService;

@Override
public List<ChapterVo> nestedList(String courseId) {

//最终要的到的数据列表
ArrayList<ChapterVo> chapterVoArrayList = new ArrayList<>();

//获取章节信息
QueryWrapper<Chapter> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("course_id", courseId);
queryWrapper1.orderByAsc("sort", "id");
List<Chapter> chapters = baseMapper.selectList(queryWrapper1);

//获取课时信息
QueryWrapper<Video> queryWrapper2 = new QueryWrapper<>();
queryWrapper2.eq("course_id", courseId);
queryWrapper2.orderByAsc("sort", "id");
List<Video> videos = videoService.list(queryWrapper2);

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

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

//填充课时vo数据
ArrayList<VideoVo> videoVoArrayList = new ArrayList<>();
int count2 = videos.size();
for (int j = 0; j < count2; j++) {

Video video = videos.get(j);
if(chapter.getId().equals(video.getChapterId())){

//创建课时vo对象
VideoVo videoVo = new VideoVo();
BeanUtils.copyProperties(video, videoVo);
videoVoArrayList.add(videoVo);
}
}
chapterVo.setChildren(videoVoArrayList);
}

return chapterVoArrayList;
}
}

3、web层

package com.guli.edu.controller.admin;

@Api(description="课程章节管理")
@CrossOrigin //跨域
@RestController
@RequestMapping("/admin/edu/chapter")
public class ChapterAdminController {

@Autowired
private ChapterService chapterService;

@ApiOperation(value = "嵌套章节数据列表")
@GetMapping("nested-list/{courseId}")
public R nestedListByCourseId(
@ApiParam(name = "courseId", value = "课程ID", required = true)
@PathVariable String courseId){

List<ChapterVo> chapterVoList = chapterService.nestedList(courseId);
return R.ok().data("items", chapterVoList);
}
}

4、Swagger测试

二、前端实现

1、定义api

chapter.js

import request from '@/utils/request'

const api_name = '/admin/edu/chapter'

export default {

getNestedTreeList(courseId) {
return request({
url: `${api_name}/nested-list/${courseId}`,
method: 'get'
})
}
}

2、定义组件脚本

定义data

courseId: '', // 所属课程
chapterNestedList: [] // 章节嵌套课时列表

created中调用init方法

created() {
console.log('chapter created')
this.init()
},

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

init() {
if (this.$route.params && this.$route.params.id) {
this.courseId = this.$route.params.id
// 根据id获取课程基本信息
this.fetchChapterNestedListByCourseId()
}
},

fetchChapterNestedListByCourseId() {
chapter.getNestedTreeList(this.courseId).then(response => {
this.chapterNestedList = response.data.items
})
},

3、定义组件模板

<el-button type="text">添加章节</el-button>
<!-- 章节 -->
<ul class="chanpterList">
<li
v-for="chapter in chapterNestedList"
:key="chapter.id">
<p>
{{ chapter.title }}

<span class="acts">
<el-button type="text">添加课时</el-button>
<el-button style="" type="text">编辑</el-button>
<el-button type="text">删除</el-button>
</span>
</p>

<!-- 视频 -->
<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>
<div>
<el-button @click="previous">上一步</el-button>
<el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
</div>

4、定义样式

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

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

<style scoped>
.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;
}

</style>