两级分类的一种解决方案 您所在的位置:网站首页 二级菜单不显示 两级分类的一种解决方案

两级分类的一种解决方案

2023-06-07 13:03| 来源: 网络整理| 查看: 265

两级分类的一种解决方案

解决方案:“数据库设计+vue的双向绑定特性” 实现

看懂以下代码前提知识:mysql、springBoot、mybatisPlus、了解vue生命周期、了解ElementUI基本使用,了解前后分离开发。

场景:现在要做一个课程的添加和修改功能,但是每一个课程都对应了课程分类(比如:Web基础课程,属于一级分类–>后端开发;属于二级分类–>java)。我们在添加课程的时候,进行选择课程分类时,应该是先选一级分类,然后才能选择二级分类,修改课程时,要求回显数据时下拉框显示该课程对应的一级分类和二级分类,效果演示见图5。

1、数据库设计:

(1)课程分类表: 在这里插入图片描述

(2)课程表 在这里插入图片描述

2、效果展示:

​ (1)添加课程时的效果: 在这里插入图片描述

在这里插入图片描述

(2)修改课程时的效果:

​ 因为是修改课程,需要进行数据回显 在这里插入图片描述

3、代码实现: 后端代码 (1)实体类Subject.java @Data @ApiModel(description = "Subject") @TableName("subject") public class Subject { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "id") private Long id; @ApiModelProperty(value = "创建时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField("create_time") private Date createTime; @ApiModelProperty(value = "更新时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField("update_time") private Date updateTime; @ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)") @JsonIgnore @TableLogic @TableField("is_deleted") private Integer isDeleted; @ApiModelProperty(value = "其他参数") @TableField(exist = false) private Map param = new HashMap(); @ApiModelProperty(value = "类别名称") @TableField("title") private String title; @ApiModelProperty(value = "父ID") @TableField("parent_id") private Long parentId; @ApiModelProperty(value = "排序字段") @TableField("sort") private Integer sort; @ApiModelProperty(value = "是否包含子节点") @TableField(exist = false) private boolean hasChildren; } (2)统一返回结果类Result //统一返回结果类 @Data public class Result { private Integer code; //状态码 private String message; //返回状态信息(成功 失败) private T data; //返回数据 public Result() {} //成功的方法,有data数据 public static Result ok(T data) { Result result = new Result(); if(data != null) { result.setData(data); } result.setCode(20000); result.setMessage("成功"); return result; } //失败的方法,有data数据 public static Result fail(T data) { Result result = new Result(); if(data != null) { result.setData(data); } result.setCode(20001); result.setMessage("失败"); return result; } public Result message(String msg){ this.setMessage(msg); return this; } public Result code(Integer code){ this.setCode(code); return this; } }

(3)课程分类控制层SubjectController: @RestController @RequestMapping(value="/admin/vod/subject") //@CrossOrigin public class SubjectController { @Autowired private SubjectService subjectService; //课程分类列表 //懒加载,每次查询一层数据 @ApiOperation("课程分类列表") @GetMapping("getChildSubject/{id}") public Result getChildSubject(@PathVariable Long id) { List list = subjectService.selectSubjectList(id); return Result.ok(list); } }

上述代码中selectSubjectList(id)

//课程分类列表 //懒加载,每次查询一层数据 @Override public List selectSubjectList(Long id) { //SELECT * FROM SUBJECT WHERE parent_id=0 QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("parent_id",id); List subjectList = baseMapper.selectList(wrapper); //subjectList遍历,得到每个subject对象,判断是否有下一层数据,有hasChildren=true for (Subject subject:subjectList) { //获取subject的id值 Long subjectId = subject.getId(); //查询 boolean isChild = this.isChildren(subjectId); //封装到对象里面 subject.setHasChildren(isChild); } return subjectList; } //判断是否有下一层数据 private boolean isChildren(Long subjectId) { QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("parent_id",subjectId); Integer count = baseMapper.selectCount(wrapper); // 1>0 true 0>0 false return count>0; } (4)课程控制类CourseController @RestController @RequestMapping(value="/admin/vod/course") //@CrossOrigin public class CourseController { @Autowired private CourseService courseService; //根据id获取课程信息 @GetMapping("get/{id}") public Result get(@PathVariable Long id) { CourseFormVo courseFormVo = courseService.getCourseInfoById(id); return Result.ok(courseFormVo); } }

上述代码中getCourseInfoById(id)

//根据id查询课程信息 @Override public CourseFormVo getCourseInfoById(Long id) { //课程基本信息 Course course = baseMapper.selectById(id); if(course == null) { return null; } //课程描述信息 CourseDescription courseDescription = descriptionService.getById(id); //封装 CourseFormVo courseFormVo = new CourseFormVo(); BeanUtils.copyProperties(course,courseFormVo); //封装描述 if(courseDescription != null) { courseFormVo.setDescription(courseDescription.getDescription()); } return courseFormVo; } 前端代码 a、引入后端api接口

​ 1)课程类别接口

import request from '@/utils/request' const api_name = '/admin/vod/subject' export default { //课程分类列表 getChildList(id) { return request({ url: `${api_name}/getChildSubject/${id}`, method: 'get' }) } }

​ 2)课程接口:

