本篇文章需要大量的耐心和思考!!

148 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

注:本篇文章需要大量的耐心和思考

这么复杂的数据类型给小编整不会了!!

前段时间对接了一个类似于级联的数据映射需求,当时项目写的比较着急,脑海里没有特别好的解决方案,但是时候写完后觉得实现的方案不是特别好,希望大家看到后有好的解决方案给小编一点提示嗷~

需求背景

服务端返回枚举类型数据,前端进行相关的映射渲染,此处数据用于列表搜索和表单新增

业务关系解释

  1. 业务类型
  2. 业务子类型
  3. 分类
  4. 数据来源

业务类型有3种,每个业务类型下平均包含了2种业务子类型,每个业务子类型各分配对应1-6种分类,一个分类一种数据来源或多个分类可能共用一种数据来源

页面关系图解

stateDiagram-v2
业务类型 --> 业务子类型
业务子类型 --> 分类
业务子类型 --> 数据来源

业务类型改变相关业务子类型发生变化,业务子类型改变同时映射分类和数据来源

服务端的返回的数据模板

{
  "type": {
    "desc": "业务类型",
    "key": {
      "0": "全局",
      "1": "短信",
      "2": "信息"
    },
    "ctype": {//业务类型——业务子类型的映射
      "0": ["1", "2", "3"],
      "1": ["4", "5"],
      "2": ["4", "5"]
    }
  },
  "ctype": {
    "desc": "业务子类型",
    "key": {
      "1": "全局1",
      "2": "全局2",
      "3": "全局3",
      "4": "全局4",
      "5": "全局5"
    },
    "category": {//业务类型和业务子类型——分类的映射
      "desc": "type,ctype",
      "0,1": ["10"],
      "0,2": ["11"],
      "0,3": ["12"],
      "1,4": ["30","31","32"],
      "1,5": ["50","51","52","53"],
      "2,4": {
        "getCategory2": true,
        "values": ["30","31"]
      },
      "2,5": ["54","55"]
    },
    "Origin": {//业务类型和业务子类型——数据来源的映射
      "desc": "type,ctype",
      "0,1": ["1","2","3"],
      "0,2": ["1","2","3"],
      "0,3": ["3","4","5","6"],
      "1,4": ["3","4","5","7"],
      "1,5": ["8","9","10"],
      "2,4": ["3","4","5","11"],
      "2,5": ["10","11"]
    }
  },
  "category": {
    "desc": "分类",
    "key": {
      "10": "分类1",
      "11": "分类2",
      "12": "分类3",
      "30": "分类4",
      "31": "分类5",
      "32": "分类6",
      "50": "分类7",
      "51": "分类8",
      "52": "分类9",
      "53": "分类10",
      "54": "分类11",
      "55": "分类12"
    },
    "category2": {//分类——子分类的映射
      "30": ["1","2"],
      "31": ["3","4","5","6"]
    }
  },
  "category2": {
    "desc": "子分类",
    "key": {
      "1": "子分类1",
      "2": "子分类2",
      "3": "子分类3",
      "4": "子分类4",
      "5": "子分类5",
      "6": "子分类6"
    }
  },
  "Origin": {
    "desc": "数据来源",
    "key": {
      "1": "数据来源1",
      "2": "数据来源2",
      "3": "数据来源3",
      "4": "数据来源4",
      "5": "数据来源5",
      "6": "数据来源6",
      "7": "数据来源7",
      "8": "数据来源8",
      "9": "数据来源9",
      "10": "数据来源10",
      "11": "数据来源11"
    }
  }
}

key对象下面都是相关的类型数据,其他都是对应的映射关系

我的想法

一开始的想法很简单,觉得可以做每次请求,每触发一次,就请求一次服务端的接口,得到对应的枚举类型直接赋值就好

沟通的结果

看到数据类型后和组长沟通了一下,因为业务场景运用在搜索和表单新增,请求会比较频繁,不建议每次触发请求,让把key对象下面的相关类型数据二次处理好存在公共的枚举数据对象中,然后在页面再请求一次接口拿映射关系,这样就相当于请求了2次

