All files / src/utils xlsx.js

0% Statements 0/83
0% Branches 0/40
0% Functions 0/12
0% Lines 0/76

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143                                                                                                                                                                                                                                                                                             
import XLSX from 'xlsx-js-style';
 
export function exportExcel(aoa, sheetName, fileName, sheetTitleData, columns, hasHeader, merges, includeStyles) {
    // return;
    // 若有标题,添加标题到第一行
    const sheet = XLSX.utils.json_to_sheet([]);
    aoa.forEach((row) => {
        // 默认设置为字符串
        row.forEach((cell) => {
            if (cell)
                cell.t = 's';
        });
    });
    // 设置列宽和行高
    if (includeStyles) {
        const cols = [];
        const rows = [];
        aoa.forEach((row, rowIndex) => {
            // 获取行高
            const heights = row.map((v) => v && v.rect && +v.rect.height).filter((v) => v !== undefined);
            const height = Math.max(...heights);
            rows[rowIndex] = { hpx: height };
        });
        if (sheetTitleData.title) {
            rows.unshift({ hpx: sheetTitleData.rect && sheetTitleData.rect.height });
        }
        // 获取列宽
        for (let i = 0; i < aoa[0].length; i++) {
            let widthResult = 0;
            for (let j = 0; j < aoa.length; j++) {
                if (aoa[j][i] && aoa[j][i].rect) {
                    const width = aoa[j][i].rect.width;
                    widthResult = Math.max(widthResult, width);
                }
            }
            cols[i] = { wpx: widthResult };
        }
        sheet['!cols'] = cols;
        sheet['!rows'] = rows;
    }
    if (sheetTitleData.title) {
        const endCell = XLSX.utils.encode_col(columns - 1) + 1;
        XLSX.utils.sheet_add_aoa(sheet, [[sheetTitleData.title]], { origin: { r: 0, c: 0 } });
        XLSX.utils.sheet_add_aoa(sheet, aoa, { origin: 'A2' });
        sheet['!merges'] = [XLSX.utils.decode_range(`A1:${endCell}`), ...merges.map((v) => ({
            s: {
                c: v.col,
                r: v.row + 1,
            },
            e: {
                c: v.col + v.colspan - 1,
                r: v.row + 1 + v.rowspan - 1,
            },
        }))];
        // 设置标题样式
        sheet.A1.s = sheetTitleData.s;
    } else {
        XLSX.utils.sheet_add_aoa(sheet, aoa, { origin: 'A1' });
        sheet['!merges'] = merges.map((v) => ({
            s: {
                c: v.col,
                r: v.row,
            },
            e: {
                c: v.col + v.colspan - 1,
                r: v.row + v.rowspan - 1,
            },
        }));
    }
    // 将文本格式的内容,转化为日期和数字格式
    Object.keys(sheet).forEach((item) => {
        const cell = sheet[item];
        const dateRegx = /^\d{4}-\d{2}-\d{2}$/;
        const percentRegx = /^\d+(\.\d+)?%$/;
        const excludeNumberRegx = /^0\d+$/;
        const value = cell.v;
        let template;
        if (cell.t === 's' && value !== '%' && percentRegx.test(value)) {
            // 根据小数位数转化为'0.00%'格式,比如一位小数就是'0.0%'
            if (value.indexOf('.') > -1) {
                const percentLength = value.split('.')[1].length;
                template = '0.' + new Array(percentLength - 1).fill(0).join('') + '%';
            } else {
                template = '0%';
            }
            cell.z = template;
            cell.t = 'n';
            cell.v = Number(value.substring(0, value.length - 1)) / 100;
        } else if (!isNaN(Number(value)) && value.length <= 15) {
            // 0开头的数字字符串,比如'001234',不会被转化为数字
            if (excludeNumberRegx.test(value))
                return;
            if (value.indexOf('.') > -1) {
                const percentLength = value.split('.')[1].length;
                template = '0.' + new Array(percentLength).fill(0).join('');
            } else {
                template = '0';
            }
            cell.z = template;
            cell.t = 'n';
        } else if (dateRegx.test(value)) {
            cell.t = 'd';
        }
    });
   
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, sheet, sheetName);
    const workbookBlob = workbook2blob(wb);
    openDownload(workbookBlob, `${fileName}.xlsx`);
}
function openDownload(blob, fileName) {
    if (typeof blob === 'object' && blob instanceof Blob) {
        blob = URL.createObjectURL(blob);
    }
    const aLink = document.createElement('a');
    aLink.href = blob;
    aLink.download = fileName || '';
    const event = new MouseEvent('click');
    aLink.dispatchEvent(event);
}
function workbook2blob(workbook) {
    const wopts = {
        bookType: 'xlsx',
        bookSST: false,
        type: 'binary',
    };
    const wbout = XLSX.write(workbook, wopts);
 
    // 将字符串转ArrayBuffer
    function s2ab(s) {
        const buf = new ArrayBuffer(s.length);
        const view = new Uint8Array(buf);
        for (let i = 0; i !== s.length; ++i)
            view[i] = s.charCodeAt(i) & 0xff;
        return buf;
    }
 
    const blob = new Blob([s2ab(wbout)], {
        type: 'application/octet-stream',
    });
    return blob;
}