/**
* 通用Excel导出工具
* 支持根据配置动态生成Excel文件,可自定义样式、格式和内容
*/
/*
使用方法
import { UniversalExcelExporter, exportExcel } from './universalExcelExport.js';
// 示例数据
const data = {
sheet1: {
headers: ['headers1', 'headers2', 'headers3', 'headers4'],
data: [
['data1', 'data2', data3, data4],
]
},
};
// 方法一:使用类方式
async function exportWithClass() {
try {
const exporter = new UniversalExcelExporter();
exporter.addSheet({
name: '销售数据', // 工作表名称
headers: data.sheet1.headers,
data: data.sheet1.data,
options: {
addTotalRow: true,
totalColumns: [2, 3], // 合计销售额和利润列
columnWidths: [15, 15, 15, 15],
style: {
header: { fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCCCCC' } } },
totalRow: { fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFEEEEEE' } } }
}
}
});
await exporter.export('导出文件名.xlsx');
console.log('导出成功');
} catch (error) {
console.error('导出失败:', error);
}
}
// 方法二:使用简化函数
async function exportWithFunction() {
try {
await exportExcel({
fileName: '导出文件名.xlsx',
sheets: [
{
headers: data.sheet1.headers,
data: data.sheet1.data,
data: data.sales.data,
options: {
addTotalRow: true,
totalColumns: [2, 3],
columnWidths: [15, 15, 15, 15],
style: {
header: { font: { bold: true, color: { argb: 'FFFFFFFF' } }, fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF5B9BD5' } } },
cells: (value, rowIndex, colIndex) => {
// 根据条件设置单元格样式
if (colIndex === 2 && value > 10000) {
return { font: { color: { argb: 'FF008000' } } };
}
return {};
}
}
}
}
]
});
console.log('导出成功');
} catch (error) {
console.error('导出失败:', error);
}
}
*/
import Excel from 'exceljs';
export class UniversalExcelExporter {
constructor() {
if(!Excel) {
throw new Error('ExcelJS库未加载,请先引入ExcelJS库');
}
this.workbook = new Excel.Workbook();
}
/**
* 添加工作表
* @param {Object} sheetConfig - 工作表配置
* @param {string} sheetConfig.name - 工作表名称
* @param {Array} sheetConfig.headers - 表头配置
* @param {Array} sheetConfig.data - 表格数据
* @param {Object} [sheetConfig.options] - 可选配置
* @param {boolean} [sheetConfig.options.addTotalRow] - 是否添加合计行
* @param {Array<string>} [sheetConfig.options.totalRowLabels] - 合计行标签
* @param {Array<number>} [sheetConfig.options.totalColumns] - 需要合计的列索引
* @param {Array<number>} [sheetConfig.options.columnWidths] - 列宽配置
* @param {Object} [sheetConfig.options.style] - 样式配置
* @param {Object} [sheetConfig.options.style.mergeCells] - 合并单元格配置
* @returns {UniversalExcelExporter} - 支持链式调用
*/
addSheet(sheetConfig) {
const { name, headers, data, options = {} } = sheetConfig;
if(!name || !headers || !Array.isArray(headers) || headers.length === 0) {
console.warn('工作表配置不完整,跳过此工作表');
return this;
}
const sheet = this.workbook.addWorksheet(name);
// 添加表头
const headerRow = sheet.addRow(headers);
this._applyCellStyle(headerRow, {
font: { bold: true },
alignment: { horizontal: 'center' },
...options.style?.header,
});
// 添加数据
if(data && Array.isArray(data) && data.length > 0) {
data.forEach((rowData, rowIndex) => {
const row = sheet.addRow(rowData);
// 应用行样式(如果有)
if(options.style?.rows) {
const rowStyle = typeof options.style.rows === 'function'
? options.style.rows(rowData, rowIndex)
: options.style.rows;
this._applyCellStyle(row, rowStyle);
}
// 应用单元格样式(如果有)
if(options.style?.cells) {
row.eachCell((cell, colIndex) => {
const cellStyle = typeof options.style.cells === 'function'
? options.style.cells(cell.value, rowIndex, colIndex)
: options.style.cells;
this._applyCellStyle(cell, cellStyle);
});
}
});
}
// 添加合计行
if(options.addTotalRow && options.totalColumns && options.totalColumns.length > 0) {
const totalRowData = new Array(headers.length).fill('');
// 设置合计行标签
if(options.totalRowLabels && options.totalRowLabels.length > 0) {
options.totalRowLabels.forEach((label, index) => {
if(index < totalRowData.length) {
totalRowData[index] = label;
}
});
}
else {
totalRowData[0] = '合计';
}
// 计算合计值
options.totalColumns.forEach(colIndex => {
if(colIndex < headers.length) {
const columnLetter = this._getColumnLetter(colIndex + 1); // 转为Excel列字母
const lastDataRow = data ? data.length + 1 : 1;
totalRowData[colIndex] = {
formula: `SUM(${columnLetter}2:${columnLetter}${lastDataRow})`,
result: this._calculateColumnSum(sheet, colIndex + 1),
};
}
});
// 添加合计行并应用样式
const totalRow = sheet.addRow(totalRowData);
this._applyCellStyle(totalRow, {
font: { bold: true },
...options.style?.totalRow,
});
}
// 设置列宽
if(options.columnWidths && options.columnWidths.length > 0) {
options.columnWidths.forEach((width, index) => {
if(index < sheet.columns.length) {
sheet.columns[index].width = width;
}
});
}
// 合并单元格
if(options.mergeCells && Array.isArray(options.mergeCells)) {
options.mergeCells.forEach(mergeRange => {
try {
sheet.mergeCells(mergeRange);
}
catch(error) {
console.warn(`合并单元格失败: ${mergeRange}`, error);
}
});
}
return this;
}
/**
* 导出Excel文件
* @param {string} fileName - 导出的文件名
* @returns {Promise} - 导出操作的Promise
*/
async export(fileName = 'ExportedExcel.xlsx') {
if(this.workbook.worksheets.length === 0) {
throw new Error('Excel文件至少需要一个工作表');
}
try {
const buffer = await this.workbook.xlsx.writeBuffer();
this._downloadFile(buffer, fileName);
return true;
}
catch(error) {
console.error('导出Excel失败:', error);
throw error;
}
}
/**
* 应用单元格样式
* @private
*/
_applyCellStyle(target, style) {
if(!style || typeof style !== 'object') return;
if(target.eachCell) {
// 针对整行应用样式
target.eachCell(cell => {
Object.assign(cell, style);
});
}
else {
// 针对单个单元格应用样式
Object.assign(target, style);
}
}
/**
* 计算列的合计值
* @private
*/
_calculateColumnSum(sheet, columnIndex) {
let sum = 0;
sheet.eachRow((row, rowIndex) => {
if(rowIndex > 1) { // 跳过表头
const cell = row.getCell(columnIndex);
const value = parseFloat(cell.value);
if(!isNaN(value)) {
sum += value;
}
}
});
return sum;
}
/**
* 将列索引转换为Excel列字母
* @private
*/
_getColumnLetter(columnIndex) {
let letter = '';
let tempIndex = columnIndex;
while(tempIndex > 0) {
const remainder = (tempIndex - 1) % 26;
letter = String.fromCharCode(65 + remainder) + letter;
tempIndex = Math.floor((tempIndex - 1) / 26);
}
return letter;
}
/**
* 下载文件
* @private
*/
_downloadFile(buffer, fileName) {
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = fileName;
link.click();
// 清理资源
setTimeout(() => {
URL.revokeObjectURL(link.href);
}, 100);
}
}
/**
* 简化的导出函数
* @param {Object} options - 导出选项
* @param {Array} options.sheets - 工作表配置数组
* @param {string} options.fileName - 文件名
* @returns {Promise} - 导出操作的Promise
*/
export async function exportExcel(options = {}) {
try {
const exporter = new UniversalExcelExporter();
if(!options.sheets || !Array.isArray(options.sheets) || options.sheets.length === 0) {
throw new Error('至少需要配置一个工作表');
}
options.sheets.forEach(sheet => {
exporter.addSheet(sheet);
});
return await exporter.export(options.fileName || 'ExportedExcel.xlsx');
}
catch(error) {
console.error('导出Excel失败:', error);
throw error;
}
}
浙公网安备 33010602011771号