【大型电商项目开发】商品服务之三级分类修改功能-15

一:基本效果完成

1.添加修改按钮

<el-button type="text" size="mini" @click="edit(data)">Update</el-button>

2.编写edit点击事件

在data中添加标题和页面属性

      //dialog的标题
      title:"",
      //当前dialog是新增还是编辑,add新增,edit编辑
      dialogType:"",
edit(data){
      this.title = "修改分类"; 
      //编辑赋值为edit
      this.dialogType = "edit";
       //点击update,打开模态框
      this.dialogVisible = true;
      //将当前更新节点的name赋值给模态框
      this.category.name = data.name;
      //通过id更新菜单
      this.category.catId = data.catId;
    },

1)this.title = “修改分类”; 是为了区分append和edit时,模态框的标题。
2)**this.dialogType = “edit”;**点击编辑时,为dialog赋值为edit
3)this.title = “添加分类”; 在新增方法添加
4)在点击模态框提交按钮时,我们要区分是新增还是编辑,通过页面状态区分。

   /**
     * 提交表单数据
     */
    submitData(){
       if(this.dialogType == "add"){
           this.addCategory();
       } else if (this.dialogType == "edit"){
           this.editCategory();
       }
    },

5)为category对象添加图标和计量单位属性

  //和form表单做数据绑定
      category:{
        catId:null,//菜单Id
        name: "",//当前菜单名称
        parentCid: 0,//父Id
        catLevel: 0,//当前菜单层级
        showStatus:1,//当前菜单默认显示
        sort:0,//菜单排序
        productUnit:"",//计量单位
        icon:"",//图标
      },

6)在el-dialog中添加图标和单位input框

    <el-form :model="category">
        <el-form-item label="图标" >
          <el-input v-model="category.icon" autocomplete="off">     </el-input>
        </el-form-item>
      </el-form>
      <el-form :model="category">
        <el-form-item label="计量单位" >
          <el-input v-model="category.productUnit" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>

3.调整edit方法

1)修改时为了获取到最新的菜单名称,我们需要从数据库获取到最新的菜单名称,所以不能用this.category.name = data.name;去获取。而是要调用后台的info/{catId}接口去获取。

/**
     * 打开编辑模态框
     */
    edit(data) {
      this.title = "修改分类";
      //编辑赋值为edit
      this.dialogType = "edit";
      //点击update,打开模态框
      this.dialogVisible = true;
      //发送请求获取节点最新数据
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
      }).then(({ data }) => {
         //请求成功
        //将当前更新节点的name赋值给模态框
        this.category.name = data.data.name;
        //通过id更新菜单
        this.category.catId = data.data.catId;
        //获取到图标
        this.category.icon = data.data.icon;
        //获取到单位
        this.category.productUnit = data.data.productUnit;
        //获取父类菜单Id
        this.category.parentCid = data.data.parentCid;
        //获取菜单层级
        this.category.catLevel = data.data.catLevel;
        //获取菜单默认显示
        this.category.showStatus = data.data.showStatus;
        //获取菜单顺序
        this.category.sort = data.data.sort;
      });
    },

2)url的写法为差值表达式,用``符号放url,${}绑定参数

`/product/category/info/${data.catId}`

3)后台接口统一返回data

    /**
     * 信息
     */
    @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);
    }

4)新增的时候为category对象重新赋值,防止新增时,模态框还有数值

/**
     * 添加节点
     */
    append(data) {
      this.title = "添加分类";
      //新增赋值为add
      this.dialogType = "add";
      //点击append,打开模态框
      this.dialogVisible = true;
      //当前节点的ID就是新增菜单的父类id
      this.category.parentCid = data.catId;
      //将当前选中菜单的层级加上一,就是子菜单的等级,为了防止是字符串,所以获取到以后先乘1,再加一
      this.category.catLevel = data.catLevel * 1 + 1;
      //对catId赋值为null
      this.category.catId = null;
      //姓名为空串
      this.category.name = "";
      //图标为空串
      this.category.icon = "";
      //单位为空串
      this.category.productUnit = "";
      //排序默认为0
      this.category.sort = 0;
      //是否显示(0-不显示,1-显示)
      this.category.showStatus = 1;
    },

