分类表设计与代码生成
分类表设计:项目设计两级分类,表设计支持无限极分类
生成持久层代码
来到我们mybatis generator的配置文件中:
执行一下generator,生成了四个类:
完成分类基本增删改查功能
首先我们先写controller,直接复制我们之前所写的EBookController重命名为CategoryController,使用快捷键ctrl+R一键替换关键词:
再替换大写的:
这时候其实有很多类是没有的:
接下来我们来编写sevice,同样直接复制之前写好的Ebook相关service:
同样直接一键替换大写和小写:
接下来我们来编写实体类:
CategoryQueryReq查询分类的时候不用请求参数,直接集成我们之前的分页请求就行:
public class CategoryQueryReq extends PageReq {
@Override
public String toString() {
return "CategoryQueryReq{} " + super.toString();
}
}
CategorySaveReq就跟我们之前设计的表的结构一致即可:
public class CategorySaveReq {
private Long id;
private Long parent;
@NotNull(message = "【名称】不能为空")
private String name;
@NotNull(message = "【排序】不能为空")
private Integer sort;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getParent() {
return parent;
}
public void setParent(Long parent) {
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", parent=").append(parent);
sb.append(", name=").append(name);
sb.append(", sort=").append(sort);
sb.append("]");
return sb.toString();
}
}
CategoryQueryResp也是跟我们的表的结构一致:
public class CategoryQueryResp {
private Long id;
private Long parent;
private String name;
private Integer sort;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getParent() {
return parent;
}
public void setParent(Long parent) {
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", parent=").append(parent);
sb.append(", name=").append(name);
sb.append(", sort=").append(sort);
sb.append("]");
return sb.toString();
}
除此之外我们要在service中删掉用名字查询的条件,因为我们分类查询没有只有分页的参数:
接下来我们来写前端界面,同样也是复制admin-ebook.vue,创建admin-category.vue,并进行大写和小写的替换:
首先我们先来对比一下电子书和分类的异同:
电子书:
分类:
所以我们要将原本的
改为:
表格对应的列我们也需要修改:
由:
改为:
由:
改为:
接下来我们修改路由:
在inex.ts中导入:
header中我们要添加:
这样我们就快速地完成了分类基本增删改查功能 。
分类表格显示优化
不需要分页,一次查出全部数据
分类的数据是有限的,所以我们可以一次性查出所有数据:
我们新增一个查询all的方法:
我们按照递增顺序返回,接着我们修改接口:
修改前端请求地址、删掉请求参数:
删掉分页信息:
删掉加载列表的分页请求参数
取消分页:
改为树形表格展示
使用递归算法将数组变成树形JSON:
/**
* 数据查询
**/
const handleQuery = () => {
loading.value = true;
// 如果不清空现有数据,则编辑保存重新加载数据后,再点编辑,则列表显示的还是编辑前的数据
level1.value = [];
axios.get("/category/all").then((response) => {
loading.value = false;
const data = response.data;
if (data.success) {
categorys.value = data.content;
console.log("原始数组:", categorys.value);
level1.value = [];
level1.value = Tool.array2Tree(categorys.value, 0);
console.log("树形结构:", level1);
} else {
message.error(data.message);
}
});
};
/**
* 使用递归将数组转为树形结构
* 父ID属性为parent
*/
public static array2Tree (array: any, parentId: number) {
if (Tool.isEmpty(array)) {
return [];
}
const result = [];
for (let i = 0; i < array.length; i++) {
const c = array[i];
// console.log(Number(c.parent), Number(parentId));
if (Number(c.parent) === Number(parentId)) {
result.push(c);
// 递归查看当前节点对应的子节点
const children = Tool.array2Tree(array, c.id);
if (Tool.isNotEmpty(children)) {
c.children = children;
}
}
}
return result;
}
分类编辑功能优化
我们要实现下图的效果:
在表单中添加选择框
我们还要解决一个问题,就是自己不能选择自己:
电子书管理增加分类选择
在电子书的编辑按钮中我们要实现可以选择多级:
我们这边遇到了一个问题,编辑完保存后,对于的界面发生变化,但是重新点编辑发现表单中还是刚刚未修改的值:
我们待会儿再来解决。级联选择组件:
选择的时候会有一个value数组就是对应着每一级的数据 。
选项也是数组:
初始化的时候我们要加载所有的分类,所以我们可以将分类管理中的代码原封不动地复制到电子书管理来。添加级联选择组件:
定义响应式变量:
当我们点击OK时执行以下函数,先拿到所选的级联分类:
而编辑按钮则是反过来,先获取到一级、二级分类,填入表单:
查询所有分类(跟之前分类管理的代码一致):
在初始的时候我们要查到所有的分类:
我们现在想实现一个效果,将表格中的分类一和分类二合并为一个分类:
定义一个普通变量用于js中计算,拿到所有分类的数据:
使用循环通过id返回name:
这样我们就实现了分类合并展示出来了。
现在我们来解决之前遗留的问题:
首页显示分类菜单
同样我们初始也是要先获取到所有的分类
使用导航菜单组件:
利用循环展示菜单:
导入:
初始我们也是要查询所有的分类:
在电子书界面会有一个小bug,我们修改一下:
点击分类菜单显示电子书
首页默认显示欢迎界面
新增一个主页的菜单:
我们首页打开的时候需要先显示欢迎菜单栏,欢迎页要显示在a-layout-content下面:
其中欢迎页和list的内容是互斥的。所以要定义一个响应式变量判断当前a-layout-content是显示什么,初始我们要显示欢迎页面:
条件渲染:
点击某分类时,显示该分类下的电子书
点击分类的时候该变量改为false,我们在点击菜单栏的回调函数中(只有二级分类才会触发或者就只有一个一级分类的时候会触发)去处理:
实现效果:
添加一个变量表示当前所在的二级分类:
通过categoryId2请求后端
修改后端模仿name写一个动态查询:
总结