import request from '@/utils/request' const api_name = '/admin/vod/course' export default { //id获取课程信息 getCourseInfoById(id) { return request({ url: `${api_name}/get/${id}`, method: 'get' }) }, } b、页面代码 元 保存并下一步 import courseApi from '@/api/vod/course' import teacherApi from '@/api/vod/teacher' import subjectApi from '@/api/vod/subject' export default { data() { return { BASE_API: 'http://localhost:8301', saveBtnDisabled: false, // 按钮是否禁用 courseInfo: {// 表单数据 price: 0, lessonNum: 0, // 以下解决表单数据不全时insert语句非空校验 teacherId: '', subjectId: '', subjectParentId: '', cover: '', description: '' }, teacherList: [], // 讲师列表 subjectList: [], // 一级分类列表 subjectLevelTwoList: []// 二级分类列表 } }, created() { // this.$parent.courseId 获取父组件中的课程courdeID if (this.$parent.courseId) { // 回显 this.fetchCourseInfoById(this.$parent.courseId) } else { // 新增 // 初始化分类列表 this.initSubjectList() } // 获取讲师列表 this.initTeacherList() }, methods: { // 获取课程信息(回显数据时调用) // 注意:我们要做的是把 “所有的一级菜单数据” 和 “该一级菜单下的二级菜单” 的数据放到subjectList和subjectLevelTwoList中即可,具体显示哪个交给div中的代码实现 fetchCourseInfoById(id) { // 调用后端接口,根据课程id查询课程信息 courseApi.getCourseInfoById(id).then(response => { // 将接口返回数据复制到data中的courseInf(表单数据),实现回显 this.courseInfo = response.data // 初始化分类列表 subjectApi.getChildList(0).then(response => { // subjectList存储的是所有的一级分类 this.subjectList = response.data // 填充二级菜单:遍历subjectList,subjectList存储的是所有一级分类,而不是某一个一级分类,所以需要遍历找出该课程所属的一级分类 this.subjectList.forEach(subject => { // subject是遍历时一级菜单中的某一个,courseInfo.subjectParentId是根据课程id查询到的课程信息中的一级菜单,都是一级菜单,比对符合即赋值即可 if (subject.id === this.courseInfo.subjectParentId) { // 拿到当前类别下的子类别列表,将子类别列表填入二级下拉菜单列表 subjectApi.getChildList(subject.id).then(response => { this.subjectLevelTwoList = response.data }) } }) }) }) }, // 获取讲师列表 initTeacherList() { teacherApi.list().then(response => { this.teacherList = response.data }) }, // 初始化分类列表 initSubjectList() { subjectApi.getChildList(0).then(response => { // 给一级分类列表赋值 this.subjectList = response.data }) }, // 选择一级分类,切换二级分类 subjectChanged(value) { subjectApi.getChildList(value).then(response => { this.courseInfo.subjectId = '' // 给二级分类列表赋值 this.subjectLevelTwoList = response.data }) }, // 上传成功回调 handleCoverSuccess(res, file) { this.courseInfo.cover = res.data }, // 上传校验 beforeCoverUpload(file) { const isJPG = file.type === 'image/jpeg' const isLt2M = file.size / 1024 / 1024 < 2 if (!isJPG) { this.$message.error('上传头像图片只能是 JPG 格式!') } if (!isLt2M) { this.$message.error('上传头像图片大小不能超过 2MB!') } return isJPG && isLt2M }, // 错误处理 handleCoverError() { console.log('error') this.$message.error('上传失败2') }, // 保存并下一步 saveAndNext() { this.saveBtnDisabled = true if (!this.$parent.courseId) { this.saveData() } else { this.updateData() } }, // 修改 updateData() { courseApi.updateCourseInfoById(this.courseInfo).then(response => { this.$message.success(response.message) this.$parent.courseId = response.data // 获取courseId this.$parent.active = 1 // 下一步 }) }, // 保存 saveData() { courseApi.saveCourseInfo(this.courseInfo).then(response => { this.$message.success(response.message) this.$parent.courseId = response.data // 获取courseId this.$parent.active = 1 // 下一步 }) } } } .tinymce-container { position: relative; line-height: normal; } .cover-uploader .avatar-uploader-icon { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; font-size: 28px; color: #8c939d; width: 640px; height: 357px; line-height: 357px; text-align: center; } .cover-uploader .avatar-uploader-icon:hover { border-color: #409EFF; } .cover-uploader img { width: 640px; height: 357px; display: block; }

解释:

(1)添加课程时,我们只需要初始化分类列表,供用户进行选择。二级菜单默认为空,用户选择了一级菜单后(@change=“subjectChanged”,发生变换就调用subjectChanged方法)会调用subjectChanged方法给二级分类列表赋值。

(2)修改课程时,我们也要做初始化分类列表,但是因为路由到这个页面时路径中会带有该课程的id,先根据该课程id查询出课程的数据(包括subjectId、subjectParentId)赋值给data中的courseInfo,在中使用利用双向绑定(v-model=“courseInfo.subjectParentId”、v-model=“courseInfo.subjectId”)即可实现下拉框直接显示该课程“具体”的一级分类和二级分类,而无需写过多的js代码。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有