二:拖拽效果完成

1.使用draggable开启拖拽功能

在el-tree组件中添加draggable属性

      <el-tree
      :data="menus"
      :props="defaultProps"
      :expand-on-click-node="false"
      :default-expanded-keys="expandedKey"
      show-checkbox
      node-key="catId"
      draggable></el-tree>

在这里插入图片描述

2.判断组件是否可以被拖拽allow-drag/allow-drop

在这里插入图片描述
1)在el-tree标签中添加:allow-drop="allowDrop"
2)在method方法中添加allowDrop方法

   /**
     * 拖拽时判定目标节点能否被放置
     */
    allowDrop(draggingNode, dropNode, type) {
      return false;
    },

注:此时代表菜单不能进行任何拖拽
3)判断被拖动的当前节点以及所在的父节点,总层数不能大于三

    /**
     * 拖拽时判定目标节点能否被放置
     */
    allowDrop(draggingNode, dropNode, type) {
      //1.判断被拖动的当前节点以及所在的父节点,总层数不能大于三
      /**
       * 1)被拖动当前节点的总层数
       * draggingNode-当前节点
       * dropNode-那个节点的这些位置
       * type-放到了那个位置
       */
      //统计当前节点的总层数
      this.countNodeLevel(draggingNode.data);
      //当前正在拖动的节点 + 父节点所在的深度不大于3就行
      //deep为当前节点深度
      let deep = (this.maxLevel - draggingNode.data.catLevel) + 1;
      if(type == "innner"){
         return (deep + dropNode.level) <= 3;
      } else {
         return (deep + dropNode.parent.level) <= 3;
      }
    },
    /**
     * 统计当前节点的总层数
     */
    countNodeLevel(node){
      //找到节点的最大深度
      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]);
          }
      }
    },
  • 使用递归判断当前选中节点底下是否有子节点
  • 当前节点的深度deep等于其子节点的最大层级 - 当前节点的层级 + 1

三:拖拽成功后的事件

1.添加拖拽成功后的事件函数

注:拖拽事件作用,将拖拽后的
1)在el-tree标签中添加@node-drop="handleDrop"
2)声明回调函数方法

      handleDrop(draggingNode, dropNode, dropType, ev) {
        console.log('tree drop: ', dropNode.label, dropType);
      },
  • draggingNode-当前正在拖拽的节点
  • dropNode-进入到了那个节点
  • dropType-进入的方式

2.获取当前节点最新的父节点Id

      //1.获取当前节点最新的父节点Id
      let pCid = 0;
      if(dropType == "before" || dropType == "after"){
        //如果是before或者after,则取兄弟Id的父类id
        pCid = dropNode.parent.data.catId; 
      } else {
        //如果是inner,则直接取进入节点的Id作为父id
        pCid = dropNode.data.catId;
      }

3.获取当前拖拽节点的最新顺序

   /**
     * 拖拽成功后,触发的事件
     */
    handleDrop(draggingNode, dropNode, dropType, ev) {
      console.log("tree drop: ", dropNode.label, dropType);
      //draggingNode-当前正在拖拽的节点
      //dropNode-进入到了那个节点
      //dropType-进入的方式
      /**
       * 1.获取当前节点最新的父节点Id
       * 2.获取当前拖拽节点的最新顺序
       * 3.获取当前拖拽节点的最新层级
       */
      let pCid = 0;
      //所有的子节点
      let siblings = null;
      if (dropType == "before" || dropType == "after") {
        //如果是before或者after,则取兄弟Id的父类id
        pCid = dropNode.parent.data.catId == undefined ? 0 : dropNode.parent.data.catId;
        //如果是before或者after,则取兄弟Id的父类的所有子节点重新排序
        siblings = dropNode.parent.childNodes;
      } else {
        //如果是inner,则直接取进入节点的Id作为父id
        pCid = dropNode.data.catId;
        //如果是inner,直接遍历进入节点的子节点重新排序
        siblings = dropNode.childNodes;
      }
      //2.获取当前拖拽节点的最新顺序--并且重新排序
      //使用对象的属性catID进行重新排序
      for (let i = 0; i < siblings.length; i++) {
        if (siblings[i].data.catId == dropNode.data.catId) {
          //如果遍历的是当前正在拖拽的节点
          this.updateNodes.push({ catId: siblings[i].data.catId, sort: i , parentCid : pCid});
        } else {
          this.updateNodes.push({ catId: siblings[i].data.catId, sort: i });
        }
      }
      //3.获取当前拖拽节点的最新层级
    },
  },

