商品服务 - 三级分类

news2024/12/26 21:59:47

1.递归查询树形结构

 @Override
    public List<CategoryEntity> listWithTree() {
        //1.查出所有分类

        List<CategoryEntity> all = this.list();
        //2.组装成父子的属性结构
        List<CategoryEntity> level1Menus = all
                .stream()
                .filter(c -> c.getParentCid().equals(0L))
                .map(categoryEntity -> categoryEntity.setChildren(getChildrenCategory(all,categoryEntity.getCatId())))
                //大于放后面 升序
                .sorted(Comparator.comparing(CategoryEntity::getSort))
                .collect(Collectors.toList());

        return level1Menus;
    }

    private List<CategoryEntity> getChildrenCategory(List<CategoryEntity> allList, long pCatId) {
        List<CategoryEntity> collect = allList.stream()
                .filter(a -> a.getParentCid() == pCatId)
                .sorted(Comparator.comparing(CategoryEntity::getSort))
                .collect(Collectors.toList());
        if (collect.isEmpty()) {
            return new ArrayList<>();
        } else {
            for (CategoryEntity categoryEntity : collect) {
                Long catId = categoryEntity.getCatId();
                List<CategoryEntity> childrenCategory = getChildrenCategory(allList, catId);
                categoryEntity.setChildren(childrenCategory);
            }
            return collect;
        }
    }

2.网关统一配置跨域问题

 

2.1添加 网关过滤器

package com.jmj.gulimall.gateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.reactive.CorsWebFilter;


@Configuration
public class GulimallCorsConfiguration {

    //网关gateway是使用webflex 进行编程的 响应式 所以用的都是reactive 包下
    @Bean
    public CorsWebFilter corsWebFilter() {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //1.配置跨域
        corsConfiguration.addAllowedHeader("*");//允许哪些头跨域
        corsConfiguration.addAllowedMethod("*");//允许哪些请求跨域
        corsConfiguration.addAllowedOrigin("*");//允许哪些请求来源 跨域
        corsConfiguration.setAllowCredentials(true);//是否允许携带cookie进行跨域 允许 否则跨域请求将会丢失一些相关cookie信息

        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);

    }


}

 但是我们发现还是出现了问题

这是因为网关配置了跨域,而网关转发的微服务也配置了跨域,所以返回了两个响应头被允许,

但是浏览器只希望有一个,所以报错,这时,我们只需要去把微服务的跨域注释掉就好了。 

这是人人fast 服务的跨域配置,也是Spring MVC的 配置

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 * <p>
 * https://www.renren.io
 * <p>
 * 版权所有,侵权必究!
 */

package io.renren.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .maxAge(3600);
    }
}

 

这是网关的路由,是有优先级的,从上优先级最高,如果匹配不上就会依次遍历。

如果不调换优先级,路径会被网关转发到 renrenfast 服务当中,导致没有token 返回invalid token  

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://www.baidu.com
          predicates:
            #访问的路径就是 如果是/hello?url=baidu  就转发到 https://www.baidu.com/hello?url=baidu
            - Query=url,baidu
        - id: test1_route
          uri: http://www.hao123.com
          predicates:
            - Query=url,hao123
        - id: product_rout
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}


##前端项目,/api

3.拖拽修改前端代码

<!--  -->
<template>
  <div>
    <el-switch v-model="isDraggable" active-text="开启拖拽" inactive-text="关闭拖拽">
    </el-switch>
    <el-tree
      :data="menus"
      :props="defaultProps"
      show-checkbox
      node-key="catId"
      :expand-on-click-node="false"
      :default-expanded-keys="expandedkey"
      @node-expand="expend"
      @node-collapse="nodeClose"
      :draggable="isDraggable"
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
    >
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <!-- 插槽,代替了原来的 label  里所显示的内容  将插槽内容显示在原来的每个结点上面  -->
        <span>{{ node.label }}</span>
        <span>
          <el-button
            v-if="node.level <= 2"
            type="text"
            size="mini"
            @click="() => append(data)"
          >
            Append
          </el-button>
          <el-button type="text" size="mini" @click="edit(data)">
            Edit
          </el-button>

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

    <el-dialog
      :title="submitTitle"
      :visible.sync="dialogVisible"
      :close-on-click-modal="false"
      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-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>
      <div slot="footer" class="dialog-footer">
        <el-button @click="cancelForm">取 消</el-button>
        <el-button type="primary" @click="submitForm">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
