/* eslint-disable */ import { saveAs } from 'file-saver' //import * as XLSX from 'xlsx' import * as XLSX from 'xlsx-style' function generateArray(table) { var out = [] var rows = table.querySelectorAll('tr') var ranges = [] for (var R = 0; R < rows.length; ++R) { var outRow = [] var row = rows[R] var columns = row.querySelectorAll('td') for (var C = 0; C < columns.length; ++C) { var cell = columns[C] var colspan = cell.getAttribute('colspan') var rowspan = cell.getAttribute('rowspan') var cellValue = cell.innerText if (cellValue !== '' && cellValue == +cellValue) cellValue = +cellValue //Skip ranges ranges.forEach(function (range) { if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) { for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null) } }) //Handle Row Span if (rowspan || colspan) { rowspan = rowspan || 1 colspan = colspan || 1 ranges.push({ s: { r: R, c: outRow.length }, e: { r: R + rowspan - 1, c: outRow.length + colspan - 1 } }) } //Handle Value outRow.push(cellValue !== '' ? cellValue : null) //Handle Colspan if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null) } out.push(outRow) } return [out, ranges] } /** * * @param {Object} workbook 工作薄 * @param {Object} worksheet 工作表 * @param {Object} cell 单元格 * 标记,引用单元格时所使用的地址格式(如:A1、C7) */ function datenum(v, date1904) { if (date1904) v += 1462 var epoch = Date.parse(v) return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000) } function sheetFromArrayOfArrays(data, opts) { var ws = {} var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } } for (var R = 0; R !== data.length; ++R) { for (var C = 0; C !== data[R].length; ++C) { if (range.s.r > R) range.s.r = R if (range.s.c > C) range.s.c = C if (range.e.r < R) range.e.r = R if (range.e.c < C) range.e.c = C var cell = { v: data[R][C] // v表示单元格原始值, t表示内容类型,s-string类型,n-number类型,b-boolean类型,d-date类型,等等 } if (cell.v == null) continue /** * 通过地址对象 { r: R, c: C } 来获取单元格,R 和 C 分别代表从 0 开始的行和列的索引。 * XLSX.utils 中的 encode_cell/decode_cell 方法可以转换单元格地址 * XLSX.utils.encode_cell({ r: 7, c: 2 }) ===》 C7 */ var cellRef = XLSX.utils.encode_cell({ c: C, r: R }) if (typeof cell.v === 'number') cell.t = 'n' else if (typeof cell.v === 'boolean') cell.t = 'b' else if (cell.v instanceof Date) { cell.t = 'n' cell.z = XLSX.SSF._table[14] cell.v = datenum(cell.v) } else cell.t = 's' ws[cellRef] = cell } } // ws['!ref']:表示所有单元格的范围,例如从A1到F8则记录为A1:F8 if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range) return ws } function sheet_from_array_of_arrays(data, opts) { var ws = {} var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } } for (var R = 0; R != data.length; ++R) { for (var C = 0; C != data[R].length; ++C) { if (range.s.r > R) range.s.r = R if (range.s.c > C) range.s.c = C if (range.e.r < R) range.e.r = R if (range.e.c < C) range.e.c = C var cell = { v: data[R][C] } // 如果单元格所在的值为空,让其值为“” if (cell.v == null) { cell.v = '' } var cell_ref = XLSX.utils.encode_cell({ c: C, r: R }) if (typeof cell.v === 'number') { cell.t = 'n' } else if (typeof cell.v === 'boolean') cell.t = 'b' else if (cell.v instanceof Date) { cell.t = 'n' cell.z = XLSX.SSF._table[14] cell.v = datenum(cell.v) } else { cell.t = 's' } ws[cell_ref] = cell } } if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range) return ws } let fontCellStyle = { font: { name: '宋体', sz: 18, color: { rgb: 'ff0000' }, bold: true }, alignment: { //对齐方式 horizontal: 'center', //水平居中 vertical: 'center' //竖直居中 } } let defaultCellStyle = { alignment: { horizontal: 'center', vertical: 'center', indent: 0 }, border: { diagonalDown: true, //斜线方向 diagonal: { color: { rgb: '303133' }, style: 'thin' } //diagonalDown与diagonal必须同时使用 } } /*自定义表头样式*/ let arr = ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1', 'K1', 'L1', 'M1', 'N1', 'O1', 'P1', 'Q1', 'R1', 'S1', 'T1', 'U1', 'V1', 'W1', 'X1', 'Y1', 'Z1'] let arr1 = ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2', 'K2', 'L2', 'M2', 'N2', 'O2', 'P2', 'Q2', 'R2', 'S2', 'T2', 'U2', 'V2', 'W2', 'X2', 'Y2', 'Z2'] let arr2 = ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3', 'K3', 'L3', 'M3', 'N3', 'O3', 'P3', 'Q3', 'R3', 'S3', 'T3', 'U3', 'V3', 'W3', 'X3', 'Y3', 'Z3'] let style = { font: { color: { rgb: '000000' }, bold: true }, border: { color: { auto: 1 }, top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } }, alignment: { horizontal: 'center', vertical: 'center' }, fill: { fgColor: { rgb: 'DCDFE6' } } } function Workbook() { if (!(this instanceof Workbook)) return new Workbook() this.SheetNames = [] this.Sheets = {} } // 字符串转为ArrayBuffer function s2ab(s) { var buf = new ArrayBuffer(s.length) var view = new Uint8Array(buf) for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF return buf } export function export_table_to_excel(id) { var theTable = document.getElementById(id) var oo = generateArray(theTable) var ranges = oo[1] /* original data */ var data = oo[0] var ws_name = 'SheetJS' var wb = new Workbook() var ws = sheet_from_array_of_arrays(data) /* add ranges to worksheet */ // ws['!cols'] = ['apple', 'banan']; ws['!merges'] = ranges /* add worksheet to workbook */ wb.SheetNames.push(ws_name) wb.Sheets[ws_name] = ws var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' }) saveAs( new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), 'test.xlsx' ) } /** * * @param {Array} multiHeader 多行表头 * @param {Array} header 表头 * @param {Array} data 数据 * @param {String} filename 文件名 * @param {Array} merges 合并单元格 * @param {Boolean} autoWidth 是否设置单元格宽度 * @param {Array} XlsWidth 列宽度数组参数 * @param {String} bookType 要生成的文件类型 */ export function exportJsonToExcel({ multiHeader = [], header, data, filename, merges = [], percent = [], autoWidth = true, bookType = 'xlsx', XlsWidth } = {}) { filename = filename || '导出excel文件' data = [...data] data.unshift(header) for (let i = multiHeader.length - 1; i > -1; i--) { data.unshift(multiHeader[i]) } var wsName = 'SheetJS' var wb = new Workbook() var ws = sheetFromArrayOfArrays(data) if (merges.length > 0) { // ws[!merges]:存放一些单元格合并信息,是一个数组,每个数组由包含s和e构成的对象组成,s表示开始,e表示结束,r表示行,c表示列 if (!ws['!merges']) ws['!merges'] = [] merges.forEach(item => { ws['!merges'].push(XLSX.utils.decode_range(item)) }) } if (autoWidth) { /* 设置worksheet每列的最大宽度 */ const colWidth = data.map(row => row.map(val => { /* 先判断是否为null/undefined */ if (val == null) { return { 'wch': 10 } } else if (val.toString().charCodeAt(0) > 255) { /* 再判断是否为中文 */ return { 'wch': val.toString().length * 2 } } else { return { 'wch': val.toString().length } } })) /* 以第一行为初始值 */ let result = colWidth[0] for (let i = 1; i < colWidth.length; i++) { for (let j = 0; j < colWidth[i].length; j++) { if (result[j] && result[j]['wch'] < colWidth[i][j]['wch']) { result[j]['wch'] = colWidth[i][j]['wch'] } } } // ws['!cols']设置单元格宽度, [{'wch': 10},{'wch': 10}] ===> 第一列和第二列设置了宽度 ws['!cols'] = result ws['!cols'] = XlsWidth; } /* add worksheet to workbook */ wb.SheetNames.push(wsName) wb.Sheets[wsName] = ws var dataInfo = wb.Sheets[wb.SheetNames[0]] // 设置单元格框线 const borderAll = { top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } } // 给所有单元格加上边框,内容居中,字体,字号,标题表头特殊格式部分后面替换 for (var i in dataInfo) { if ( i == '!ref' || i == '!merges' || i == '!cols' || i == '!rows' || i == 'A1' ) {} else { dataInfo[i + ''].s = { border: borderAll, alignment: { horizontal: 'center', vertical: 'center' }, font: { name: '微软雅黑', sz: 12 } } } } const arrabc = [ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ] // 给标题、表格描述信息、表头等部分加上特殊格式 arrabc.some(function(v) { for (let j = 1; j < (data.length + 1); j++) { const _v = v + j if (dataInfo[_v]) { dataInfo[_v].s = {} // 标题部分A1-Z1 dataInfo['A' + j].s = { border: borderAll, font: { name: '微软雅黑', sz: 12, color: { rgb: '000000' }, bold: true }, alignment: { horizontal: 'center', vertical: 'center' } } dataInfo['B' + j].s = { border: borderAll, numFmt: '0', font: { name: '微软雅黑', sz: 12, color: { rgb: '000000' } }, alignment: { horizontal: 'right', vertical: 'center' } } dataInfo[v + j].s = { border: borderAll, numFmt: '0.00', font: { name: '微软雅黑', sz: 12, color: { rgb: '000000' } }, alignment: { horizontal: 'right', vertical: 'center' } } // 头部 if (j == 1) { dataInfo[v + j].s = { border: borderAll, font: { name: '微软雅黑', sz: 18, color: { rgb: '000000' }, bold: true }, alignment: { horizontal: 'center', vertical: 'center' }, fill: { fgColor: { rgb: 'f0f0f0' } } } } // 百分比 % if (percent.length != 0) { for (let index = 0; index < percent.length; index++) { if (j == percent[index]) { dataInfo[v + percent[index]].s = { numFmt: '0.00%', border: borderAll, font: { name: '微软雅黑', sz: 12, color: { rgb: '000000' } }, alignment: { horizontal: 'right', vertical: 'center' }, fill: { fgColor: { rgb: 'FFF8DC' } } } } } } } } }) var wbout = XLSX.write(wb, { bookType: bookType, bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性 type: 'binary' }) saveAs( new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `${filename}.${bookType}` ) } // 主要修改内容在这里 export function export_json_to_excel({ multiHeader = [], header, data, filename, merges = [], percent = [], autoWidth = true, bookType = 'xlsx' } = {}) { /* original data */ filename = filename || 'excel-list' data = [...data] data.unshift(header) for (let i = multiHeader.length - 1; i > -1; i--) { data.unshift(multiHeader[i]) } var ws_name = 'SheetJS' var wb = new Workbook() var ws = sheet_from_array_of_arrays(data) if (merges.length > 0) { if (!ws['!merges']) ws['!merges'] = [] merges.forEach(item => { ws['!merges'].push(XLSX.utils.decode_range(item)) }) } // 设置单元格宽度 if (autoWidth) { /* 设置worksheet每列的最大宽度*/ const colWidth = data.map(row => row.map(val => { /* 先判断是否为null/undefined*/ if (val == null || val == undefined) { return { wch: 20 } } else if (val.toString().charCodeAt(0) > 255) { /* 再判断是否为中文*/ return { wch: val.toString().length * 2 } } else { return { 'wch': val.toString().length * 2 } } }) ) /* 以主表第二行为初始值,因为我的第一行是表格标题,会比较长,所以以主表第二行为初始值*/ const result = colWidth[0] for (let i = 1; i < colWidth.length; i++) { for (let j = 0; j < colWidth[i].length; j++) { if (result[j]['wch'] < colWidth[i][j]['wch']) { result[j]['wch'] = colWidth[i][j]['wch'] } } } ws['!cols'] = result } /* add worksheet to workbook */ wb.SheetNames.push(ws_name) wb.Sheets[ws_name] = ws var dataInfo = wb.Sheets[wb.SheetNames[0]] // 设置单元格框线 const borderAll = { top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } } // 给所有单元格加上边框,内容居中,字体,字号,标题表头特殊格式部分后面替换 for (var i in dataInfo) { if (i == '!ref' || i == '!merges' || i == '!cols' || i == '!rows' || i == 'A1') { } else { dataInfo[i + ''].s = { border: borderAll, alignment: { horizontal: 'center', vertical: 'center' }, font: { name: '微软雅黑', sz: 12 } } } } const arrabc = [ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ] // 给标题、表格描述信息、表头等部分加上特殊格式 arrabc.some(function(v) { for (let j = 1; j < (data.length + 1); j++) { const _v = v + j if (dataInfo[_v]) { dataInfo[_v].s = {} // 标题部分A1-Z1 dataInfo['A' + j].s = { border: borderAll, font: { name: '微软雅黑', sz: 12, color: { rgb: '000000' }, bold: true }, alignment: { horizontal: 'center', vertical: 'center' } } dataInfo[v + j].s = { border: borderAll, numFmt: '0.00', font: { name: '微软雅黑', sz: 12, color: { rgb: '000000' } }, alignment: { horizontal: 'right', vertical: 'center' } } // 头部 if (j == 1) { dataInfo[v + j].s = { border: borderAll, font: { name: '微软雅黑', sz: 13, color: { rgb: '000000' }, bold: true }, alignment: { horizontal: 'center', vertical: 'center' }, fill: { fgColor: { rgb: 'f0f0f0' } } } } // 百分比 % if (percent.length != 0) { for (let index = 0; index < percent.length; index++) { if (j == percent[index]) { dataInfo[v + percent[index]].s = { numFmt: '0.00%', border: borderAll, font: { name: '微软雅黑', sz: 12, color: { rgb: '000000' } }, alignment: { horizontal: 'right', vertical: 'center' }, fill: { fgColor: { rgb: 'FFF8DC' } } } } } } } } }) var wbout = XLSX.write(wb, { bookType: bookType, bookSST: false, type: 'binary' }) saveAs( new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `${filename}.${bookType}` ) } /*二级表头*/ export function export_json_to_excelPro({ multiHeader = [], header, data, filename, merges = [], autoWidth = true, bookType = 'xlsx' } = {}) { /* original data */ filename = filename || 'excel-list' data = [...data] data.unshift(header); for (let i = multiHeader.length - 1; i > -1; i--) { data.unshift(multiHeader[i]) } var ws_name = "SheetJS"; var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); if (merges.length > 0) { if (!ws['!merges']) ws['!merges'] = []; merges.forEach(item => { ws['!merges'].push(XLSX.utils.decode_range(item)) }) } if (autoWidth) { /*设置worksheet每列的最大宽度*/ const colWidth = data.map(row => row.map(val => { /*先判断是否为null/undefined*/ if (val == null) { return { 'wch': 10 }; } /*再判断是否为中文*/ else if (val.toString().charCodeAt(0) > 255) { return { 'wch': val.toString().length * 2 }; } else { return { 'wch': val.toString().length }; } })) /*以第一行为初始值*/ let result = colWidth[0]; for (let i = 1; i < colWidth.length; i++) { for (let j = 0; j < colWidth[i].length; j++) { if (result[j]['wch'] < colWidth[i][j]['wch']) { result[j]['wch'] = colWidth[i][j]['wch']; } } } ws['!cols'] = result; } /* add worksheet to workbook */ wb.SheetNames.push(ws_name); wb.Sheets[ws_name] = ws; var wbout = XLSX.write(wb, { bookType: bookType, bookSST: false, type: 'binary' }); saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), `${filename}.${bookType}`); } /*三级表头的*/ export function export_json_to_excelProPlus({ multiHeader = [], // 第一行表头 multiHeader2 = [], // 第二行表头 header, // 第三行表头 data, filename, //文件名 merges = [], // 合并 autoWidth = true, bookType = 'xlsx' } = {}) { /* original data */ filename = filename || '列表' data = [...data] var ws_name = 'SheetJS' data.unshift(multiHeader) data.unshift(multiHeader2) data.unshift(header) var wb = new Workbook() var ws = sheet_from_array_of_arrays(data) if (merges.length > 0) { if (!ws['!merges']) ws['!merges'] = [] merges.forEach(item => { ws['!merges'].push(XLSX.utils.decode_range(item)) }) } if (autoWidth) { /*设置worksheet每列的最大宽度*/ const colWidth = data.map(row => row.map(val => { /*先判断是否为null/undefined*/ if (val == null) { return { wch: 10 } } else if (val.toString().charCodeAt(0) > 255) { /*再判断是否为中文*/ return { wch: val.toString().length * 2 } } else { return { wch: val.toString().length } } }) ) /*以第一行为初始值*/ let result = colWidth[0] for (let i = 1; i < colWidth.length; i++) { for (let j = 0; j < colWidth[i].length; j++) { if (result[j]['wch'] < colWidth[i][j]['wch']) { result[j]['wch'] = colWidth[i][j]['wch'] } } } ws['!cols'] = result } /* add worksheet to workbook */ wb.SheetNames.push(ws_name) wb.Sheets[ws_name] = ws var dataInfo = wb.Sheets[wb.SheetNames[0]] for (var i = 0; i < multiHeader.length; i++) { dataInfo[arr[i]].s = style } for (var j = 0; j < multiHeader2.length; j++) { dataInfo[arr1[j]].s = style } for (var k = 0; k < header.length; k++) { dataInfo[arr2[k]].s = style } var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' }) saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `${filename}.${bookType}`) }