赞
踩
<template> <div> <el-switch v-model="value1" active-text="开启拖拽" inactive-text="关闭拖拽"> </el-switch> <el-button type="primary" @click="SaveChanges">保存更改</el-button> <el-button type="danger" @click="batchDelete">批量删除</el-button> <el-tree ref="menuTree" @node-drop="handleDrop" :allow-drop="allowDrop" :draggable="value1" :default-expanded-keys="expandedKey" :data="data" :props="defaultProps" :expand-on-click-node="false" :show-checkbox ="true" node-key="catId"> <span class="custom-tree-node" slot-scope="{ node, data }"> <span>{{ node.label }}</span> <span> <el-button v-if="data.catLevel == 1 || data.catLevel == 2" type="text" size="mini" @click="() => append(data)"> 添加 </el-button> <el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)"> 删除 </el-button> <el-button type="text" size="mini" @click="() => exit(node, data)"> 编辑 </el-button> </span> </span> </el-tree> <el-dialog :title="title" :visible.sync="dialogFormVisible" :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.sort" autocomplete="off"></el-input> </el-form-item> <!-- <el-upload--> <!-- :label-width="formLabelWidth"--> <!-- action=""--> <!-- list-type="picture-card"--> <!-- :on-preview="handlePictureCardPreview"--> <!-- :on-remove="handleRemove">--> <!-- <i class="el-icon-plus"></i>--> <!-- </el-upload>--> <!-- <el-dialog :label-width="formLabelWidth" :visible.sync="dialogVisible">--> <!-- <img width="100%" :src="dialogImageUrl" alt="">--> <!-- </el-dialog>--> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">取 消</el-button> <el-button v-if="title =='添加菜单'" type="primary" @click="setMenu">确 定</el-button> <el-button v-if="title =='编辑菜单'" type="primary" @click="exitMenu">确 定</el-button> </div> </el-dialog> </div> </template> <script> export default { data() { return { catIds:[], ExpandID:[], value1: true, updateNodes: [], maxLevel:0, title:'', category:{ name: '', parentCid: 0, catLevel: 0, sort: 0, icon: '', showStatus: 1 }, exitcategory:{ catId:'', name:'', icon:'', sort:'' }, data: [], defaultProps: { children: 'children', label: 'name' }, dialogFormVisible: false, form: { name: '', region: '', date1: '', date2: '', delivery: false, type: [], resource: '', desc: '' }, formLabelWidth: '120px', dialogImageUrl: '', dialogVisible: false, expandedKey: [] } }, //监控data中的数据变化 watch: { //监控开关按钮的状态变化 oldName之前的值 newName改变后的值 value1(newName,oldName){ if(newName == false){ this.ExpandID=[]; this.updateNodes=[]; this.maxLevel=0; console.log("结果:==",this.ExpandID,this.updateNodes,this.maxLevel); } } }, //方法集合 methods: { //批量删除选中的菜单 batchDelete(){ console.log(this.$refs.menuTree.getCheckedNodes()); let checkedNodes = this.$refs.menuTree.getCheckedNodes(); console.log(checkedNodes); if(checkedNodes.length > 0){ for(let i=0;i<checkedNodes.length;i++){ this.catIds.push(checkedNodes[i].catId) } console.log("统计出来的id串:",this.catIds); this.$confirm('是否确定删除选中菜单?', '提示', { confirmButtonText: '确定删除', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$http({ url: this.$http.adornUrl('/product/category/delete'), method: 'post', data: this.$http.adornData(this.catIds,false) }).then(({data}) => { console.log(data) if (data && data.code === 0) { this.$message({ message: '删除成功', type: 'success', duration: 1500, onClose: () => { this.getMenus() this.expandedKey = [checkedNodes[0].parentCid] } }) } else { this.$message.error(data.msg) } }); }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }); }); } }, //保存更改 SaveChanges(){ this.$http({ url: this.$http.adornUrl(`/product/category/update/sort`), method: 'post', data: this.$http.adornData(this.updateNodes,false) }).then(({ data }) => { if (data && data.code === 0) { this.$message({ message: '拖拽成功', type: 'success', onClose: () => { this.getMenus() this.expandedKey = this.ExpandID; } }) } else { this.$message.error(data.msg) } this.updateNodes = []; // this.ExpandID = []; }).catch(err=>{ console.log(err) }) }, //拖拽完成时触发的事件 handleDrop(draggingNode, dropNode, dropType, ev) { //清空 // this.ExpandID = []; console.log('当前被拖动的节点:====',draggingNode,'tree drop: ===', dropNode, dropType); //展开id this.ExpandID.push(draggingNode.data.catId); // 1、 改变当前被拖动的父ID var updateCatId = 0; var childNodes = null; var level = 0; if(dropType == "inner"){ updateCatId = dropNode.data.catId; childNodes = dropNode.childNodes; level = dropNode.level + 1; }else{ updateCatId = dropNode.parent.data.catId == null?0:dropNode.parent.data.catId ; childNodes = dropNode.parent.childNodes; level = dropNode.level; } console.log(updateCatId) console.log("childNodes:=========",childNodes) // 2、 排序 当前拖拽节点的最新顺序 for(let i = 0;i < childNodes.length;i++){ if(childNodes[i].data.catId == draggingNode.data.catId){ //当前节点的默认层级 let catLevel = draggingNode.level; if(childNodes[i].level != draggingNode.level){ //如果能够进来 就表示当前节点的层级发生了变化 catLevel = childNodes[i].level; //修改子节点的层级 this.updateChildNodeLevel(childNodes[i]); } console.log("层级:",catLevel); //如果遍历的是当前正在拖拽的节点 当前拖动的父ID和层级 也要修改 this.updateNodes.push({catId:childNodes[i].data.catId,sort: i,parentCid: updateCatId,level: level}); }else{ this.updateNodes.push({catId:childNodes[i].data.catId,sort: i}); } } // 3、 拖动完成 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}); if(node.childNodes[i].childNodes.length > 0){ this.updateChildNodeLevel(node.childNodes[i]); } } } }, //菜单拖拽 allowDrop(draggingNode, dropNode, type) { //1、 被拖动的当前节点以及所在的父节点总层数不能大于3 //获取最大子节点的深度 this.maxLevel = 0; this.countNodeLevel(draggingNode.data); console.log("拖动===============================",draggingNode,dropNode,type) let deep = (this.maxLevel - draggingNode.data.catLevel)+1; console.log("深度:",deep) // this.maxLevel if(type == "inner"){ return (deep+ dropNode.level) <=3 }else{ return (deep + dropNode.parent.level)<=3; } // 被拖动的当前节点总层数 draggingNode 当前拖动的菜单信息 dropNode 被拖动到的菜单信息 }, countNodeLevel(node){ this.maxLevel = 0; //找到所有子节点,求出最大深度 maxLevel if(this.maxLevel < node.catLevel){ this.maxLevel = node.catLevel } if(node.children != null && node.children.length >0){ for(let i=0;i<node.children.length;i++){ if(node.children[i].catLevel > this.maxLevel){ this.maxLevel = node.children[i].catLevel; } this.countNodeLevel(node.children[i]); } } }, //编辑菜单方法:↓ exitMenu(){ this.exitcategory.icon = this.category.icon this.exitcategory.name = this.category.name this.exitcategory.sort = this.category.sort this.$http({ url: this.$http.adornUrl(`/product/category/update`), method: 'post', data: this.$http.adornData(this.exitcategory,false) }).then(({ data }) => { if (data && data.code === 0) { this.$message({ message: '编辑成功', type: 'success', onClose: () => { this.getMenus() this.expandedKey = [ this.exitcategory.catId] } }) this.dialogFormVisible = false } else { this.$message.error(data.msg) } }).catch(err=>{ console.log(err) }) console.log("这是编辑") }, //编辑菜单:↓↓↓ exit(node,data){ this.exitcategory.catId = data.catId this.$http({ url: this.$http.adornUrl(`/product/category/info/${data.catId}`), method: 'post' }).then(({ data }) => { console.log("成功获取到菜单数据....", data.data) this.category.name = data.data.name this.category.icon = data.data.icon this.category.sort = data.data.sort this.category.parentCid = data.data.parentCid }).catch(err=>{ console.log(err) }) this.title = "编辑菜单" this.dialogFormVisible = true console.log("data=======",data,"node",node) }, //添加菜单:↓↓↓ setMenu(){ this.$http({ url: this.$http.adornUrl('/product/category/save'), method: 'post', data: this.$http.adornData(this.category,false) }).then(({data}) => { // console.log(data) // console.log("添加成功!") if (data && data.code === 0) { this.dialogFormVisible = false this.$message({ message: '添加成功', type: 'success', onClose: () => { this.getMenus() this.expandedKey = [this.category.parentCid] } }) } else { this.$message.error(data.msg) } }).catch(err => { console.log(err) }) }, handleRemove(file, fileList) { console.log(file, fileList); }, handlePictureCardPreview(file) { this.dialogImageUrl = file.url; console.log(this.dialogImageUrl) this.dialogVisible = true; }, getMenus() { this.$http({ url: this.$http.adornUrl('/product/category/list/tree'), method: 'get' }).then(({ data }) => { console.log("成功获取到菜单数据....", data.data) this.data = data.data }) }, remove(node, data) { this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { var ids = [data.catId] console.log("remove=======data:",data,"node:",node) this.$http({ url: this.$http.adornUrl('/product/category/delete'), method: 'post', data: this.$http.adornData(ids,false) }).then(({data}) => { console.log(data) if (data && data.code === 0) { this.$message({ message: '删除成功', type: 'success', duration: 1500, onClose: () => { this.getMenus() this.expandedKey = [node.parent.data.catId] } }) } else { this.$message.error(data.msg) } }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }); }); }, append(data) { this.category.name = "" this.category.sort = 0 this.category.icon = "" this.title = "添加菜单" //字符串*1 可以将字符串转换成数值 this.category.catLevel = (data.catLevel * 1) + 1 this.category.parentCid = data.catId this.dialogFormVisible = true console.log("append=======",data) } }, //生命周期 创建完成 可以访问当前this实例 created() { this.getMenus(); } } </script>
package com.atguigu.gulimall.product.controller; import com.atguigu.common.utils.R; import com.atguigu.gulimall.product.entity.CategoryEntity; import com.atguigu.gulimall.product.service.CategoryService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Arrays; import java.util.List; /** * 商品三级分类 * * @author leifengyang * @email leifengyang@gmail.com * @date 2019-10-01 22:50:32 */ @RestController @RequestMapping("product/category") public class CategoryController { @Autowired private CategoryService categoryService; /** * 查出所有分类以及子分类,以树形结构组装起来 */ @RequestMapping("/list/tree") public R list(){ List<CategoryEntity> entities = categoryService.listWithTree(); return R.ok().put("data", entities); } /** * 信息 */ @RequestMapping("/info/{catId}") //@RequiresPermissions("product:category:info") public R info(@PathVariable("catId") Long catId){ CategoryEntity category = categoryService.getById(catId); return R.ok().put("data", category); } /** * 保存 */ @RequestMapping("/save") //@RequiresPermissions("product:category:save") public R save(@RequestBody CategoryEntity category){ categoryService.save(category); return R.ok(); } @RequestMapping("/update/sort") //@RequiresPermissions("product:category:update") public R updateSort(@RequestBody CategoryEntity[] category){ //maibeitisi-pulasi 的updateBatchById 就是批量修改 categoryService.updateBatchById(Arrays.asList(category)); return R.ok(); } /** * 修改 */ @RequestMapping("/update") //@RequiresPermissions("product:category:update") public R update(@RequestBody CategoryEntity category){ categoryService.updateCascade(category); return R.ok(); } /** * 删除 * @RequestBody:获取请求体,必须发送POST请求 * SpringMVC自动将请求体的数据(json),转为对应的对象 */ @RequestMapping("/delete") //@RequiresPermissions("product:category:delete") public R delete(@RequestBody Long[] catIds){ //categoryService.removeByIds(Arrays.asList(catIds)); categoryService.removeMenuByIds(Arrays.asList(catIds)); return R.ok(); } }
package com.atguigu.gulimall.product.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.gulimall.product.entity.CategoryEntity;import java.util.List;
import java.util.Map;/**
* 商品三级分类
*
* @author leifengyang
* @email leifengyang@gmail.com
* @date 2019-10-01 21:08:48
*/
public interface CategoryService extends IService<CategoryEntity> {PageUtils queryPage(Map<String, Object> params);
List<CategoryEntity> listWithTree();
void removeMenuByIds(List<Long> asList);
/**
* 找到catelogId的完整路径;
* [父/子/孙]
* @param catelogId
* @return
*/
Long[] findCatelogPath(Long catelogId);void updateCascade(CategoryEntity category);
}
package com.atguigu.gulimall.product.service.impl; import com.atguigu.common.utils.PageUtils; import com.atguigu.common.utils.Query; import com.atguigu.gulimall.product.dao.CategoryDao; import com.atguigu.gulimall.product.entity.CategoryEntity; import com.atguigu.gulimall.product.service.CategoryBrandRelationService; import com.atguigu.gulimall.product.service.CategoryService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service("categoryService") public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService { // @Autowired // CategoryDao categoryDao; @Autowired CategoryBrandRelationService categoryBrandRelationService; @Override public PageUtils queryPage(Map<String, Object> params) { IPage<CategoryEntity> page = this.page( new Query<CategoryEntity>().getPage(params), new QueryWrapper<CategoryEntity>() ); return new PageUtils(page); } @Override public List<CategoryEntity> listWithTree() { //1、查出所有分类 List<CategoryEntity> entities = baseMapper.selectList(null); //2、组装成父子的树形结构 //2.1)、找到所有的一级分类 List<CategoryEntity> level1Menus = entities.stream().filter((categoryEntity) -> //filter 过滤掉不满足条件的所有数据 categoryEntity.getParentCid() == 0 ).map((menu)->{ //map 对当前filter过滤后的每个元素进行处理 menu.setChildren(getChildrens(menu,entities)); return menu; }).sorted((menu1,menu2)->{ //进行排序 //2、菜单的排序 return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort()); }).collect(Collectors.toList()); // collect 集合 返回 //sorted排序 //map 影响 //stream api collect 收集 // List<CategoryEntity> level1Menus = entities.stream().filter(categoryEntity -> // categoryEntity.getParentCid() == 0 // ).map((menu)->{ // menu.setChildren(getChildrens(menu,entities)); // return menu; // }).sorted((menu1,menu2)->{ // return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort()); // }).collect(Collectors.toList()); // List<CategoryEntity> resultList = bulidPermission(entities); return level1Menus; } //把返回所有菜单list集合进行封装的方法 public static List<CategoryEntity> bulidPermission(List<CategoryEntity> permissionList) { //创建list集合,用于数据最终封装 List<CategoryEntity> finalNode = new ArrayList<>(); //把所有菜单list集合遍历,得到顶层菜单 pid=0菜单,设置level是1 for(CategoryEntity permissionNode : permissionList) { //得到顶层菜单 pid=0菜单 if(permissionNode.getCatLevel() == 1) { //设置顶层菜单的level是1 permissionNode.setCatLevel(1); //根据顶层菜单,向里面进行查询子菜单,封装到finalNode里面 finalNode.add(selectChildren(permissionNode,permissionList)); } } return finalNode; } private static CategoryEntity selectChildren(CategoryEntity permissionNode, List<CategoryEntity> permissionList) { //1 因为向一层菜单里面放二层菜单,二层里面还要放三层,把对象初始化 permissionNode.setChildren(new ArrayList<CategoryEntity>()); //2 遍历所有菜单list集合,进行判断比较,比较id和pid值是否相同 for(CategoryEntity it : permissionList) { //判断 id和pid值是否相同 if(permissionNode.getCatId().equals(it.getParentCid())) { //把父菜单的level值+1 int level = permissionNode.getCatLevel()+1; it.setCatLevel(level); //如果children为空,进行初始化操作 if(permissionNode.getChildren() == null) { permissionNode.setChildren(new ArrayList<CategoryEntity>()); } //把查询出来的子菜单放到父菜单里面 permissionNode.getChildren().add(selectChildren(it,permissionList)); } } return permissionNode; } @Override public void removeMenuByIds(List<Long> asList) { //TODO 1、检查当前删除的菜单,是否被别的地方引用 //逻辑删除 baseMapper.deleteBatchIds(asList); } //[2,25,225] @Override public Long[] findCatelogPath(Long catelogId) { List<Long> paths = new ArrayList<>(); List<Long> parentPath = findParentPath(catelogId, paths); Collections.reverse(parentPath); return parentPath.toArray(new Long[parentPath.size()]); } /** * 级联更新所有关联的数据 * @param category */ @Transactional @Override public void updateCascade(CategoryEntity category) { this.updateById(category); categoryBrandRelationService.updateCategory(category.getCatId(),category.getName()); } //225,25,2 private List<Long> findParentPath(Long catelogId,List<Long> paths){ //1、收集当前节点id paths.add(catelogId); CategoryEntity byId = this.getById(catelogId); if(byId.getParentCid()!=0){ findParentPath(byId.getParentCid(),paths); } return paths; } //递归查找所有菜单的子菜单 private List<CategoryEntity> getChildrens(CategoryEntity root,List<CategoryEntity> all){ List<CategoryEntity> children = all.stream().filter(categoryEntity -> { return categoryEntity.getParentCid() == root.getCatId(); //如果不满足这个条件就过滤掉 }).map(categoryEntity -> { //对没有过滤掉的每个元素进行处理 //1、找到子菜单 categoryEntity.setChildren(getChildrens(categoryEntity,all)); return categoryEntity; }).sorted((menu1,menu2)->{ //2、菜单的排序 return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort()); }).collect(Collectors.toList()); return children; } }
均使用MybatisPlus自带的baseMapper里面的功能来实现
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。