class UpdateCategoryData {
  constructor(catId, parentCid, sort, catLevel) {
    this.catId = catId;
    this.parentCid = parentCid;
    this.sort = sort;
    this.catLevel = catLevel;
  }
}
export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    return {
      isDraggable: false,
      submitType: "",
      submitTitle: "",
      dialogVisible: false,
      menus: [],
      defaultProps: {
        children: "children",
        label: "name",
      },
      expandedkey: [],
      copyCategory: {},
      category: {
        catId: null,
        name: "",
        parentCid: 0,
        catLevel: 0,
        showStatus: 1,
        productUnit: "",
        icon: "",
        sort: 0,
      },
    };
  },
  //监听属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    /**
     *
     * @param {*} draggingNode 拖拽的节点
     * @param {*} dropNode  拖拽到的哪个节点
     * @param {*} dropType 拖拽类型, 前后或者 内部
     * @param {*} event  事件对象
     */
    handleDrop(draggingNode, dropNode, dropType, event) {
      console.log(draggingNode, dropNode, dropType);

      //1.当前节点最新的父节点Id,
      let updateArray = new Array();

      let draggingNodeLevel = draggingNode.level;
      if (dropType == "inner") {
        let dropNodeId = dropNode.data.catId;
        let dropNodeLevel = dropNode.level;
        let childrenNew = dropNode.data.children;
        for (const index in childrenNew) {
          let { catId } = childrenNew[index];
          let updateCategoryData = new UpdateCategoryData(
            catId,
            dropNodeId,
            index,
            dropNodeLevel + 1
          );
          updateArray.push(updateCategoryData);
        }

        let div = dropNodeLevel + 1 - draggingNodeLevel;
        //递归把子节点都遍历完
        if (div != 0) {
          this.recursivelyTraverseChildNodes(
            draggingNode.data.children,
            div,
            updateArray
          );
        }
      } else {
        //往前插入节点或者后插入节点
        let parentLevel = dropNode.parent.level;
        console.log(parentLevel);
        let parentChildrenArr = {};
        if (parentLevel == 0) {
          parentChildrenArr = dropNode.parent.data;
        } else {
          parentChildrenArr = dropNode.parent.data.children;
        }

        let parentCid = dropNode.data.parentCid;
        for (const index in parentChildrenArr) {
          let { catId } = parentChildrenArr[index];
          let updateCategoryData = new UpdateCategoryData(
            catId,
            parentCid,
            index,
            parentLevel + 1
          );
          updateArray.push(updateCategoryData);
        }

        let div = parentLevel + 1 - draggingNodeLevel;
        console.log("parentLevel", parentLevel);
        console.log("draggingNodeLevel", draggingNodeLevel);
        //递归把子节点都遍历完
        if (div != 0) {
          this.recursivelyTraverseChildNodes(
            draggingNode.data.children,
            div,
            updateArray
          );
        }
      }

      console.log(updateArray);
      //发送http请求修改
      this.$http({
        url: this.$http.adornUrl("/product/category/updateList"),
        method: "post",
        data: this.$http.adornData(updateArray, false),
      }).then(({ data }) => {
        this.success("修改位置与排序成功");
        this.getMenus();
      });
    },
    recursivelyTraverseChildNodes(children, div, arr) {
      if (children == null || children.length == 0) {
        //没有子节点了
        return;
      } else {
        for (const child of children) {
          let updateCategoryData = new UpdateCategoryData(
            child.catId,
            child.parentCid,
            child.sort,
            child.catLevel + div
          );
          arr.push(updateCategoryData);
          this.recursivelyTraverseChildNodes(child.children, div, arr);
        }
      }
    },
    allowDrop(draggingNode, dropNode, type) {
      //1、被拖动的当前节点以及所在的父节点总层数不能大于3
      console.log("allowDrop", draggingNode, dropNode, type);
      let level = this.countNodeLevel(
        draggingNode.data,
        draggingNode.data.catLevel
      );
      if (type == "inner") {
        if (dropNode.level + level <= 3) {
          return true;
        } else {
          return false;
        }
      }

      if (type == "next") {
        if (dropNode.parent.level + level <= 3) {
          return true;
        } else {
          return false;
        }
      }

      if (type == "prev") {
        if (dropNode.parent.level + level <= 3) {
          return true;
        } else {
          return false;
        }
      }
      //1)被拖动的当前节点总层数
      return false;
    },
    //递归查找该节点加上子类最深层级一共有几层;包含自己算
    countNodeLevel(node, l) {
      let children = node.children;
      let levelMax = 0;
      if (children.length == 0) {
        return node.catLevel - l + 1;
      } else {
        for (let child of children) {
          let level = this.countNodeLevel(child, l);
          if (level > levelMax) {
            levelMax = level;
          }
        }
      }
      return levelMax;
    },
    resetCategory() {
      Object.assign(this.category, this.copyCategory);
      //如果你希望在 console.log 输出的时候看到对象的当前状态,
      //你可以在赋值操作之前进行 console.log,或者使用对象解构等方法创建一个新的对象进行输出,以确保输出的是当前状态的副本而不是对象的引用。
      let categoryre = {};
      Object.assign(categoryre, this.category);
      console.log("执行了重置", categoryre);
    },
    submitForm() {
      if (this.submitType == "add") {
        this.addCategory();
      }
      if (this.submitType == "edit") {
        this.updateCategory();
      }
    },
    updateCategory() {
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData(this.category, false),
      }).then(({ data }) => {
        this.success("修改成功");
        this.getMenus();
        this.resetCategory();
        this.dialogVisible = false;
      });
    },
    edit(data) {
      this.submitType = "edit";
      this.submitTitle = "修改分类菜单";
      console.log("正在修改数据", data);
      this.dialogVisible = true;

      //发送http请求获取回显数据
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
      }).then(({ data }) => {
        let categoryEdit = data.data;
        console.log("回显数据", categoryEdit);
        this.category.catId = categoryEdit.catId;
        this.category.name = categoryEdit.name;
        this.category.parentCid = categoryEdit.parentCid;
        this.category.catLevel = categoryEdit.catLevel;
        this.category.showStatus = categoryEdit.showStatus;
        this.category.productUnit = categoryEdit.productUnit;
        this.category.icon = categoryEdit.icon;
        this.category.sort = categoryEdit.sort;
        console.log("category被回显数据", this.category);
      });
    },
    cancelForm() {
      this.resetCategory();
      this.dialogVisible = false;
    },
    append(data) {
      this.resetCategory();
      console.log("append", this.category);
      this.category.parentCid = data.catId;
      this.category.catLevel = data.catLevel + 1;
      this.category.showStatus = 1;
      this.category.sort = 0;
      this.dialogVisible = true;
      this.submitType = "add";
      this.submitTitle = "添加分类菜单";
    },
    addCategory() {
      console.log("提交三级分类的数据", this.category);

      this.$http({
        url: this.$http.adornUrl("/product/category/save"),
        method: "post",
        data: this.$http.adornData(this.category, false),
      }).then(({ data }) => {
        this.success("添加分类成功");
        this.getMenus();
      });

      this.resetCategory();
      this.dialogVisible = false;
    },
    remove(node, data) {
      console.log("remove", node, data);
      let ids = [data.catId];
      // console.log(this); //vue
      this.$confirm(`是否删除【${data.name}】菜单`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          // console.log(this); //vue
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(({ data }) => {
            // console.log(this); //vue
            this.$message({
              message: "菜单删除成功",
              type: "success",
            });
            // node.visible = false;
            this.getMenus();
            //设置需要默认展开的菜单
          });
        })
        .catch(() => {
          this.$message({
            message: "取消了删除",
            type: "warning",
          });
        });
    },
    expend(data, node, _) {
      console.log("展开了", node.data.catId);
      this.expandedkey.push(node.data.catId);
    },
    nodeClose(data, node, _) {
      let id = node.data.catId;
      console.log("收起了", id);
      let index = this.expandedkey.indexOf(id);
      this.expandedkey.splice(index, 1);
    },
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        console.log("成功获取到菜单数据:", data.data);
        this.menus = data.data;
      });
    },
    success(msg) {
      this.$message({
        message: msg,
        type: "success",
      });
    },
    error(msg) {
      this.$message({
        message: msg,
        type: "warning",
      });
    },
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getMenus();
    Object.assign(this.copyCategory, this.category);
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style  scoped>
</style>

