/**
* 查询所有产品,并以属性列表展示
*/
@RequestMapping("/list/tree")
//@RequiresPermissions("product:category:list")
public R list(){
List<CategoryEntity> entities=categoryService.listWithTree();
return R.ok().put("data", entities);
}
/**
* 所有子节点
*/
@TableField(exist=false)
private List<CategoryEntity> children;
public List<CategoryEntity> listWithTree() {
//1.查询所有产品信息
List<CategoryEntity> list = baseMapper.selectList(null);
//TODO 2.查询所有子菜单信息
List<CategoryEntity> level1Menu = list.stream().
filter(categoryEntity ->
//找到所有一级菜单
categoryEntity.getParentCid() == 0).
map((menu1) -> {
//给所有的一级菜单找到他们的子节点
menu1.setChildren(getchildren(menu1, list));
return menu1;
}).
sorted(
//排序菜单
Comparator.comparingInt(CategoryEntity::getSort)).
collect(
//收集所有一级菜单信息
Collectors.toList());
return level1Menu;
}
private List<CategoryEntity> getchildren(CategoryEntity menu1, List<CategoryEntity> list) {
List<CategoryEntity> children = list.stream().
filter(
categoryEntity -> categoryEntity.getParentCid().equals(menu1.getCatId())).
map((menu) -> {
menu.setChildren(getchildren(menu, list));
return menu;
}).
sorted(
//排序菜单
Comparator.comparingInt(menuOne -> (menuOne.getSort() == null ? 0 : menuOne.getSort()))).
collect(
//收集所有一级菜单信息
Collectors.toList());
return children;
}
进入文件,首选项,用户片段配置vue模板
{
"vue全局模板": {
"prefix": "vue",
"body": [
"",
"",
"",
"",
"",
""
],
"description": "生成vue模板"
}
}
需要加的话,加在全局模板里面
"http-get请求": {
"prefix": "httpget",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'get',",
"params: this.\\$http.adornParams({})",
"}).then(({ data }) => {",
"})"
],
"description": "httpGET请求"
},
"http-post请求": {
"prefix": "httppost",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'post',",
"data: this.\\$http.adornData(data, false)",
"}).then(({ data }) => { });"
],
"description": "httpPOST请求"
}
创建src/views/product/category.vue与之对应
<template>
<div>
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick">el-tree>
div>
template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
export default {
//import引入的组件需要注入到对象中才能使用
components: {
},
data() {
return {
data: [],
defaultProps: {
children: "children",
label: "label"
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
},
getMenus() {
this.$http({
url: this.$http.adornUrl("/product/category/list/tree"),
method: "get"
}).then(data => {
console.log("获取数据成功,获取数据是:" + data);
});
}
},
//监听属性 类似于data概念
computed: {
},
//监控data中的数据变化
watch: {
},
//生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus();
},
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
//生命周期 - 创建之前
beforeCreate() {
},
//生命周期 - 挂载之前
beforeMount() {
},
//生命周期 - 更新之前
beforeUpdate() {
},
//生命周期 - 更新之后
updated() {
},
//生命周期 - 销毁之前
beforeDestroy() {
},
//生命周期 - 销毁完成
destroyed() {
},
//如果页面有keep-alive缓存功能,这个函数会触发
activated() {
}
};
script>
<style lang='scss' scoped>
//@import url(); 引入公共css类
style>
如果直接调用方法,就会出现404错误,因为访问的地址是http://localhost:8080/renren-fast/product/category/list/tree,需要转发的查询地址是http://localhost:10000/product/category/list/tree
所以要去修改vue的统一访问链接,让其访问后台。
application.yml
application:
name: renren-fast
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
再次连接发现路由地址多了一个api,需要在路由配置中进行修改
gateway:
routes:
- id: base_route
uri: lb://renren-fast
predicates:
- Path=/api/**
filters:
- RewritePath=/api/(?>.*), /renren-fast/$\{
segment}
@Configuration
public class MyCorsConfiguration {
@Bean
public CorsWebFilter corsWebFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
//配置跨域
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
methods: {
handleNodeClick(data) {
console.log(data);
},
getMenus() {
this.$http({
url: this.$http.adornUrl("/product/category/list/tree"),
method: "get"
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data);
this.menus = data.data;
});
}
},
//生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus();
},
参数 | 说明 | 默认值 |
---|---|---|
node-key | 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 | |
show-checkbox | 节点是否可被选择 | false |
expand-on-click-node | 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。 | true |
{
{ node.label }}
append(data)">添加
remove(node, data)">删除
采用逻辑删除功能
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
logic-delete-value: 1
logic-not-delete-value: 0
/**
* 是否显示[0-不显示,1显示]
*/
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(catIds, false)
}).then(({ data }) => {
//刷新出删除后菜单
this.getMenus();
console.log(node, data);
});
remove(node, data) {
var catIds = [data.catId];
this.$confirm(`是否要删除目录【${data.name}】?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(catIds, false)
}).then(({ data }) => {
//刷新出删除后菜单
this.getMenus();
console.log(node, data);
});
})
.catch(() => {
});
}
}
//消息提示删除成功
this.$message({
message: "删除成功!",
type: "success"
});
:default-expanded-keys="expandedkeys" //设置属性
data() {
return {
menus: [],
expandedkeys: [],//设置为空
//刷新出删除后菜单
this.getMenus();
//展开到被删除结点的父菜单
this.expandedkeys=[node.parent.data.catId];
这是一段信息
设置默认不打开对话框
data() {
return {
menus: [],
expandedkeys: [],
dialogVisible: false,//默认不打开
点击添加触发append函数
this.dialogVisible = true;
append(data) {
console.log("append方法", data);
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
},
addCategory() {
console.log("addCategory方法Category", this.category);
//发送保存请求
this.$http({
url: this.$http.adornUrl("/product/category/save"),
method: "post",
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
//消息提示删除成功
this.$message({
message: "添加成功!",
type: "success"
});
});
//关闭对话框
this.dialogVisible = false;
//刷新出删除后菜单
this.getMenus();
//展开到被删除结点的父菜单
this.expandedkeys = [this.category.parentCid];
}
edit(data)">编辑
data() {
return {
submitType: "",
title: "",
menus: [],
expandedkeys: [],
dialogVisible: false,
category: {
carId: null,
name: "",
parentCid: 0,
catLevel: 0,
showStatus: 1,
sort: 0,
icon: "",
productUnit: ""
},
getMenus() {
this.$http({
url: this.$http.adornUrl("/product/category/list/tree"),
method: "get",
params: this.$http.adornParams({})
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data);
this.menus = data.data;
});
},
append(data) {
console.log("append方法", data);
this.title = "添加目录";
this.submitType = "add";
this.dialogVisible = true;
this.category.name = "";
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.icon = "";
this.category.productUnit = "";
this.category.sort = 0;
this.category.showStatus = 1;
},
addCategory() {
console.log("addCategory方法Category", this.category);
//发送保存请求
this.$http({
url: this.$http.adornUrl("/product/category/save"),
method: "post",
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
//消息提示删除成功
this.$message({
message: "添加成功!",
type: "success"
});
//关闭对话框
this.dialogVisible = false;
//刷新出删除后菜单
this.getMenus();
//展开到被删除结点的父菜单
this.expandedkeys = [this.category.parentCid];
});
},
edit(data) {
this.title = "修改目录";
this.dialogVisible = true;
this.submitType = "edit";
//重新发送请求获取数据
this.$http({
url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
method: "get",
params: this.$http.adornParams({})
}).then(({ data }) => {
//请求查找数据成功
console.log("要回显的数据", data);
this.category.parentCid = data.data.parentCid;
this.category.catId = data.data.catId;
this.category.catLevel = data.data.catLevel * 1;
this.category.name = data.data.name;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.sort = data.data.sort;
this.category.showStatus = data.data.showStatus;
});
},
editCategory() {
//console.log("editCategory方法Category", this.category);
var { catId, name, icon, productUnit } = this.category; //获取解构需要的数据
//发送修改请求
this.$http({
url: this.$http.adornUrl("/product/category/update"),
method: "post",
data: this.$http.adornData({ catId, name, icon, productUnit }, false)
}).then(({ data }) => {
//消息提示删除成功
this.$message({
message: "修改成功!",
type: "success"
});
//关闭对话框
this.dialogVisible = false;
console.log("看看这里的数据", this.category);
//刷新出删除后菜单
this.getMenus();
//展开到被删除结点的父菜单
this.expandedkeys = [this.category.parentCid];
});
},
submitData() {
if (this.submitType == "add") {
this.addCategory();
}
if (this.submitType == "edit") {
this.editCategory();
}
},
:draggable="true"
//判断是否能够拖拽
allowDrop(draggingNode, dropNode, type) {
console.log(draggingNode, dropNode, type);
//如果当前结点的深度加拖到的结点的深度小于等于3就可以拖动
//计算当前拖动结点的最大深度
this.countDepth(draggingNode);
//计算当前拖动结点的深度
var deep = Math.abs(this.maxDepth-draggingNode.level+1)
console.log("最大深度",deep);
//1.如果拖动类型为inner
if(type="inner") {
return (deep+dropNode.level)<=3;
}else {
return (deep+dropNode.parent.level)<=3;
}
},
//计算最大深度
countDepth(node) {
//如果存在子节点,计算其深度
if (node.childNodes != null && node.childNodes.length > 0) {
var cNodes = node.childNodes;
for (let index = 0; index < cNodes.length; index++) {
this.maxDepth = Math.max(this.maxDepth,cNodes[index].level);
this.countDepth(cNodes[index]);
}
}
}
handleDrop(draggingNode, dropNode, dropType, ev) {
console.log("tree drop: ", draggingNode, dropNode, dropType);
//1.找到当前结点的父节点
let pCid = 0;
let siblings = null; //定义兄弟结点
//如果是放在内部
if (dropType == "inner") {
pCid = dropNode.data.catId;
siblings = dropNode.childNodes;
} else {
pCid =
dropNode.parent.data.catId == undefined
? 0
: dropNode.parent.data.catId;
siblings = dropNode.parent.childNodes;
}
this.pCid.push(pCid);
//2.找到当前结点最新顺序,需要将所在结点进行排序
//遍历新结点按照遍历顺序进行排序
for (let i = 0; i < siblings.length; i++) {
let catLevel = draggingNode.level;
//如果遍历到了拖拽的结点,需要对层级进行修改
if (siblings[i].data.catId == draggingNode.data.catId) {
//如果层级发生变化
if (catLevel != siblings[i].level) {
//修改层级,并且修改其子结点层级
catLevel = siblings[i].level;
this.modifySubs(siblings[i]);
}
//放入修改参数
this.updateNodes.push({
catId: siblings[i].data.catId,
sort: i,
parentCid: pCid,
catLevel: catLevel
});
} else {
//其余排序修改
this.updateNodes.push({
catId: siblings[i].data.catId,
sort: i,
catLevel: catLevel
});
}
}
//3.更新当前结点最新的层级
console.log("updateNodes", this.updateNodes);
},
//修改子节点的层级
modifySubs(childNode) {
if (childNode.childNodes != null && childNodes.length > 0) {
for (let i = 0; i < childNode.childNodes.length; i++) {
this.updateNodes.push({
catId: childNode.childNodes[i].data.catId,
cataLevel: childNode.childNodes[i].level
});
this.modifySubs(childNode[i]);
}
}
}
}
/**
* 批量修改功能
*/
@RequestMapping("/update/sort")
//@RequiresPermissions("product:category:update")
public R update(@RequestBody CategoryEntity[] category){
categoryService.updateBatchById(Arrays.asList(category));
return R.ok();
}
完善前台handleDrop方法,将要修改的数据发送给后台进行修改
//3.更新当前结点最新的层级
console.log("updateNodes", this.updateNodes);
this.$http({
url: this.$http.adornUrl("/product/category/update/sort"),
method: "post",
data: this.$http.adornData(this.updateNodes, false)
}).then(({ data }) => {
this.$message({
message: "批量拖拽成功!",
type: "success"
});
//刷新出菜单
this.getMenus();
//展开父菜单
this.expandedkeys = [pCid];
//初始化
this.updateNodes=[];
this.maxDepth=0;
});
批量保存
将批量httppost方法放到保存这
batchSave() {
this.$http({
url: this.$http.adornUrl("/product/category/update/sort"),
method: "post",
data: this.$http.adornData(this.updateNodes, false)
}).then(({ data }) => {
this.$message({
message: "批量拖拽成功!",
type: "success"
});
//刷新出菜单
this.getMenus();
//展开父菜单
this.expandedkeys = this.pCid;
//初始化
this.updateNodes = [];
this.maxDepth = 0;
});
}
批量删除
ref=“menuTree”
该属性表示树形结构的唯一标识
使用自带方法getCheckedNodes,(leafOnly, includeHalfChecked) 接收两个 boolean 类型的参数,1. 是否只是叶子节点,默认值为 false
2. 是否包含半选节点,默认值为 false
//批量删除方法
batchDelete() {
let ids = []; //所有选中结点ID
//获取树形控件中被选中的所有结点
let checkedNodes = this.$refs.menuTree.getCheckedNodes();
for (let i = 0; i < checkedNodes.length; i++) {
ids.push(checkedNodes[i].catId);
}
console.log("被选中的结点", ids);
}
//批量删除方法
batchDelete() {
let ids = []; //所有选中结点ID
//获取树形控件中被选中的所有结点
let checkedNodes = this.$refs.menuTree.getCheckedNodes();
for (let i = 0; i < checkedNodes.length; i++) {
ids.push(checkedNodes[i].catId);
}
this.$confirm(`是否要批量删除目录【${ids}】?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
//消息提示删除成功
this.$message({
message: "批量删除成功!",
type: "success"
});
//刷新出删除后菜单
this.getMenus();
});
})
.catch(() => {});
}