电商项目——商品服务-API-三级分类——第九章——上篇

电商项目——初识电商——第一章——上篇
电商项目——分布式基础概念和电商项目微服务架构图,划分图的详解——第二章——上篇
电商项目——电商项目的虚拟机环境搭建_VirtualBox,Vagrant——第三章——上篇
电商项目——Linux虚拟机中安装docker,mysql,redis_VirtualBox——第四章——上篇
电商项目——电商项目的环境搭建_开发工具&环境搭建——第五章——上篇
电商项目——快速开发人人开源搭建后台管理系统&代码生成器逆向工程搭建——第六章——上篇
电商项目——分布式组件(SpringCloud Alibaba,SpringCloud)——第七章——上篇
电商项目——前端基础——第八章——上篇
电商项目——商品服务-API-三级分类——第九章——上篇
电商项目——商品服务-API-品牌管理——第十章——上篇
电商项目——商品服务-API-属性分组——第十一章——上篇
电商项目——商品服务-API-品牌管理——第十二章——上篇
电商项目——商品服务-API-平台属性——第十三章——上篇
电商项目——商品服务-API-新增商品——第十四章——上篇
电商项目——商品服务-API-商品管理——第十五章——上篇
电商项目——商品服务-API-仓库管理——第十六章——上篇

文章目录

  • 1:查询-递归树形结构获取数据
  • 2:配置网关路由与路径重写
  • 3:网关统一配置跨域
  • 4:查询-树形展示三级分类数据
  • 5:删除-页面效果
  • 6:删除-逻辑删除
  • 7:删除-删除效果细化
  • 8:新增-新增效果完成
  • 9:修改-基本修改效果完成
  • 10:修改-拖拽效果
  • 11:修改-拖拽数据收集
  • 12:修改-拖拽功能完成
  • 13:修改-批量拖拽效果
  • 14: 修改-批量删除
  • 15:小结

讲完了前面几章的内容,现在我们就可以对后台管理系统,和微服务项目进行开发了,我们先从三级分类说起
默认mall-product的环境已经全部配置好了

1:查询-递归树形结构获取数据

电商项目——商品服务-API-三级分类——第九章——上篇_第1张图片
三级分类(电商里面经常用到的功能):所有的数据都是来源于数据库,我们要对三级分类进行维护,进行增删改查,我们首先就必须要后台管理系统来可以维护我们的整个数据。所以我们引出了下面的问题,解决了下面问题,我们就可以在搭建前端界面进行前后端连接

问题:如何查出所有三级分类以及子分类,并以树形结构组装起来?,我们看这篇的思路分析
电商项目——如何查出所有三级分类,并以树形结构组装起来?

2:配置网关路由与路径重写

接下来我们来编写后台管理系统的前端项目,来维护三级分类的增删改查

我们先进行测试看是否后台管理系统可以成功启动
启动renren-fast和renren-fast-vue
在这里插入图片描述
在这里插入图片描述
电商项目——商品服务-API-三级分类——第九章——上篇_第2张图片
第一步:我们要写商品系统的相关内容,看如下操作
电商项目——商品服务-API-三级分类——第九章——上篇_第3张图片
跟商品系统有关的项目都放在我自己新增的商品系统目录下,然后我们在商品系统的目录下,增加一个菜单
电商项目——商品服务-API-三级分类——第九章——上篇_第4张图片
最终的效果如下
电商项目——商品服务-API-三级分类——第九章——上篇_第5张图片
搭建分类维护功能,我们期望展示出整个三级分类,然后可以对三级分类进行增删改查,而我们想要做这个功能,就要先了解脚手架工程的一些基本规范
电商项目——商品服务-API-三级分类——第九章——上篇_第6张图片
脚手架工程的基本规范1:
电商项目——商品服务-API-三级分类——第九章——上篇_第7张图片
脚手架工程的基本规范2:
电商项目——商品服务-API-三级分类——第九章——上篇_第8张图片

