首先需要导包:node-xlsx
npm i node-xlsx
导出的Excel在面对tree树形结构数据的时候,为了保证导出的数据便于浏览;第二块需要学习的地方就是合并单元格时的规则
{s: {c: 0, r: 1}, e: {c: 0, r: 37}}
c:为Excel的行,r:为Excel的列;类似一个坐标的概念;该示例为两个端点间的范围进行单元格合并;
tree树形结构数据处理
以下案例数据为三层数据结构整理处理之后如下;姓名、类型两列数据需要进行处理(单元格合并)
const data = [
['姓名','类型','标题2','标题3'],
['张三', '类型1', "***", "***"],
['张三', '类型1', "***", '--'],
['张三', '类型2', "***", '--'],
['张三', '类型2', "***", '--'],
['张三', '类型3', "***", '--'],
['张三', '类型3', "***", '=='],
['张三', '类型3', "***", '=='],
['李四', '类型4', "***", '=='],
['李四', '类型4', "***", '=='],
['李四', '类型4', "***", '=='],
['李四', '类型5', "***", '=='],
['王五', '类型6', "***", '=='],
['王五', '类型7', "***", '=='],
];
4、以下案例代码如下:
async downloadExcel() {
let data: any[] = await this.getObj();
// data数据遍历整合
let processingData: any[] = this.processingData(data);
// 需要进行合并的数据进行计数,分别为多少项
let firstNames = processingData.reduce((obj, name) => {
if (name[0] != '应急耗材') {
if (name[0] in obj) {
obj[name[0]]++
} else {
obj[name[0]] = 1
}
}
return obj
}, {});
let secondNames = processingData.reduce((obj, name) => {
if (name[1] != '耗材类别') {
if (name[1] in obj) {
obj[name[1]]++
} else {
obj[name[1]] = 1
}
}
return obj
}, {});
// 遍历成一个数组
let firstNumber: any[] = [];
Object.keys(firstNames).forEach((key) => {
firstNumber.push(firstNames[key])
});
let secondNumber: any[] = [];
Object.keys(secondNames).forEach((key) => {
secondNumber.push(secondNames[key])
});
//{s: {c: 0, r: 1}, e: {c: 0, r: 37}}: c:为Excel的行,r:为Excel的列;类似一个坐标的概念;该示例为两点范围进行单元格合并
let merges: any[] = [];
let ac: number = 0;
for (let i = 0; i < firstNumber.length; i++) {
let a = firstNumber[i], b = 0, c = 1, d = 0;
if (i == 0) {
let obj = {s: {c: 0, r: c}, e: {c: 0, r: a + b}};
merges.push(obj)
}
if (i !== firstNumber.length - 1) {
d = firstNumber[i + 1];
if (i == 0) {
ac += a + 1;
let obj = {s: {c: 0, r: ac}, e: {c: 0, r: ac + d - 1}};
merges.push(obj)
} else {
ac += a;
let obj = {s: {c: 0, r: ac}, e: {c: 0, r: ac + d - 1}};
merges.push(obj)
}
}
}
ac = 0;
for (let i = 0; i < secondNumber.length; i++) {
let a = secondNumber[i], b = 0, c = 1, d = 0;
if (i == 0) {
let obj = {s: {c: 1, r: c}, e: {c: 1, r: a + b}};
merges.push(obj)
}
if (i !== secondNumber.length - 1) {
d = secondNumber[i + 1];
if (i == 0) {
ac += a + 1;
let obj = {s: {c: 1, r: ac}, e: {c: 1, r: ac + d - 1}};
merges.push(obj)
} else {
ac += a;
let obj = {s: {c: 1, r: ac}, e: {c: 1, r: ac + d - 1}};
merges.push(obj)
}
}
}
// 以下注释代码,即为Excel合并单元格所需的规则
/*const range = [
{s: {c: 0, r: 1}, e: {c: 0, r: 37}},
{s: {c: 0, r: 38}, e: {c: 0, r: 78}},
{s: {c: 0, r: 79}, e: {c: 0, r: 105}},
{s: {c: 0, r: 106}, e: {c: 0, r: 114}},
{s: {c: 0, r: 115}, e: {c: 0, r: 123}},
{s: {c: 0, r: 124}, e: {c: 0, r: 149}},
{s: {c: 0, r: 150}, e: {c: 0, r: 190}},
{s: {c: 0, r: 191}, e: {c: 0, r: 196}},
{s: {c: 0, r: 197}, e: {c: 0, r: 262}},
{s: {c: 0, r: 263}, e: {c: 0, r: 266}},
{s: {c: 1, r: 1}, e: {c: 1, r: 11}},
{s: {c: 1, r: 12}, e: {c: 1, r: 21}},
{s: {c: 1, r: 22}, e: {c: 1, r: 33}},
{s: {c: 1, r: 34}, e: {c: 1, r: 37}},
{s: {c: 1, r: 38}, e: {c: 1, r: 54}},
{s: {c: 1, r: 55}, e: {c: 1, r: 78}},
{s: {c: 1, r: 79}, e: {c: 1, r: 84}},
{s: {c: 1, r: 85}, e: {c: 1, r: 91}},
{s: {c: 1, r: 92}, e: {c: 1, r: 105}},
{s: {c: 1, r: 106}, e: {c: 1, r: 108}},
{s: {c: 1, r: 109}, e: {c: 1, r: 114}},
{s: {c: 1, r: 115}, e: {c: 1, r: 123}},
{s: {c: 1, r: 124}, e: {c: 1, r: 149}},
{s: {c: 1, r: 150}, e: {c: 1, r: 175}},
{s: {c: 1, r: 176}, e: {c: 1, r: 190}},
{s: {c: 1, r: 191}, e: {c: 1, r: 196}},
{s: {c: 1, r: 197}, e: {c: 1, r: 203}},
{s: {c: 1, r: 204}, e: {c: 1, r: 210}},
{s: {c: 1, r: 211}, e: {c: 1, r: 237}},
{s: {c: 1, r: 238}, e: {c: 1, r: 262}},
{s: {c: 1, r: 263}, e: {c: 1, r: 266}},
];*/
const sheetOptions = {
'!merges': merges,
// 设置每一列Excel的宽度:第一列20,第二列30,以此类推
'!cols': [{wch: 20}, {wch: 30}, {wch: 40}, {wch: 20}],
};
// 将处理好之后的数据 processingData 以及单元格合并的规则 sheetOptions 等内容转换成buffer文件
const buffer: any = xlsx.build([{name: 'myFirstSheet', data: processingData, options: sheetOptions}]);
let path_: string = path.join(__dirname, '../download/');
let name: string = fecha.format(new Date(), 'YYYYMMDDHHmmss') + '.xlsx';
await fs.writeFileSync(path.join(path_, name), buffer);
return path.join(__dirname, '../download/', name);
}
希望我的内容能帮到有需要的人,谢谢。