硅谷课堂第五天-讲师管理模块前端
文章目录
一、讲师设置路由定义
1、修改路由
修改 src/router/index.js 文件,重新定义constantRouterMap
**注意:**每个路由的name不能相同
export const constantRouterMap = [
{ path: '/login', component: () => import('@/views/login/index'), hidden: true },
{ path: '/404', component: () => import('@/views/404'), hidden: true },
// 首页
{
path: '/',
component: Layout,
redirect: '/dashboard',
name: 'Dashboard',
children: [{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '硅谷课堂后台管理系统', icon: 'dashboard' }
}]
},
// 讲师管理
{
path: '/vod',
component: Layout,
redirect: '/vod/teacher/list',//重定向地址
name: 'vod',
meta: { title: '讲师管理', icon: 'el-icon-s-help' },
children: [
{
path: 'teacher/list',
name: 'TeacherList',
component: () => import('@/views/vod/teacher/list'),
meta: { title: '讲师列表', icon: 'table' }
},
{
path: 'teacher/create',
name: 'TeacherCreate',
component: () => import('@/views/vod/teacher/form'),
meta: { title: '添加讲师', icon: 'tree' }
},
{
path: 'teacher/edit/:id',
name: 'TeacherEdit',
component: () => import('@/views/vod/teacher/form'),
meta: { title: '编辑讲师' },
hidden: true
}
]
}
2、创建vue组件
在src/views文件夹下创建以下文件夹和文件
3、form.vue
<template>
<div class="app-container">
<!-- 输入表单 -->
<el-form label-width="120px">
<el-form-item label="讲师名称">
<el-input v-model="teacher.name" />
</el-form-item>
<el-form-item label="入驻时间">
<el-date-picker v-model="teacher.joinDate" value-format="yyyy-MM-dd" />
</el-form-item>
<el-form-item label="讲师排序">
<el-input-number v-model="teacher.sort" :min="0"/>
</el-form-item>
<el-form-item label="讲师头衔">
<el-select v-model="teacher.level">
<!--
数据类型一定要和取出的json中的一致,否则没法回填
因此,这里value使用动态绑定的值,保证其数据类型是number
-->
<el-option :value="1" label="高级讲师"/>
<el-option :value="2" label="首席讲师"/>
</el-select>
</el-form-item>
<el-form-item label="讲师简介">
<el-input v-model="teacher.intro"/>
</el-form-item>
<el-form-item label="讲师资历">
<el-input v-model="teacher.career" :rows="10" type="textarea"/>
</el-form-item>
<!-- 讲师头像 on-success上传成功调用的方法,before-upload上传前校验on-error错误调用的方法-->
<el-form-item label="讲师头像">
<el-upload
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:on-error="handleAvatarError"
:action="BASE_API+'/admin/vod/file/upload'"
class="avatar-uploader">
<img v-if="teacher.avatar" :src="teacher.avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"/>
</el-upload>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveOrUpdate()">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import teacherApi from '@/api/vod/teacher'
export default {
data() {
return {
BASE_API: 'http://localhost:8301',
// 初始化讲师默认数据
teacher: {
sort: 0,
level: 1
},
saveBtnDisabled: false // 保存按钮是否禁用,防止表单重复提交
}
},
// 页面渲染成功
created() {
//获取路径id值,根据id查询得到数据
if(this.$route.params.id){
const id = this.$route.params.id
this.fetchDataById(id)
}
},
methods: {
// 上传成功回调
handleAvatarSuccess(res, file) {
// console.log(res)
if (res.code==20000) {
// console.log(res)
this.teacher.avatar = res.data
// 强制重新渲染
this.$forceUpdate()//vue中强制刷新页面的方法
} else {
this.$message.error('上传失败 (非0)')
}
},
// 错误处理
handleAvatarError() {
console.log('error')
this.$message.error('上传失败(http失败)')
},
// 上传校验
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/png'
const isLt2M = file.size / 1024 / 1024 < 2
if (!isJPG) {
this.$message.error('上传头像图片只能是 PNG 格式!')
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!')
}
return isJPG && isLt2M
},
saveOrUpdate() {
// 保存按钮选择功能
this.saveBtnDisabled = true
if (!this.teacher.id) {//js写法!this.teacher.id表示有id值,this.teacher.id表示没有id值
this.saveData()
} else {
this.updateData()
}
},
// 新增讲师
saveData() {
// debugger
teacherApi.saveTeacher(this.teacher).then(response => {
this.$message({
type: 'success',
message: response.message
})
//跳转回列表页面this.$router
this.$router.push({ path: '/vod/teacher/list' })
})
},
// 根据id更新记录
updateData() {
// teacher数据的获取
teacherApi.updateTeacher(this.teacher).then(response => {
this.$message({
type: 'success',
message: response.message
})
this.$router.push({ path: '/vod/teacher/list' })
})
},
// 根据id查询记录
fetchDataById(id) {
teacherApi.getById(id).then(response => {
this.teacher = response.data//将data里面数据模型tearcher赋值
})
},
}
}
</script>
<style scoped>
.avatar-uploader .avatar-uploader-icon {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar-uploader .avatar-uploader-icon:hover {
border-color: #409EFF;
}
.avatar-uploader img {
width: 178px;
height: 178px;
display: block;
}
</style>
4、list.vue初始化
<template>
<div class="app-container">
讲师列表
</div>
</template>
二、讲师列表(增删改查)
1、定义api
创建文件 src/api/vod/teacher.js
import request from '@/utils/request'
const api_name='/admin/vod/teacher'//抽出来公共的用const定义然后参数获取
export default{
//讲师条件查询带分页
//根据的是后端接口的参数,current当前页,limit每页记录数,searchobj条件对象
pageList(current,limit,searchObj){
return request({
url: `${api_name}/findQueryPage/${current}/${limit}`,//``模板字符串取到current,limit参数值
method: 'post',
//使用json格式传递后台用来requestbody所以是json,写法data:searchobj
//使用普通格式传递 写法 params:searchObj
data:searchObj
})
},
//讲师删除
removeTeacherId(id){
return request({
url: `${api_name}/remove/${id}`,
method: 'delete',
})
},
//讲师添加
saveTeacher(teacher){
return request({
url: `${api_name}/save`,
method: 'post',
//使用json格式传递后台用来requestbody所以是json,写法data:searchobj
//使用普通格式传递 写法 params:searchObj
data:teacher
})
},
//查询讲师信息
getById(id) {
return request({
url: `${api_name}/get/${id}`,
method: 'get'
})
},
//查询所有讲师
list(){
return request({
url: `${api_name}/findAll`,
method: 'get'
})
},
//讲师修改
updateTeacher(teacher){
return request({
url:`${api_name}/update`,
method:'put',
data:teacher
})
},
//批量删除
batchRemove(idList) {
return request({
url: `${api_name}/batchRemove`,
method: `delete`,
data: idList
})
},
}
2、讲师vue组件
src/views/vod/teacher/list.vue
<template>
<div class="app-container">
讲师列表
<!--查询表单-->
<el-card class="operate-container" shadow="never">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="名称">
<el-input v-model="searchObj.name" placeholder="讲师名" />
</el-form-item>
<el-form-item label="头衔">
<el-select v-model="searchObj.level" clearable placeholder="头衔">
<el-option value="1" label="高级讲师"/>
<el-option value="0" label="首席讲师"/>
</el-select>
</el-form-item>
<el-form-item label="入驻时间">
<el-date-picker
v-model="searchObj.joinDateBegin"
placeholder="开始时间"
value-format="yyyy-MM-dd" />
</el-form-item>
<el-form-item label="-">
<el-date-picker
v-model="searchObj.joinDateEnd"
placeholder="结束时间"
value-format="yyyy-MM-dd" />
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
</el-card>
<!-- 表格 -->
<!-- 工具按钮 -->
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<span style="margin-top: 5px">数据列表</span>
<el-button class="btn-add" @click="add()" style="margin-left: 10px;">添加</el-button>
<el-button class="btn-add" @click="batchRemove()" >批量删除</el-button>
</el-card>
<el-table
:data="list"
border
stripe
@selection-change="handleSelectionChange">
<el-table-column type="selection"/>
<el-table-column
label="#"
width="50">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="name" label="名称" width="80" />
<el-table-column label="头衔" width="90">
<!--scope代表整个表格,row是每一行,level为属性名-->
<template slot-scope="scope">
<el-tag v-if="scope.row.level === 1" type="success" size="mini">高级讲师</el-tag>
<el-tag v-if="scope.row.level === 0" size="mini">首席讲师</el-tag>
</template>
</el-table-column>
<el-table-column prop="intro" label="简介" />
<el-table-column prop="sort" label="排序" width="60" />
<el-table-column prop="joinDate" label="入驻时间" width="160" />
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="removeById(scope.row.id)">删除</el-button>
<router-link :to="'/vod/teacher/edit/'+scope.row.id">
<el-button type="text" size="mini">修改</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 @为vue中绑定事件的意思 -->
<el-pagination
:current-page="page"
:total="total"
:page-size="limit"
:page-sizes="[5, 10, 20, 30, 40, 50, 100]"
style="padding: 30px 0; text-align: center;"
layout="total, sizes, prev, pager, next, jumper"
@size-change="changePageSize"
@current-change="changeCurrentPage"
/>
</div>
</template>
<script>
//引入定义接口js文件
import teacherApi from '@/api/vod/teacher'
export default{
// 定义数据模型
data() {
return {
list: [], // 讲师列表
total: 0, // 总记录数
page: 1, // 页码
limit: 10, // 每页记录数
searchObj: {}, // 查询条件
multipleSelection: []// 批量删除选中的记录列表
}
},
created(){//页面渲染之前
this.ferchData()
},
methods:{//具体方法
ferchData(){
// 调用api,参数为data里面定义的数据模型
teacherApi.pageList(this.page, this.limit, this.searchObj)
.then(response => {
console.log(response)
// //debugger
this.list = response.data.records//records是json串中列表内容
this.total = response.data.total
})
},
//改变每页显示记录数,为前面绑定的changePageSize事件
changePageSize(size){
this.limit=size
this.ferchData()
},
//改变页码数
changeCurrentPage(page){
this.page=page
this.ferchData()
},
//清空
resetData(){
this.searchObj={}
this.ferchData()
},
// 根据id删除数据
removeById(id) {
this.$confirm('此操作将删除讲师该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return teacherApi.removeTeacherId(id)
}).then((response) => {
this.ferchData()
this.$message.success(response.message)
})
},
//跳转到添加表单页面
add(){
this.$router.push({path:'/vod/teacher/create'})
},
//复选框发生变化,调用方法,选中复选框行内容传递
handleSelectionChange(selection){
this.multipleSelection=selection//data模型里面的multipleSelection
},
// 批量删除
batchRemove() {
//判断非空
if (this.multipleSelection.length === 0) {
this.$message.warning('请选择要删除的记录!')
return//结束
}
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 点击确定,远程调用ajax
// 遍历selection,将id取出放入id列表
//箭头函数
var idList = []
this.multipleSelection.forEach(item => {
idList.push(item.id)
})
// 调用api
return teacherApi.batchRemove(idList)
}).then((response) => {
this.ferchData()
this.$message.success(response.message)
}).catch(error => {
if (error === 'cancel') {
this.$message.info('取消删除')
}
})
},
}
}
</script>
三、讲师后端实现(增删改查)
1、讲师控制层(controller)实现
* <p>
* 讲师 前端控制器
* </p>
*
* @author atguigu
* @since 2022-12-02
*/
@Api(tags = "讲师管理接口")
@RestController
@RequestMapping("/admin/vod/teacher")
@CrossOrigin//跨域
public class TeacherController {
@Autowired
private TeacherService teacherService;
//http://localhost:8301/admin/vod/teacher/findAll restful风格
//1.查询所有讲师
@ApiOperation("所有讲师列表")
@GetMapping("findAll")
public Result findAllTeacher(){
//模拟异常
// try {
// int i=10/0;
// }catch (Exception e){
// //抛出异常
// throw new GgktException(201,"执行自定义异常处理");
// }
//调用service方法
List<Teacher>list=teacherService.list();
return Result.ok(list).message("查询数据成功");
}
//2.逻辑删除讲师{id}是占位符,必须用@PathVariavle进行绑定
@ApiOperation("逻辑删除讲师")
@DeleteMapping("remove/{id}")
public Result removeById(@ApiParam(name = "id", value = "ID", required = true)@PathVariable Long id){
boolean isSuccess = teacherService.removeById(id);
if(isSuccess) {
return Result.ok(null);
} else {
return Result.fail(null);
}
}
// //3 条件查询分页 TeacherQueryVo接受分页数据
// @ApiOperation("条件查询分页")
// @GetMapping("findQueryPage/{current}/{limit}")
// public Result findPage(@PathVariable long current,
// @PathVariable long limit,
// TeacherQueryVo teacherQueryVo){
// //创建page对象
// Page<Teacher> pageParam=new Page<>(current,limit);
// //判断TeacherQueryVo对象是否为空,为空查询全部,一般写在service层
// if (teacherQueryVo==null){
// IPage<Teacher> pageModel=teacherService.page(pageParam,null);
// return Result.ok(pageModel);
// }else{
// //获取条件值,进行非空判断,条件封装
// String name=teacherQueryVo.getName();
// Integer level=teacherQueryVo.getLevel();
// String joinDateBegin=teacherQueryVo.getJoinDateBegin();
// String joinDateEnd=teacherQueryVo.getJoinDateEnd();
// QueryWrapper<Teacher> wrapper=new QueryWrapper<>();
// //wrapper条件里面的为数据库属性
// if (!StringUtils.isEmpty(name)){
// wrapper.like("name",name);
// }
// if (!StringUtils.isEmpty(level)){
// wrapper.eq("level",level);
// }
// if (!StringUtils.isEmpty(joinDateBegin)){
// wrapper.ge("join_date",joinDateBegin);
// }
// if (!StringUtils.isEmpty(joinDateEnd)){
// wrapper.le("join_date",joinDateEnd);
// }
// //调用方法分页查询
// IPage<Teacher>pageModel=teacherService.page(pageParam,wrapper);
// //返回
// return Result.ok(pageModel);
// }
// }
//3 条件查询分页 TeacherQueryVo接受分页数据 @RequestBody实现 它必须与Post使用,参数可以为空
@ApiOperation("条件查询分页")
@PostMapping("findQueryPage/{current}/{limit}")
public Result findPage(@PathVariable long current,
@PathVariable long limit,
@RequestBody(required = false) TeacherQueryVo teacherQueryVo){
//创建page对象
Page<Teacher> pageParam=new Page<>(current,limit);
//判断TeacherQueryVo对象是否为空,为空查询全部,一般写在service层
if (teacherQueryVo==null){
IPage<Teacher> pageModel=teacherService.page(pageParam,null);
return Result.ok(pageModel);
}else{
//获取条件值,进行非空判断,条件封装
String name=teacherQueryVo.getName();
Integer level=teacherQueryVo.getLevel();
String joinDateBegin=teacherQueryVo.getJoinDateBegin();
String joinDateEnd=teacherQueryVo.getJoinDateEnd();
QueryWrapper<Teacher> wrapper=new QueryWrapper<>();
//wrapper条件里面的为数据库属性
if (!StringUtils.isEmpty(name)){
wrapper.like("name",name);
}
if (!StringUtils.isEmpty(level)){
wrapper.eq("level",level);
}
if (!StringUtils.isEmpty(joinDateBegin)){
wrapper.ge("join_date",joinDateBegin);
}
if (!StringUtils.isEmpty(joinDateEnd)){
wrapper.le("join_date",joinDateEnd);
}
//调用方法分页查询
IPage<Teacher>pageModel=teacherService.page(pageParam,wrapper);
System.out.println(pageModel);
//返回
return Result.ok(pageModel);
}
}
//4.添加讲师
@ApiOperation(value="新增")
@PostMapping("saveTeacher")
public Result save(@RequestBody Teacher teacher){
boolean isSuccess=teacherService.save(teacher);
if (isSuccess){
return Result.ok(null);
}else {
return Result.fail(null);
}
}
//5.根据id获取讲师信息
@ApiOperation(value = "获取")
@GetMapping("get/{id}")
public Result get(@PathVariable Long id) {
Teacher teacher = teacherService.getById(id);
return Result.ok(teacher);
}
//6.修改讲师
@ApiOperation(value = "修改")
@PutMapping("update")
public Result updateById(@RequestBody Teacher teacher) {
boolean isSuccess=teacherService.updateById(teacher);
if (isSuccess){
return Result.ok(null);
}else {
return Result.fail(null);
}
}
//7.批量删除讲师
@ApiOperation(value = "根据id列表删除")
@DeleteMapping("batchRemove")
public Result batchRemove(@RequestBody List<Long> idList) {
boolean isSuccess=teacherService.removeByIds(idList);
if (isSuccess){
return Result.ok(null);
}else {
return Result.fail(null);
}
}
}
2、讲师数据访问层(mapper)实现
/*
* <p>
* 讲师 Mapper 接口
* </p>
*
* @author atguigu
* @since 2022-12-02
*/
public interface TeacherMapper extends BaseMapper<Teacher> {
}
3、讲师业务层(serive)实现
/**
* <p>
* 讲师 服务类
* </p>
*
* @author atguigu
* @since 2022-12-02
*/
public interface TeacherService extends IService<Teacher> {
}
4、讲师业务实现层(seriveimpl)实现
/**
* <p>
* 讲师 服务实现类
* </p>
*
* @author atguigu
* @since 2022-12-02
*/
@Service
public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher> implements TeacherService {
}
5、讲师实体类(pojo)实现
@Data
@ApiModel(description = "Teacher")
@TableName("teacher")
public class Teacher extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "讲师姓名")
@TableField("name")
private String name;
@ApiModelProperty(value = "讲师简介")
@TableField("intro")
private String intro;
@ApiModelProperty(value = "讲师资历,一句话说明讲师")
@TableField("career")
private String career;
@ApiModelProperty(value = "头衔 1高级讲师 2首席讲师")
@TableField("level")
private Integer level;
@ApiModelProperty(value = "讲师头像")
@TableField("avatar")
private String avatar;
@ApiModelProperty(value = "排序")
@TableField("sort")
private Integer sort;
@ApiModelProperty(value = "入驻时间")
@JsonFormat(pattern = "yyyy-MM-dd")
@TableField("join_date")
private Date joinDate;
}