4.批量删除

封装复用方法 闭包

<!--  -->
<template>
  <div>
    <el-switch
      v-model="isDraggable"
      active-text="开启拖拽"
      inactive-text="关闭拖拽"
    >
    </el-switch>
    <el-button type="danger" round @click="batchDelete">批量删除</el-button>
    <el-tree
      :data="menus"
      :props="defaultProps"
      show-checkbox
      node-key="catId"
      :expand-on-click-node="false"
      :default-expanded-keys="expandedkey"
      @node-expand="expend"
      @node-collapse="nodeClose"
      :draggable="isDraggable"
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
      ref="menuTree"
    >
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <!-- 插槽,代替了原来的 label  里所显示的内容  将插槽内容显示在原来的每个结点上面  -->
        <span>{{ node.label }}</span>
        <span>
          <el-button
            v-if="node.level <= 2"
            type="text"
            size="mini"
            @click="() => append(data)"
          >
            Append
          </el-button>
          <el-button type="text" size="mini" @click="edit(data)">
            Edit
          </el-button>

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

    <el-dialog
      :title="submitTitle"
      :visible.sync="dialogVisible"
      :close-on-click-modal="false"
      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-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>
      <div slot="footer" class="dialog-footer">
        <el-button @click="cancelForm">取 消</el-button>
        <el-button type="primary" @click="submitForm">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