第二步:在renren-fast-vue中搭建分类维护路径的对应目录如下,并进行前端显示三级分类数据的搭建
电商项目——商品服务-API-三级分类——第九章——上篇_第9张图片
我们就可以在category中使用ElementUI进行前端显示三级分类数据的搭建

第三步:在renren-fast-vue中的src/views/modules/product/路径下搭建category.vue

我们使用ElementUI组件中的Tree树形控件来完成我们的功能,并且还要向后端发送请求在返回数据给前端
代码如下




我们进行测试
电商项目——商品服务-API-三级分类——第九章——上篇_第10张图片
解决办法:我们要改变基本路径http://localhost:8080/renren-fast的值把它变成网关的基本路径(我们以后要上线很多微服务项目,我们不肯能一直去renren-fast-vue中一直修改基本路径的端口,所以我们把所有的请求发送给网关,网关在分配到指定的路径的微服务中)
电商项目——商品服务-API-三级分类——第九章——上篇_第11张图片
在进行测试,发现下面问题
电商项目——商品服务-API-三级分类——第九章——上篇_第12张图片
解决办法:把renren-fast注册到注册中心中,并且配置网关的routes
renren-fast

  1. 引入mall-common依赖
		<dependency>
			<groupId>com.atstudying.mallgroupId>
			<artifactId>mall-commonartifactId>
			<version>0.0.1-SNAPSHOTversion>
		dependency>
  1. 编译application.yml配置
spring:
  application:
    name: renren-fast
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  1. 导入@EnableDiscoveryClient
@EnableDiscoveryClient
@SpringBootApplication
public class RenrenApplication {
     

	public static void main(String[] args) {
     
		SpringApplication.run(RenrenApplication.class, args);
	}

}
  1. mall-gateway中
    配置网关的routes
    电商项目——商品服务-API-三级分类——第九章——上篇_第13张图片
    在进行测试,发现下面问题
    电商项目——商品服务-API-三级分类——第九章——上篇_第14张图片
    解决办法:重新配置好网关的路由,新增一个路径重写功能
    mall-gateway
    电商项目——商品服务-API-三级分类——第九章——上篇_第15张图片
    在进行测试:发现如下问题
    电商项目——商品服务-API-三级分类——第九章——上篇_第16张图片

从8001访问到88出现了跨域问题,默认拒绝跨域请求

我们下一章就来介绍如何解决跨域问题

3:网关统一配置跨域

上一小节,我们配置了网关路由和路径重写(renren-fast),我们的验证码也刷新出来了,但是我们在登录测试的时候,发现报了一个跨域的问题
什么是跨域呢?怎么解决跨域问题呢?下面这篇文章为大家一一解答

HTTP访问控制(CORS)——预检请求问题的解决
上面这篇文章的第四节就是解决网关统一配置跨域的一个案例演示

我们根据上面这篇文章成功解决跨域问题后,再次登录,发现登录,发现还是登录不了,进行检查,发现下面问题
在这里插入图片描述
解决办法:renren-fast中注释掉有关跨域的代码
电商项目——商品服务-API-三级分类——第九章——上篇_第17张图片
重新启动renren-fast,并重新登录,发现登录成功

4:查询-树形展示三级分类数据

