UNPKG

@sparta-utils/excel-validate-helper

Version:

Excel 读取、校验、错误标注和导出工具库

123 lines (122 loc) 5.3 kB
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' }); } }