不久前,咱们接了一个本身作前端后端产品的活,今后过上了可怜巴巴敲代码开开心心收获知识的日子呢。javascript
用户小姐姐在群里说,系统筛选工卡有效期很差使。(系统:不不不,不是个人锅前端
我看了一下数据库,发现,咱们原定的有效期格式是这样的java
整整齐齐。数据库
数据库中当时的数据是这样的json
甚至是这样的后端
看到这种状况,我以为确定是输入的时候输的不太对(年轻…app
因而我决定从 Excel 下手ui
小姐姐们的操做流程是先用咱们的系统导出一份 Excel,编辑以后再导入系统的,那只要我把这工卡一列的格式限制为日期,就必定能够统一格式的,嗯。this
咱们项目使用了 js-xlsx 处理表格的导入导出,下面是导出 Excel 的伪代码:spa
import * as XLSX from 'xlsx';
const xlsxMineType = 'application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet'
const data = 数据.map((s: any) => ({
ID: s.id,
工卡有效期: s.card_expired,
……
}));
const sheet = XLSX.utils.json_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, sheet, '员工信息表');
const wbbuf = XLSX.write(wb, {
type: 'base64'
});
this.success({ name: "员工信息表.xlsx", data: wbbuf, type:xlsxMineType });
复制代码
经过 json_to_sheet 能够拿到包含单元格信息的对象
{
A2: { t: 'n', v: 3776 },
B2: { t: 's', v: '2019-04-01' },
A3: { t: 'n', v: 3831 },
B3: { t: 's', v: '2019-04-01' },
A1: { t: 's', v: 'ID' },
B1: { t: 's', v: '工卡有效期' },
'!ref': 'A1:B3'
}
复制代码
对象中以单元格位置做为 key,每一个单元格的值(v)、类型(t)等等属性做为 value。其中单元格的类型支持:
b
Boolean, n
Number, e
error, s
String, d
Date
看起来 Date 类型十分符合上面的要求,就尝试了一下:
const sheet = XLSX.utils.json_to_sheet(data);
// 筛选出除表头的工卡列
Object.keys(sheet).filter(item => /^B/.test(item) && item !== "B1").forEach(key => {
sheet[key].t = "d";
})
复制代码
然鹅,若是工卡有效期原本就为空,这时候导出,打开 Excel 会报错,而且空的位置会变成 NaN
翻阅了各类中英文文档、Issue,导出一百多个员工信息表以后,我发现 Excel 真的很奇妙,或许应该在 js 上来格式化导入的数据,而不是限制单元格的类型。
若是不控制单元格类型的话,那么当管理员输入日期的时候,这个单元格多是:文本、常规、日期、自定义类型,因此只要保证无论单元格是什么格式,程序都能拿到正确的数据就行了。
当管理员使的工卡有效期的单元格类型是文本或者常规的时候,则比较简单,程序能够按预期解析出来一个相应的字符串,用 moment 解析一下,就能够得到想要的格式的数据了。
那么当有效期单元格的类型是日期和自定义的时候,咱们拿到的数据是像下图同样
这也就是以前数据库中奇怪的数字的由来,这个数字的意义,实际上是当前日期距离 1900 年 1月 0 日的天数。还须要注意的是,Excel 中有个 bug:
它觉得 1900 年是闰年,因此咱们拿到的天数都会多了一天,由于转换以前还须要先进行减一操做…
item.工卡有效期 = new Date(1900, 0, expried - 1)
复制代码
这样以后就能够拿到正确的日期啦。咕叽。