上节我们解决了跨域,我们现在来继续编写商品系统目录下分类维护菜单的代码
电商项目——商品服务-API-三级分类——第九章——上篇_第18张图片
我么刷新上面界面,并检查元素发现,跨域问题解决了,可是请求却找不到
电商项目——商品服务-API-三级分类——第九章——上篇_第19张图片
解决办法,我么以前配置网关路由默认是全部转到renren-fast的,所以我们的请求找不到,我们现在去网关配置一个mall-product的网关路由,让请求跳转到该路由下。
电商项目——商品服务-API-三级分类——第九章——上篇_第20张图片
我们进行如下测试,发现数据成功获取
http://localhost:88/api/product/category/list/tree
如上的地址经过网关会变成如下地址
http://localhost:30000/product/category/list/tree
因为,我们配置的网关路由在起作用,如上两个地址的访问都会得到下面的图的效果

      - id: mall-product
        uri: lb://mall-product
        predicates:
          - Path=/api/product/**
        filters:
          - RewritePath=/api/(?>.*),/$\{
     segment}  

电商项目——商品服务-API-三级分类——第九章——上篇_第21张图片
我们看见数据已经成功返回给了前端界面,可是我们要怎么展示呢?
电商项目——商品服务-API-三级分类——第九章——上篇_第22张图片
category.vue

 methods: {
        handleNodeClick(data){
          console.log(data)
        },
        // 获取数据列表
        getDataList () {
          this.$http({
            url: this.$http.adornUrl('/product/category/list/tree'),
            method: 'get'

          }).then( data => {
            console.log("成功获取到菜单数据:"+data)

          })
        }
      created () {
// 
        this.getDataList();
      },

我们发现data中有很多属性,可是我们要的数据是在data.data中,所以我们可以在前端的category.vue中进行项目解构
电商项目——商品服务-API-三级分类——第九章——上篇_第23张图片
如下category.vue中部分代码演示片段({data})(解构)

  // 获取数据列表
        getDataList () {
          this.$http({
            url: this.$http.adornUrl('/product/category/list/tree'),
            method: 'get'

          }).then( ({data}) => {
            console.log("成功获取到菜单数据:"+data.data)
          })
        }

完整的代码如下
category.vue




我们的商品系统下的分类维护中成功显示出三级分类数据
电商项目——商品服务-API-三级分类——第九章——上篇_第24张图片

5:删除-页面效果

我们先来编写菜单删除功能,哪些菜单可以被删除呢?那就是没有子菜单,并且没有被别的地方引用的菜单,操作如下
第一步:我们先来展示前端界面的删除效果,我们去eliment中找到Tree树形控件下的自定义节点内容,把它的代码引入,如下代码演示
电商项目——商品服务-API-三级分类——第九章——上篇_第25张图片




就会变成如下效果
电商项目——商品服务-API-三级分类——第九章——上篇_第26张图片
第二步:只有我们这个菜单是一级菜单或者是二级菜单的时候才显示append按钮(三级分类不可以追加元素);无论是一级分类还是二级分类,只要我们没子节点就可以删除;所以我们进行修改按钮,在合适的时机显示出来,添加如下v-if语句,v-if里面的判断值怎么得出呢?
我们要进行检查界面,观察点击按钮后,在控制台上打印值的变化,如下
电商项目——商品服务-API-三级分类——第九章——上篇_第27张图片

 
            Append
          
          

6:删除-逻辑删除

这章我们就来编写发送真正的请求,来进行删除功能的完成
在mall-product中找到CategoryController.java
CategoryController.java
如下方法中我们必须要知道一些知识

  • @RequestBody:获取请求体,必须发送post请求(只有post请求才有请求体,get请求没有请求体)
  • springmvc(web)自动将请求体的数据(json),转化为对应的对象
@RestController
@RequestMapping("product/category")
public class CategoryController {
     
    @RequestMapping("/delete")
    public R delete(@RequestBody Long[] catIds){
     
		categoryService.removeByIds(Arrays.asList(catIds));

        return R.ok();
    }

我们推荐大家使用postman来发送请求(可以进行模拟测试)
进行如下测试
我们在数据库中插入一个id=10000的数据

insert  into `pms_category`(`cat_id`,`name`,`parent_cid`,`cat_level`,`show_status`,`sort`,`icon`,`product_unit`,`product_count`) values (10000,'测试',0,1,1,0,NULL,NULL,0)

在这里插入图片描述
测试是否可以删除成功
电商项目——商品服务-API-三级分类——第九章——上篇_第28张图片
返回如下值,说明删除成功,数据库中也没有10000的值

{
    "msg": "success",
    "code": 0
}

在这里插入图片描述
但是我们真正的删除功能没有这么简单,如下进行简单演示
CategoryController.java

    @RequestMapping("/delete")
    public R delete(@RequestBody Long[] catIds){
     

        //1:检查当前删除的菜单,是否被其他地方引用
//		categoryService.removeByIds(Arrays.asList(catIds));
        //Arrays.asList()该方法是将数组转化成List集合的方法。
        categoryService.removeMenuByIds(Arrays.asList(catIds));

        return R.ok();
    }

CategoryServiceImpl.java

 @Override
    public void removeMenuByIds(List<Long> asList) {
     

        //1:todo 检查当前删除的菜单,是否被别的地方引用
        //原生调用basemapper中的deleteBatchIds批量删除方法
        //这个是物理删除,删除完是真的没了,
        baseMapper.deleteBatchIds(asList);
    }

我们用到上面的删除(物理删除),还要考虑到检查当前删除的菜单,是否被别的地方引用,以后考虑

我们在这里用逻辑删除的方法来实现

  • 逻辑删除是选择某个字段作为标识位置来表示是否被删除,在pms_category中就可以选择show_status来作为标识位

怎么配置逻辑删除呢?看下面步骤
3.1.1以后的mybatis-plus-boot-starter可以省略一二两步
第一步:配置全局的逻辑删除规则(可以省略)
mall-product中的nacos配置文件
电商项目——商品服务-API-三级分类——第九章——上篇_第29张图片
第二步:配置逻辑删除的组件Bean(省略)
第三步:给实体类的字段上加上逻辑删除注解
CategoryEntity.java

//...
	/**
	 * 是否显示[0-不显示,1显示]
	 * 	 * String value() default "";
	 String delval() default "";
	 */
	@TableLogic(value = "1",delval="0")
	private Integer showStatus;

