项目需求
1.左侧第一列"源字段"为上传xml文件,传到后台解、、析返回来的列表;左侧第二列"目标字段"为数据库表字段列表;
2.选中"源字段列表"中某一项,在"目标字段列表"中匹配相似度较高的一项,排序放在列表最前面,变为选中状态;从最后一位开始比对,直至比对倒数五位;
3.点击"添加"按钮将匹配到的左右字段放入映射结果列表;
4.选中某个映射结果项点击"删除"按钮,将字段再分别存入"源字段列表"和"目标字段列表"中;
如下图:
为什么要从最后一位开始比对往前类推?因为上传的xml文件中字段包含级别关系,后台返回来的结果可能是【一级字段.二级字段】,实际想要匹配目标字段是【二级字段】,因此不能从前往后匹配。如果不存在这个问题可以直接将"源字段"和"目标字段"每个项转为字符串数组比对,只要匹配上X个字符就可认为匹配成功。
实现思路
1.选择“源字段”拿到value值,循环“目标字段”拿到value值,两个value值进行转小写、去下划线等操作;进行全等验证;
template:
<div class="mappingGroup d-flex">
<div class="leftCon mainCon">
<p class="title">源字段</p>
<ul>
<li v-for="(item, index) in sourceList" :key="item.index" :class="sourceflag == index ? 'active' : ''" @click="chooseSource(index)">{{ item.value }}</li>
</ul>
</div>
<div class="middleCon mainCon">
<p class="title">目标字段</p>
<ul>
<li v-for="(item, index) in targetList" :key="item.index" :class="targetflag == index ? 'active' : ''" @click="chooseTarget(index)">{{ item.value }}</li>
</ul>
</div>
<div class="btnGroup">
<el-button type="primary" icon="el-icon-d-arrow-right" @click="addMapping()"></el-button><!-- 添加 -->
<el-button type="primary" icon="el-icon-d-arrow-left" @click="delMapping()"></el-button><!-- 删除 -->
</div>
<div class="rightCon mainCon">
<p class="title">映射结果</p>
<ul>
<li v-for="(item, index) in resultList" :key="item.index" :class="resultflag == index ? 'active' : ''" @click="chooseResult(index)">{{ item.value }}</li>
</ul>
</div>
</div>
script:
data() {
return {
//源字段列表、目标字段列表为后台返回的数据,映射结果列表为需要保存传给后台的数据
sourceList: [],// 源字段列表
sourceflag: -1, // 样式控制
sourceTxt: "", //选中的源字段
targetList: [], // 目标字段列表
targetflag: -1, // 样式控制
targetTxt: "", //选中的目标字段
resultList: [], // 映射结果列表
resultflag: -1, // 样式控制
resultTxt: "", //选中的结果字段
};
}
methods: {
// 选择源字段
chooseSource(index) {
this.targetTxt = ""; // 每次点击先清空之前存储的目标字段value值
this.sourceflag = index; //切换选中样式
this.sourceTxt = this.sourceList[index].value; //选中的源字段value值
this.resultflag = -1;
// 处理目标字段
for (let i = 0; i < this.targetList.length; i++) {
// 如果左右字符串全等
if (this.targetList[i].value.replace(/_/g, "").toLowerCase().trim() == this.sourceTxt.replace(/_/g, "").toLowerCase().trim()) {
this.targetTxt = this.targetList[i].value;
this.targetList.splice(i, 1); //先从数组中删除匹配项
this.targetList.unshift({ //在数组前插入匹配项
value: this.targetTxt,
});
this.targetflag = 0; //切换样式
return;
}
}
}
}
2.如果不全等,则对源字段value1和目标字段value2进行字符串转数组,匹配最后一位,如果匹配成功则权重order=1,继续匹配后两位,如果匹配成功则权重order=2...直到匹配完后五位,order=5,根据order的值进行目标字段列表排序
script:
methods: {
// 选择源字段
chooseSource(index) {
this.targetTxt = ""; // 每次点击先清空之前存储的目标字段value值
this.sourceflag = index; //切换选中样式
this.sourceTxt = this.sourceList[index].value; //选中的源字段value值
this.resultflag = -1;
// order为权重,匹配位数越多权重越大,按权重排序
this.targetList.forEach((item) => {
item.order = 0;
});
// 处理目标字段
for (let i = 0; i < this.targetList.length; i++) {
// 如果左右字符串全等
if (this.targetList[i].value.replace(/_/g, "").toLowerCase().trim() == this.sourceTxt.replace(/_/g, "").toLowerCase().trim()) {
this.targetTxt = this.targetList[i].value;
this.targetList.splice(i, 1); //先从数组中删除匹配项
this.targetList.unshift({ //在数组前插入匹配项
value: this.targetTxt,
});
this.targetflag = 0; //切换样式
return;
}
// 不全等的 从最后一位开始匹配 字符串转数组截取后再转字符串进行比对
let txt1 = [...this.sourceTxt.replace(/_/g, "").toLowerCase().trim()]; // 源字段字符串数组
// 匹配最后一位
if (txt1.slice(-1).toString() ==[...this.targetList[i].value.replace(/_/g,"").toLowerCase().trim()].slice(-1).toString()
) {
this.targetList[i].order = 1; //设置权重为1
// 匹配最后两位
for (let j = 0; j < this.targetList.length; j++) {
if (txt1.slice(-2).toString() == [...this.targetList[j].value.replace(/_/g, "").toLowerCase().trim()].slice(-2).toString()) {
this.targetList[j].order = 2; //设置权重为2
// 匹配最后三位
for (let x = 0; x < this.targetList.length; x++) {
if (txt1.slice(-3).toString() == [...this.targetList[x].value.replace(/_/g, "").toLowerCase().trim()].slice(-3).toString()) {
this.targetList[x].order = 3; //设置权重为3
// 匹配最后四位
for (let y = 0; y < this.targetList.length; y++) {
if (txt1.slice(-4).toString() == [...this.targetList[y].value.replace(/_/g, "").toLowerCase().trim()].slice(-4).toString()) {
this.targetList[y].order = 4; //设置权重为4
// 匹配最后五位
for (let z = 0; z < this.targetList.length; z++) {
if (txt1.slice(-5).toString() == [...this.targetList[z].value.replace(/_/g, "").toLowerCase().trim()].slice(-5).toString()) {
this.targetList[z].order = 5; //设置权重为5
}
}
}
}
}
}
}
}
this.targetflag = 0; //切换样式
this.targetList.sort(this.compare("order")); //排序
this.targetTxt = this.targetList[0].value;
} else {
console.log("无匹配项");
}
}
},
// 目标字段按权重排序
compare(attr) {
return function (a, b) {
var val1 = a[attr];
var val2 = b[attr];
return val2 - val1;
};
},
}
如下图:选中"123.imagingMode"会先按照最后一位“e"进行匹配,此时会从右侧匹配到"imagingMode"和"processingType",他们两个的order都为1,再找后两位"de",此时只能匹配到"imagingMode",他的order=2,以此类推直到匹配完五位order=5
3.点击【添加】按钮,将拿到的源字段value和目标字段value进行拼接,存入映射数组,并删除源字段数组和目标字段数组中相应字段
script:
// 添加
addMapping() {
if (this.sourceTxt == "" || this.targetTxt == "") {
this.$message.error("请先选择源字段和目标字段");
} else {
let resultTxt = this.sourceTxt + " " + this.targetTxt;
this.resultList.push({ value: resultTxt });
// 删除源列表目标列表选中的字段
this.sourceList.splice(this.sourceflag, 1);
this.targetList.splice(this.targetflag, 1);
// 源列表目标列表样式置空
this.sourceflag = -1;
this.targetflag = -1;
// 清空拼接的字符串
this.sourceTxt = "";
this.targetTxt = "";
}
},
4.选中映射目标字段,点击【删除】按钮,将字段拆分为val1和val2两个字符串,分别插入源字段数组和目标字段数组
// 删除
delMapping() {
if (this.resultflag == -1) {
this.$message.error("请先选择映射结果");
} else {
this.sourceList.push({ value: this.resultTxt.split(" ")[0] });
this.targetList.push({ value: this.resultTxt.split(" ")[1] });
this.resultList.splice(this.resultflag, 1);
this.resultflag = -1;
}
},
1.每次选中源字段时注意目标字段列表的索引值;
2.flag只为控制样式;
3.全等匹配成功是伪排序,先删除再插入;字符匹配为权重排序;
4.每次选择源字段先将列表order都重置为0,并清空之前存储源字段和目标字段的变量,否则会造成数据混乱;