[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07商品信息三级分类API的编写(使用Element-ui树形组件)

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07三级分类API

一、获取三级分类树形列表

一、controller调用

    /**
     * 查询所有产品,并以属性列表展示
     */
    @RequestMapping("/list/tree")
    //@RequiresPermissions("product:category:list")
    public R list(){
     
        List<CategoryEntity> entities=categoryService.listWithTree();
        return R.ok().put("data", entities);
    }

二、递归查找子节点

1.修改entity

	/**
	 * 所有子节点
	 */
	@TableField(exist=false)
	private List<CategoryEntity> children;

2.递归查找子节点

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全局模板

{
     
    "vue全局模板": {
     
        "prefix": "vue",
        "body": [
            "",
            "",
            "",
            ""
        ],
        "description": "生成vue模板"
    }
}

vueHTTP请求模板

需要加的话,加在全局模板里面

    "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请求"
    }

1.创建目录菜单

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07商品信息三级分类API的编写(使用Element-ui树形组件)_第1张图片
[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07商品信息三级分类API的编写(使用Element-ui树形组件)_第2张图片
[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07商品信息三级分类API的编写(使用Element-ui树形组件)_第3张图片

2.找到对应vue目录

1.创建文件

创建src/views/product/category.vue与之对应

2.创建树形模板

<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>

3.网关统一访问

1.更改前端访问路径

如果直接调用方法,就会出现404错误,因为访问的地址是http://localhost:8080/renren-fast/product/category/list/tree,需要转发的查询地址是http://localhost:10000/product/category/list/tree

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07商品信息三级分类API的编写(使用Element-ui树形组件)_第4张图片

所以要去修改vue的统一访问链接,让其访问后台。

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07商品信息三级分类API的编写(使用Element-ui树形组件)_第5张图片

2.注册renren-fast到nacos

application.yml

application:
  name: renren-fast
cloud:
  nacos:
    discovery:
      server-addr: 127.0.0.1:8848
3.修改路由

再次连接发现路由地址多了一个api,需要在路由配置中进行修改

gateway:
  routes:
    - id: base_route
      uri: lb://renren-fast
      predicates:
        - Path=/api/**
      filters:
        - RewritePath=/api/(?>.*), /renren-fast/$\{
     segment}
4.配置跨域
@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);
    }
}

3.设置树形结构

[项目练手笔记-谷粒商城(SpringCloud Alibaba+vue前后端分离)]day03-day07商品信息三级分类API的编写(使用Element-ui树形组件)_第6张图片

  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();
  },

4.删除功能编写

1.增加一些必要属性

参数 说明 默认值
node-key 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
show-checkbox 节点是否可被选择 false
expand-on-click-node 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。 true

2.添加删除添加框


        {
    { node.label }}
        
          添加
          删除
        
      

3.后台添加删除功能

采用逻辑删除功能

1.配置yml
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0
2.配置entity
/**
 * 是否显示[0-不显示,1显示]
 */
@TableLogic(value = "1",delval = "0")
private Integer showStatus;

4.前台添加删除功能

1.给网页发送指定post请求
      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);
      });
2.删除确认框
    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(() => {
        });
    }
  }
3.删除提示成功框
            //消息提示删除成功
            this.$message({
              message: "删除成功!",
              type: "success"
            });
4.设置默认展开菜单
      :default-expanded-keys="expandedkeys"	//设置属性
        data() {
          return {
            menus: [],
            expandedkeys: [],//设置为空
       
       
       
       			//刷新出删除后菜单
            this.getMenus();
            //展开到被删除结点的父菜单
            this.expandedkeys=[node.parent.data.catId];

5.添加功能编写

1.使用对话框模拟

    
      这是一段信息
      
        取 消
        确 定
      
    

设置默认不打开对话框

  data() {
    return {
      menus: [],
      expandedkeys: [],
      dialogVisible: false,//默认不打开

点击添加触发append函数

      this.dialogVisible = true;

2.自定义对话框

    
      
        
          
        
      
      
        取 消
        确 定
      
    

3.函数编写

    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];
    }

6.编辑功能编写

1.添加编辑按钮

          编辑

2.参数设置

  data() {
    return {
      submitType: "",
      title: "",
      menus: [],
      expandedkeys: [],
      dialogVisible: false,
      category: {
        carId: null,
        name: "",
        parentCid: 0,
        catLevel: 0,
        showStatus: 1,
        sort: 0,
        icon: "",
        productUnit: ""
      },

3.修改添加,编写编辑方法

    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();
      }
    },

7.开启拖拽

1.开启tree的拖拽

      :draggable="true" 

2.拖拽方法

    //判断是否能够拖拽
    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]);
              
          }
      }
    }

8.拖拽事件补充

1.增加拖拽完成后事件

    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]);
        }
      }
    }
  }

9.拖拽功能后台数据获取

1.修改controller

/**
 * 批量修改功能
 */
@RequestMapping("/update/sort")
//@RequiresPermissions("product:category:update")
public R update(@RequestBody CategoryEntity[] category){
     
    categoryService.updateBatchById(Arrays.asList(category));
    return R.ok();
}

2.发送httppost请求

完善前台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;
      });

10.拖拽功能完善

1.增加功能开关

    
    批量保存

2.批量保存

将批量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;
      });
    }

11.批量删除功能

1.添加按钮

    批量删除

2.添加el-tree属性

ref=“menuTree”

该属性表示树形结构的唯一标识

3.获取选中结点

使用自带方法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);
    }

4.将结点信息发送给后台删除

    //批量删除方法
    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(() => {});
    }

你可能感兴趣的:(分布式微服务,学习笔记,练手开源项目,前后端分离,SpringCloud开源项目,谷粒商城,三级分类)