进行测试:
我们可以调整日志级别:让dao下的日志也可以打印
电商项目——商品服务-API-三级分类——第九章——上篇_第30张图片
电商项目——商品服务-API-三级分类——第九章——上篇_第31张图片

7:删除-删除效果细化

接下来我们完成点击删除,发送请求,删除菜单的功能
电商项目——商品服务-API-三级分类——第九章——上篇_第32张图片
后端有关的代码

@RestController
@RequestMapping("product/category")
public class CategoryController {
     
    @RequestMapping("/delete")
    public R delete(@RequestBody Long[] catIds){
     
        categoryService.removeMenuByIds(Arrays.asList(catIds));
        return R.ok();
    }

前端有关的代码进行编写

  remove(node, data) {
           console.log(node,data);
          // 获取数据列表
          var ids=[data.catId]
            this.$http({

              url: this.$http.adornUrl('/product/category/delete'),
              method: 'post',
              data: this.$http.adornData(ids,false)

            }).then( ({data}) => {
              console.log("删除成功:")
              this.menus=data.data;

            })

        },

电商项目——商品服务-API-三级分类——第九章——上篇_第33张图片
电商项目——商品服务-API-三级分类——第九章——上篇_第34张图片
在这里插入图片描述

电商项目——商品服务-API-三级分类——第九章——上篇_第35张图片

未实现的功能:我们要完成删除一个按钮,提示框会弹出来(是否确认删除这个节点),删除完以后,还是要展开的状态,所以我们完成下面的操作来实现功能
category.vue
部分代码展示片段

<el-tree
    :data="menus"
    show-checkbox
    :props="defaultProps"
    node-key="catId"
    :default-expanded-keys="expandkey"
    :expand-on-click-node="false">
 data () {
     
            // 这里存放数据",
        return {
     
            expandkey: [],
            menus: [],
            defaultProps: {
     
              children: 'children',
              label: 'name'
            }
        }
       },
        methods: {
     
  remove(node, data) {
     
           console.log(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({
     
                type: '菜单删除成功',
                message: '删除成功!'
              });
              this.getDataList();
                            this.expandkey=node.parent.data.catId;
              console.log(this.expandkey)
            })
          }).catch(() => {
     
            this.$message({
     
              type: 'info',
              message: '已取消删除'
            });
          });


        },