class UpdateCategoryData {
  constructor(catId, parentCid, sort, catLevel) {
    this.catId = catId;
    this.parentCid = parentCid;
    this.sort = sort;
    this.catLevel = catLevel;
  }
}
export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    return {
      isDraggable: false,
      submitType: "",
      submitTitle: "",
      dialogVisible: false,
      menus: [],
      defaultProps: {
        children: "children",
        label: "name",
      },
      expandedkey: [],
      copyCategory: {},
      category: {
        catId: null,
        name: "",
        parentCid: 0,
        catLevel: 0,
        showStatus: 1,
        productUnit: "",
        icon: "",
        sort: 0,
      },
    };
  },
  //监听属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    confirm(msg,success,error){
      this.$confirm(msg, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        success();
      }).catch(()=>{
        error();
      });
    },
    batchDelete() {
      let deleteArray = this.$refs.menuTree.getCheckedNodes();
      console.log("被选中的元素", deleteArray);
      let ids = deleteArray.map((c) => {
        return c.catId;
      });
      console.log("被选中的Id", ids);

      // this.$confirm(`是否批量删除`, "提示", {
      //   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.success("批量删除成功");
        //   this.getMenus();
        // });
      // }).catch((error)=>{
      //   this.error("取消批量删除");
      // });

        this.confirm("是否批量删除",()=>{
          this.$http({
          url: this.$http.adornUrl("/product/category/delete"),
          method: "post",
          data: this.$http.adornData(ids, false),
        }).then(({ data }) => {
          this.success("批量删除成功");
          this.getMenus();
        });
        },()=>{
            this.error("取消批量删除");
        })


    },
    /**
     *
     * @param {*} draggingNode 拖拽的节点
     * @param {*} dropNode  拖拽到的哪个节点
     * @param {*} dropType 拖拽类型, 前后或者 内部
     * @param {*} event  事件对象
     */
    handleDrop(draggingNode, dropNode, dropType, event) {
      console.log(draggingNode, dropNode, dropType);

      //1.当前节点最新的父节点Id,
      let updateArray = new Array();

      let draggingNodeLevel = draggingNode.level;
      if (dropType == "inner") {
        let dropNodeId = dropNode.data.catId;
        let dropNodeLevel = dropNode.level;
        let childrenNew = dropNode.data.children;
        for (const index in childrenNew) {
          let { catId } = childrenNew[index];
          let updateCategoryData = new UpdateCategoryData(
            catId,
            dropNodeId,
            index,
            dropNodeLevel + 1
          );
          updateArray.push(updateCategoryData);
        }

        let div = dropNodeLevel + 1 - draggingNodeLevel;
        //递归把子节点都遍历完
        if (div != 0) {
          this.recursivelyTraverseChildNodes(
            draggingNode.data.children,
            div,
            updateArray
          );
        }
      } else {
        //往前插入节点或者后插入节点
        let parentLevel = dropNode.parent.level;
        console.log(parentLevel);
        let parentChildrenArr = {};
        if (parentLevel == 0) {
          parentChildrenArr = dropNode.parent.data;
        } else {
          parentChildrenArr = dropNode.parent.data.children;
        }

        let parentCid = dropNode.data.parentCid;
        for (const index in parentChildrenArr) {
          let { catId } = parentChildrenArr[index];
          let updateCategoryData = new UpdateCategoryData(
            catId,
            parentCid,
            index,
            parentLevel + 1
          );
          updateArray.push(updateCategoryData);
        }

        let div = parentLevel + 1 - draggingNodeLevel;
        console.log("parentLevel", parentLevel);
        console.log("draggingNodeLevel", draggingNodeLevel);
        //递归把子节点都遍历完
        if (div != 0) {
          this.recursivelyTraverseChildNodes(
            draggingNode.data.children,
            div,
            updateArray
          );
        }
      }

      console.log(updateArray);
      //发送http请求修改
      this.$http({
        url: this.$http.adornUrl("/product/category/updateList"),
        method: "post",
        data: this.$http.adornData(updateArray, false),
      }).then(({ data }) => {
        this.success("修改位置与排序成功");
        this.getMenus();
      });
    },
    recursivelyTraverseChildNodes(children, div, arr) {
      if (children == null || children.length == 0) {
        //没有子节点了
        return;
      } else {
        for (const child of children) {
          let updateCategoryData = new UpdateCategoryData(
            child.catId,
            child.parentCid,
            child.sort,
            child.catLevel + div
          );
          arr.push(updateCategoryData);
          this.recursivelyTraverseChildNodes(child.children, div, arr);
        }
      }
    },
    allowDrop(draggingNode, dropNode, type) {
      //1、被拖动的当前节点以及所在的父节点总层数不能大于3
      console.log("allowDrop", draggingNode, dropNode, type);
      let level = this.countNodeLevel(
        draggingNode.data,
        draggingNode.data.catLevel
      );
      if (type == "inner") {
        if (dropNode.level + level <= 3) {
          return true;
        } else {
          return false;
        }
      }

      if (type == "next") {
        if (dropNode.parent.level + level <= 3) {
          return true;
        } else {
          return false;
        }
      }

      if (type == "prev") {
        if (dropNode.parent.level + level <= 3) {
          return true;
        } else {
          return false;
        }
      }
      //1)被拖动的当前节点总层数
      return false;
    },
    //递归查找该节点加上子类最深层级一共有几层;包含自己算
    countNodeLevel(node, l) {
      let children = node.children;
      let levelMax = 0;
      if (children.length == 0) {
        return node.catLevel - l + 1;
      } else {
        for (let child of children) {
          let level = this.countNodeLevel(child, l);
          if (level > levelMax) {
            levelMax = level;
          }
        }
      }
      return levelMax;
    },
    resetCategory() {
      Object.assign(this.category, this.copyCategory);
      //如果你希望在 console.log 输出的时候看到对象的当前状态,
      //你可以在赋值操作之前进行 console.log,或者使用对象解构等方法创建一个新的对象进行输出,以确保输出的是当前状态的副本而不是对象的引用。
      let categoryre = {};
      Object.assign(categoryre, this.category);
      console.log("执行了重置", categoryre);
    },
    submitForm() {
      if (this.submitType == "add") {
        this.addCategory();
      }
      if (this.submitType == "edit") {
        this.updateCategory();
      }
    },
    updateCategory() {
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData(this.category, false),
      }).then(({ data }) => {
        this.success("修改成功");
        this.getMenus();
        this.resetCategory();
        this.dialogVisible = false;
      });
    },
    edit(data) {
      this.submitType = "edit";
      this.submitTitle = "修改分类菜单";
      console.log("正在修改数据", data);
      this.dialogVisible = true;

      //发送http请求获取回显数据
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
      }).then(({ data }) => {
        let categoryEdit = data.data;
        console.log("回显数据", categoryEdit);
        this.category.catId = categoryEdit.catId;
        this.category.name = categoryEdit.name;
        this.category.parentCid = categoryEdit.parentCid;
        this.category.catLevel = categoryEdit.catLevel;
        this.category.showStatus = categoryEdit.showStatus;
        this.category.productUnit = categoryEdit.productUnit;
        this.category.icon = categoryEdit.icon;
        this.category.sort = categoryEdit.sort;
        console.log("category被回显数据", this.category);
      });
    },
    cancelForm() {
      this.resetCategory();
      this.dialogVisible = false;
    },
    append(data) {
      this.resetCategory();
      console.log("append", this.category);
      this.category.parentCid = data.catId;
      this.category.catLevel = data.catLevel + 1;
      this.category.showStatus = 1;
      this.category.sort = 0;
      this.dialogVisible = true;
      this.submitType = "add";
      this.submitTitle = "添加分类菜单";
    },
    addCategory() {
      console.log("提交三级分类的数据", this.category);

      this.$http({
        url: this.$http.adornUrl("/product/category/save"),
        method: "post",
        data: this.$http.adornData(this.category, false),
      }).then(({ data }) => {
        this.success("添加分类成功");
        this.getMenus();
      });

      this.resetCategory();
      this.dialogVisible = false;
    },
    remove(node, data) {
      console.log("remove", node, data);
      let ids = [data.catId];
      // console.log(this); //vue
      this.$confirm(`是否删除【${data.name}】菜单`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          // console.log(this); //vue
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(({ data }) => {
            // console.log(this); //vue
            this.$message({
              message: "菜单删除成功",
              type: "success",
            });
            // node.visible = false;
            this.getMenus();
            //设置需要默认展开的菜单
          });
        })
        .catch(() => {
          this.$message({
            message: "取消了删除",
            type: "warning",
          });
        });
    },
    expend(data, node, _) {
      console.log("展开了", node.data.catId);
      this.expandedkey.push(node.data.catId);
    },
    nodeClose(data, node, _) {
      let id = node.data.catId;
      console.log("收起了", id);
      let index = this.expandedkey.indexOf(id);
      this.expandedkey.splice(index, 1);
    },
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        console.log("成功获取到菜单数据:", data.data);
        this.menus = data.data;
      });
    },
    success(msg) {
      this.$message({
        message: msg,
        type: "success",
      });
    },
    error(msg) {
      this.$message({
        message: msg,
        type: "warning",
      });
    },
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getMenus();
    Object.assign(this.copyCategory, this.category);
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style  scoped>
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1564117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OSError: Can‘t load tokenizer for ‘bert-base-chinese‘

