业务需求
前端管理界面需要做导入导出的EXCEL功能,用户可以填写excel模板的信息进行批量新增数据,当然也需要做数据校验
解决方案
考虑到excel导入需要做数据校验,放前端解析方便校验因此放前端解析
开发准备
使用js-xlsx用作数据转换。详细文档地址
开发demo
效果
核心代码
对应的表头名转换为对应的系统字段,将每行数据转换为json
// 遍历每张表读取
// workbook.Sheets 是以表名为索引值的 sheet 为表名
for (var sheet in workbook.Sheets) {
// Object的hasOwnProperty()方法返回一个布尔值,判断对象是否包含特定的自身(非继承)属性。判断
if (workbook.Sheets.hasOwnProperty(sheet)) {
var fromTo = workbook.Sheets[sheet]['!ref']; // sheet['!ref']:表示作用单元格的范围,例如从A1到F8则记录为A1:F8;
var datas = workbook.Sheets[sheet];// 根据读取的表名作为索引值,获取指定工作表
try{
// 判断配置单元格导入配置中有没有填入对应的单元格坐标,没有则默认自动生成
//从A1 B1 C1 D1 ...顺序往下
if(!("Site" in configs.model[0])){
for (var f = 0; f < configs.model.length;f++) {
var num = f+1;
var stringName=""; // 数字排序转字母排序 1->A 2->B 3->C 如此类推
// 在26位单字母范内
if(num >= 1 && num <= 26) {
stringName = String.fromCharCode(64 + parseInt(num));
}
// 超过26位字母范围 27->AA 28->AB 28->AC ... 如此类推
else {
while(num > 26) {
var count = parseInt(num/26);
var remainder = num%26;
if(remainder == 0)
{
remainder = 26;
count--;
stringName = String.fromCharCode(64 + parseInt(remainder)) + stringName;
}
else
{
stringName = String.fromCharCode(64 + parseInt(remainder)) + stringName;
}
num = count;
}
stringName = String.fromCharCode(64 + parseInt(num)) + stringName;
}
configs.model[f].Site = stringName+"1";
}
}
for (var i = 0; i < configs.model.length; i++) {
datas[configs.model[i].Site].v = configs.model[i].Name; // 更改表头名为系统数据库字段,v:表示原始值;
datas[configs.model[i].Site].w = configs.model[i].Name;//更改表头名为系统数据库字段,w:格式化后的内容
}
var num = i+1;
var stringName="";
// 数字排序转字母排序
if(num > 0) {
if(num >= 1 && num <= 26) {
stringName = String.fromCharCode(64 + parseInt(num));
} else {
while(num > 26) {
var count = parseInt(num/26);
var remainder = num%26;
if(remainder == 0) {
remainder = 26;
count--;
stringName = String.fromCharCode(64 + parseInt(remainder)) + stringName;
} else {
stringName = String.fromCharCode(64 + parseInt(remainder)) + stringName;
}
num = count;
}
stringName = String.fromCharCode(64 + parseInt(num)) + stringName;
}
}
// 如果后面还有内容则抛出异常
if(datas[stringName+"1"]!=null){
throw "";
}
}
catch(err){
layer.msg("导入的文件出错!");
$('#' + configs.targetid).val("");
return;
}
// 如果有不规范数据可以在这里进行处理datas
persons = persons.concat(XLSX.utils.sheet_to_json(datas));// 转换为json格式,将每一行数据转换成一个json实体
break; // 只读了第一张表
}
}
数据校验及转换
for (let index = 0; index < persons.length; index++) {
var element = persons[index];
for (var t = 0; t < configs.model.length; t++) {
element[configs.model[t].Name] = $.trim(element[configs.model[t].Name]); // 去除前后空格
// 如果配置中有标识需要校验数据则校验
if("Rule" in configs.model[t]){
// Rule()在validator.js
Validatemsg = Validatemsg + Rule(element[configs.model[t].Name], (element["__rowNum__"]+1), configs.model[t]);
}
// 该列填写的内容是市或县,需要转化为对应的市县代码
if(configs.model[t].CityOrDistrict!=null){
if(configs.model[t].CityOrDistrict == "city"){
var cityCode = $.getCityToName(element[configs.model[t].Name]);
element.city_code = cityCode;
}
else if(configs.model[t].CityOrDistrict == "district"){
var county = $.getCountyToName(element[configs.model[t].Name]);
element.district_code = county;
}
}
// 该列填写内容为枚举值,转化为对应的代码枚举
if(configs.model[t].Enumobj!=null){
var haveenum = false;
for(var u=0;u<configs.model[t].Enumobj.length;u++){
if(configs.model[t].Enumobj[u].Description == element[configs.model[t].Name]){
element[configs.model[t].Name] = configs.model[t].Enumobj[u].Value;
haveenum = true;
}
}
if(!haveenum){
var strh = configs.model[t].ErrorMessage.substring(configs.model[t].ErrorMessage.length-2,configs.model[t].ErrorMessage.length); //截取
Validatemsg = Validatemsg + "第"+ (element["__rowNum__"] + 1 )+"行" + configs.model[t].ErrorMessage + "不存在该"+strh+"!<br>";
}
}
}
}
demo下载
链接: excel导入demo