8:新增-新增效果完成

接下来我们编写点击Append为它增加子分类的功能
电商项目——商品服务-API-三级分类——第九章——上篇_第36张图片
前端页面效果演示:希望点击append,可以出来一个对话框,点击确定按钮,完成新增,如下
电商项目——商品服务-API-三级分类——第九章——上篇_第37张图片
思路:

  • 我们要去Element UI中找到Dialog对话框,并引入代码,
    电商项目——商品服务-API-三级分类——第九章——上篇_第38张图片

  • 我们就要在对话框中的确定按钮编写一个监听事件addCategory(),这个事件里面我们写一个发生新增路径的请求方法,然后测试就可以完成上面的演示

代码和第九章的代码全部整合了

9:修改-基本修改效果完成

前端页面效果演示:
当我们点击修改按钮的时候,弹出一个对话框,数据都会回显到对话框中,然后我们再来动态输入新的内容,输入完以后点击确定,完成真正的修改
在这里插入图片描述
电商项目——商品服务-API-三级分类——第九章——上篇_第39张图片
思路:

  • 要求我们点击修改按钮,所以我们要新增一个修改按钮为Alter,弹出一个对话框,数据都会回显到对话框中,所以我们要设置一个监听的click事件为alter(data),并且在里面发送一个url,实时的获取数据库中的数据,最后回显到对话框中

监听按钮

 
          
            Alter
          

监听事件

 // 修改按钮
        alter(data){
          console.log("修改按钮");
          this.dialogVisible= true;
          this.flag=1;
          // console.log("当前节点的数据",data)
          this.$http({
            url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
            method: 'get'
            // 服务端传送的数据
          }).then(({data})=>{
            console.log("查询当前节点后的节信息",data)
            this.category.productUnit=data.category.productUnit;
            this.category.icon=data.category.icon;
            this.category.name=data.category.name;
            this.category.catId=data.category.catId;
            this.category.catLevel=data.category.catLevel;
            this.category.showStatus=data.category.showStatus;
            this.category.sort=data.category.sort;
            this.category.productCount=data.category.productCount;
            console.log("发送查询请求后,赋值给category的数据展示",this.category)
          })
        },

对话框的代码(使用Element UI编写的)


        
          
        
        
          

        
        
          

        
      
  • 完成上述步骤以后我们已经可以弹出一个对话框了,可是对话框里的确定按钮是有玄机的,如下图讲解,然后点击确定完成修改
    电商项目——商品服务-API-三级分类——第九章——上篇_第40张图片
    对话框中按钮代码演示
  
    取 消
    确 定
    

对话框中按钮确 定中触发的点击事件updateCategory()的代码

  //修改三级分类数据
        updateCategory(){
          console.log("修改当前节点的数据");

          console.log("当前节点的category",this.category);
// 对象发送出去给后端,选择指定的对象的值
          var {catId,productUnit,name,icon}=this.category;
          this.$http({
            url: this.$http.adornUrl(`/product/category/update`),
            method: 'post',
            data: this.$http.adornData(this.category,false)

            // 服务端传送的数据
          }).then(({data}) =>{
            this.$message({
              type: '数据修改成功',
              message: '修改成功!'
            });
            this.getDataList();
            this.dialogVisible=false;
            // this.expandedKey = [this.category.parentCid]
            console.log("数据修改成功")
          })
        },

如下是完整版的代码演示
category.vue

<template>
<!--  使用 scoped slot 会传入两个参数node和data,分别表示当前节点的 Node 对象和当前节点的数据-->
  <!--label	指定节点标签为节点对象的某个属性值,,children	指定子树为节点对象的某个属性值,,,data	展示数据-->