文章目录 OSError: Cant load tokenizer for bert-base-chinese1.问题描述2.解决办法 OSError: Can’t load tokenizer for ‘bert-base-chinese’ 1.问题描述 使用from_pretrained()函数从预训练的权重中加载模型时报错&#xff1a; OSError: Can’t load tokenizer for ‘…

2024最新软件测试【测试理论+ 性能测试】面试题(内附答案)

一、测试理论 3.1 你们原来项目的测试流程是怎么样的? 我们的测试流程主要有三个阶段&#xff1a;需求了解分析、测试准备、测试执行。 1、需求了解分析阶段 我们的 SE 会把需求文档给我们自己先去了解一到两天这样&#xff0c;之后我们会有一个需求澄清会议&#xff0c; …

基于龙芯2k1000 mips架构ddr调试心得(二)

1、内存控制器概述 龙芯处理器内部集成的内存控制器的设计遵守 DDR2/3 SDRAM 的行业标准&#xff08;JESD79-2 和 JESD79-3&#xff09;。在龙芯处理器中&#xff0c;所实现的所有内存读/写操作都遵守 JESD79-2B 及 JESD79-3 的规定。龙芯处理器支持最大 4 个 CS&#xff08;由…

NoSQL(非关系型数据库)之Redis的简介与安装