4.获取当前拖拽节点的最新层级

/**
     * 拖拽成功后,触发的事件
     */
    handleDrop(draggingNode, dropNode, dropType, ev) {
      console.log("tree drop: ", dropNode.label, dropType);
      //draggingNode-当前正在拖拽的节点
      //dropNode-进入到了那个节点
      //dropType-进入的方式
      /**
       * 1.获取当前节点最新的父节点Id
       * 2.获取当前拖拽节点的最新顺序
       * 3.获取当前拖拽节点的最新层级
       */
      let pCid = 0;
      //所有的子节点
      let siblings = null;
      if (dropType == "before" || dropType == "after") {
        //如果是before或者after,则取兄弟Id的父类id
        pCid =
          dropNode.parent.data.catId == undefined
            ? 0
            : dropNode.parent.data.catId;
        //如果是before或者after,则取兄弟Id的父类的所有子节点重新排序
        siblings = dropNode.parent.childNodes;
      } else {
        //如果是inner,则直接取进入节点的Id作为父id
        pCid = dropNode.data.catId;
        //如果是inner,直接遍历进入节点的子节点重新排序
        siblings = dropNode.childNodes;
      }
      //2.获取当前拖拽节点的最新顺序--并且重新排序
      //使用对象的属性catID进行重新排序
      for (let i = 0; i < siblings.length; i++) {
        if (siblings[i].data.catId == dropNode.data.catId) {
          //如果遍历的是当前正在拖拽的节点
          let catLevel = draggingNode.level; //当前节点的默认层级
          if (siblings[i].level != draggingNode.level) {
            //如果拖拽前后层级不一样,则说明层级发生了变化
            catLevel = siblings[i].level;
            /**
             * 修改字节点的层级--递归修改
             * siblings[i]-修改这个对象下所有字节点的层级
             */
            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 });
        }
      }
      //3.获取当前拖拽节点的最新层级
    },
    /**
     * 修改字节点的层级
     * node-需要修改哪个子节点的层级
     */
    updateChildNodeLevel(node) {
      if (node.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.updateNodes(node.childNodes[i]);
        }
      }
    },
  },

注:此处逻辑较为复杂,建议多在开发者模式多调试

四:后台接口功能实现

1.编辑CategoryController,添加批量修改方法

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

1)传入category对象数组,通过updateBatchById批量修改
2)使用Arrays.asList将数据转化为集合

2.前台发送请求给后台

/**
     * 拖拽成功后,触发的事件
     */
    handleDrop(draggingNode, dropNode, dropType, ev) {
      //draggingNode-当前正在拖拽的节点
      //dropNode-进入到了那个节点
      //dropType-进入的方式
      /**
       * 1.获取当前节点最新的父节点Id
       * 2.获取当前拖拽节点的最新顺序
       * 3.获取当前拖拽节点的最新层级
       */
      let pCid = 0;
      //所有的子节点
      let siblings = null;
      if (dropType == "before" || dropType == "after") {
        //如果是before或者after,则取兄弟Id的父类id
        pCid =
          dropNode.parent.data.catId == undefined
            ? 0
            : dropNode.parent.data.catId;
        //如果是before或者after,则取兄弟Id的父类的所有子节点重新排序
        siblings = dropNode.parent.childNodes;
      } else {
        //如果是inner,则直接取进入节点的Id作为父id
        pCid = dropNode.data.catId;
        //如果是inner,直接遍历进入节点的子节点重新排序
        siblings = dropNode.childNodes;
      }
      //2.获取当前拖拽节点的最新顺序--并且重新排序
      //使用对象的属性catID进行重新排序
      for (let i = 0; i < siblings.length; i++) {
        if (siblings[i].data.catId == dropNode.data.catId) {
          //如果遍历的是当前正在拖拽的节点
          let catLevel = draggingNode.level; //当前节点的默认层级
          if (siblings[i].level != draggingNode.level) {
            //如果拖拽前后层级不一样,则说明层级发生了变化
            catLevel = siblings[i].level;
            /**
             * 修改字节点的层级--递归修改
             * siblings[i]-修改这个对象下所有字节点的层级
             */
            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 });
        }
      }
      //3.获取当前拖拽节点的最新层级
      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.expandedKey = [pCid];
        this.updateNodes = [];
        this.maxLevel = 0;
      });
    },

