@sparta-utils/excel-validate-helper
Version:
Excel 读取、校验、错误标注和导出工具库
123 lines (122 loc) • 5.3 kB
JavaScript
import ExcelJS from 'exceljs';
const DEFAULT_MARKER_OPTIONS = {
defaultNote: '数据错误',
outputType: 'note',
sheetName: '',
errorColumnTitle: '错误信息',
allowMultiSheet: false,
errorColumnIndex: 0
};
const LEVEL_STYLES = {
error: {
font: { color: { argb: 'FFFF0000' }, bold: true },
fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFC7CE' } },
border: createBorder('FFFF0000')
},
warning: {
font: { color: { argb: 'FF996600' }, bold: true },
fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFEB9C' } },
border: createBorder('FF996600')
},
info: {
font: { color: { argb: 'FF0000FF' }, italic: true },
fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFC6EFCE' } },
border: createBorder('FF0000FF')
}
};
function createBorder(argb) {
return {
top: { style: 'thin', color: { argb } },
left: { style: 'thin', color: { argb } },
bottom: { style: 'thin', color: { argb } },
right: { style: 'thin', color: { argb } }
};
}
function mergeStyle(custom, defaults) {
return Object.assign(Object.assign({}, defaults), custom);
}
function applyCellStyle(cell, level, customStyle) {
const base = LEVEL_STYLES[level] || LEVEL_STYLES.error;
cell.style = {
// @ts-ignore some explanation ← ❌ 不会生效
font: mergeStyle(customStyle === null || customStyle === void 0 ? void 0 : customStyle.font, base.font),
alignment: mergeStyle(customStyle === null || customStyle === void 0 ? void 0 : customStyle.alignment, {
vertical: 'middle',
horizontal: 'center'
}),
// @ts-ignore some explanation ← ❌ 不会生效
fill: mergeStyle(customStyle === null || customStyle === void 0 ? void 0 : customStyle.fill, base.fill),
// @ts-ignore some explanation ← ❌ 不会生效
border: mergeStyle(customStyle === null || customStyle === void 0 ? void 0 : customStyle.border, base.border)
};
}
function addNote(cell, note) {
cell.note = note;
}
function getOrCreateWorksheet(workbook, name) {
if (!name)
return workbook.worksheets[0];
return workbook.getWorksheet(name) || workbook.addWorksheet(name);
}
function writeErrorColumn(worksheet, errorMap, colIndex, title) {
const header = worksheet.getRow(1);
header.getCell(colIndex).value = title;
header.getCell(colIndex).font = { bold: true, color: { argb: 'FFFF0000' } };
const errorCol = worksheet.getColumn(colIndex);
errorCol.width = 50;
for (const [rowNum, messages] of errorMap.entries()) {
const cell = worksheet.getRow(rowNum).getCell(colIndex);
cell.value = messages.join('\n');
cell.alignment = { wrapText: true, vertical: 'middle' };
cell.font = { color: { argb: 'FF990000' }, italic: true };
}
}
export class ExcelMarker {
static async markErrors(file, errors, options) {
var _a, _b;
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(await file.arrayBuffer());
const opts = Object.assign(Object.assign({}, DEFAULT_MARKER_OPTIONS), options);
const groupBySheet = new Map();
for (const error of errors) {
const sheetKey = opts.allowMultiSheet
? error.sheetName || opts.sheetName
: opts.sheetName;
if (!groupBySheet.has(sheetKey))
groupBySheet.set(sheetKey, []);
groupBySheet.get(sheetKey).push(error);
}
for (const [sheetName, sheetErrors] of groupBySheet.entries()) {
const sheet = getOrCreateWorksheet(workbook, sheetName);
const originalColCount = sheet.columnCount;
const errMap = new Map();
for (const err of sheetErrors) {
if (err.row <= 0 || err.col <= 0)
continue;
const level = (_a = err.level) !== null && _a !== void 0 ? _a : 'error';
const reason = err.reason || opts.defaultNote;
const row = sheet.getRow(err.row);
const cell = row.getCell(err.col);
if (cell.value == null)
cell.value = '';
if (opts.outputType === 'note' || opts.outputType === 'both') {
addNote(cell, reason);
}
if (opts.outputType === 'column' || opts.outputType === 'both') {
const existing = (_b = errMap.get(err.row)) !== null && _b !== void 0 ? _b : [];
existing.push(`列 ${err.col}(${level}):${reason}`);
errMap.set(err.row, existing);
}
applyCellStyle(cell, level, opts.style);
}
if (opts.outputType === 'column' || opts.outputType === 'both') {
const writeIndex = opts.errorColumnIndex || originalColCount + 1;
writeErrorColumn(sheet, errMap, writeIndex, opts.errorColumnTitle);
}
}
const buffer = await workbook.xlsx.writeBuffer();
return new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
}
}