一、简介 1.1 关系型数据库与非关系型数据库 1.1.1 概念 1.1.2 区别 1.2 非关系型数据库产生背景 1.3 redis 简介 1.4 redis 优点 1.5 redis 快的原因 二、安装 2.1 关闭核心防护 2.2 安装相关依赖 2.3 解压软件包并进行编译安装 2.4 设置 Redis 服务所需相关配置文…

每日一题:c语言实现n的阶乘

目录 一、要求 二、代码 三、结果 一、要求 实现n的阶乘&#xff0c;已知n&#xff01;1*2*3*…*n 二、代码 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h>int main() {//初始化变量n为要求的几阶&#xff0c;jiecheng存储结果的&#xff0c;初始化为1…

黄金票据复现

黄金票据&#xff1a; 在AS-REP里面的ticket的encpart是使用krbtgt的hash进行加密&#xff0c;如果拥有krbtgt的hash就可以给我们自己签发任意用户的TGT票据&#xff0c;这个票据称之为黄金票据 使用Mimikatz伪造Kerberos黄金票据 Mimikatz命令&#xff1a;Kerberos&#xf…

File类 --java学习笔记

在java中&#xff0c;存储数据一般有如下几种方法&#xff1a; 而它们都是内存中的数据容器它们记住的数据&#xff0c;在断电&#xff0c;或者程序终止时会丢失 这种时候就可以使用File类和Io流&#xff0c;就数据存储在文件中 File File是java.io.包下的类&#xff0c; Fi…

