@sparta-utils/excel-validate-helper
Version:
Excel 读取、校验、错误标注和导出工具库
530 lines (454 loc) • 22.3 kB
Markdown
# @sparta-utils/excel-validate-helper
Excel 读取、校验、错误标注和导出工具库,基于 [exceljs](https://github.com/exceljs/exceljs)。
## 目录
- [安装](#安装)
- [包中方法介绍](#包中方法介绍)
- [使用示例](#使用示例)
- [单独使用某方法示例](#单独使用某方法示例)
- [全部方法联合使用示例](#全部方法联合使用示例)
---
## 安装
你可以通过 npm 或 yarn 直接安装本库:
```bash
npm install @sparta-utils/excel-validate-helper
# 或
yarn add @sparta-utils/excel-validate-helper
```
## 使用示例
```ts
import {
ExcelReader,
ExcelValidator,
ExcelMarker,
ExcelExporter
} from '@sparta-utils/excel-validate-helper';
async function processExcel(file: File) {
// 1. 读取文件
const = await ExcelReader.read(file, 4);
const { headers, data } = await ExcelReader.read(file, {
dataStartRow: 4,
sheetIndex: 0,
onProgress: (progress) => {
console.log(`读取进度:${progress}%`)
},
mapHeaders: (header) => header.trim(),
filterEmptyRows: true, // 过滤空行
progressStep: 5, // 进度5%通知一次
})
console.log('表头:', headers);
console.log('数据:', data);
// 2. 校验数据
const result = ExcelValidator.validate(data, {
colHeaders: ['姓名', '身份证', '手机号', '年龄', '邮箱'],
fieldNames: ['name', 'idCard', 'phone', 'age', 'email'],
rules: {
0: { required: true },
1: { required: true, pattern: ExcelValidator.getPredefinedPattern('idCard') },
2: { pattern: ExcelValidator.getPredefinedPattern('phone') },
3: { type: 'number', min: 18, max: 65 },
4: { pattern: ExcelValidator.getPredefinedPattern('email') }
},
uniqueGroupCols: [1, 2], // 身份证 + 手机号联合唯一
onProgress: (current, total) => {
console.log(`校验进度: ${current}/${total}`)
}
})
if (result.err.length) {
console.warn('校验失败:', result.err);
// 3. 标注错误
// const errors: CellError[] = [
// { row: 2, col: 3, reason: '缺失必填项', level: 'error' },
// { row: 3, col: 2, reason: '数值超限', level: 'warning' },
// { row: 4, col: 5, reason: '格式建议', level: 'info' },
// { row: 6, col: 1, reason: '跨 Sheet 错误', sheetName: 'Sheet2' }
// ]
const errors: CellError[] = result.err
const options = {
outputType: 'both', //错误输出方式(默认 note)
allowMultiSheet: true, // 是否支持多sheet标记
errorColumnTitle: '数据校验信息', // 错误信息列标题
errorColumnIndex: 10 // 错误信息输入的列,不传则默认最后一列
}
const markedBlob = await ExcelMarker.markErrors(file, errors, options)
// 4. 导出带标注的Excel
ExcelExporter.export(markedBlob, {
fileName: '错误标注.xlsx',
format: 'xlsx',
onSuccess: () => {
console.log('✅ 文件导出成功')
},
onError: (err) => {
console.error('❌ 导出失败', err)
},
onProgress: (progress) => {
console.log(`进度:${progress}%`)
}
})
} else {
console.log('校验通过,数据:', result.succ);
// 继续业务逻辑处理 result.succ
}
}
```
## 包中方法介绍
- 本包导出了四个核心类:
## 1. ExcelReader
---
`ExcelReader` 是一个基于 [ExcelJS](https://github.com/exceljs/exceljs) 的前端 Excel 读取工具类,支持读取 `.xlsx` 文件,灵活配置数据起始行、工作表索引、进度回调、数据映射与空行过滤,方便你快速将 Excel 文件转换为结构化数据,适合用于表格导入、数据展示等场景。
- 快速使用示例
```ts
import { ExcelReader } from './ExcelReader'
const fileInput = document.getElementById('fileInput') as HTMLInputElement
fileInput.addEventListener('change', async () => {
const file = fileInput.files?.[0]
if (!file) return
try {
const result = await ExcelReader.read(file, {
dataStartRow: 4,
sheetIndex: 0,
onProgress: (progress) => {
console.log(`读取进度:${progress}%`)
},
mapHeaders: (header) => header.trim(),
mapRow: (row) => row.map(cell => (typeof cell === 'string' ? cell.trim() : cell)),
filterEmptyRows: true,
progressStep: 5,
})
console.log('读取完成:', result)
} catch (error) {
console.error('读取出错:', error)
}
})
```
# 参数说明
| 参数名 | 类型 | 说明 | 默认值 |
| ----------------- | ---------------------------- | ---------------------------------------------------- | ---- |
| `dataStartRow` | `number` | 数据开始行,Excel 中第几行开始读取数据,前一行为表头。例如4表示第4行开始读取数据(第3行为表头) | 4 |
| `sheetIndex` | `number` | 读取第几个工作表,索引从0开始 | 0 |
| `onProgress` | `(progress: number) => void` | 读取进度回调,参数为百分比,例如50表示完成一半 | 无 |
| `mapHeaders` | `(header: string) => string` | 表头映射函数,用于对表头字符串进行自定义处理,如去除空格、大小写转换 | 无 |
| `mapRow` | `(row: any[]) => any[]` | 行数据映射函数,用于对每行数据做转换处理,如去除单元格空格、类型转换等 | 无 |
| `filterEmptyRows` | `boolean` | 是否过滤全为空的行,避免读取无效数据行 | true |
| `progressStep` | `number` | 进度回调的最小步长,避免频繁触发回调 | 5 |
- 返回结果
函数返回一个 Promise,resolve 一个对象,结构如下:
```ts
interface ExcelReadResult {
headers: string[] // 读取的表头字段数组,顺序对应数据列
data: any[][] // 读取的数据二维数组,每一行为一条数据,首列是 Excel 行号
totalRows: number // 当前工作表总行数
sheetName: string // 当前读取的工作表名称
fileName: string // 上传的 Excel 文件名
}
```
- mapHeaders 使用示例及功能
mapHeaders 是一个函数,用于对 Excel 表头字符串进行处理。它接受一个字符串参数(当前表头文本),返回一个字符串(处理后的表头)。
常见用法包括:
去除表头两端空白字符
替换或重命名表头字段
转换为驼峰命名或小写
示例:
```ts
const mapHeaders = (header: string): string => {
// 去空格并转为小写驼峰
return header.trim().replace(/\s+(\w)/g, (_, c) => c.toUpperCase())
}
示例应用:
const result = await ExcelReader.read(file, {
mapHeaders,
})
console.log(result.headers)
```
- mapRow 使用示例及功能
mapRow 是一个函数,用于对读取的每行数据进行自定义处理。它接受一个数组参数(该行所有单元格数据,不含行号),返回一个处理后的数组。
常见用法包括:
去除每个单元格字符串的空白字符
类型转换,比如将数字字符串转换为数字
日期格式化
数据校验和修正
示例:
```ts
const mapRow = (row: any[]): any[] => {
return row.map(cell => {
if (typeof cell === 'string') {
return cell.trim()
}
if (typeof cell === 'number') {
return cell
}
// 你也可以增加对日期、布尔值等特殊处理
return cell
})
}
示例应用:
const result = await ExcelReader.read(file, {
mapRow,
})
console.log(result.data)
```
## 2. ExcelValidator
---
一个功能强大且灵活的 Excel 数据校验工具,支持常用验证规则、列唯一、组合列唯一、自定义规则等。易用且向下兼容,适合日常 Excel 数据导入校验场景。
# 功能特点:
- 支持必填项、数字范围、邮箱、手机号、身份证等常用规则校验
- 支持单列唯一校验
- 支持组合列唯一校验(多列拼接判断唯一)
- 支持自定义正则表达式规则
- 支持自定义函数校验
- 数字类型自动 `trim` + 转换成数字
- 验证错误定位准确,支持 Excel 行号(从1开始)、列号(从0开始)
- 进度回调支持大数据场景
# API 参数说明
| 参数名 | 类型 | 说明 |
| ----------------- | --------------------------------------- | ----------------------- |
| `colHeaders` | `string[]` | Excel 列标题,用于错误提示 |
| `fieldNames` | `string[]` | 字段映射,用于生成结果对象 |
| `rules` | `Record<number, ColumnRule>` | 校验规则集合,key 是列索引 |
| `uniqueGroupCols` | `number[]` | 组合唯一校验列索引数组,列值拼接做唯一性检查 |
| `startRowIndex` | `number` | 起始行号(默认2),对应 Excel 实际行号 |
| `onProgress` | `(curr: number, total: number) => void` | 校验进度回调 |
- 校验规则 ColumnRule 说明
| 属性 | 类型 | 说明 |
| ---------- | ----------------------------------------------------------------- | ---------------------------------------- |
| `required` | `boolean` | 是否必填 |
| `type` | `'string' \| 'number' \| 'boolean' \| 'date'` | 数据类型,number 会自动 trim 和转数字 |
| `pattern` | `RegExp` | 自定义正则表达式校验 |
| `min` | `number` | 数字类型最小值 |
| `max` | `number` | 数字类型最大值 |
| `unique` | `boolean` | 该列是否要求唯一(全表) |
| `custom` | `(val: any, row: any[], rowIndex: number) => string \| undefined` | 自定义校验函数,返回错误信息表示校验失败,返回 `undefined` 表示通过 |
- 内置常用正则模板
可以通过 ExcelValidator.getPredefinedPattern(name) 获取,支持:
| 名称 | 说明 |
| -------- | ----- |
| `idCard` | 身份证号码 |
| `phone` | 手机号码 |
| `tel` | 固话号码 |
| `email` | 邮箱地址 |
- 使用示例
```ts
const result = ExcelValidator.validate(data, {
colHeaders: ['姓名', '身份证', '手机号', '年龄', '邮箱'],
fieldNames: ['name', 'idCard', 'phone', 'age', 'email'],
rules: {
0: { required: true },
1: { required: true, pattern: ExcelValidator.getPredefinedPattern('idCard') },
2: { pattern: ExcelValidator.getPredefinedPattern('phone') },
3: { type: 'number', min: 18, max: 65 },
4: { pattern: ExcelValidator.getPredefinedPattern('email') }
},
uniqueGroupCols: [1, 2], // 身份证 + 手机号联合唯一
onProgress: (current, total) => {
console.log(`校验进度: ${current}/${total}`)
}
})
1. 基础规则配置示例
const rules = {
0: { required: true }, // 姓名必填
1: { required: true, pattern: ExcelValidator.getPredefinedPattern('idCard') }, // 身份证必填且格式正确
2: { pattern: ExcelValidator.getPredefinedPattern('phone') }, // 手机号格式校验
3: { type: 'number', min: 18, max: 60 }, // 年龄数字范围校验
4: { pattern: ExcelValidator.getPredefinedPattern('email') } // 邮箱格式校验
}
2. 单列唯一校验
const rules = {
1: { unique: true } // 身份证号列唯一
}
3. 组合列唯一校验
const uniqueGroupCols = [1, 2] // 身份证 + 手机号 联合唯一
4. 自定义正则表达式
const rules = {
5: { pattern: /^[A-Z]{3}\d{4}$/ } // 第6列必须是3个大写字母+4个数字
}
5. 自定义函数校验
const rules = {
3: {
custom: (val, row, rowIndex) => {
if (val < 0 || val > 100) return '数值必须在0到100之间'
if (row[0] === '特殊标记' && val < 50) return '特殊标记项最小值为50'
return undefined
}
}
}
返回结果结构
{
err: CellError[], // 错误列表,每条包括 Excel 行号、列号及错误原因
succ: any[] // 解析成功后的对象数组,字段名对应 fieldNames 配置
}
```
---
## 3. ExcelMarker
---
ExcelMarker 是一个基于 [ExcelJS](https://github.com/exceljs/exceljs) 的轻量级工具类,用于在 Excel 文件中标注错误单元格、批注或添加错误列信息,支持错误等级样式、跨 Sheet 标注、灵活输出方式等。
- ✨ 功能特性
- ✅ 支持单元格错误标注:添加批注、修改样式
- ✅ 支持错误等级样式(error/warning/info)
- ✅ 支持在额外列中记录每行错误信息
- ✅ 支持不同 Sheet 多处错误标注
- ✅ 支持自定义“错误列”插入位置
- ✅ 支持批注(note)、错误列(column)、或二者同时输出(both)
- 📚 API 使用说明
ExcelMarker.markErrors(file, errors, options?)
参数说明
| 参数 | 类型 | 必填 | 说明 |
| --------- | --------------- | -- | ------------------------ |
| `file` | `File` | ✅ | 待处理的 Excel 文件对象(`.xlsx`) |
| `errors` | `CellError[]` | ✅ | 错误信息数组,包含具体行列、等级、原因等 |
| `options` | `MarkerOptions` | ❌ | 标注配置项,详见下方 |
CellError 类型定义
```ts
interface CellError {
row: number // 行号(从 1 开始)
col: number // 列号(从 1 开始)
reason?: string // 错误原因(默认显示 defaultNote)
level?: 'error' | 'warning' | 'info' // 错误等级(默认 error)
sheetName?: string // 错误所在 sheet 名(需开启 allowMultiSheet)
}
```
MarkerOptions 类型定义
```ts
interface MarkerOptions {
style?: CellStyle // 自定义样式覆盖默认错误样式
defaultNote?: string // 当错误无 reason 时的默认批注内容
outputType?: 'note' | 'column' | 'both' // 错误输出方式(默认 note)
sheetName?: string // 默认工作表名称(若未指定 error.sheetName)
errorColumnTitle?: string // 错误列标题(默认 "错误信息")
allowMultiSheet?: boolean // 是否允许跨 Sheet 标注(默认 false)
errorColumnIndex?: number // 错误列插入位置(默认追加在最后)
}
```
CellStyle(可选样式覆盖)
```ts
interface CellStyle {
font?: Partial<ExcelJS.Font>
alignment?: Partial<ExcelJS.Alignment>
fill?: Partial<ExcelJS.Fill>
border?: Partial<ExcelJS.Borders>
}
```
- 🧪 示例代码
```ts
import { ExcelMarker, CellError } from './ExcelMarker'
const file = fileInput.files[0] // 来自 <input type="file" />
const errors: CellError[] = [
{ row: 2, col: 3, reason: '缺失必填项', level: 'error' },
{ row: 3, col: 2, reason: '数值超限', level: 'warning' },
{ row: 4, col: 5, reason: '格式建议', level: 'info' },
{ row: 6, col: 1, reason: '跨 Sheet 错误', sheetName: 'Sheet2' }
]
const options = {
outputType: 'both',
allowMultiSheet: true,
errorColumnTitle: '数据校验信息',
errorColumnIndex: 10
}
ExcelMarker.markErrors(file, errors, options).then(blob => {
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = '标注后的数据.xlsx'
link.click()
URL.revokeObjectURL(url)
})
```
- 🎨 错误等级样式说明
| Level | 背景色 | 字体颜色 | 描述 |
| --------- | ------------- | --------- | ---- |
| `error` | `#FFC7CE`(红) | `#FF0000` | 严重错误 |
| `warning` | `#FFEB9C`(黄) | `#996600` | 警告提示 |
| `info` | `#C6EFCE`(蓝绿) | `#0000FF` | 信息提示 |
你可以通过 style 参数进一步自定义颜色、边框、对齐方式等样式细节。
- 🛠 依赖
ExcelJS
---
## 4. ExcelExporter
---
一个功能强大且灵活的 Excel 数据校验工具,支持常用验证规则、列唯一、组合列唯一、自定义规则等。易用且向下兼容,适合日常 Excel 数据导入校验场景。
- 功能特点
- 支持必填项、数字范围、邮箱、手机号、身份证等常用规则校验
- 支持单列唯一校验
- 支持组合列唯一校验(多列拼接判断唯一)
- 支持自定义正则表达式规则
- 支持自定义函数校验
- 数字类型自动 `trim` + 转换成数字
- 验证错误定位准确,支持 Excel 行号(从1开始)、列号(从0开始)
- 进度回调支持大数据场景
- API 参数说明
| 参数名 | 类型 | 说明 |
| ----------------- | --------------------------------------- | ----------------------- |
| `colHeaders` | `string[]` | Excel 列标题,用于错误提示 |
| `fieldNames` | `string[]` | 字段映射,用于生成结果对象 |
| `rules` | `Record<number, ColumnRule>` | 校验规则集合,key 是列索引 |
| `uniqueGroupCols` | `number[]` | 组合唯一校验列索引数组,列值拼接做唯一性检查 |
| `startRowIndex` | `number` | 起始行号(默认2),对应 Excel 实际行号 |
| `onProgress` | `(curr: number, total: number) => void` | 校验进度回调 |
- 校验规则 ColumnRule 说明
| 属性 | 类型 | 说明 |
| ---------- | ----------------------------------------------------------------- | ---------------------------------------- |
| `required` | `boolean` | 是否必填 |
| `type` | `'string' \| 'number' \| 'boolean' \| 'date'` | 数据类型,number 会自动 trim 和转数字 |
| `pattern` | `RegExp` | 自定义正则表达式校验 |
| `min` | `number` | 数字类型最小值 |
| `max` | `number` | 数字类型最大值 |
| `unique` | `boolean` | 该列是否要求唯一(全表) |
| `custom` | `(val: any, row: any[], rowIndex: number) => string \| undefined` | 自定义校验函数,返回错误信息表示校验失败,返回 `undefined` 表示通过 |
- 内置常用正则模板
可以通过 ExcelValidator.getPredefinedPattern(name) 获取,支持:
| 名称 | 说明 |
| -------- | ----- |
| `idCard` | 身份证号码 |
| `phone` | 手机号码 |
| `tel` | 固话号码 |
| `email` | 邮箱地址 |
- 使用示例
```ts
const result = ExcelValidator.validate(data, {
colHeaders: ['姓名', '身份证', '手机号', '年龄', '邮箱'],
fieldNames: ['name', 'idCard', 'phone', 'age', 'email'],
rules: {
0: { required: true },
1: { required: true, pattern: ExcelValidator.getPredefinedPattern('idCard') },
2: { pattern: ExcelValidator.getPredefinedPattern('phone') },
3: { type: 'number', min: 18, max: 65 },
4: { pattern: ExcelValidator.getPredefinedPattern('email') }
},
uniqueGroupCols: [1, 2], // 身份证 + 手机号联合唯一
onProgress: (current, total) => {
console.log(`校验进度: ${current}/${total}`)
}
})
1. 基础规则配置示例
const rules = {
0: { required: true }, // 姓名必填
1: { required: true, pattern: ExcelValidator.getPredefinedPattern('idCard') }, // 身份证必填且格式正确
2: { pattern: ExcelValidator.getPredefinedPattern('phone') }, // 手机号格式校验
3: { type: 'number', min: 18, max: 60 }, // 年龄数字范围校验
4: { pattern: ExcelValidator.getPredefinedPattern('email') } // 邮箱格式校验
}
2. 单列唯一校验
const rules = {
1: { unique: true } // 身份证号列唯一
}
3. 组合列唯一校验
const uniqueGroupCols = [1, 2] // 身份证 + 手机号 联合唯一
4. 自定义正则表达式
const rules = {
5: { pattern: /^[A-Z]{3}\d{4}$/ } // 第6列必须是3个大写字母+4个数字
}
5. 自定义函数校验
const rules = {
3: {
custom: (val, row, rowIndex) => {
if (val < 0 || val > 100) return '数值必须在0到100之间'
if (row[0] === '特殊标记' && val < 50) return '特殊标记项最小值为50'
return undefined
}
}
}
返回结果结构
{
err: CellError[], // 错误列表,每条包括 Excel 行号、列号及错误原因
succ: any[] // 解析成功后的对象数组,字段名对应 fieldNames 配置
}
```
---