携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
注:本篇文章需要大量的耐心和思考
这么复杂的数据类型给小编整不会了!!
前段时间对接了一个类似于级联的数据映射需求,当时项目写的比较着急,脑海里没有特别好的解决方案,但是时候写完后觉得实现的方案不是特别好,希望大家看到后有好的解决方案给小编一点提示嗷~
需求背景
服务端返回枚举类型数据,前端进行相关的映射渲染,此处数据用于列表搜索和表单新增
业务关系解释
- 业务类型
- 业务子类型
- 分类
- 数据来源
业务类型有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
}
}
}
}
我知道大家看完很凌乱,小编写完也很凌乱😭,如果大家此刻正在看这篇文章有好的方案记得滴滴我喔~,现在的解决方案实在太菜了😭,的亏注释写的多,但是不想让后人骂小编呀~
注:小声吐槽,小编承受得住😰