[Linux]基础IO(中)---理解重定向与系统调用dup2的使用、缓冲区的意义

重定向理解 在Linux下&#xff0c;当打开一个文件时&#xff0c;进程会遍历文件描述符表&#xff0c;找到当前没有被使用的 最小的一个下标&#xff0c;作为新的文件描述符。 代码验证&#xff1a; ①&#xff1a;先关闭下标为0的文件&#xff0c;在打开一个文件&#xff0c;…

基于 NGINX 的 ngx_http_geoip2 模块 来禁止国外 IP 访问网站

基于 NGINX 的 ngx_http_geoip2 模块 来禁止国外 IP 访问网站 一、安装 geoip2 扩展依赖 [rootfxkj ~]# yum install libmaxminddb-devel -y二、下载 ngx_http_geoip2_module 模块 [rootfxkj tmp]# git clone https://github.com/leev/ngx_http_geoip2_module.git三、解压模…

android 使用ollvm混淆so

使用到的工具 ndk 21.4.7075529&#xff08;android studio上下载的&#xff09;cmake 3.10.2.4988404&#xff08;android studio上下载的&#xff09;llvm-9.0.1llvm-mingw-20230130-msvcrt-x86_64.zipPython 3.11.5 环境配置 添加cmake mingw环境变量如下图: 编译 下载…

