Bootstrap

tree树形结构数据用Ts导出Excel合并单元格

  1. 首先需要导包:node-xlsx

npm i node-xlsx
  1. 导出的Excel在面对tree树形结构数据的时候,为了保证导出的数据便于浏览;第二块需要学习的地方就是合并单元格时的规则

{s: {c: 0, r: 1}, e: {c: 0, r: 37}}

c:为Excel的行,r:为Excel的列;类似一个坐标的概念;该示例为两个端点间的范围进行单元格合并;

  1. 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);
    }

希望我的内容能帮到有需要的人,谢谢。

;