后端
业务类
@Override
public List < CategoryEntity > listWithTree ( ) {
List < CategoryEntity > list = baseMapper. selectList ( null ) ;
List < CategoryEntity > level1 = list. stream ( )
. filter ( x -> x. getParentCid ( ) == 0 )
. peek ( x -> x. setChildren ( getChildren ( x, list) ) )
. sorted ( ( x1, x2) -> {
return ( x1. getSort ( ) == null ? 0 : x1. getSort ( ) ) - ( x2. getSort ( ) == null ? 0 : x2. getSort ( ) ) ;
} )
. collect ( Collectors . toList ( ) ) ;
return level1;
}
private List < CategoryEntity > getChildren ( CategoryEntity root, List < CategoryEntity > list) {
List < CategoryEntity > entities = list. stream ( )
. filter ( x -> x. getParentCid ( ) . equals ( root. getCatId ( ) ) )
. map ( x -> {
x. setChildren ( getChildren ( x, list) ) ;
return x;
} )
. sorted ( ( x1, x2) -> {
return ( x1. getSort ( ) == null ? 0 : x1. getSort ( ) ) - ( x2. getSort ( ) == null ? 0 : x2. getSort ( ) ) ;
} )
. collect ( Collectors . toList ( ) ) ;
return entities;
}
实体类
create table pms_category
(
cat_id bigint auto_increment comment '分类id'
primary key ,
name char ( 50 ) null comment '分类名称' ,
parent_cid bigint null comment '父分类id' ,
cat_level int null comment '层级' ,
show_status tinyint null comment '是否显示[0-不显示,1显示]' ,
sort int null comment '排序' ,
icon char ( 255 ) null comment '图标地址' ,
product_unit char ( 50 ) null comment '计量单位' ,
product_count int null comment '商品数量'
)
comment '商品三级分类' charset = utf8mb4;
前端
< template>
< div>
< el- switch style= "display: block" v- model= "draggable" active- color= "#13ce66" inactive- color= "#ff4949"
active- text= "开启拖拽" inactive- text= "关闭拖拽" >
< / el- switch >
< el- button type= "success" @click= "batchSave" v- if = "draggable" > 批量保存< / el- button>
< el- button type= "danger" @click= "batchDelete" > 批量删除< / el- button>
< el- tree : data= "menus" : props= "defaultProps" : expand- on- click- node= "false" show- checkbox node- key= "catId"
: default - expanded- keys= "expandKey" : draggable= "draggable" : allow- drop= "allowDrop" @node- drop= "handleDrop"
ref= "menuTree" >
< span class = "custom-tree-node" slot- scope= "{ node, data }" >
< span> { { node. label } } < / span>
< span>
< el- button v- if = "node.level <= 2" type= "text" size= "mini" @click= "() => append(data)" >
Append
< / el- button>
< el- button v- if = "node.childNodes.length == 0" type= "text" size= "mini" @click= "() => remove(node, data)" >
Delete
< / el- button>
< el- button type= "text" size= "mini" @click= "() => edit(data)" >
edit
< / el- button>
< / span>
< / span>
< / el- tree>
< el- dialog : title= "title" : visible. sync= "dialogVisible" width= "30%" : close- on- click- modal= "false" >
< el- form : model= "category" >
< el- form- item label= "分类名称" >
< el- input v- model= "category.name" autocomplete= "off" > < / el- input>
< / el- form- item>
< el- form- item label= "图标" >
< el- input v- model= "category.icon" autocomplete= "off" > < / el- input>
< / el- form- item>
< el- form- item label= "计量单位" >
< el- input v- model= "category.productUnit" autocomplete= "off" > < / el- input>
< / el- form- item>
< / el- form>
< span slot= "footer" class = "dialog-footer" >
< el- button @click= "dialogVisible = false" > 取 消< / el- button>
< el- button type= "primary" @click= "submitData" > 确 定< / el- button>
< / span>
< / el- dialog>
< / div>
< / template>
< script>
export default {
data ( ) {
return {
pCid : [ ] ,
draggable : false ,
updateNodes : [ ] ,
maxLevel : 0 ,
title : "" ,
dialogType : "" ,
category : {
catId : null ,
name : "" ,
parentCid : 0 ,
catLevel : 0 ,
showStatus : 1 ,
sort : 0 ,
icon : "" ,
productUnit : "" ,
} ,
dialogVisible : false ,
menus : [ ] ,
defaultProps : {
children : "children" ,
label : "name" ,
} ,
expandKey : [ ] ,
} ;
} ,
activated ( ) {
this . getMenus ( ) ;
} ,
methods : {
getMenus ( ) {
this . $http ( {
url : this . $http. adornUrl ( "/product/category/list/tree" ) ,
method : "get" ,
} ) . then ( ( { data } ) => {
console. log ( "成功获取到菜单数据" , data. list) ;
this . menus = data. list;
} ) ;
} ,
append ( data ) {
this . category. name = "" ;
this . category. catId = null ;
this . category. icon = "" ;
this . category. productUnit = "" ;
this . category. showStatus = 1 ;
this . category. sort = 0 ;
this . category. parentCid = data. catId;
this . category. catLevel = data. catLevel * 1 + 1 ;
this . dialogVisible = true ;
console. log ( "打开添加的提示框:" , data) ;
this . dialogType = "add" ;
this . title = "添加分类" ;
} ,
edit ( data ) {
console. log ( "当前菜单的详情" , data) ;
this . dialogVisible = true ;
this . dialogType = "edit" ;
this . title = "修改分类" ;
this . $http ( {
url : this . $http. adornUrl ( ` /product/category/info/ ${ data. catId} ` ) ,
method : "get" ,
params : this . $http. adornParams ( { } ) ,
} ) . then ( ( { data } ) => {
console. log ( "需要回显的数据" , data) ;
this . category. name = data. category. name;
this . category. catId = data. category. catId;
this . category. icon = data. category. icon;
this . category. productUnit = data. category. productUnit;
this . category. parentCid = data. category. parentCid;
} ) ;
} ,
remove ( node, data ) {
console. log ( "remove" , node, data) ;
var ids = [ 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 ( ids, false ) ,
} ) . then ( ( { data } ) => {
this . $message ( {
message : "删除成功" ,
type : "success" ,
} ) ;
this . getMenus ( ) ;
this . expandKey = [ node. parent. data. catId] ;
} ) ;
} )
. catch ( ( ) => { } ) ;
} ,
addCategory ( ) {
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 . expandKey = [ this . category. parentCid] ;
} ) ;
console. log ( "添加三级分类:" , this . category) ;
} ,
editCategory ( ) {
var { catId, name, icon, productUnit } = this . category;
var data = {
catId : catId,
name : name,
icon : icon,
productUnit : productUnit,
} ;
this . $http ( {
url : this . $http. adornUrl ( "/product/category/update" ) ,
method : "post" ,
data : this . $http. adornData ( data, false ) ,
} ) . then ( ( { data } ) => {
this . $message ( {
message : "修改成功" ,
type : "success" ,
} ) ;
this . dialogVisible = false ;
this . getMenus ( ) ;
this . expandKey = [ this . category. parentCid] ;
} ) ;
} ,
submitData ( ) {
if ( this . dialogType == "add" ) {
this . addCategory ( ) ;
}
if ( this . dialogType == "edit" ) {
this . editCategory ( ) ;
}
} ,
allowDrop ( draggingNode, dropNode, type ) {
this . countNodeLevel ( draggingNode) ;
let deep = Math. abs ( this . maxLevel - draggingNode. level) + 1 ;
console. log ( "拖拽树级节点深度" , deep) ;
if ( type == "inner" ) {
return deep + dropNode. level <= 3 ;
} else {
return deep + dropNode. parent. level <= 3 ;
}
console. log ( "拖拽树级节点" , draggingNode, dropNode, type) ;
} ,
countNodeLevel ( node ) {
if ( node. childNodes != null && node. childNodes. length > 0 ) {
for ( let i = 0 ; i < node. childNodes. length; i++ ) {
if ( node. childNodes[ i] . level > this . maxLevel) {
this . maxLevel = node. childNodes[ i] . level;
}
this . countNodeLevel ( node. childNodes[ i] ) ;
}
}
} ,
handleDrop ( draggingNode, dropNode, dropType, ev ) {
console. log (
"拖拽树级节点成功后的响应事件: " ,
draggingNode,
dropNode,
dropType
) ;
let pCid = 0 ;
let siblings = null ;
if ( dropType == "before" || dropType == "after" ) {
pCid =
dropNode. parent. data. catId == undefined
? 0
: dropNode. parent. data. catId;
siblings = dropNode. parent. childNodes;
} else {
pCid = dropNode. data. catId;
siblings = dropNode. childNodes;
}
this . pCid. push ( pCid) ;
for ( let i = 0 ; i < siblings. length; i++ ) {
if ( siblings[ i] . data. catId == draggingNode. data. catId) {
let catLevel = draggingNode. level;
if ( siblings[ i] . level != draggingNode. level) {
catLevel = siblings[ i] . level;
this . updateChildNodeLevel ( 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
} ) ;
}
}
console. log ( "updateNodes" , this . updateNodes) ;
} ,
updateChildNodeLevel ( node ) {
if ( node. childNodes. length > 0 ) {
for ( let i = 0 ; i < node. childNodes. length; i++ ) {
var cNode = node. childNodes[ i] . data;
this . updateNodes. push ( {
catId : cNode. catId,
catLevel : node. childNodes[ i] . level,
} ) ;
this . updateChildNodeLevel ( node. childNodes[ i] ) ;
}
}
} ,
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 . expandKey = this . pCid;
this . updateNodes = [ ] ;
this . maxLevel = 0 ;
} ) ;
} ,
batchDelete ( ) {
let catIds = [ ] ;
let checkNodes = this . $refs. menuTree. getCheckedNodes ( ) ;
console. log ( "被选中的节点为 " , checkNodes) ;
for ( let i = 0 ; i < checkNodes. length; i++ ) {
catIds. push ( checkNodes[ i] . catId) ;
}
this . $confirm ( ` 此操作将永久删除菜单, 是否继续? ` , "提示" , {
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 . $message ( {
message : "批量删除成功" ,
type : "success" ,
} ) ;
this . getMenus ( ) ;
} ) ;
} ) . catch ( ( ) => {
} ) ;
} ,
} ,
} ;
< / script>
< style lang= "scss" scoped> < / style>
最终实现效果
排序变化
拖拽实现 使用开关来表示是否开启拖拽功能
批量删除