react-util-tools 1.0.24 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -3
- package/dist/index.cjs +437 -2
- package/dist/index.d.cts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +373 -1
- package/package.json +8 -3
- package/src/excel/README.md +388 -0
- package/src/excel/example.md +425 -0
- package/src/excel/index.ts +245 -0
- package/src/index.ts +78 -0
- package/src/string/README.md +441 -0
- package/src/string/index.ts +527 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# Excel 模块使用示例
|
|
2
|
+
|
|
3
|
+
## React 组件示例
|
|
4
|
+
|
|
5
|
+
### 1. Excel 文件上传和解析
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import React, { useState } from 'react'
|
|
9
|
+
import { readExcelToJSON } from 'react-util-tools'
|
|
10
|
+
|
|
11
|
+
interface UserData {
|
|
12
|
+
name: string
|
|
13
|
+
age: number
|
|
14
|
+
email: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function ExcelUploader() {
|
|
18
|
+
const [data, setData] = useState<UserData[]>([])
|
|
19
|
+
const [loading, setLoading] = useState(false)
|
|
20
|
+
|
|
21
|
+
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
22
|
+
const file = e.target.files?.[0]
|
|
23
|
+
if (!file) return
|
|
24
|
+
|
|
25
|
+
setLoading(true)
|
|
26
|
+
try {
|
|
27
|
+
const jsonData = await readExcelToJSON<UserData>(file)
|
|
28
|
+
setData(jsonData)
|
|
29
|
+
console.log('解析成功:', jsonData)
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('解析失败:', error)
|
|
32
|
+
alert('文件解析失败,请检查文件格式')
|
|
33
|
+
} finally {
|
|
34
|
+
setLoading(false)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div>
|
|
40
|
+
<input
|
|
41
|
+
type="file"
|
|
42
|
+
accept=".xlsx,.xls,.csv"
|
|
43
|
+
onChange={handleFileChange}
|
|
44
|
+
disabled={loading}
|
|
45
|
+
/>
|
|
46
|
+
{loading && <p>正在解析...</p>}
|
|
47
|
+
{data.length > 0 && (
|
|
48
|
+
<table>
|
|
49
|
+
<thead>
|
|
50
|
+
<tr>
|
|
51
|
+
<th>姓名</th>
|
|
52
|
+
<th>年龄</th>
|
|
53
|
+
<th>邮箱</th>
|
|
54
|
+
</tr>
|
|
55
|
+
</thead>
|
|
56
|
+
<tbody>
|
|
57
|
+
{data.map((row, index) => (
|
|
58
|
+
<tr key={index}>
|
|
59
|
+
<td>{row.name}</td>
|
|
60
|
+
<td>{row.age}</td>
|
|
61
|
+
<td>{row.email}</td>
|
|
62
|
+
</tr>
|
|
63
|
+
))}
|
|
64
|
+
</tbody>
|
|
65
|
+
</table>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default ExcelUploader
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. 导出数据为 Excel
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import React from 'react'
|
|
78
|
+
import { exportJSONToExcel } from 'react-util-tools'
|
|
79
|
+
|
|
80
|
+
interface Product {
|
|
81
|
+
id: number
|
|
82
|
+
name: string
|
|
83
|
+
price: number
|
|
84
|
+
stock: number
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function ProductList() {
|
|
88
|
+
const products: Product[] = [
|
|
89
|
+
{ id: 1, name: 'iPhone 15', price: 5999, stock: 100 },
|
|
90
|
+
{ id: 2, name: 'iPad Pro', price: 6999, stock: 50 },
|
|
91
|
+
{ id: 3, name: 'MacBook Pro', price: 12999, stock: 30 }
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
const handleExport = () => {
|
|
95
|
+
exportJSONToExcel(
|
|
96
|
+
products,
|
|
97
|
+
'products.xlsx',
|
|
98
|
+
'ProductList'
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div>
|
|
104
|
+
<button onClick={handleExport}>导出为 Excel</button>
|
|
105
|
+
<table>
|
|
106
|
+
<thead>
|
|
107
|
+
<tr>
|
|
108
|
+
<th>ID</th>
|
|
109
|
+
<th>产品名称</th>
|
|
110
|
+
<th>价格</th>
|
|
111
|
+
<th>库存</th>
|
|
112
|
+
</tr>
|
|
113
|
+
</thead>
|
|
114
|
+
<tbody>
|
|
115
|
+
{products.map(product => (
|
|
116
|
+
<tr key={product.id}>
|
|
117
|
+
<td>{product.id}</td>
|
|
118
|
+
<td>{product.name}</td>
|
|
119
|
+
<td>¥{product.price}</td>
|
|
120
|
+
<td>{product.stock}</td>
|
|
121
|
+
</tr>
|
|
122
|
+
))}
|
|
123
|
+
</tbody>
|
|
124
|
+
</table>
|
|
125
|
+
</div>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default ProductList
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 3. 多工作表导出
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
import React from 'react'
|
|
136
|
+
import { XLSX, utils, exportExcelFile } from 'react-util-tools'
|
|
137
|
+
|
|
138
|
+
function MultiSheetExport() {
|
|
139
|
+
const handleExport = () => {
|
|
140
|
+
// 创建工作簿
|
|
141
|
+
const workbook = utils.book_new()
|
|
142
|
+
|
|
143
|
+
// 用户数据
|
|
144
|
+
const users = [
|
|
145
|
+
{ name: '张三', age: 25, department: '技术部' },
|
|
146
|
+
{ name: '李四', age: 30, department: '市场部' }
|
|
147
|
+
]
|
|
148
|
+
const userSheet = utils.json_to_sheet(users)
|
|
149
|
+
utils.book_append_sheet(workbook, userSheet, '员工列表')
|
|
150
|
+
|
|
151
|
+
// 销售数据
|
|
152
|
+
const sales = [
|
|
153
|
+
{ month: '1月', revenue: 100000, profit: 20000 },
|
|
154
|
+
{ month: '2月', revenue: 120000, profit: 25000 }
|
|
155
|
+
]
|
|
156
|
+
const salesSheet = utils.json_to_sheet(sales)
|
|
157
|
+
utils.book_append_sheet(workbook, salesSheet, '销售数据')
|
|
158
|
+
|
|
159
|
+
// 导出
|
|
160
|
+
exportExcelFile(workbook, 'company-report.xlsx')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<button onClick={handleExport}>
|
|
165
|
+
导出多工作表报表
|
|
166
|
+
</button>
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export default MultiSheetExport
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 4. 读取指定工作表
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import React, { useState } from 'react'
|
|
177
|
+
import { readExcelFile, getSheetNames, workbookToJSON } from 'react-util-tools'
|
|
178
|
+
|
|
179
|
+
function MultiSheetReader() {
|
|
180
|
+
const [sheets, setSheets] = useState<string[]>([])
|
|
181
|
+
const [selectedSheet, setSelectedSheet] = useState<string>('')
|
|
182
|
+
const [data, setData] = useState<any[]>([])
|
|
183
|
+
|
|
184
|
+
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
185
|
+
const file = e.target.files?.[0]
|
|
186
|
+
if (!file) return
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const workbook = await readExcelFile(file)
|
|
190
|
+
const sheetNames = getSheetNames(workbook)
|
|
191
|
+
setSheets(sheetNames)
|
|
192
|
+
|
|
193
|
+
// 默认读取第一个工作表
|
|
194
|
+
if (sheetNames.length > 0) {
|
|
195
|
+
const firstSheet = sheetNames[0]
|
|
196
|
+
setSelectedSheet(firstSheet)
|
|
197
|
+
const jsonData = workbookToJSON(workbook, firstSheet)
|
|
198
|
+
setData(jsonData)
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error('读取失败:', error)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const handleSheetChange = async (sheetName: string) => {
|
|
206
|
+
setSelectedSheet(sheetName)
|
|
207
|
+
// 重新读取文件并获取指定工作表
|
|
208
|
+
// 实际应用中应该缓存 workbook
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<div>
|
|
213
|
+
<input type="file" accept=".xlsx,.xls" onChange={handleFileChange} />
|
|
214
|
+
|
|
215
|
+
{sheets.length > 0 && (
|
|
216
|
+
<div>
|
|
217
|
+
<label>选择工作表:</label>
|
|
218
|
+
<select value={selectedSheet} onChange={e => handleSheetChange(e.target.value)}>
|
|
219
|
+
{sheets.map(sheet => (
|
|
220
|
+
<option key={sheet} value={sheet}>
|
|
221
|
+
{sheet}
|
|
222
|
+
</option>
|
|
223
|
+
))}
|
|
224
|
+
</select>
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
|
|
228
|
+
{data.length > 0 && (
|
|
229
|
+
<pre>{JSON.stringify(data, null, 2)}</pre>
|
|
230
|
+
)}
|
|
231
|
+
</div>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export default MultiSheetReader
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 5. 从 HTML 表格导出
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
import React, { useRef } from 'react'
|
|
242
|
+
import { tableToSheet, utils, exportExcelFile } from 'react-util-tools'
|
|
243
|
+
|
|
244
|
+
function TableExporter() {
|
|
245
|
+
const tableRef = useRef<HTMLTableElement>(null)
|
|
246
|
+
|
|
247
|
+
const handleExport = () => {
|
|
248
|
+
if (!tableRef.current) return
|
|
249
|
+
|
|
250
|
+
const worksheet = tableToSheet(tableRef.current)
|
|
251
|
+
const workbook = utils.book_new()
|
|
252
|
+
utils.book_append_sheet(workbook, worksheet, 'Sheet1')
|
|
253
|
+
|
|
254
|
+
exportExcelFile(workbook, 'table-export.xlsx')
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<div>
|
|
259
|
+
<button onClick={handleExport}>导出表格</button>
|
|
260
|
+
|
|
261
|
+
<table ref={tableRef}>
|
|
262
|
+
<thead>
|
|
263
|
+
<tr>
|
|
264
|
+
<th>姓名</th>
|
|
265
|
+
<th>年龄</th>
|
|
266
|
+
<th>城市</th>
|
|
267
|
+
</tr>
|
|
268
|
+
</thead>
|
|
269
|
+
<tbody>
|
|
270
|
+
<tr>
|
|
271
|
+
<td>张三</td>
|
|
272
|
+
<td>25</td>
|
|
273
|
+
<td>北京</td>
|
|
274
|
+
</tr>
|
|
275
|
+
<tr>
|
|
276
|
+
<td>李四</td>
|
|
277
|
+
<td>30</td>
|
|
278
|
+
<td>上海</td>
|
|
279
|
+
</tr>
|
|
280
|
+
</tbody>
|
|
281
|
+
</table>
|
|
282
|
+
</div>
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export default TableExporter
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 6. 高级用法 - 自定义样式和格式
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
import React from 'react'
|
|
293
|
+
import { XLSX, utils, exportExcelFile } from 'react-util-tools'
|
|
294
|
+
|
|
295
|
+
function AdvancedExport() {
|
|
296
|
+
const handleExport = () => {
|
|
297
|
+
const data = [
|
|
298
|
+
{ name: '张三', score: 95, grade: 'A' },
|
|
299
|
+
{ name: '李四', score: 87, grade: 'B' },
|
|
300
|
+
{ name: '王五', score: 92, grade: 'A' }
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
// 创建工作表
|
|
304
|
+
const worksheet = utils.json_to_sheet(data)
|
|
305
|
+
|
|
306
|
+
// 设置列宽
|
|
307
|
+
worksheet['!cols'] = [
|
|
308
|
+
{ wch: 15 }, // 姓名列宽度
|
|
309
|
+
{ wch: 10 }, // 分数列宽度
|
|
310
|
+
{ wch: 10 } // 等级列宽度
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
// 合并单元格(如果需要)
|
|
314
|
+
// worksheet['!merges'] = [
|
|
315
|
+
// { s: { r: 0, c: 0 }, e: { r: 0, c: 2 } } // 合并第一行的 A-C 列
|
|
316
|
+
// ]
|
|
317
|
+
|
|
318
|
+
// 创建工作簿
|
|
319
|
+
const workbook = utils.book_new()
|
|
320
|
+
utils.book_append_sheet(workbook, worksheet, 'Scores')
|
|
321
|
+
|
|
322
|
+
// 导出
|
|
323
|
+
exportExcelFile(workbook, 'student-scores.xlsx', {
|
|
324
|
+
bookType: 'xlsx',
|
|
325
|
+
compression: true
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return (
|
|
330
|
+
<button onClick={handleExport}>
|
|
331
|
+
导出成绩单
|
|
332
|
+
</button>
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export default AdvancedExport
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## 纯 JavaScript 示例
|
|
340
|
+
|
|
341
|
+
### Node.js 环境
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
import { readFile, jsonToWorkbook, exportExcelFile } from 'react-util-tools'
|
|
345
|
+
import fs from 'fs'
|
|
346
|
+
|
|
347
|
+
// 读取 Excel 文件
|
|
348
|
+
async function readExcelInNode() {
|
|
349
|
+
const buffer = fs.readFileSync('input.xlsx')
|
|
350
|
+
const workbook = readFile(buffer)
|
|
351
|
+
const data = workbookToJSON(workbook)
|
|
352
|
+
console.log(data)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// 导出 Excel 文件
|
|
356
|
+
function exportExcelInNode() {
|
|
357
|
+
const data = [
|
|
358
|
+
{ name: 'John', age: 30 },
|
|
359
|
+
{ name: 'Jane', age: 25 }
|
|
360
|
+
]
|
|
361
|
+
|
|
362
|
+
const workbook = jsonToWorkbook(data)
|
|
363
|
+
writeFile(workbook, 'output.xlsx')
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## 常见问题
|
|
368
|
+
|
|
369
|
+
### 1. 如何处理大文件?
|
|
370
|
+
|
|
371
|
+
对于大文件,建议分批处理或使用流式读取:
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
import { readExcelFile, getSheetNames, getSheet, sheetToAOA } from 'react-util-tools'
|
|
375
|
+
|
|
376
|
+
async function processBigFile(file: File) {
|
|
377
|
+
const workbook = await readExcelFile(file)
|
|
378
|
+
const sheet = getSheet(workbook, 'Sheet1')
|
|
379
|
+
|
|
380
|
+
// 转换为数组,逐行处理
|
|
381
|
+
const rows = sheetToAOA(sheet)
|
|
382
|
+
|
|
383
|
+
// 分批处理
|
|
384
|
+
const batchSize = 1000
|
|
385
|
+
for (let i = 0; i < rows.length; i += batchSize) {
|
|
386
|
+
const batch = rows.slice(i, i + batchSize)
|
|
387
|
+
await processBatch(batch)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### 2. 如何处理日期格式?
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
import { readExcelFile, workbookToJSON } from 'react-util-tools'
|
|
396
|
+
|
|
397
|
+
async function handleDates(file: File) {
|
|
398
|
+
const workbook = await readExcelFile(file, {
|
|
399
|
+
cellDates: true // 将日期解析为 Date 对象
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
const data = workbookToJSON(workbook)
|
|
403
|
+
console.log(data)
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 3. 如何导出 CSV?
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
import { jsonToWorkbook, getSheet, sheetToCSV } from 'react-util-tools'
|
|
411
|
+
|
|
412
|
+
function exportToCSV(data: any[]) {
|
|
413
|
+
const workbook = jsonToWorkbook(data)
|
|
414
|
+
const sheet = getSheet(workbook, 'Sheet1')
|
|
415
|
+
const csv = sheetToCSV(sheet)
|
|
416
|
+
|
|
417
|
+
// 下载 CSV
|
|
418
|
+
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
|
|
419
|
+
const url = URL.createObjectURL(blob)
|
|
420
|
+
const link = document.createElement('a')
|
|
421
|
+
link.href = url
|
|
422
|
+
link.download = 'data.csv'
|
|
423
|
+
link.click()
|
|
424
|
+
}
|
|
425
|
+
```
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SheetJS (xlsx) 封装
|
|
3
|
+
* 完整导出 SheetJS 的所有功能
|
|
4
|
+
* 文档:https://docs.sheetjs.com/
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as XLSX from 'xlsx'
|
|
8
|
+
|
|
9
|
+
// 导出整个 XLSX 对象,保留所有功能
|
|
10
|
+
export { XLSX }
|
|
11
|
+
|
|
12
|
+
// 导出常用类型
|
|
13
|
+
export type {
|
|
14
|
+
WorkBook,
|
|
15
|
+
WorkSheet,
|
|
16
|
+
CellObject,
|
|
17
|
+
Range,
|
|
18
|
+
WritingOptions,
|
|
19
|
+
ParsingOptions,
|
|
20
|
+
BookType,
|
|
21
|
+
Sheet2JSONOpts,
|
|
22
|
+
JSON2SheetOpts
|
|
23
|
+
} from 'xlsx'
|
|
24
|
+
|
|
25
|
+
// 导出常用方法(方便直接使用)
|
|
26
|
+
export const {
|
|
27
|
+
read,
|
|
28
|
+
readFile,
|
|
29
|
+
write,
|
|
30
|
+
writeFile,
|
|
31
|
+
writeFileXLSX,
|
|
32
|
+
utils
|
|
33
|
+
} = XLSX
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 读取 Excel 文件(从 File 对象)
|
|
37
|
+
* @param file File 对象
|
|
38
|
+
* @param options 解析选项
|
|
39
|
+
* @returns Promise<WorkBook>
|
|
40
|
+
*/
|
|
41
|
+
export function readExcelFile(
|
|
42
|
+
file: File,
|
|
43
|
+
options?: XLSX.ParsingOptions
|
|
44
|
+
): Promise<XLSX.WorkBook> {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const reader = new FileReader()
|
|
47
|
+
|
|
48
|
+
reader.onload = (e) => {
|
|
49
|
+
try {
|
|
50
|
+
const data = e.target?.result
|
|
51
|
+
const workbook = XLSX.read(data, options)
|
|
52
|
+
resolve(workbook)
|
|
53
|
+
} catch (error) {
|
|
54
|
+
reject(error)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
reader.onerror = () => {
|
|
59
|
+
reject(new Error('Failed to read file'))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
reader.readAsArrayBuffer(file)
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 将 WorkBook 转换为 JSON 数据
|
|
68
|
+
* @param workbook WorkBook 对象
|
|
69
|
+
* @param sheetName 工作表名称(可选,默认第一个)
|
|
70
|
+
* @param options 转换选项
|
|
71
|
+
* @returns JSON 数据数组
|
|
72
|
+
*/
|
|
73
|
+
export function workbookToJSON<T = any>(
|
|
74
|
+
workbook: XLSX.WorkBook,
|
|
75
|
+
sheetName?: string,
|
|
76
|
+
options?: XLSX.Sheet2JSONOpts
|
|
77
|
+
): T[] {
|
|
78
|
+
const sheet = sheetName
|
|
79
|
+
? workbook.Sheets[sheetName]
|
|
80
|
+
: workbook.Sheets[workbook.SheetNames[0]]
|
|
81
|
+
|
|
82
|
+
if (!sheet) {
|
|
83
|
+
throw new Error(`Sheet "${sheetName}" not found`)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return XLSX.utils.sheet_to_json<T>(sheet, options)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 从 JSON 数据创建 WorkBook
|
|
91
|
+
* @param data JSON 数据数组
|
|
92
|
+
* @param sheetName 工作表名称(默认 'Sheet1')
|
|
93
|
+
* @param options 转换选项
|
|
94
|
+
* @returns WorkBook 对象
|
|
95
|
+
*/
|
|
96
|
+
export function jsonToWorkbook<T = any>(
|
|
97
|
+
data: T[],
|
|
98
|
+
sheetName = 'Sheet1',
|
|
99
|
+
options?: XLSX.JSON2SheetOpts
|
|
100
|
+
): XLSX.WorkBook {
|
|
101
|
+
const worksheet = XLSX.utils.json_to_sheet(data, options)
|
|
102
|
+
const workbook = XLSX.utils.book_new()
|
|
103
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName)
|
|
104
|
+
return workbook
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 导出 Excel 文件(浏览器下载)
|
|
109
|
+
* @param workbook WorkBook 对象
|
|
110
|
+
* @param filename 文件名(默认 'export.xlsx')
|
|
111
|
+
* @param options 写入选项
|
|
112
|
+
*/
|
|
113
|
+
export function exportExcelFile(
|
|
114
|
+
workbook: XLSX.WorkBook,
|
|
115
|
+
filename = 'export.xlsx',
|
|
116
|
+
options?: XLSX.WritingOptions
|
|
117
|
+
): void {
|
|
118
|
+
XLSX.writeFile(workbook, filename, options)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 从 JSON 数据直接导出 Excel 文件
|
|
123
|
+
* @param data JSON 数据数组
|
|
124
|
+
* @param filename 文件名(默认 'export.xlsx')
|
|
125
|
+
* @param sheetName 工作表名称(默认 'Sheet1')
|
|
126
|
+
* @param options 写入选项
|
|
127
|
+
*/
|
|
128
|
+
export function exportJSONToExcel<T = any>(
|
|
129
|
+
data: T[],
|
|
130
|
+
filename = 'export.xlsx',
|
|
131
|
+
sheetName = 'Sheet1',
|
|
132
|
+
options?: XLSX.WritingOptions
|
|
133
|
+
): void {
|
|
134
|
+
const workbook = jsonToWorkbook(data, sheetName)
|
|
135
|
+
exportExcelFile(workbook, filename, options)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 读取 Excel 文件并转换为 JSON
|
|
140
|
+
* @param file File 对象
|
|
141
|
+
* @param sheetName 工作表名称(可选,默认第一个)
|
|
142
|
+
* @param parseOptions 解析选项
|
|
143
|
+
* @param jsonOptions JSON 转换选项
|
|
144
|
+
* @returns Promise<JSON 数据数组>
|
|
145
|
+
*/
|
|
146
|
+
export async function readExcelToJSON<T = any>(
|
|
147
|
+
file: File,
|
|
148
|
+
sheetName?: string,
|
|
149
|
+
parseOptions?: XLSX.ParsingOptions,
|
|
150
|
+
jsonOptions?: XLSX.Sheet2JSONOpts
|
|
151
|
+
): Promise<T[]> {
|
|
152
|
+
const workbook = await readExcelFile(file, parseOptions)
|
|
153
|
+
return workbookToJSON<T>(workbook, sheetName, jsonOptions)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 获取 WorkBook 中所有工作表的名称
|
|
158
|
+
* @param workbook WorkBook 对象
|
|
159
|
+
* @returns 工作表名称数组
|
|
160
|
+
*/
|
|
161
|
+
export function getSheetNames(workbook: XLSX.WorkBook): string[] {
|
|
162
|
+
return workbook.SheetNames
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 获取指定工作表
|
|
167
|
+
* @param workbook WorkBook 对象
|
|
168
|
+
* @param sheetName 工作表名称
|
|
169
|
+
* @returns WorkSheet 对象
|
|
170
|
+
*/
|
|
171
|
+
export function getSheet(
|
|
172
|
+
workbook: XLSX.WorkBook,
|
|
173
|
+
sheetName: string
|
|
174
|
+
): XLSX.WorkSheet {
|
|
175
|
+
const sheet = workbook.Sheets[sheetName]
|
|
176
|
+
if (!sheet) {
|
|
177
|
+
throw new Error(`Sheet "${sheetName}" not found`)
|
|
178
|
+
}
|
|
179
|
+
return sheet
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 将 WorkSheet 转换为 CSV 字符串
|
|
184
|
+
* @param worksheet WorkSheet 对象
|
|
185
|
+
* @param options 转换选项
|
|
186
|
+
* @returns CSV 字符串
|
|
187
|
+
*/
|
|
188
|
+
export function sheetToCSV(
|
|
189
|
+
worksheet: XLSX.WorkSheet,
|
|
190
|
+
options?: XLSX.Sheet2CSVOpts
|
|
191
|
+
): string {
|
|
192
|
+
return XLSX.utils.sheet_to_csv(worksheet, options)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 将 WorkSheet 转换为 HTML 字符串
|
|
197
|
+
* @param worksheet WorkSheet 对象
|
|
198
|
+
* @param options 转换选项
|
|
199
|
+
* @returns HTML 字符串
|
|
200
|
+
*/
|
|
201
|
+
export function sheetToHTML(
|
|
202
|
+
worksheet: XLSX.WorkSheet,
|
|
203
|
+
options?: XLSX.Sheet2HTMLOpts
|
|
204
|
+
): string {
|
|
205
|
+
return XLSX.utils.sheet_to_html(worksheet, options)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 从 HTML 表格创建 WorkSheet
|
|
210
|
+
* @param table HTML 表格元素或字符串
|
|
211
|
+
* @param options 转换选项
|
|
212
|
+
* @returns WorkSheet 对象
|
|
213
|
+
*/
|
|
214
|
+
export function tableToSheet(
|
|
215
|
+
table: HTMLElement | string,
|
|
216
|
+
options?: XLSX.Table2SheetOpts
|
|
217
|
+
): XLSX.WorkSheet {
|
|
218
|
+
return XLSX.utils.table_to_sheet(table, options)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 从 AOA (Array of Arrays) 创建 WorkSheet
|
|
223
|
+
* @param data 二维数组
|
|
224
|
+
* @param options 转换选项
|
|
225
|
+
* @returns WorkSheet 对象
|
|
226
|
+
*/
|
|
227
|
+
export function aoaToSheet(
|
|
228
|
+
data: any[][],
|
|
229
|
+
options?: XLSX.AOA2SheetOpts
|
|
230
|
+
): XLSX.WorkSheet {
|
|
231
|
+
return XLSX.utils.aoa_to_sheet(data, options)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 将 WorkSheet 转换为 AOA (Array of Arrays)
|
|
236
|
+
* @param worksheet WorkSheet 对象
|
|
237
|
+
* @param options 转换选项
|
|
238
|
+
* @returns 二维数组
|
|
239
|
+
*/
|
|
240
|
+
export function sheetToAOA(
|
|
241
|
+
worksheet: XLSX.WorkSheet,
|
|
242
|
+
options?: XLSX.Sheet2JSONOpts
|
|
243
|
+
): any[][] {
|
|
244
|
+
return XLSX.utils.sheet_to_json(worksheet, { ...options, header: 1 })
|
|
245
|
+
}
|