目录
1、课程列表
1.1、后端
1.1.1、定义列表查询的 VO
@ApiModel(value = "Course查询对象", description = "课程查询对象封装")
@Data
public class CourseQuery {
@ApiModelProperty(value = "课程名称")
private String title;
@ApiModelProperty(value = "讲师id")
private String teacherId;
@ApiModelProperty(value = "一级类别id")
private String subjectParentId;
@ApiModelProperty(value = "二级类别id")
private String subjectId;
@ApiModelProperty(value = "课程状态 Draft未发布 Normal已发布")
private String status;
}
1.1.2、条件分页查询课程信息
EduCourseController
/**
* 条件分页查询课程列表
* @param page 页码
* @param limit 每页记录数
* @param courseQuery 条件查询对象
* @return
*/
@ApiOperation("条件分页查询课程列表")
@GetMapping("/list/{page}/{limit}")
public R getCourseList(
@ApiParam(name = "page", value = "当前页码", required = true) @PathVariable Long page,
@ApiParam(name = "limit", value = "每页记录数", required = true) @PathVariable Long limit,
@ApiParam(name = "courseQuery", value = "查询对象", required = false) @RequestBody CourseQuery courseQuery
) {
Page<EduCourse> coursePage = new Page<>(page, limit);
// 封装查询条件
LambdaQueryWrapper<EduCourse> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(!StringUtils.isEmpty(courseQuery.getTitle()), EduCourse::getTitle, courseQuery.getTitle());
queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getTeacherId()), EduCourse::getTeacherId, courseQuery.getTeacherId());
queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getSubjectParentId()), EduCourse::getSubjectParentId, courseQuery.getSubjectParentId());
queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getSubjectId()), EduCourse::getSubjectId, courseQuery.getSubjectId());
queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getStatus()), EduCourse::getStatus, courseQuery.getStatus());
courseService.page(coursePage, queryWrapper);
long total = coursePage.getTotal();
List<EduCourse> records = coursePage.getRecords();
Map<String, Object> map = new HashMap();
map.put("total", total);
map.put("records", records);
return R.ok().data(map);
}
1.2、前端
1.2.1、定义 API
src\api\edu\course.js
/**
* 条件分页查询课程列表
* @param {*} page 页码
* @param {*} limit 每页记录数
* @param {*} courseQuery 条件查询对象
* @returns
*/
getCoursePage(page,limit,courseQuery) {
return request({
url: `/eduservice/course/list/${page}/${limit}`,
method: 'POST',
data: courseQuery
})
}
1.2.2、列表及表单
src\views\edu\course\list.vue
组件:
<template>
<div class="app-container">
<!--查询表单-->
<el-form :inline="true" class="demo-form-inline">
<!-- 所属分类:级联下拉列表 -->
<!-- 一级分类 -->
<el-form-item label="课程类别">
<el-select v-model="courseQuery.subjectParentId" placeholder="请选择" @change="subjectLevelOneChanged">
<el-option v-for="subject in subjectOneList" :key="subject.id" :label="subject.title"
:value="subject.id" />
</el-select>
<!-- 二级分类 -->
<el-select v-model="courseQuery.subjectId" placeholder="请选择">
<el-option v-for="subject in subjectTwoList" :key="subject.id" :label="subject.title" :value="subject.id" />
</el-select>
</el-form-item>
<!-- 标题 -->
<el-form-item>
<el-input v-model="courseQuery.title" placeholder="课程标题" />
</el-form-item>
<!-- 讲师 -->
<el-form-item>
<el-select v-model="courseQuery.teacherId" placeholder="请选择讲师">
<el-option v-for="teacher in teacherList" :key="teacher.id" :label="teacher.name" :value="teacher.id" />
</el-select>
</el-form-item>
<!-- 课程状态 -->
<el-form-item>
<el-select v-model="courseQuery.status" clearable placeholder="课程状态">
<el-option value="Normal" label="已发布" />
<el-option value="Draft" label="未发布" />
</el-select>
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
<!-- 表格 -->
<el-table v-loading="listLoading" :data="list" element-loading-text="数据加载中" border fit highlight-current-row
row-class-name="myClassList">
<el-table-column label="序号" width="70" align="center">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="课程信息" width="470" align="center">
<template slot-scope="scope">
<div class="info">
<div class="pic">
<img :src="scope.row.cover" alt="scope.row.title" width="150px">
</div>
<div class="title">
<a href="">{{ scope.row.title }}</a>
<p>{{ scope.row.lessonNum }}课时</p>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center">
<template slot-scope="scope">
{{ scope.row.gmtCreate.substr(0, 10) }}
</template>
</el-table-column>
<el-table-column label="发布时间" align="center">
<template slot-scope="scope">
{{ scope.row.gmtModified.substr(0, 10) }}
</template>
</el-table-column>
<el-table-column label="价格" width="100" align="center">
<template slot-scope="scope">
{{ Number(scope.row.price) === 0 ? '免费' :
'¥' + scope.row.price.toFixed(2) }}
</template>
</el-table-column>
<el-table-column prop="buyCount" label="付费学员" width="100" align="center">
<template slot-scope="scope">
{{ scope.row.buyCount }}人
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template slot-scope="scope">
<router-link :to="'/edu/course/info/'+scope.row.id">
<el-button type="text" size="mini" icon="el-icon-edit">编辑课程信息</el-button>
</router-link>
<router-link :to="'/edu/course/chapter/'+scope.row.id">
<el-button type="text" size="mini" icon="el-icon-edit">编辑课程大纲</el-button>
</router-link>
<el-button type="text" size="mini" icon="el-icon-delete">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="page"
:page-size="limit"
:total="total"
style="padding: 30px 0; text-align: center;"
layout="total, prev, pager, next, jumper"
@current-change="getList"
/>
</div>
</template>>
样式:
<style scoped>
.myClassList .info {
width: 450px;
overflow: hidden;
}
.myClassList .info .pic {
width: 150px;
height: 90px;
overflow: hidden;
float: left;
}
.myClassList .info .pic a {
display: block;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.myClassList .info .pic img {
display: block;
width: 100%;
}
.myClassList td .info .title {
width: 280px;
float: right;
height: 90px;
}
.myClassList td .info .title a {
display: block;
height: 48px;
line-height: 24px;
overflow: hidden;
color: #00baf2;
margin-bottom: 12px;
}
.myClassList td .info .title p {
line-height: 20px;
margin-top: 5px;
color: #818181;
}
</style>
1.2.3、组件 JS
src\views\edu\course\list.vue
<script>
import course from '@/api/edu/course.js'
import subject from '@/api/edu/subject.js'
export default {
data() {
return {
listLoading: true, // 是否显示loading信息
list: null, // 数据列表
total: 0, // 总记录数
page: 1, // 页码
limit: 3, // 每页记录数
courseQuery: { // 查询条件
subjectParentId: '',
subjectId: '',
title: '',
teacherId: '',
status: ''
},
teacherList: [], // 讲师列表
subjectOneList: [], // 一级分类列表
subjectTwoList: [] // 二级分类列表
}
},
created() {
this.getList();
this.getListTeacher();
this.getOneSubject();
},
methods: {
/**
* 获取课程信息
*/
getList(page = 1) { // 若没有page参数。默认为1
this.listLoading = true;
this.page = page;
course.getCoursePage(this.page,this.limit,this.courseQuery).then(response => {
this.list = response.data.records;
this.total = response.data.total;
});
this.listLoading = false;
},
/**
* 表单清空方法
*/
resetData() {
this.courseQuery = {}
this.getList()
},
/**
* 获取所有讲师信息
*/
getListTeacher() {
course.getTeacherList().then(response => {
this.teacherList = response.data.items;
})
},
/**
* 查询所有一级分类(一级分类下含有其包含的二级分类)
*/
getOneSubject() {
subject.getSubjectList().then(response => {
this.subjectOneList = response.data.list;
})
},
/**
* 更换选择的一级分类调用的方法,更新二级分类数据
* @param {*} value 一级分类ID
*/
subjectLevelOneChanged(value) {
// 初始化
this.subjectTwoList = [];
this.courseQuery.subjectId = '';
// 遍历所有一级分类,若其ID和value的值相等,将其孩子(二级分类)赋值给subjectTwoList
for (var i = 0; i < this.subjectOneList.length; i++) {
if (value === this.subjectOneList[i].id) {
// 二级分类赋值
this.subjectTwoList = this.subjectOneList[i].children;
}
}
},
}
}
</script>
2、课程删除
2.1、后端
2.1.1、根据课程 ID 删除小节信息
EduVideoService
/**
* 根据课程ID删除小节
* @param courseId 课程ID
*/
void removeVideoByCourseId(String courseId);
EduVideoServiceImpl
/**
* 根据课程ID删除小节
* @param courseId 课程ID
*/
@Override
public void removeVideoByCourseId(String courseId) {
LambdaQueryWrapper<EduVideo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EduVideo::getCourseId, courseId);
this.remove(queryWrapper);
}
2.1.2、根据课程 ID 删除章节信息
EduChapterService
/**
* 根据课程ID删除章节
* @param courseId 课程ID
*/
void removeChapterByCourseId(String courseId);
EduChapterServiceImpl
/**
* 根据课程ID删除章节
* @param courseId 课程ID
*/
@Override
public void removeChapterByCourseId(String courseId) {
LambdaQueryWrapper<EduChapter> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EduChapter::getCourseId, courseId);
this.remove(queryWrapper);
}
2.1.3、根据课程 ID 删除课程所有信息
EduCourseService
/**
* 删除课程
* @param courseId 课程ID
*/
void removeCourse(String courseId);
EduCourseServiceImpl
/**
* 删除课程
* @param courseId 课程ID
*/
@Override
public void removeCourse(String courseId) {
// 删除小节
videoService.removeVideoByCourseId(courseId);
// 删除章节
chapterService.removeChapterByCourseId(courseId);
// 删除描述
descriptionService.removeById(courseId);
// 删除课程信息
this.removeById(courseId);
}
EduCourseController
/**
* 删除课程
* @param courseId 课程ID
* @return
*/
@DeleteMapping("/{courseId}")
public R deleteCourse(
@ApiParam(name = "courseId", value = "课程ID", required = true) @PathVariable String courseId
) {
courseService.removeCourse(courseId);
return R.ok();
}
2.2、前端
2.2.1、定义 API
src\api\edu\course.js
/**
* 删除课程
* @param {*} courseId 课程ID
* @returns
*/
removeCourseById(courseId) {
return request({
url: `/eduservice/course/${courseId}`,
method: 'DELETE'
})
}
2.2.2、删除按钮绑定事件
<el-button type="text" size="mini" icon="el-icon-delete" @click="removeCourse(scope.row.id)">删除</el-button>
2.2.3、删除方法
src\views\edu\course\list.vue
/**
* 删除课程
* @param {} courseId
*/
removeCourse(courseId) {
this.$confirm('此操作将永久删除该课程信息, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
// 确认删除
.then(() => {
course.removeCourseById(courseId).then(response => {
// 提示信息
this.$message({
type: 'success',
message: '删除成功!'
});
// 重新加载列表
if (this.list.length == 1) {
this.page = this.page - 1;
}
this.getList(this.page);
})
})
// 取消删除
.catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
3、完整页面
<template>
<div class="app-container">
<!--查询表单-->
<el-form :inline="true" class="demo-form-inline">
<!-- 所属分类:级联下拉列表 -->
<!-- 一级分类 -->
<el-form-item label="课程类别">
<el-select v-model="courseQuery.subjectParentId" placeholder="请选择" @change="subjectLevelOneChanged">
<el-option v-for="subject in subjectOneList" :key="subject.id" :label="subject.title"
:value="subject.id" />
</el-select>
<!-- 二级分类 -->
<el-select v-model="courseQuery.subjectId" placeholder="请选择">
<el-option v-for="subject in subjectTwoList" :key="subject.id" :label="subject.title" :value="subject.id" />
</el-select>
</el-form-item>
<!-- 标题 -->
<el-form-item>
<el-input v-model="courseQuery.title" placeholder="课程标题" />
</el-form-item>
<!-- 讲师 -->
<el-form-item>
<el-select v-model="courseQuery.teacherId" placeholder="请选择讲师">
<el-option v-for="teacher in teacherList" :key="teacher.id" :label="teacher.name" :value="teacher.id" />
</el-select>
</el-form-item>
<!-- 课程状态 -->
<el-form-item>
<el-select v-model="courseQuery.status" clearable placeholder="课程状态">
<el-option value="Normal" label="已发布" />
<el-option value="Draft" label="未发布" />
</el-select>
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
<!-- 表格 -->
<el-table v-loading="listLoading" :data="list" element-loading-text="数据加载中" border fit highlight-current-row
row-class-name="myClassList">
<el-table-column label="序号" width="70" align="center">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="课程信息" width="470" align="center">
<template slot-scope="scope">
<div class="info">
<div class="pic">
<img :src="scope.row.cover" alt="scope.row.title" width="150px">
</div>
<div class="title">
<a href="">{{ scope.row.title }}</a>
<p>{{ scope.row.lessonNum }}课时</p>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center">
<template slot-scope="scope">
{{ scope.row.gmtCreate.substr(0, 10) }}
</template>
</el-table-column>
<el-table-column label="发布时间" align="center">
<template slot-scope="scope">
{{ scope.row.gmtModified.substr(0, 10) }}
</template>
</el-table-column>
<el-table-column label="价格" width="100" align="center">
<template slot-scope="scope">
{{ Number(scope.row.price) === 0 ? '免费' :
'¥' + scope.row.price.toFixed(2) }}
</template>
</el-table-column>
<el-table-column prop="buyCount" label="付费学员" width="100" align="center">
<template slot-scope="scope">
{{ scope.row.buyCount }}人
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template slot-scope="scope">
<router-link :to="'/edu/course/info/'+scope.row.id">
<el-button type="text" size="mini" icon="el-icon-edit">编辑课程信息</el-button>
</router-link>
<router-link :to="'/edu/course/chapter/'+scope.row.id">
<el-button type="text" size="mini" icon="el-icon-edit">编辑课程大纲</el-button>
</router-link>
<el-button type="text" size="mini" icon="el-icon-delete" @click="removeCourse(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="page"
:page-size="limit"
:total="total"
style="padding: 30px 0; text-align: center;"
layout="total, prev, pager, next, jumper"
@current-change="getList"
/>
</div>
</template>>
<script>
import course from '@/api/edu/course.js'
import subject from '@/api/edu/subject.js'
export default {
data() {
return {
listLoading: true, // 是否显示loading信息
list: null, // 数据列表
total: 0, // 总记录数
page: 1, // 页码
limit: 3, // 每页记录数
courseQuery: { // 查询条件
subjectParentId: '',
subjectId: '',
title: '',
teacherId: '',
status: ''
},
teacherList: [], // 讲师列表
subjectOneList: [], // 一级分类列表
subjectTwoList: [] // 二级分类列表
}
},
created() {
this.getList();
this.getListTeacher();
this.getOneSubject();
},
methods: {
/**
* 获取课程信息
*/
getList(page = 1) { // 若没有page参数。默认为1
this.listLoading = true;
this.page = page;
course.getCoursePage(this.page,this.limit,this.courseQuery).then(response => {
this.list = response.data.records;
this.total = response.data.total;
});
this.listLoading = false;
},
/**
* 表单清空方法
*/
resetData() {
this.courseQuery = {}
this.getList()
},
/**
* 获取所有讲师信息
*/
getListTeacher() {
course.getTeacherList().then(response => {
this.teacherList = response.data.items;
})
},
/**
* 查询所有一级分类(一级分类下含有其包含的二级分类)
*/
getOneSubject() {
subject.getSubjectList().then(response => {
this.subjectOneList = response.data.list;
})
},
/**
* 更换选择的一级分类调用的方法,更新二级分类数据
* @param {*} value 一级分类ID
*/
subjectLevelOneChanged(value) {
// 初始化
this.subjectTwoList = [];
this.courseQuery.subjectId = '';
// 遍历所有一级分类,若其ID和value的值相等,将其孩子(二级分类)赋值给subjectTwoList
for (var i = 0; i < this.subjectOneList.length; i++) {
if (value === this.subjectOneList[i].id) {
// 二级分类赋值
this.subjectTwoList = this.subjectOneList[i].children;
}
}
},
/**
* 删除课程
* @param {} courseId
*/
removeCourse(courseId) {
this.$confirm('此操作将永久删除该课程信息, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
// 确认删除
.then(() => {
course.removeCourseById(courseId).then(response => {
// 提示信息
this.$message({
type: 'success',
message: '删除成功!'
});
// 重新加载列表
if (this.list.length == 1) {
this.page = this.page - 1;
}
this.getList(this.page);
})
})
// 取消删除
.catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
}
}
</script>
<style scoped>
.myClassList .info {
width: 450px;
overflow: hidden;
}
.myClassList .info .pic {
width: 150px;
height: 90px;
overflow: hidden;
float: left;
}
.myClassList .info .pic a {
display: block;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.myClassList .info .pic img {
display: block;
width: 100%;
}
.myClassList td .info .title {
width: 280px;
float: right;
height: 90px;
}
.myClassList td .info .title a {
display: block;
height: 48px;
line-height: 24px;
overflow: hidden;
color: #00baf2;
margin-bottom: 12px;
}
.myClassList td .info .title p {
line-height: 20px;
margin-top: 5px;
color: #818181;
}
</style>