feat: input-excel 支持 xls 格式上传 (#6753)

* feat: input-excel 支持 xls 格式上传

* 避免误修改文件
This commit is contained in:
吴多益 2023-04-28 14:19:51 +08:00 committed by GitHub
parent f712db65c6
commit b894c36fa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 42 deletions

View File

@ -13,6 +13,8 @@ order: 14
1. 节省后端开发成本,无需再次解析 Excel
2. 可以前端实时预览效果,比如配合 input-table 组件进行二次修改
> 2.10.0 以上版本支持 xls 文件格式2.9.0 及以下版本只支持 xlsx
## 基本使用
默认情况下只解析第一个 sheet 的内容,下面的例子中,选择上传文件后,就能知道最终会解析成什么数据

View File

@ -466,6 +466,7 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'!echarts-stat/**',
'!papaparse/**',
'!exceljs/**',
'!xlsx/**',
'!docsearch.js/**',
'!monaco-editor/**.css',
'!amis-ui/lib/components/RichText.js',
@ -506,6 +507,8 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'exceljs.js': ['exceljs/**'],
'xlsx.js': ['xlsx/**'],
'markdown.js': [
'amis-ui/lib/components/Markdown.js',
'highlight.js/**',
@ -547,6 +550,7 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'!echarts/**',
'!papaparse/**',
'!exceljs/**',
'!xlsx/**',
'!highlight.js/**',
'!argparse/**',
'!entities/**',
@ -758,6 +762,7 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'!echarts-stat/**',
'!papaparse/**',
'!exceljs/**',
'!xlsx/**',
'!docsearch.js/**',
'!monaco-editor/**.css',
'!src/components/RichText.tsx',
@ -803,6 +808,8 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'pkg/exceljs.js': ['exceljs/**'],
'pkg/xlsx.js': ['xlsx/**'],
'pkg/barcode.js': ['amis-ui/lib/components/BarCode.tsx', 'jsbarcode/**'],
'pkg/markdown.js': [
@ -857,6 +864,7 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'!echarts/**',
'!papaparse/**',
'!exceljs/**',
'!xlsx/**',
'!amis-core/lib/utils/markdown.ts',
'!highlight.js/**',
'!argparse/**',

View File

@ -69,7 +69,8 @@
"react-transition-group": "4.4.2",
"sortablejs": "1.15.0",
"tslib": "^2.3.1",
"video-react": "0.15.0"
"video-react": "0.15.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@fortawesome/fontawesome-free": "^6.1.1",

View File

@ -89,56 +89,76 @@ export default class ExcelControl extends React.PureComponent<
@autobind
handleDrop(files: File[]) {
const {allSheets, onChange, parseImage} = this.props;
const excel = files[0];
const fileName = excel.name;
const reader = new FileReader();
reader.readAsArrayBuffer(excel);
reader.onload = async () => {
if (reader.result) {
import('exceljs').then(async (ExcelJS: any) => {
this.ExcelJS = ExcelJS;
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(reader.result);
let sheetsResult: any = [];
if (allSheets) {
workbook.eachSheet((worksheet: any) => {
if (parseImage) {
sheetsResult.push({
sheetName: worksheet.name,
data: this.readWorksheet(worksheet),
images: this.readImages(worksheet, workbook)
});
} else {
sheetsResult.push({
sheetName: worksheet.name,
data: this.readWorksheet(worksheet)
});
// 如果是 xls 就用 xlsx 解析一下转成 xlsx 然后用 exceljs 解析
// 为啥不直接用 xlsx 解析内容?因为它的社区版本不支持读图片,只有收费版才支持
if (fileName.toLowerCase().endsWith('.xls')) {
import('xlsx').then(XLSX => {
const workbook = XLSX.read(
new Uint8Array(reader.result as ArrayBuffer),
{
cellDates: true
}
});
} else {
const worksheet = workbook.worksheets[0];
if (parseImage) {
const images = this.readImages(worksheet, workbook);
sheetsResult = {
data: this.readWorksheet(worksheet),
images
};
} else {
sheetsResult = this.readWorksheet(worksheet);
}
}
const dispatcher = await this.dispatchEvent('change', sheetsResult);
if (dispatcher?.prevented) {
return;
}
onChange(sheetsResult);
this.setState({filename: files[0].name});
});
);
const xlsxFile = XLSX.writeXLSX(workbook, {type: 'array'});
this.processExcelFile(xlsxFile, fileName);
});
} else {
this.processExcelFile(reader.result, fileName);
}
}
};
}
processExcelFile(excelData: ArrayBuffer | string, fileName: string) {
const {allSheets, onChange, parseImage} = this.props;
import('exceljs').then(async (ExcelJS: any) => {
this.ExcelJS = ExcelJS;
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(excelData);
let sheetsResult: any = [];
if (allSheets) {
workbook.eachSheet((worksheet: any) => {
if (parseImage) {
sheetsResult.push({
sheetName: worksheet.name,
data: this.readWorksheet(worksheet),
images: this.readImages(worksheet, workbook)
});
} else {
sheetsResult.push({
sheetName: worksheet.name,
data: this.readWorksheet(worksheet)
});
}
});
} else {
const worksheet = workbook.worksheets[0];
if (parseImage) {
const images = this.readImages(worksheet, workbook);
sheetsResult = {
data: this.readWorksheet(worksheet),
images
};
} else {
sheetsResult = this.readWorksheet(worksheet);
}
}
const dispatcher = await this.dispatchEvent('change', sheetsResult);
if (dispatcher?.prevented) {
return;
}
onChange(sheetsResult);
this.setState({filename: fileName});
});
}
/** 读取工作表里的图片 */
readImages(worksheet: any, workbook: any) {
const {imageDataURI} = this.props;
@ -319,7 +339,7 @@ export default class ExcelControl extends React.PureComponent<
<Dropzone
key="drop-zone"
onDrop={this.handleDrop}
accept=".xlsx"
accept=".xlsx,.xls"
multiple={false}
disabled={disabled}
>