<!--  node-key	每个树节点用来作为唯一标识的属性,整棵树应该是唯一的-->
<!--  default-expand-all	是否默认展开所有节点-->
<!--  default-expanded-keys	默认展开的节点的 key 的数组-->
  <!--    :default-expanded-keys="expandkey"-->

  <!--  expand-on-click-node	是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。-->
  <div>
  <el-tree
    :data="menus"
    show-checkbox
    :title="titlevalue"
    :props="defaultProps"
    node-key="catId"
    :expand-on-click-node="false">
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{
     {
      node.label }}</span>
        <span>
          <el-button
            type="text"
            size="mini"
            @click="() => append(data)"
            v-if="data.catLevel<=2"

          >
            Append
          </el-button>
          <el-button
            type="text"
            size="mini"
            @click="() => remove(node, data)"
            v-if="data.children.length==0"
          >
            Delete
          </el-button>
          <el-button
            type="text"
            size="mini"
            @click="() => alter(data)"
          >
            Alter
          </el-button>
        </span>
      </span>
  </el-tree>

<!--    需要设置visible属性,它接收Boolean,当为true时显示 Dialog-->
    <el-dialog
      title="商品数据"
      :visible.sync="dialogVisible"
      width="30%"
     >
      <el-form :model="category">
        <el-form-item label="商品名称" :label-width="formLabelWidth">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="商品图标地址" :label-width="formLabelWidth">
          <el-input v-model="category.icon" autocomplete="off"></el-input>

        </el-form-item>
        <el-form-item label="商品计量单位" :label-width="formLabelWidth">
          <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="flag==0?addCategory():updateCategory()">确 定</el-button>
    </span>
    </el-dialog>
  </div>
</template>

