JS - 将对象数组导出到具有多个合并标题行的 .xlsx 文件

问题描述 投票:0回答:1

我有这个有人手动创建的 excel 文件,我需要尝试以编程方式重新创建它。

我有一个将数据导出到 csv 文件的 node.js(TS) 服务。 显然我不能生成看起来像这样的 csv 文件。 我需要稍微改变逻辑并尝试生成尽可能接近此文件的 xlsx 文件:

我环顾四周,找不到任何有用的东西。 不要介意颜色,我对第 1 行和第 2 行更感兴趣。

  1. 是否可以使用 Javascript 以编程方式执行类似的操作?
  2. 如果答案是肯定的,一个包名和一个简短的解释/例子会很有帮助。

谢谢!

我尝试了 XSLX 包 (https://www.npmjs.com/package/xlsx) 但甚至没有接近预期的结果。

javascript node.js excel typescript xlsx
1个回答
0
投票

使用

exceljs

演示 我使用这个 excel 文件。

代码

const ExcelJS = require('exceljs');
const fs = require('fs');

const wb = new ExcelJS.Workbook();
// input excel file name
const fileName = 'bar-code-data.xlsx';
const csv_fileName = 'result.csv';

// convert index to column name
const columnName = (index) => {
    var cname = String.fromCharCode(65 + ((index - 1) % 26))
    if (index > 26)
        cname = String.fromCharCode(64 + (index - 1) / 26) + cname
    return cname;
}

// apped row into CSV
const appendToCSV = (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16) => {
    const csv = `${c1},${c2},${c3},${c4},${c5},${c6},${c7},${c8},${c9},${c10},${c11},${c12},${c13},${c14},${c15},${c16}\n`;
    try {
        fs.appendFileSync(csv_fileName, csv);
    } catch (err) {
        console.error(err);
    }
}

wb.xlsx.readFile(fileName).then(() => {
    const ws = wb.getWorksheet('Sheet1');
    // get merged cells title
    const a1_title = ws.getCell('A1').value
    const d1_title = ws.getCell('D1').value
    const h1_title = ws.getCell('H1').value
    const m1_title = ws.getCell('M1').value

    // set row loop count variables
    const headerColumn = 1
    const start_row = 3
    const how_many_rows = 2

    // reading excel cell data
    for (let row_number = start_row; row_number < start_row + how_many_rows; row_number++) {
        if (row_number == start_row) {
            // reading sub titles
            const a1_sub_title1 = a1_title + ' ' + ws.getCell(columnName(headerColumn) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const a1_sub_title2 = a1_title + ' ' +  ws.getCell(columnName(headerColumn + 1) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const a1_sub_title3 = a1_title + ' ' +  ws.getCell(columnName(headerColumn + 2) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const a1_sub_title4 = a1_title + ' ' +  ws.getCell(columnName(headerColumn + 3) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")

            const d1_sub_title1 = d1_title + ' ' + ws.getCell(columnName(headerColumn + 4) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const d1_sub_title2 = d1_title + ' ' + ws.getCell(columnName(headerColumn + 5) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const d1_sub_title3 = d1_title + ' ' + ws.getCell(columnName(headerColumn + 6) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")

            const h1_sub_title1 = h1_title + ' ' + ws.getCell(columnName(headerColumn + 7) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const h1_sub_title2 = h1_title + ' ' + ws.getCell(columnName(headerColumn + 8) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const h1_sub_title3 = h1_title + ' ' + ws.getCell(columnName(headerColumn + 9) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const h1_sub_title4 = h1_title + ' ' + ws.getCell(columnName(headerColumn + 10) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const h1_sub_title5 = h1_title + ' ' + ws.getCell(columnName(headerColumn + 11) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")

            const m1_sub_title1 = m1_title + ' ' + ws.getCell(columnName(headerColumn + 12) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const m1_sub_title2 = m1_title + ' ' + ws.getCell(columnName(headerColumn + 13) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const m1_sub_title3 = m1_title + ' ' + ws.getCell(columnName(headerColumn + 14) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            const m1_sub_title4 = m1_title + ' ' + ws.getCell(columnName(headerColumn + 15) + String(row_number - 1)).value.replace(/\r?\n|\r/g, " ")
            // save header title
            appendToCSV(a1_sub_title1, a1_sub_title1, a1_sub_title3, a1_sub_title4,
                d1_sub_title1, d1_sub_title2, d1_sub_title3,
                h1_sub_title1, h1_sub_title2, h1_sub_title3, h1_sub_title4, h1_sub_title5,
                m1_sub_title1, m1_sub_title2, m1_sub_title3, m1_sub_title4)
        }

        const barcode = ws.getCell(columnName(headerColumn) + String(row_number)).value
        const ppid = ws.getCell(columnName(headerColumn + 1) + String(row_number)).value
        const site = ws.getCell(columnName(headerColumn + 2) + String(row_number)).value

        const s1_tube_type = ws.getCell(columnName(headerColumn + 3) + String(row_number)).value
        const s1_within_window = ws.getCell(columnName(headerColumn + 4) + String(row_number)).value
        const s1_initial_quantity = ws.getCell(columnName(headerColumn + 5) + String(row_number)).value
        const s1_temperature_deviation = ws.getCell(columnName(headerColumn + 6) + String(row_number)).value

        const sp1_tube_type = ws.getCell(columnName(headerColumn + 7) + String(row_number)).value
        const sp1_initial_quantity = ws.getCell(columnName(headerColumn + 8) + String(row_number)).value
        const sp1_qc_status = ws.getCell(columnName(headerColumn + 9) + String(row_number)).value
        const sp1_pre_qc_check1 = ws.getCell(columnName(headerColumn + 10) + String(row_number)).value
        const sp1_pre_qc_check2 = ws.getCell(columnName(headerColumn + 11) + String(row_number)).value

        const s2_tube_type = ws.getCell(columnName(headerColumn + 12) + String(row_number)).value
        const s2_within_window = ws.getCell(columnName(headerColumn + 13) + String(row_number)).value
        const s2_initial_quantity = ws.getCell(columnName(headerColumn + 14) + String(row_number)).value
        const s2_temperature_deviation = ws.getCell(columnName(headerColumn + 15) + String(row_number)).value

        // save data row
        appendToCSV((barcode === null)? '' : barcode,
            (ppid === null)? '' : ppid,
            (site === null)? '' : site,
            (s1_tube_type === null)? '' : s1_tube_type,
            (s1_within_window === null)? '' : s1_within_window,
            (s1_initial_quantity === null)? '' : s1_initial_quantity,
            (s1_temperature_deviation === null)? '' : s1_temperature_deviation,
            (sp1_tube_type === null)? '' : sp1_tube_type,
            (sp1_initial_quantity === null)? '' : sp1_initial_quantity,
            (sp1_qc_status === null)? '' : sp1_qc_status,
            (sp1_pre_qc_check1 === null)? '' : sp1_pre_qc_check1,
            (sp1_pre_qc_check2 === null)? '' : sp1_pre_qc_check2,
            (s2_tube_type === null)? '' : s2_tube_type,
            (s2_within_window === null)? '' : s2_within_window,
            (s2_initial_quantity === null)? '' : s2_initial_quantity,
            (s2_temperature_deviation === null)? '' : s2_temperature_deviation)
    }

}).catch(err => {
    console.log(err.message);
});

结果

贴士

#1 此代码将多行标题替换为单行标题

replace(/\r?\n|\r/g, " ")

#2

columnName
功能:按数字转换列名

columnName(1) -> A
columnName(2) -> B

#3 空检查 如果值为空,则替换空白字符

(value === null)? '' : value

#4 追加行

csv
字符串将附加到 CSV 文件中

fs.appendFileSync(csv_fileName, csv);
© www.soinside.com 2019 - 2024. All rights reserved.