在这里插入图片描述

3.优化handleDrop方法

1)更新成功后将updateNodes和maxLevel设置为初始状态

this.updateNodes = [];
this.maxLevel = 0;

五:优化拖拽页面

1.设定一个拖拽功能开启和关闭功能,防误触

<el-switch v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽">
    </el-switch>

1)v-model="draggable"的draggable属性动态设置拖拽功能是否开启
2)在el-tree标签中为draggable属性设置为绑定事件
3)在data中设置draggable属性默认为false

2.设定修改后批量提交修改顺序功能,防止频繁访问数据库

1)添加批量保存按钮

<el-button @click="batchSave">批量保存</el-button>

2)完善batchSave方法
注:将handleDrop方法中的http请求复制到batchSave中

   /**
     * 批量保存方法
     */
    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.expandedKey = [pCid];
        this.updateNodes = [];
        this.maxLevel = 0;
      });
    },

3)当拖拽功能开启的时候才让批量保存按钮显示出来

<el-button v-if="draggable" @click="batchSave">批量保存</el-button>

4)在data中定义全局pCid属性
5)还有一些优化,过于繁琐,就不一一列举了,看代码吧!!!

<template>
  <div>
    <el-switch
      v-model="draggable"
      active-text="开启拖拽"
      inactive-text="关闭拖拽"
    >
    </el-switch>
    <el-button v-if="draggable" @click="batchSave">批量保存</el-button>
    <el-tree
      :data="menus"
      :props="defaultProps"
      :expand-on-click-node="false"
      :default-expanded-keys="expandedKey"
      show-checkbox
      node-key="catId"
      :draggable="draggable"
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
    >
      <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="node.level <= 2"
            >Append</el-button
          >
          <el-button
            type="text"
            size="mini"
            @click="() => remove(node, data)"
            v-if="node.childNodes.length == 0"
            >Delete</el-button
          >
          <el-button type="text" size="mini" @click="edit(data)"
            >Update</el-button
          >
        </span>
      </span>
    </el-tree>
    <el-dialog :title="title" :visible.sync="dialogVisible" width="30%">
      <el-form :model="category">
        <el-form-item label="分类名称">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <el-form :model="category">
        <el-form-item label="图标">
          <el-input v-model="category.icon" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <el-form :model="category">
        <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>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    return {
      pCid:[],
      //是否开启拖拽功能
      draggable: false,
      //拖拽后所有需要修改的节点
      updateNodes: [],
      //最大层级
      maxLevel: 0,
      //dialog的标题
      title: "",
      //当前dialog是新增还是编辑,add新增,edit编辑
      dialogType: "",
      //和form表单做数据绑定
      category: {
        catId: null, //菜单Id
        name: "", //当前菜单名称
        parentCid: 0, //父Id
        catLevel: 0, //当前菜单层级
        showStatus: 1, //当前菜单默认显示
        sort: 0, //菜单排序
        productUnit: "", //计量单位
        icon: "", //图标
      },
      //三级菜单数据
      menus: [],
      //默认展开的数组
      expandedKey: [],
      //是否显示新增模态框,默认是false
      dialogVisible: false,
      //三级菜单展开时的属性
      defaultProps: {
        children: "children",
        label: "name",
      },
    };
  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    /**
     * 获取三级菜单数据
     */
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        console.log("成功获取到菜单数据...", data.data);
        this.menus = data.data;
      });
    },
    /**
     * 添加节点
     */
    append(data) {
      this.title = "添加分类";
      //新增赋值为add
      this.dialogType = "add";
      //点击append,打开模态框
      this.dialogVisible = true;
      //当前节点的ID就是新增菜单的父类id
      this.category.parentCid = data.catId;
      //将当前选中菜单的层级加上一,就是子菜单的等级,为了防止是字符串,所以获取到以后先乘1,再加一
      this.category.catLevel = data.catLevel * 1 + 1;
      //对catId赋值为null
      this.category.catId = null;
      //姓名为空串
      this.category.name = "";
      //图标为空串
      this.category.icon = "";
      //单位为空串
      this.category.productUnit = "";
      //排序默认为0
      this.category.sort = 0;
      //是否显示(0-不显示,1-显示)
      this.category.showStatus = 1;
    },
    /**
     * 新增模态框,确定按钮点击事件
     */
    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",
        });
        //关闭当前dialog模态框
        this.dialogVisible = false;
        //刷新页面
        this.getMenus();
        //设置出需要默认展开的菜单
        this.expandedKey = [this.category.parentCid];
      });
    },
    /**
     * 打开编辑模态框
     */
    edit(data) {
      this.title = "修改分类";
      //编辑赋值为edit
      this.dialogType = "edit";
      //点击update,打开模态框
      this.dialogVisible = true;
      //发送请求获取节点最新数据
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
      }).then(({ data }) => {
        //请求成功
        //将当前更新节点的name赋值给模态框
        this.category.name = data.data.name;
        //通过id更新菜单
        this.category.catId = data.data.catId;
        //获取到图标
        this.category.icon = data.data.icon;
        //获取到单位
        this.category.productUnit = data.data.productUnit;
        //获取父类菜单Id
        this.category.parentCid = data.data.parentCid;
        //获取菜单层级
        this.category.catLevel = data.data.catLevel;
        //获取菜单默认显示
        this.category.showStatus = data.data.showStatus;
        //获取菜单顺序
        this.category.sort = data.data.sort;
      });
    },
    /**
     * 提交表单数据
     */
    submitData() {
      if (this.dialogType == "add") {
        this.addCategory();
      } else if (this.dialogType == "edit") {
        this.editCategory();
      }
    },
    /**
     * 修改方法,确定按钮点击事件
     */
    editCategory() {
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData(this.category, false),
      }).then(({ data }) => {
        this.$message({
          message: "菜单修改成功",
          type: "success",
        });
        //关闭当前dialog模态框
        this.dialogVisible = false;
        //刷新页面
        this.getMenus();
        //设置出需要默认展开的菜单
        this.expandedKey = [this.category.parentCid];
      });
    },
    /**
     * 移除节点
     */
    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.expandedKey = [node.parent.data.catId];
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除",
          });
        });
    },
    /**
     * 拖拽时判定目标节点能否被放置
     */
    allowDrop(draggingNode, dropNode, type) {
      //1.判断被拖动的当前节点以及所在的父节点,总层数不能大于三
      /**
       * 1)被拖动当前节点的总层数
       * draggingNode-当前节点
       * dropNode-那个节点的这些位置
       * type-放到了那个位置
       */
      //统计当前节点的总层数
      this.countNodeLevel(draggingNode);
      //当前正在拖动的节点 + 父节点所在的深度不大于3就行
      //deep为当前节点深度
      let deep = Math.abs(this.maxLevel - draggingNode.catLevel) + 1;
      if (type == "innner") {
        return deep + dropNode.level <= 3;
      } else {
        return deep + dropNode.parent.level <= 3;
      }
    },
    /**
     * 统计当前节点的总层数
     */
    countNodeLevel(node) {
      //找到节点的最大深度
      if (node.childNodes != null && node.childNodes.length > 0) {
        for (let i = 0; i < node.children.length; i++) {
          if (node.childNodes[i].level > this.maxLevel) {
            this.maxLevel = node.childNodes[i].level;
          }
          this.countNodeLevel(node.childNodes[i]);
        }else {
          this.maxLevel = node.level;
      }
      }
    },
    /**
     * 拖拽成功后,触发的事件
     */
    handleDrop(draggingNode, dropNode, dropType, ev) {
      //draggingNode-当前正在拖拽的节点
      //dropNode-进入到了那个节点
      //dropType-进入的方式
      /**
       * 1.获取当前节点最新的父节点Id
       * 2.获取当前拖拽节点的最新顺序
       * 3.获取当前拖拽节点的最新层级
       */
      let pCid = 0;
      //所有的子节点
      let siblings = null;
      if (dropType == "before" || dropType == "after") {
        //如果是before或者after,则取兄弟Id的父类id
        pCid =
          dropNode.parent.data.catId == undefined
            ? 0
            : dropNode.parent.data.catId;
        //如果是before或者after,则取兄弟Id的父类的所有子节点重新排序
        siblings = dropNode.parent.childNodes;
      } else {
        //如果是inner,则直接取进入节点的Id作为父id
        pCid = dropNode.data.catId;
        //如果是inner,直接遍历进入节点的子节点重新排序
        siblings = dropNode.childNodes;
      }
      this.pCid.push(pCid);
      //2.获取当前拖拽节点的最新顺序--并且重新排序
      //使用对象的属性catID进行重新排序
      for (let i = 0; i < siblings.length; i++) {
        if (siblings[i].data.catId == dropNode.data.catId) {
          //如果遍历的是当前正在拖拽的节点
          let catLevel = draggingNode.level; //当前节点的默认层级
          if (siblings[i].level != draggingNode.level) {
            //如果拖拽前后层级不一样,则说明层级发生了变化
            catLevel = siblings[i].level;
            /**
             * 修改字节点的层级--递归修改
             * siblings[i]-修改这个对象下所有字节点的层级
             */
            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 });
        }
      }
    },
    /**
     * 修改字节点的层级
     * node-需要修改哪个子节点的层级
     */
    updateChildNodeLevel(node) {
      if (node.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.updateNodes(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.expandedKey = this.pCid;
        this.updateNodes = [];
        this.maxLevel = 0;
        //this.pCid = 0;
      });
    },
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    /**
     * 加载页面的时候查询三级菜单
     */
    this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java电商项目中,商品服务三级分类删除代码实现可以参考以下步骤: 1. 首先需要在数据库中删除该三级分类的记录,可以通过以下SQL语句实现: ``` DELETE FROM category WHERE id = #{id} AND level = 3; ``` 其中,`id`表示三级分类的ID,`level`表示分类级别。 2. 在商品服务的实现类中添加删除三级分类的方法,调用以上SQL语句实现删除操作。例如: ```java public class CategoryServiceImpl implements CategoryService { @Autowired private CategoryMapper categoryMapper; @Override public int deleteCategory(Long id) { Category category = categoryMapper.selectByPrimaryKey(id); if (category == null || category.getLevel() != 3) { return 0; } return categoryMapper.deleteByPrimaryKey(id); } //... } ``` 其中,`categoryMapper`为MyBatis的Mapper接口,`selectByPrimaryKey()`方法用于根据ID查询分类信息,`deleteByPrimaryKey()`方法用于根据ID删除分类记录。在删除操作之前,需要判断分类是否存在且为三级分类。 3. 在Controller中添加删除三级分类的接口,例如: ```java @RestController @RequestMapping("/category") public class CategoryController { @Autowired private CategoryService categoryService; //... @DeleteMapping("/{id}") public Result deleteCategory(@PathVariable Long id) { int count = categoryService.deleteCategory(id); if (count == 0) { return Result.failure("删除失败"); } return Result.success(); } } ``` 其中,`@DeleteMapping("/{id}")`表示接收DELETE请求,并且URL中的`{id}`参数为要删除的分类ID。`deleteCategory()`方法调用商品服务中的删除三级分类的方法,并返回操作结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随意石光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值