<script>
    export default {
     
        // import引入的组件需要注入到对象中才能使用",
      components: {
     },
      data () {
     
            // 这里存放数据",
        return {
     
        titlevalue: '',
            flag: '',
            dialogVisible: false,
            expandkey: [],
            menus: [],
            defaultProps: {
     
              children: 'children',
              label: 'name'
            },
          category: {
     
            name: '',
            parentCid: '',
            catLevel: '',
            showStatus: 1,
            sort: 1,
            icon: '',
            productUnit: '',
            catId: ''
          },
          formLabelWidth: '120px'
        }
       },
        // 监听属性 类似于data概念",
      computed: {
     },
        // 监控data中的数据变化",
      watch: {
     },
        // 方法集合",
      methods: {
     
        //修改三级分类数据
        updateCategory(){
     
          console.log("修改当前节点的数据");

          console.log("当前节点的category",this.category);
// 对象发送出去给后端,选择指定的对象的值
          var {
     catId,productUnit,name,icon}=this.category;
          this.$http({
     
            url: this.$http.adornUrl(`/product/category/update`),
            method: 'post',
            data: this.$http.adornData(this.category,false)

            // 服务端传送的数据
          }).then(({
     data}) =>{
     
            this.$message({
     
              type: '数据修改成功',
              message: '修改成功!'
            });
            this.getDataList();
            this.dialogVisible=false;
            // this.expandedKey = [this.category.parentCid]
            console.log("数据修改成功")
          })
        },
        //添加三级分类数据
        addCategory(){
     
          console.log("增加三级分类数据");

          console.log("提交三级分类数据",this.category);
          this.$http({
     

            url: this.$http.adornUrl('/product/category/save'),
            method: 'post',
            data: this.$http.adornData(this.category,false)
            // ,this.category.parentCid,this.category.catLevel,this.category.icon,this.category.productUnit,this.category.sort,this.category.showStatus
          }).then( ({
     data}) => {
     
            this.$message({
     
              type: '数据增加成功',
              message: '增加成功!'
            });
            this.getDataList();
            this.dialogVisible=false;
            // this.expandedKey = [this.category.parentCid]
            console.log("数据增加成功")
          })
        },
        // 修改按钮
        alter(data){
     
          console.log("修改按钮");
          this.dialogVisible= true;
          this.flag=1;
           this.titlevalue="修改商品数据";
          // console.log("当前节点的数据",data)
          this.$http({
     
            url: this.$http.adornUrl(`/product/category/info/${
     data.catId}`),
            method: 'get'
            // 服务端传送的数据
          }).then(({
     data})=>{
     
            console.log("查询当前节点后的节信息",data)
            this.category.productUnit=data.category.productUnit;
            this.category.icon=data.category.icon;
            this.category.name=data.category.name;
            this.category.catId=data.category.catId;
            this.category.catLevel=data.category.catLevel;
            this.category.showStatus=data.category.showStatus;
            this.category.sort=data.category.sort;
            this.category.productCount=data.category.productCount;
            console.log("发送查询请求后,赋值给category的数据展示",this.category)
          })
        },
        //增加按钮
        append(data) {
     
          console.log("增加按钮")

          this.dialogVisible= true;
          this.flag=0;
           this.titlevalue="增加商品";
          // console.log(data);
          this.category.parentCid=data.catId;
          // 防止变成字符串,所以乘1+1
          this.category.catLevel=data.catLevel*1+1;
          // console.log(this.category.parentCid);
          // console.log(this.category.catLevel);

        },

        //删除按钮
        remove(node, data) {
     
          console.log("删除按钮");

          console.log(node,data);
          // 获取数据列表
          var ids=[data.catId]
          // console.log(data.name)
          // eslint-disable-next-line no-template-curly-in-string
          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({
     
                type: '菜单删除成功',
                message: '删除成功!'
              });
               this.getDataList();
              this.expandedKey = [node.parent.data.catId]
              console.log('删除成功')

            })


          }).catch(() => {
     
            this.$message({
     
              type: 'info',
              message: '已取消删除'
            });
          });


        },
        // 获取数据列表
        getDataList () {
     
          this.$http({
     
            url: this.$http.adornUrl('/product/category/list/tree'),
            method: 'get'

          }).then( ({
     data}) => {
     
            console.log("成功获取到菜单数据:",data.data)
            this.menus=data.data;
            // console.log(this.menus)

          })
        }
      },
        // 生命周期 - 创建之前",数据模型未加载,方法未加载,html模板未加载
      beforeCreate () {
     

      },

        // 生命周期 - 创建完成(可以访问当前this实例)",数据模型已加载,方法已加载,html模板已加载,html模板未渲染
      created () {
     
// 
        this.getDataList();
      },
    }
    </script>

完成之后的效果就和前端页面效果演示的一样

10:修改-拖拽效果

实现:完成拖拽功能
电商项目——商品服务-API-三级分类——第九章——上篇_第41张图片
在这里插入图片描述

  • 思路
    核心点:无论拖动任何节点,这个节点的最终总层数不可以大于3

  • 我们先去elementui中查找有关拖拽的文档资料如下,我们使用它来判断是否可以被拖拽放到指定位置,就可以编写
    :allow-drop=“allowDrop”

allow-drop	拖拽时判定目标节点能否被放置。type 参数有三种情况:'prev'、'inner' 和 'next',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后	Function(draggingNode, dropNode, type)
  • 我们进行编写allowDrop方法,我们根据核心点的内容,我们要先计算出正在拖拽节点的最大级别,然后减去正在拖拽节点的层级加1就是正在拖拽节点的深度。
  • 然后我们写一个判断语句,来判断如果正在拖拽节点的深度加上放到被放入节点的位置的层级小等于三,则就可以放入(这个说的是拖到里面的情况),如果拖到的是前后左右,就是正在拖拽节点的深度加上所在位置节点的父节点深度小等于三,则就可以放入(这个说的是拖到左右的情况)
    allowDrop方法代码演示