代码随想录算法训练营第四十一天|343. 整数拆分,96. 不同的二叉搜索树

343. 整数拆分 题目 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 输入: n 10 输出: 36 解释: 10 3 3 4, 3 3 4 36。 解题思路 dp[i] …

Python读取Excel根据每行信息生成一个PDF——并自定义添加文本,可用于制作准考证

文章目录 有点小bug的:最终代码(无换行):有换行最终代码无bug根据Excel自动生成PDF,目录结构如上 有点小bug的: # coding=utf-8 import pandas as pd from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import letter from reportlab.pdfbase import pdf…

每日五道java面试题之消息中间件MQ篇(三)

目录&#xff1a; 第一题. 如何确保消息正确地发送至 RabbitMQ&#xff1f; 如何确保消息接收方消费了消息&#xff1f;第二题. 如何保证RabbitMQ消息的可靠传输&#xff1f;第三题. 为什么不应该对所有的 message 都使用持久化机制&#xff1f;第四题. 如何保证高可用的&#…

腾讯云2024年4月优惠券及最新活动入口

腾讯云是腾讯集团倾力打造的云计算品牌&#xff0c;提供全球领先的云计算、大数据、人工智能等技术产品与服务。为了吸引用户上云&#xff0c;腾讯云经常推出各种优惠活动。本文将为大家分享腾讯云优惠券及最新活动入口&#xff0c;助力大家轻松上云&#xff01; 一、优惠券领取…

IO-DAY4

使用文件IO 实现父进程向子进程发送信息&#xff0c;并总结中间可能出现的各种问题 #include<myhead.h> char* my_write(char *buf) {int wfdopen("./write.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);write(wfd,buf,sizeof(buf));close(wfd);return buf; } char* …

一.基本指令(1.1)

一、操作系统&#xff1a; 1.1本质&#xff1a; 操作系统是一款进行软硬件资源管理的软件。 1.2操作系统如何管理硬件&#xff1a; 硬件接入电脑&#xff0c;操作系统装载硬件的驱动之后&#xff0c;硬件就会被纳入操作系统的管理体系。因此&#xff0c;有时一些硬件初次接入电…

HTTPS跟HTTP有区别吗?

HTTPS和HTTP的区别&#xff0c;白话一点说就是&#xff1a; 1. 安全程度&#xff1a; - HTTP&#xff1a;就像是你和朋友面对面聊天&#xff0c;说的话大家都能听见&#xff08;信息明文传输&#xff0c;容易被偷听&#xff09;。 - HTTPS&#xff1a;就像是你们俩戴着加密耳机…

【js刷题:数据结构数组篇之有序数组的平方】

有序数组的平方 一、题目二、解题方法1、暴力解法2、双指针思路代码 三、力扣刷题合并两个有序数组 一、题目 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 二、解题方法 1、暴力解法 c…

RESTful规范总结

概念&#xff1a;RESTful&#xff08;Representational State Transfer 的缩写&#xff09;是一种广泛使用的API架构风格。 1.资源&#xff1a;在REST API的设计中&#xff0c;首先需要面向资源建模&#xff0c;其中每个节点是是一个简单资源或集合资源。 1.1一个集合包含相同…

Win10本地搭建HTTP服务器和FTP服务器

一、开启windows功能 1.进入电脑控制面板-程序-启用或关闭windows功能 2.勾选这3个功能以及展开的全部勾选 二、搭建http服务器 1.打开Internet Information Server&#xff08;IIS&#xff09;管理器 在开始菜单里面找到IIS管理器管理控制台或者搜索IIS打开 2.添加网站 进…