react-util-tools 1.0.23 → 1.0.25
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 +90 -3
- package/dist/index.cjs +229 -2
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +200 -1
- package/package.json +18 -12
- 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 +45 -1
package/dist/index.js
CHANGED
|
@@ -75,6 +75,66 @@ function getQueryParamAll(key, url) {
|
|
|
75
75
|
return searchParams.getAll(key);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// src/cookie/index.ts
|
|
79
|
+
function setCookie(name, value, options = {}) {
|
|
80
|
+
let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
81
|
+
if (options.expires) {
|
|
82
|
+
const expires = options.expires instanceof Date ? options.expires : new Date(Date.now() + options.expires * 1e3);
|
|
83
|
+
cookieString += `; expires=${expires.toUTCString()}`;
|
|
84
|
+
}
|
|
85
|
+
if (options.path) {
|
|
86
|
+
cookieString += `; path=${options.path}`;
|
|
87
|
+
}
|
|
88
|
+
if (options.domain) {
|
|
89
|
+
cookieString += `; domain=${options.domain}`;
|
|
90
|
+
}
|
|
91
|
+
if (options.secure) {
|
|
92
|
+
cookieString += "; secure";
|
|
93
|
+
}
|
|
94
|
+
if (options.sameSite) {
|
|
95
|
+
cookieString += `; SameSite=${options.sameSite}`;
|
|
96
|
+
}
|
|
97
|
+
document.cookie = cookieString;
|
|
98
|
+
}
|
|
99
|
+
function getCookie(name) {
|
|
100
|
+
const nameEQ = encodeURIComponent(name) + "=";
|
|
101
|
+
const cookies = document.cookie.split(";");
|
|
102
|
+
for (let cookie of cookies) {
|
|
103
|
+
cookie = cookie.trim();
|
|
104
|
+
if (cookie.indexOf(nameEQ) === 0) {
|
|
105
|
+
return decodeURIComponent(cookie.substring(nameEQ.length));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
function removeCookie(name, options = {}) {
|
|
111
|
+
setCookie(name, "", {
|
|
112
|
+
...options,
|
|
113
|
+
expires: /* @__PURE__ */ new Date(0)
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function hasCookie(name) {
|
|
117
|
+
return getCookie(name) !== null;
|
|
118
|
+
}
|
|
119
|
+
function getAllCookies() {
|
|
120
|
+
const cookies = {};
|
|
121
|
+
const cookieArray = document.cookie.split(";");
|
|
122
|
+
for (let cookie of cookieArray) {
|
|
123
|
+
cookie = cookie.trim();
|
|
124
|
+
const [name, ...valueParts] = cookie.split("=");
|
|
125
|
+
if (name) {
|
|
126
|
+
cookies[decodeURIComponent(name)] = decodeURIComponent(valueParts.join("="));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return cookies;
|
|
130
|
+
}
|
|
131
|
+
function clearAllCookies(options = {}) {
|
|
132
|
+
const cookies = getAllCookies();
|
|
133
|
+
for (const name in cookies) {
|
|
134
|
+
removeCookie(name, options);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
78
138
|
// src/device/index.ts
|
|
79
139
|
function getUserAgent() {
|
|
80
140
|
return navigator.userAgent.toLowerCase();
|
|
@@ -302,6 +362,39 @@ function formatPercent(value, options = {}) {
|
|
|
302
362
|
const num = multiply2 ? value * 100 : value;
|
|
303
363
|
return num.toFixed(decimals) + "%";
|
|
304
364
|
}
|
|
365
|
+
function maskEmail(email) {
|
|
366
|
+
if (!email || typeof email !== "string") {
|
|
367
|
+
return "";
|
|
368
|
+
}
|
|
369
|
+
const atIndex = email.indexOf("@");
|
|
370
|
+
if (atIndex <= 0) {
|
|
371
|
+
return email;
|
|
372
|
+
}
|
|
373
|
+
const localPart = email.substring(0, atIndex);
|
|
374
|
+
const domainPart = email.substring(atIndex);
|
|
375
|
+
const visiblePart = localPart.substring(0, 3);
|
|
376
|
+
return `${visiblePart}***${domainPart}`;
|
|
377
|
+
}
|
|
378
|
+
function unmaskEmail(maskedEmail, originalEmail) {
|
|
379
|
+
if (!maskedEmail || !originalEmail) {
|
|
380
|
+
return "";
|
|
381
|
+
}
|
|
382
|
+
if (!maskedEmail.includes("***@")) {
|
|
383
|
+
return maskedEmail;
|
|
384
|
+
}
|
|
385
|
+
const maskedParts = maskedEmail.split("***@");
|
|
386
|
+
const atIndex = originalEmail.indexOf("@");
|
|
387
|
+
if (atIndex <= 0) {
|
|
388
|
+
return maskedEmail;
|
|
389
|
+
}
|
|
390
|
+
const originalPrefix = originalEmail.substring(0, 3);
|
|
391
|
+
const originalDomain = originalEmail.substring(atIndex + 1);
|
|
392
|
+
const maskedDomain = maskedParts[1];
|
|
393
|
+
if (maskedParts[0] === originalPrefix && maskedDomain === originalDomain) {
|
|
394
|
+
return originalEmail;
|
|
395
|
+
}
|
|
396
|
+
return maskedEmail;
|
|
397
|
+
}
|
|
305
398
|
|
|
306
399
|
// src/date/index.ts
|
|
307
400
|
import {
|
|
@@ -750,18 +843,101 @@ function negate(value) {
|
|
|
750
843
|
return 0;
|
|
751
844
|
}
|
|
752
845
|
}
|
|
846
|
+
|
|
847
|
+
// src/excel/index.ts
|
|
848
|
+
import * as XLSX from "xlsx";
|
|
849
|
+
var {
|
|
850
|
+
read: read2,
|
|
851
|
+
readFile,
|
|
852
|
+
write,
|
|
853
|
+
writeFile: writeFile2,
|
|
854
|
+
writeFileXLSX,
|
|
855
|
+
utils: utils2
|
|
856
|
+
} = XLSX;
|
|
857
|
+
function readExcelFile(file, options) {
|
|
858
|
+
return new Promise((resolve, reject) => {
|
|
859
|
+
const reader = new FileReader();
|
|
860
|
+
reader.onload = (e) => {
|
|
861
|
+
try {
|
|
862
|
+
const data = e.target?.result;
|
|
863
|
+
const workbook = XLSX.read(data, options);
|
|
864
|
+
resolve(workbook);
|
|
865
|
+
} catch (error) {
|
|
866
|
+
reject(error);
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
reader.onerror = () => {
|
|
870
|
+
reject(new Error("Failed to read file"));
|
|
871
|
+
};
|
|
872
|
+
reader.readAsArrayBuffer(file);
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
function workbookToJSON(workbook, sheetName, options) {
|
|
876
|
+
const sheet = sheetName ? workbook.Sheets[sheetName] : workbook.Sheets[workbook.SheetNames[0]];
|
|
877
|
+
if (!sheet) {
|
|
878
|
+
throw new Error(`Sheet "${sheetName}" not found`);
|
|
879
|
+
}
|
|
880
|
+
return XLSX.utils.sheet_to_json(sheet, options);
|
|
881
|
+
}
|
|
882
|
+
function jsonToWorkbook(data, sheetName = "Sheet1", options) {
|
|
883
|
+
const worksheet = XLSX.utils.json_to_sheet(data, options);
|
|
884
|
+
const workbook = XLSX.utils.book_new();
|
|
885
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
886
|
+
return workbook;
|
|
887
|
+
}
|
|
888
|
+
function exportExcelFile(workbook, filename = "export.xlsx", options) {
|
|
889
|
+
XLSX.writeFile(workbook, filename, options);
|
|
890
|
+
}
|
|
891
|
+
function exportJSONToExcel(data, filename = "export.xlsx", sheetName = "Sheet1", options) {
|
|
892
|
+
const workbook = jsonToWorkbook(data, sheetName);
|
|
893
|
+
exportExcelFile(workbook, filename, options);
|
|
894
|
+
}
|
|
895
|
+
async function readExcelToJSON(file, sheetName, parseOptions, jsonOptions) {
|
|
896
|
+
const workbook = await readExcelFile(file, parseOptions);
|
|
897
|
+
return workbookToJSON(workbook, sheetName, jsonOptions);
|
|
898
|
+
}
|
|
899
|
+
function getSheetNames(workbook) {
|
|
900
|
+
return workbook.SheetNames;
|
|
901
|
+
}
|
|
902
|
+
function getSheet(workbook, sheetName) {
|
|
903
|
+
const sheet = workbook.Sheets[sheetName];
|
|
904
|
+
if (!sheet) {
|
|
905
|
+
throw new Error(`Sheet "${sheetName}" not found`);
|
|
906
|
+
}
|
|
907
|
+
return sheet;
|
|
908
|
+
}
|
|
909
|
+
function sheetToCSV(worksheet, options) {
|
|
910
|
+
return XLSX.utils.sheet_to_csv(worksheet, options);
|
|
911
|
+
}
|
|
912
|
+
function sheetToHTML(worksheet, options) {
|
|
913
|
+
return XLSX.utils.sheet_to_html(worksheet, options);
|
|
914
|
+
}
|
|
915
|
+
function tableToSheet(table, options) {
|
|
916
|
+
return XLSX.utils.table_to_sheet(table, options);
|
|
917
|
+
}
|
|
918
|
+
function aoaToSheet(data, options) {
|
|
919
|
+
return XLSX.utils.aoa_to_sheet(data, options);
|
|
920
|
+
}
|
|
921
|
+
function sheetToAOA(worksheet, options) {
|
|
922
|
+
return XLSX.utils.sheet_to_json(worksheet, { ...options, header: 1 });
|
|
923
|
+
}
|
|
753
924
|
export {
|
|
754
925
|
default2 as Decimal,
|
|
926
|
+
XLSX,
|
|
755
927
|
abs,
|
|
756
928
|
add,
|
|
757
929
|
addDaysToDate,
|
|
758
930
|
addDaysUTC,
|
|
759
931
|
addMonthsToDate,
|
|
760
932
|
addMonthsUTC,
|
|
933
|
+
aoaToSheet,
|
|
761
934
|
ceil,
|
|
935
|
+
clearAllCookies,
|
|
762
936
|
debounceFn as debounce,
|
|
763
937
|
divide,
|
|
764
938
|
equals,
|
|
939
|
+
exportExcelFile,
|
|
940
|
+
exportJSONToExcel,
|
|
765
941
|
floor,
|
|
766
942
|
formatDate,
|
|
767
943
|
formatDateOnly,
|
|
@@ -775,10 +951,12 @@ export {
|
|
|
775
951
|
formatUTCDateOnly,
|
|
776
952
|
formatUTCTimeOnly,
|
|
777
953
|
fromUTC,
|
|
954
|
+
getAllCookies,
|
|
778
955
|
getAllQueryParams,
|
|
779
956
|
getBrowser,
|
|
780
957
|
getBrowserEngine,
|
|
781
958
|
getBrowserVersion,
|
|
959
|
+
getCookie,
|
|
782
960
|
getDaysDiff,
|
|
783
961
|
getDeviceInfo,
|
|
784
962
|
getDevicePixelRatio,
|
|
@@ -793,6 +971,8 @@ export {
|
|
|
793
971
|
getQueryParam,
|
|
794
972
|
getQueryParamAll,
|
|
795
973
|
getScreenResolution,
|
|
974
|
+
getSheet,
|
|
975
|
+
getSheetNames,
|
|
796
976
|
getStartOfDay,
|
|
797
977
|
getStartOfMonth,
|
|
798
978
|
getStartOfWeek,
|
|
@@ -823,6 +1003,7 @@ export {
|
|
|
823
1003
|
getViewportSize,
|
|
824
1004
|
greaterThan,
|
|
825
1005
|
greaterThanOrEqual,
|
|
1006
|
+
hasCookie,
|
|
826
1007
|
isAfterDate,
|
|
827
1008
|
isAndroid,
|
|
828
1009
|
isBeforeDate,
|
|
@@ -834,19 +1015,37 @@ export {
|
|
|
834
1015
|
isTouchDevice,
|
|
835
1016
|
isValidDate,
|
|
836
1017
|
isWeChat,
|
|
1018
|
+
jsonToWorkbook,
|
|
837
1019
|
lessThan,
|
|
838
1020
|
lessThanOrEqual,
|
|
1021
|
+
maskEmail,
|
|
839
1022
|
multiply,
|
|
840
1023
|
negate,
|
|
841
1024
|
parseDate,
|
|
842
1025
|
parseMoney,
|
|
1026
|
+
read2 as read,
|
|
1027
|
+
readExcelFile,
|
|
1028
|
+
readExcelToJSON,
|
|
1029
|
+
readFile,
|
|
1030
|
+
removeCookie,
|
|
843
1031
|
round,
|
|
1032
|
+
setCookie,
|
|
1033
|
+
sheetToAOA,
|
|
1034
|
+
sheetToCSV,
|
|
1035
|
+
sheetToHTML,
|
|
844
1036
|
subDaysFromDate,
|
|
845
1037
|
subDaysUTC,
|
|
846
1038
|
subMonthsFromDate,
|
|
847
1039
|
subMonthsUTC,
|
|
848
1040
|
subtract,
|
|
1041
|
+
tableToSheet,
|
|
849
1042
|
throttleFn as throttle,
|
|
850
1043
|
toISOString,
|
|
851
|
-
toUTC
|
|
1044
|
+
toUTC,
|
|
1045
|
+
unmaskEmail,
|
|
1046
|
+
utils2 as utils,
|
|
1047
|
+
workbookToJSON,
|
|
1048
|
+
write,
|
|
1049
|
+
writeFile2 as writeFile,
|
|
1050
|
+
writeFileXLSX
|
|
852
1051
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-util-tools",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "A collection of useful utilities: throttle, debounce, date formatting, device detection, money formatting, decimal calculations and more",
|
|
3
|
+
"version": "1.0.25",
|
|
4
|
+
"description": "A collection of useful utilities: throttle, debounce, date formatting, device detection, money formatting, decimal calculations, Excel processing and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -14,6 +14,15 @@
|
|
|
14
14
|
"require": "./dist/index.cjs"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
19
|
+
"dev": "tsup src/index.ts --watch",
|
|
20
|
+
"prepublishOnly": "pnpm run build",
|
|
21
|
+
"release:patch": "pnpm version patch --no-git-tag-version && git add . && git commit -m 'chore: release v%s' && git tag v$(node -p \"require('./package.json').version\") && git push --follow-tags && pnpm publish --no-git-checks",
|
|
22
|
+
"release:minor": "pnpm version minor --no-git-tag-version && git add . && git commit -m 'chore: release v%s' && git tag v$(node -p \"require('./package.json').version\") && git push --follow-tags && pnpm publish --no-git-checks",
|
|
23
|
+
"release:major": "pnpm version major --no-git-tag-version && git add . && git commit -m 'chore: release v%s' && git tag v$(node -p \"require('./package.json').version\") && git push --follow-tags && pnpm publish --no-git-checks",
|
|
24
|
+
"release": "pnpm run release:patch"
|
|
25
|
+
},
|
|
17
26
|
"keywords": [
|
|
18
27
|
"react",
|
|
19
28
|
"utils",
|
|
@@ -27,6 +36,10 @@
|
|
|
27
36
|
"browser-detection",
|
|
28
37
|
"money-format",
|
|
29
38
|
"url-params",
|
|
39
|
+
"excel",
|
|
40
|
+
"xlsx",
|
|
41
|
+
"sheetjs",
|
|
42
|
+
"cookie",
|
|
30
43
|
"typescript"
|
|
31
44
|
],
|
|
32
45
|
"author": "alice & bobby",
|
|
@@ -53,14 +66,7 @@
|
|
|
53
66
|
"dependencies": {
|
|
54
67
|
"date-fns": "^4.1.0",
|
|
55
68
|
"date-fns-tz": "^3.2.0",
|
|
56
|
-
"decimal.js": "^10.6.0"
|
|
57
|
-
|
|
58
|
-
"scripts": {
|
|
59
|
-
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
60
|
-
"dev": "tsup src/index.ts --watch",
|
|
61
|
-
"release:patch": "pnpm version patch --no-git-tag-version && git add . && git commit -m 'chore: release v%s' && git tag v$(node -p \"require('./package.json').version\") && git push --follow-tags && pnpm publish --no-git-checks",
|
|
62
|
-
"release:minor": "pnpm version minor --no-git-tag-version && git add . && git commit -m 'chore: release v%s' && git tag v$(node -p \"require('./package.json').version\") && git push --follow-tags && pnpm publish --no-git-checks",
|
|
63
|
-
"release:major": "pnpm version major --no-git-tag-version && git add . && git commit -m 'chore: release v%s' && git tag v$(node -p \"require('./package.json').version\") && git push --follow-tags && pnpm publish --no-git-checks",
|
|
64
|
-
"release": "pnpm run release:patch"
|
|
69
|
+
"decimal.js": "^10.6.0",
|
|
70
|
+
"xlsx": "^0.18.5"
|
|
65
71
|
}
|
|
66
|
-
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# Excel - SheetJS 封装
|
|
2
|
+
|
|
3
|
+
基于 [SheetJS (xlsx)](https://docs.sheetjs.com/) 的 Excel 文件处理工具,保留了 SheetJS 的所有原生功能。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- ✅ 完整导出 SheetJS 所有功能
|
|
8
|
+
- 📖 读取 Excel 文件(.xlsx, .xls, .csv 等)
|
|
9
|
+
- 📝 创建和导出 Excel 文件
|
|
10
|
+
- 🔄 JSON 与 Excel 互转
|
|
11
|
+
- 🌐 支持多种格式(CSV, HTML, AOA 等)
|
|
12
|
+
- 💻 浏览器和 Node.js 环境均可使用
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install react-util-tools
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 基础用法
|
|
21
|
+
|
|
22
|
+
### 导入模块
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import {
|
|
26
|
+
XLSX, // 完整的 XLSX 对象
|
|
27
|
+
readExcelFile, // 读取 Excel 文件
|
|
28
|
+
exportJSONToExcel, // 导出 JSON 为 Excel
|
|
29
|
+
workbookToJSON, // WorkBook 转 JSON
|
|
30
|
+
jsonToWorkbook, // JSON 转 WorkBook
|
|
31
|
+
utils // XLSX 工具函数
|
|
32
|
+
} from 'react-util-tools'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 常用功能
|
|
36
|
+
|
|
37
|
+
### 1. 读取 Excel 文件
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { readExcelFile, workbookToJSON } from 'react-util-tools'
|
|
41
|
+
|
|
42
|
+
// 从 File 对象读取
|
|
43
|
+
async function handleFileUpload(file: File) {
|
|
44
|
+
try {
|
|
45
|
+
const workbook = await readExcelFile(file)
|
|
46
|
+
|
|
47
|
+
// 获取所有工作表名称
|
|
48
|
+
console.log(workbook.SheetNames) // ['Sheet1', 'Sheet2']
|
|
49
|
+
|
|
50
|
+
// 转换为 JSON
|
|
51
|
+
const data = workbookToJSON(workbook)
|
|
52
|
+
console.log(data)
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('读取失败:', error)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 在 React 中使用
|
|
59
|
+
function ExcelUploader() {
|
|
60
|
+
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
61
|
+
const file = e.target.files?.[0]
|
|
62
|
+
if (file) {
|
|
63
|
+
await handleFileUpload(file)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return <input type="file" accept=".xlsx,.xls" onChange={handleChange} />
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2. 直接读取为 JSON
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { readExcelToJSON } from 'react-util-tools'
|
|
75
|
+
|
|
76
|
+
async function loadExcelData(file: File) {
|
|
77
|
+
// 读取第一个工作表
|
|
78
|
+
const data = await readExcelToJSON(file)
|
|
79
|
+
console.log(data)
|
|
80
|
+
|
|
81
|
+
// 读取指定工作表
|
|
82
|
+
const sheet2Data = await readExcelToJSON(file, 'Sheet2')
|
|
83
|
+
console.log(sheet2Data)
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. 导出 JSON 为 Excel
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { exportJSONToExcel } from 'react-util-tools'
|
|
91
|
+
|
|
92
|
+
function exportData() {
|
|
93
|
+
const data = [
|
|
94
|
+
{ name: '张三', age: 25, city: '北京' },
|
|
95
|
+
{ name: '李四', age: 30, city: '上海' },
|
|
96
|
+
{ name: '王五', age: 28, city: '广州' }
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
// 导出为 Excel 文件
|
|
100
|
+
exportJSONToExcel(data, 'users.xlsx', 'UserList')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 在 React 中使用
|
|
104
|
+
function ExportButton() {
|
|
105
|
+
return <button onClick={exportData}>导出 Excel</button>
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 4. 创建多工作表 Excel
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { XLSX, utils, exportExcelFile } from 'react-util-tools'
|
|
113
|
+
|
|
114
|
+
function exportMultiSheet() {
|
|
115
|
+
// 创建工作簿
|
|
116
|
+
const workbook = utils.book_new()
|
|
117
|
+
|
|
118
|
+
// 第一个工作表
|
|
119
|
+
const users = [
|
|
120
|
+
{ name: '张三', age: 25 },
|
|
121
|
+
{ name: '李四', age: 30 }
|
|
122
|
+
]
|
|
123
|
+
const sheet1 = utils.json_to_sheet(users)
|
|
124
|
+
utils.book_append_sheet(workbook, sheet1, '用户列表')
|
|
125
|
+
|
|
126
|
+
// 第二个工作表
|
|
127
|
+
const products = [
|
|
128
|
+
{ product: 'iPhone', price: 5999 },
|
|
129
|
+
{ product: 'iPad', price: 3999 }
|
|
130
|
+
]
|
|
131
|
+
const sheet2 = utils.json_to_sheet(products)
|
|
132
|
+
utils.book_append_sheet(workbook, sheet2, '产品列表')
|
|
133
|
+
|
|
134
|
+
// 导出文件
|
|
135
|
+
exportExcelFile(workbook, 'data.xlsx')
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 5. 自定义表头
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { jsonToWorkbook, exportExcelFile } from 'react-util-tools'
|
|
143
|
+
|
|
144
|
+
function exportWithCustomHeaders() {
|
|
145
|
+
const data = [
|
|
146
|
+
{ name: '张三', age: 25, city: '北京' },
|
|
147
|
+
{ name: '李四', age: 30, city: '上海' }
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
// 自定义表头
|
|
151
|
+
const workbook = jsonToWorkbook(data, 'Sheet1', {
|
|
152
|
+
header: ['姓名', '年龄', '城市']
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
exportExcelFile(workbook, 'custom-headers.xlsx')
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 6. 使用 AOA (Array of Arrays)
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { aoaToSheet, utils, exportExcelFile } from 'react-util-tools'
|
|
163
|
+
|
|
164
|
+
function exportFromArray() {
|
|
165
|
+
const data = [
|
|
166
|
+
['姓名', '年龄', '城市'],
|
|
167
|
+
['张三', 25, '北京'],
|
|
168
|
+
['李四', 30, '上海'],
|
|
169
|
+
['王五', 28, '广州']
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
const worksheet = aoaToSheet(data)
|
|
173
|
+
const workbook = utils.book_new()
|
|
174
|
+
utils.book_append_sheet(workbook, worksheet, 'Sheet1')
|
|
175
|
+
|
|
176
|
+
exportExcelFile(workbook, 'array-data.xlsx')
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 7. 转换为 CSV
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { readExcelFile, getSheet, sheetToCSV } from 'react-util-tools'
|
|
184
|
+
|
|
185
|
+
async function convertToCSV(file: File) {
|
|
186
|
+
const workbook = await readExcelFile(file)
|
|
187
|
+
const sheet = getSheet(workbook, 'Sheet1')
|
|
188
|
+
const csv = sheetToCSV(sheet)
|
|
189
|
+
|
|
190
|
+
console.log(csv)
|
|
191
|
+
|
|
192
|
+
// 下载 CSV
|
|
193
|
+
const blob = new Blob([csv], { type: 'text/csv' })
|
|
194
|
+
const url = URL.createObjectURL(blob)
|
|
195
|
+
const a = document.createElement('a')
|
|
196
|
+
a.href = url
|
|
197
|
+
a.download = 'data.csv'
|
|
198
|
+
a.click()
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 8. 从 HTML 表格创建 Excel
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { tableToSheet, utils, exportExcelFile } from 'react-util-tools'
|
|
206
|
+
|
|
207
|
+
function exportTableToExcel() {
|
|
208
|
+
const table = document.querySelector('table')
|
|
209
|
+
if (!table) return
|
|
210
|
+
|
|
211
|
+
const worksheet = tableToSheet(table)
|
|
212
|
+
const workbook = utils.book_new()
|
|
213
|
+
utils.book_append_sheet(workbook, worksheet, 'Sheet1')
|
|
214
|
+
|
|
215
|
+
exportExcelFile(workbook, 'table-export.xlsx')
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 高级用法
|
|
220
|
+
|
|
221
|
+
### 使用完整的 XLSX 对象
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import { XLSX } from 'react-util-tools'
|
|
225
|
+
|
|
226
|
+
// 访问所有 SheetJS 功能
|
|
227
|
+
const workbook = XLSX.read(data, { type: 'binary' })
|
|
228
|
+
const worksheet = workbook.Sheets[workbook.SheetNames[0]]
|
|
229
|
+
|
|
230
|
+
// 设置单元格样式(需要 xlsx-style 或 xlsx-js-style)
|
|
231
|
+
worksheet['A1'].s = {
|
|
232
|
+
font: { bold: true },
|
|
233
|
+
fill: { fgColor: { rgb: 'FFFF00' } }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 合并单元格
|
|
237
|
+
worksheet['!merges'] = [
|
|
238
|
+
{ s: { r: 0, c: 0 }, e: { r: 0, c: 2 } }
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
// 设置列宽
|
|
242
|
+
worksheet['!cols'] = [
|
|
243
|
+
{ wch: 20 },
|
|
244
|
+
{ wch: 15 },
|
|
245
|
+
{ wch: 30 }
|
|
246
|
+
]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 读取选项
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { readExcelFile } from 'react-util-tools'
|
|
253
|
+
|
|
254
|
+
const workbook = await readExcelFile(file, {
|
|
255
|
+
type: 'binary', // 数据类型
|
|
256
|
+
cellDates: true, // 将日期解析为 Date 对象
|
|
257
|
+
cellNF: false, // 不保存数字格式
|
|
258
|
+
cellStyles: false, // 不保存样式
|
|
259
|
+
sheetStubs: false, // 不生成空单元格
|
|
260
|
+
raw: false // 不使用原始值
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 写入选项
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import { exportExcelFile } from 'react-util-tools'
|
|
268
|
+
|
|
269
|
+
exportExcelFile(workbook, 'output.xlsx', {
|
|
270
|
+
bookType: 'xlsx', // 文件类型
|
|
271
|
+
type: 'binary', // 输出类型
|
|
272
|
+
compression: true, // 启用压缩
|
|
273
|
+
Props: { // 文档属性
|
|
274
|
+
Title: '数据报表',
|
|
275
|
+
Author: '系统管理员',
|
|
276
|
+
CreatedDate: new Date()
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## 支持的文件格式
|
|
282
|
+
|
|
283
|
+
### 读取格式
|
|
284
|
+
- `.xlsx` - Excel 2007+ XML 格式
|
|
285
|
+
- `.xlsb` - Excel 2007+ 二进制格式
|
|
286
|
+
- `.xlsm` - Excel 2007+ 宏文件
|
|
287
|
+
- `.xls` - Excel 97-2004 格式
|
|
288
|
+
- `.csv` - 逗号分隔值
|
|
289
|
+
- `.txt` - 文本文件
|
|
290
|
+
- `.ods` - OpenDocument 电子表格
|
|
291
|
+
- 更多格式请参考 [SheetJS 文档](https://docs.sheetjs.com/)
|
|
292
|
+
|
|
293
|
+
### 导出格式
|
|
294
|
+
- `xlsx` - Excel 2007+ XML 格式(默认)
|
|
295
|
+
- `xlsb` - Excel 2007+ 二进制格式
|
|
296
|
+
- `xls` - Excel 97-2004 格式
|
|
297
|
+
- `csv` - 逗号分隔值
|
|
298
|
+
- `txt` - UTF-16 文本
|
|
299
|
+
- `html` - HTML 表格
|
|
300
|
+
- `ods` - OpenDocument 电子表格
|
|
301
|
+
|
|
302
|
+
## API 参考
|
|
303
|
+
|
|
304
|
+
### 核心导出
|
|
305
|
+
|
|
306
|
+
- `XLSX` - 完整的 SheetJS 对象
|
|
307
|
+
- `utils` - SheetJS 工具函数集合
|
|
308
|
+
- `read` - 读取数据
|
|
309
|
+
- `write` - 写入数据
|
|
310
|
+
- `readFile` - 读取文件(Node.js)
|
|
311
|
+
- `writeFile` - 写入文件
|
|
312
|
+
|
|
313
|
+
### 封装函数
|
|
314
|
+
|
|
315
|
+
#### readExcelFile(file, options?)
|
|
316
|
+
从 File 对象读取 Excel 文件
|
|
317
|
+
|
|
318
|
+
#### workbookToJSON(workbook, sheetName?, options?)
|
|
319
|
+
将 WorkBook 转换为 JSON 数组
|
|
320
|
+
|
|
321
|
+
#### jsonToWorkbook(data, sheetName?, options?)
|
|
322
|
+
从 JSON 数组创建 WorkBook
|
|
323
|
+
|
|
324
|
+
#### exportExcelFile(workbook, filename?, options?)
|
|
325
|
+
导出 Excel 文件(浏览器下载)
|
|
326
|
+
|
|
327
|
+
#### exportJSONToExcel(data, filename?, sheetName?, options?)
|
|
328
|
+
直接从 JSON 导出 Excel 文件
|
|
329
|
+
|
|
330
|
+
#### readExcelToJSON(file, sheetName?, parseOptions?, jsonOptions?)
|
|
331
|
+
读取 Excel 文件并转换为 JSON
|
|
332
|
+
|
|
333
|
+
#### getSheetNames(workbook)
|
|
334
|
+
获取所有工作表名称
|
|
335
|
+
|
|
336
|
+
#### getSheet(workbook, sheetName)
|
|
337
|
+
获取指定工作表
|
|
338
|
+
|
|
339
|
+
#### sheetToCSV(worksheet, options?)
|
|
340
|
+
将工作表转换为 CSV 字符串
|
|
341
|
+
|
|
342
|
+
#### sheetToHTML(worksheet, options?)
|
|
343
|
+
将工作表转换为 HTML 字符串
|
|
344
|
+
|
|
345
|
+
#### tableToSheet(table, options?)
|
|
346
|
+
从 HTML 表格创建工作表
|
|
347
|
+
|
|
348
|
+
#### aoaToSheet(data, options?)
|
|
349
|
+
从二维数组创建工作表
|
|
350
|
+
|
|
351
|
+
#### sheetToAOA(worksheet, options?)
|
|
352
|
+
将工作表转换为二维数组
|
|
353
|
+
|
|
354
|
+
## TypeScript 支持
|
|
355
|
+
|
|
356
|
+
完整的 TypeScript 类型定义:
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import type {
|
|
360
|
+
WorkBook,
|
|
361
|
+
WorkSheet,
|
|
362
|
+
CellObject,
|
|
363
|
+
Range,
|
|
364
|
+
WritingOptions,
|
|
365
|
+
ParsingOptions,
|
|
366
|
+
BookType,
|
|
367
|
+
Sheet2JSONOpts,
|
|
368
|
+
JSON2SheetOpts
|
|
369
|
+
} from 'react-util-tools'
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## 注意事项
|
|
373
|
+
|
|
374
|
+
1. **浏览器环境**:文件读取使用 FileReader API
|
|
375
|
+
2. **文件大小**:处理大文件时注意内存占用
|
|
376
|
+
3. **样式支持**:基础版本不支持样式,需要额外的库
|
|
377
|
+
4. **日期格式**:Excel 日期需要特殊处理
|
|
378
|
+
5. **公式**:默认读取公式的计算结果,不是公式本身
|
|
379
|
+
|
|
380
|
+
## 相关链接
|
|
381
|
+
|
|
382
|
+
- [SheetJS 官方文档](https://docs.sheetjs.com/)
|
|
383
|
+
- [SheetJS GitHub](https://github.com/SheetJS/sheetjs)
|
|
384
|
+
- [在线演示](https://sheetjs.com/demos)
|
|
385
|
+
|
|
386
|
+
## 示例项目
|
|
387
|
+
|
|
388
|
+
完整的使用示例请参考项目中的示例代码。
|