实现结果

    // 映射处理数据函数
    setData(refName, index, typeOne, typeTwo, data) { // ref名字 当前下标 当前下标的映射数据 要赋值的参数 进行筛选过滤的data
      const { blackListForm, category2List, blacklistsOptionsData } = this; // 当前业务下标
      let type = ''
      if (refName === 'dialogRef') { // 新增的业务线类型从表单的选项取
        type = blackListForm.type
      } else { // 搜索的业务线类型从tab取
        type = this.type
      }
      const actionData = blacklistsOptionsData?.[typeOne][typeTwo];
      let newdata = [];
      const newIndex = type + "," + index;
      if (typeTwo === "category" || typeTwo === "Origin") { // 不同的业务线分类可能存在子分类要区分
        // 分类 或者数据来源
        for (const key in actionData) {
          if (Array.isArray(actionData[newIndex])) {
            newdata = data?.filter((val) =>
              actionData[newIndex]?.includes(val.key)
            );
          } else {
            // 短信-信息-分类的子集分类区分
            newdata = category2List;//特殊子分类单独赋值
          }
        }
      } else { // 正常情况
        newdata = data?.filter((val) => actionData[index].includes(val.key));
      }
      const name = typeTwo === "Origin" ? "origin" : typeTwo; // 因为返回的参数名称和定义的不一样,做了一些判断
      this.$refs?.[refName]?.set({
        type: "options",
        data: {
          [name]: newdata,
        },
      });
    }

首次页面加载的时候默认业务类型是全局,初始加载枚举数据接口,拿到映射关系存放进data里,调用setData函数

this.setData("searchs", "0", "type", "ctype", ctypeList);
传搜索ref名字、当前选中的value、当前value映射出的下一级数据、要赋值参数名字、需要筛选过滤的data

列表时,监听了tab的下标值,每次change调用setData

  watch: {
    type(val, oldVal) {
      const { ctypeList } = this//公共数据里的枚举数据
      if (val !== oldVal) {
        this.setData("searchs", val, "type", "ctype", ctypeList);
        this.$refs.searchs.reset();//每次切换搜索项重置
      }
    },
  },

当搜索change下拉框,change事件,通过setData函数处理得到对应的下拉数据

    async changeSearch(val, oldVal) {
      const { categoryList, OriginList } = this;
      if (val.ctype && val.ctype !== oldVal.ctype) {
        // 业务类型和分类的联动
        await this.setData(
          "searchs",
          val.ctype,
          "ctype",
          "category",
          categoryList
        );
        // 业务类型和数据来源的联动
        await this.setData(
          "searchs",
          val.ctype,
          "ctype",
          "Origin",
          OriginList
        );
      }
    },

功能是实现了,但是我觉得这个方法实现的实在是太烂了😭 其次就是表单新增的时候,要区分参数传值

意思:

  • 当选择业务类型是短信 分类是分类4
  • 当选择业务类型是信息 分类是子分类1和子分类2
  • 子分类1子分类2分类4子集
onFormSubmit(values){
const newData = { ...values };
      // 注释: 信息-分类category2(子分类1/子分类2)要传父级category 分类4(30)
      const newIndex = values.type + "," + values.ctype; //短信-信息的分类映射关系的拼接下标
      const categoryObj = this.blacklistsOptionsData.ctype.category[newIndex] // 分类的子集映射对象
      if (!Array.isArray(categoryObj) && categoryObj.getCategory2) { // 确定当前业务线的分类是否存在子集
        const category2Obj = this.blacklistsOptionsData.category.category2 // 分类父级和子集的映射关系
        for (const key in category2Obj) {
          if (category2Obj[key].includes(newData.category)) { // 当前分类是否存在于父级的映射关系中
            newData.category2 = newData.category
            newData.category = key
          }
        }
      }

}

我知道大家看完很凌乱,小编写完也很凌乱😭,如果大家此刻正在看这篇文章有好的方案记得滴滴我喔~,现在的解决方案实在太菜了😭,的亏注释写的多,但是不想让后人骂小编呀~

注:小声吐槽,小编承受得住😰