//拖拽方法
        allowDrop(draggingNode, dropNode, type){
          //1:被拖拽节点以及所在节点的父节点总层数不大于3
          console.log("要拖拽的节点",draggingNode,dropNode,type);
          this.countLevel(draggingNode.data)
          //1:当前正在拖动的节点+父节点所在深度不大于3即可
         let deep =this.maxLevel - draggingNode.level + 1
          console.log("深度:"+deep)
          if (type=="inner"){
            //返回true,可以拖动
            console.log("inner:"+(deep+dropNode.level))
            return (deep+dropNode.level)<=3;
          }else {
            // console.log("dropNode.parent.level:"+dropNode.parent.level)

            console.log("非inner:"+(deep+dropNode.parent.level))

            return (deep+dropNode.parent.level)<=3;
          }
          return ;
        },
        countLevel(node){
          //找到所有子节点并求出最大深度
          console.log("要脱拽当前节点的子节点",node);

          if (node.children!=null && node.children.length >0){
            for (let i=0;i this.maxLevel){

                this.maxLevel=node.children[i].catLevel;
              }
              this.countLevel(node.children[i]);

            }
          }

        }

11:修改-拖拽数据收集

未完成:
实现:当我们完成拖拽的时候就应该把数据的最新信息发送到数据库进行保存,这些信息就包含最新的父节点id,排序,最新该节点的层级
在这里插入图片描述
思路:

  • 我们要先监听拖拽这个事件,当拖拽成功后,我们就要讲所有的数据保存到数据库中,我们先去官网找一下那个事件是可以实现上面方法的,找到如下
node-drop	拖拽成功完成时触发的事件	共四个参数,依次为:被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置(before、after、inner)、event

12:修改-拖拽功能完成

未完成

13:修改-批量拖拽效果

实现:我们需要拖动的时候,我们在拖动它,不需要就禁止它
未完成

14: 修改-批量删除

实现:我们要完成如下功能,点击一些数据,我们点击批量删除即可,全部删除(逻辑删除)
电商项目——商品服务-API-三级分类——第九章——上篇_第42张图片

电商项目——商品服务-API-三级分类——第九章——上篇_第43张图片
电商项目——商品服务-API-三级分类——第九章——上篇_第44张图片
思路:去Elimentui,Tree树形控件中寻找有关可选节点被选择,就可以返回目前被选中的节点所组成的数组的有关信息,果然找到了如下
电商项目——商品服务-API-三级分类——第九章——上篇_第45张图片
那要怎么用呢?我们在Elimentui中继续找有关用法,发现节点过滤有它的用法
电商项目——商品服务-API-三级分类——第九章——上篇_第46张图片

  • 我们先编写一个批量删除的按钮,在里写一个监听事件如下
 this.$refs.tree.getCheckedNodes()
  this.$refs指定是当前vue实例里的所有组件(el-button,el-dialog,el-form),
  我们拿到哪个组件呢?我们在tree组件里写一个ref="tree",拿到this.$refs.tree的组件

      批量删除
    

监听事件代码如下

 //批量删除,拖拽的数据
        batchDelete(){
          let catIds=[];
        
          let checkNodes=this.$refs.tree.getCheckedNodes();
          console.log("被选中的元素",checkNodes);

          for (let i=0;i{
            this.$http({
              url: this.$http.adornUrl(`/product/category/delete`),
              method: 'post',
              data: this.$http.adornData(catIds,false)

              // 服务端传送的数据
            }).then(({data}) =>{
              this.$message({
                type: '批量删除数据成功',
                message: '批量删除数据成功!'
              });
              this.getDataList();
              console.log("批量删除数据成功")
            })
          })

要想让上面配置生效,我们还得在树形控件中,加入如下代码


完成操作,即可成功演示上面代码

15:小结

使用人人开源管理后台系统来体会前后端分离技术

你可能感兴趣的:(电商项目)