exceljs-wrpper-to-excel-export
Version:
A simple Excel export utility using ExcelJS
331 lines (330 loc) • 20.1 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.excelJsWrapperToExcelExport = void 0;
var exceljs_1 = __importDefault(require("exceljs"));
var constants_1 = require("./constants");
var validateConfig = function (config) {
if (!config || !config.columns || config.columns.length === 0) {
throw new Error("Invalid configuration: Columns are missing.");
}
return true;
};
var sanitizeSheetName = function (name) {
return name.replace(/[:\/\\\?\*\[\]]/g, "").slice(0, 31);
};
var AdjustColumnWidth = function (worksheet, columnConfigs, maxColumnWidth) {
worksheet.columns.forEach(function (column) {
//const lengths = column.values.map((v: any) => v.toString().length);
var lengths = column.values.map(function (v) {
return v != null ? v.toString().length : 0; // Use 0 for null/undefined values
});
var columnKey = column.key;
var columnConfig = columnConfigs && columnConfigs.find(function (config) { return config.key === columnKey; });
var maxLength = Math.max.apply(Math, lengths.filter(function (v) { return typeof v === "number"; })) + 3;
// Set column width based on columnConfig or defaultMaxColumnWidth
var maxWidth = (columnConfig === null || columnConfig === void 0 ? void 0 : columnConfig.maxWidth) || maxColumnWidth;
if (maxWidth) {
column.width = maxLength > maxWidth ? maxWidth : maxLength + 3;
}
else {
column.width = maxLength;
}
});
};
// Function to calculate row height based on the content length (text wrapping)
var calculateRowHeight = function (rowValues, columns) {
var maxLines = 1; // Default height for 1 line of text
columns.forEach(function (col) {
var _a, _b, _c;
var cellValue = rowValues[col.key];
if (typeof cellValue === "string" && ((_b = (_a = col.style) === null || _a === void 0 ? void 0 : _a.alignment) === null || _b === void 0 ? void 0 : _b.wrapText)) {
var wrappedLines = Math.ceil(cellValue.length / ((_c = col.width) !== null && _c !== void 0 ? _c : 10)); // Estimate the number of lines after wrapping
maxLines = Math.max(maxLines, wrappedLines); // Adjust maxLines for the row
}
});
var lineHeight = 15; // Approximate height per line of text (in points)
return maxLines * lineHeight;
};
var convertToDate = function (dateString) {
// Extract the timestamp from the string
var timestamp;
timestamp =
dateString && dateString.includes("Date")
? parseInt(dateString.replace(/\/Date\((\d+)\)\//, "$1"))
: dateString;
// Create a new Date object from the timestamp
return timestamp ? new Date(timestamp) : "";
};
// Function to group data by a specified key
var groupBy = function (data, key) {
return data.reduce(function (result, item) {
(result[item[key]] = result[item[key]] || []).push(item);
return result;
}, {});
};
var excelJsWrapperToExcelExport = function (fileName, sheetConfigs) { return __awaiter(void 0, void 0, void 0, function () {
var workbook_1, sheetIndex_1, defSheetName_1, buffer, blob, url, a, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
workbook_1 = new exceljs_1.default.Workbook();
sheetIndex_1 = 0;
defSheetName_1 = "";
sheetConfigs.forEach(function (_a) {
var name = _a.name, config = _a.config, data = _a.data, extraHeaders = _a.extraHeaders;
sheetIndex_1++;
defSheetName_1 = constants_1.constants.defaultSheetPrefix + sheetIndex_1;
var currentRowIndex = 1;
var sheetName = sanitizeSheetName(name ? name : defSheetName_1);
// Validate configuration
validateConfig(config);
var worksheet = workbook_1.addWorksheet(sheetName);
// *** Extra Headers Region ***
// Add Extra Headers (if any)
if (extraHeaders) {
extraHeaders.forEach(function (extraHeader, rowIndex) {
// Add the extra header row with empty values
var row = worksheet.addRow([]);
// Merge cells based on mergeAcross array if provided
if (extraHeader.mergeAcross) {
var currentCol_1 = 1; // Start from the first column
//length of extraHeader.values should equals to extraHeader.mergeAcross.lenght
extraHeader.mergeAcross.forEach(function (mergeCount, valueIndex) {
var startCol = currentCol_1;
var endCol = startCol + mergeCount - 1;
// Set value in the starting column only
var cell = worksheet.getCell(rowIndex + 1, startCol);
cell.value = extraHeader.values[valueIndex];
// Merge the cells for the current value
worksheet.mergeCells(rowIndex + 1, startCol, rowIndex + 1, endCol);
// Move to the next column
currentCol_1 = endCol + 1;
});
}
// Apply styles to the row if provided
if (extraHeader.style) {
row.eachCell(function (cell) {
if (extraHeader.style)
cell.style = extraHeader.style;
});
}
// Move to the next row for column headers
currentRowIndex++;
});
}
// *** END Extra Headers Region ***
// *** Set Column configurations Region ***
// Add Column Headers
worksheet.columns = config.columns.map(function (col) { return ({
// header: col.header,
key: col.key,
width: col.width || 15,
style: col.style,
}); });
// Add Column Headers explicitly (in case styles/extra formatting are needed)
var headerRow = worksheet.getRow(currentRowIndex);
config.columns.forEach(function (col, colIndex) {
var cell = headerRow.getCell(colIndex + 1);
cell.value = col.header;
if (col.headerStyle) {
cell.style = col.headerStyle; // Apply individual column header styles
}
});
// Move to the next row for data after headers
currentRowIndex++;
// *** END Set Column configurations Region ***
// *** groupBy Region ***
if (config.groupBy) {
// Group the data by the specified key
var groupedData_1 = groupBy(data, config.groupBy);
// Add rows for each group and calculate group sums
Object.keys(groupedData_1).forEach(function (groupKey) {
var _a;
// Insert group header row
if (config.groupHeaderRow) {
var groupHeaderRow = worksheet.addRow([
"".concat(config.groupBy, ": ").concat(groupKey),
]);
groupHeaderRow.font = { bold: true };
}
// Insert rows for the group data
groupedData_1[groupKey].forEach(function (item) {
var row = config.columns.reduce(function (acc, col) {
acc[col.key] = item[col.key];
return acc;
}, {});
worksheet.addRow(row);
});
// Calculate and add the group total row
var lastGroupRowNumber = ((_a = worksheet.lastRow) === null || _a === void 0 ? void 0 : _a.number) || 1;
var groupSumRow = {};
config.columns.forEach(function (col, index) {
if (col.sum) {
var columnLetter = worksheet.getColumn(index + 1).letter; // Get Excel column letter (A, B, C)
groupSumRow[col.key] = {
formula: "SUM(".concat(columnLetter).concat(lastGroupRowNumber - groupedData_1[groupKey].length + 1, ":").concat(columnLetter).concat(lastGroupRowNumber, ")"),
};
}
else {
groupSumRow[col.key] = ""; // No sum for this column
}
});
// Add the group sum row
var newGroupSumRow = worksheet.addRow(groupSumRow);
newGroupSumRow.font = { bold: true }; // Make the sum row bold for distinction
// Apply style to group sum row
if (config.groupSumRowStyle) {
newGroupSumRow.eachCell(function (cell) {
if (config.groupSumRowStyle)
cell.style = config.groupSumRowStyle;
});
}
// Add a label "Total" in the first column of the sum row
var groupTotalLableCell = config.groupTotalLableCell
? config.groupTotalLableCell
: constants_1.constants.groupTotalLableCell;
worksheet.getCell("".concat(groupTotalLableCell).concat(newGroupSumRow.number)).value = config.groupTotalLable
? config.groupTotalLable
: constants_1.constants.groupTotalLable;
});
// *** END groupBy Region ***
}
else {
// *** Append Simple/Normal Data Region ***
data.forEach(function (item, rowIndex) {
var row = {};
config.columns.forEach(function (col, colIndex) {
try {
if (col.formula) {
// Replace any placeholders in formula (e.g., {row}, {column}, etc.)
var columnLetter = worksheet.getColumn(colIndex + 1).letter; // Get Excel column letter (A, B, C)
var formula = col.formula
.replace(/\{row\}/g, (rowIndex + currentRowIndex).toString()) // Replace {row} with actual row number
.replace(/\{column\}/g, columnLetter); // Replace {column} with column letter
// Assign the complex formula to the cell
row[col.key] = { formula: formula };
}
else if (col.type && col.type.toLowerCase() == "date") {
var datevalue = convertToDate(item[col.key]);
// Create a new Date object from the timestamp and set it to cell value
row[col.key] = datevalue;
worksheet.getColumn(colIndex + 1).numFmt = col.dateFormat
? col.dateFormat
: constants_1.constants.defaultDateFormat;
}
else {
row[col.key] = item[col.key];
}
}
catch (error) {
console.error("".concat(constants_1.constants.messges.formulaErrorMessage, " ").concat(col.key, ":"), error);
row[col.key] = null;
}
});
worksheet.addRow(row);
});
// *** END Append Simple/Normal Data Region ***
// *** Merge vertically consecutive duplicate values for columns with mergeDuplicateRows: true ***
config.columns.forEach(function (col, colIndex) {
if (col.mergeDuplicateRows) {
// Find the first data row and last data row
var firstDataRow = currentRowIndex;
var lastDataRow = worksheet.lastRow
? worksheet.lastRow.number
: firstDataRow - 1;
var startRow = firstDataRow;
var prevValue = worksheet
.getRow(startRow)
.getCell(colIndex + 1).value;
for (var rowNum = firstDataRow + 1; rowNum <= lastDataRow + 1; rowNum++) {
var cellValue = rowNum <= lastDataRow
? worksheet.getRow(rowNum).getCell(colIndex + 1).value
: null;
if (cellValue !== prevValue) {
if (rowNum - startRow > 1 &&
prevValue !== null &&
prevValue !== undefined &&
prevValue !== "") {
worksheet.mergeCells(startRow, colIndex + 1, rowNum - 1, colIndex + 1);
// Set vertical alignment to top for the merged cell
var mergedCell = worksheet.getCell(startRow, colIndex + 1);
mergedCell.alignment = Object.assign({}, mergedCell.alignment, { vertical: "top" });
}
startRow = rowNum;
prevValue = cellValue;
}
}
}
});
// *** END Merge vertically consecutive duplicate values ***
}
// *** Auto Adjust Columns Width Region ***
if (config.autoAdjustColumnsWidth)
AdjustColumnWidth(worksheet, config.columns, config.maxColumnWidth);
});
return [4 /*yield*/, workbook_1.xlsx.writeBuffer()];
case 1:
buffer = _a.sent();
if (!buffer) {
throw new Error(constants_1.constants.messges.bufferErrorMessage);
}
blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
url = window.URL.createObjectURL(blob);
a = document.createElement("a");
a.href = url;
a.download = fileName ? fileName : constants_1.constants.defaultFileName;
a.click();
window.URL.revokeObjectURL(url);
return [3 /*break*/, 3];
case 2:
error_1 = _a.sent();
console.error(constants_1.constants.messges.consolErrorMessage, error_1);
alert(constants_1.constants.messges.defaultErrorMessage);
return [3 /*break*/, 3];
case 3: return [2 /*return*/];
}
});
}); };
exports.excelJsWrapperToExcelExport = excelJsWrapperToExcelExport;
;