@cfmm/umi-plugins-ui-v2 0.0.16 → 0.0.17
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/dist/cjs/components/CrudTable.tpl +2 -2
- package/dist/cjs/components/ImportExecl.tpl +3 -1
- package/dist/cjs/types/ImportExeclTypes.d.ts +1 -1
- package/dist/cjs/types/ImportExeclTypes.js +1 -1
- package/dist/cjs/utils/importHelper.tpl +18 -7
- package/dist/esm/components/CrudTable.tpl +2 -2
- package/dist/esm/components/ImportExecl.tpl +3 -1
- package/dist/esm/types/ImportExeclTypes.d.ts +1 -1
- package/dist/esm/types/ImportExeclTypes.js +1 -1
- package/dist/esm/utils/importHelper.tpl +18 -7
- package/package.json +1 -1
|
@@ -887,7 +887,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
887
887
|
label: (
|
|
888
888
|
<ImportExecl key="importMultiLang" rangeStart={{ c: 0, r: 2 }} onChange={importMultiLang}>
|
|
889
889
|
<span>
|
|
890
|
-
<UploadOutlined style={{ marginRight:
|
|
890
|
+
<UploadOutlined style={{ marginRight: 6 }} />
|
|
891
891
|
{formatMessage({ id: 'cfmmUI.common.button.importMultiLang', defaultMessage: '导入多语言' })}
|
|
892
892
|
</span>
|
|
893
893
|
</ImportExecl>
|
|
@@ -926,7 +926,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
926
926
|
{...(importData?.attributes || {})}
|
|
927
927
|
>
|
|
928
928
|
<div style={{ color: !actionLoading ? 'rgba(0, 0, 0, 0.88)' : 'rgba(0, 0, 0, 0.25)' }}>
|
|
929
|
-
<UploadOutlined style={{ marginRight:
|
|
929
|
+
<UploadOutlined style={{ marginRight: 6 }} />
|
|
930
930
|
{formatMessage({ id: 'cfmmUI.common.button.importData', defaultMessage: '导入数据' })}
|
|
931
931
|
</div>
|
|
932
932
|
</ImportExecl>
|
|
@@ -14,6 +14,8 @@ const ImportExecl = <T,>(props: ImportExeclProps<T>) => {
|
|
|
14
14
|
max,
|
|
15
15
|
header,
|
|
16
16
|
rangeStart,
|
|
17
|
+
defval,
|
|
18
|
+
blankrows,
|
|
17
19
|
uploadProps,
|
|
18
20
|
buttonProps,
|
|
19
21
|
children,
|
|
@@ -36,7 +38,7 @@ const ImportExecl = <T,>(props: ImportExeclProps<T>) => {
|
|
|
36
38
|
0,
|
|
37
39
|
);
|
|
38
40
|
|
|
39
|
-
const data = await importExexl({ file: info.file, rangeStart, max, header });
|
|
41
|
+
const data = await importExexl({ file: info.file, rangeStart, max, header, defval, blankrows });
|
|
40
42
|
const result = await onChange?.(data as T, info.file as UploadFile);
|
|
41
43
|
|
|
42
44
|
hide?.();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
1
|
+
export declare const ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u7A7A\u5355\u5143\u683C\u5360\u4F4D\u503C\uFF1B\u4F20\u5165\u540E\u6BCF\u884C\u5BF9\u8C61\u4F1A\u5305\u542B\u4E0E\u8868\u5934\u5BF9\u9F50\u7684\u5168\u90E8 key\uFF08\u7A7A\u5355\u5143\u683C\u4E3A\u8BE5\u503C\uFF09\uFF0C\u5426\u5219 SheetJS \u4F1A\u7701\u7565\u7A7A\u5355\u5143\u683C\u5BF9\u5E94\u5B57\u6BB5\n */\n defval?: unknown;\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.ImportExeclTypes = void 0;
|
|
7
|
-
var ImportExeclTypes = exports.ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
7
|
+
var ImportExeclTypes = exports.ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u7A7A\u5355\u5143\u683C\u5360\u4F4D\u503C\uFF1B\u4F20\u5165\u540E\u6BCF\u884C\u5BF9\u8C61\u4F1A\u5305\u542B\u4E0E\u8868\u5934\u5BF9\u9F50\u7684\u5168\u90E8 key\uFF08\u7A7A\u5355\u5143\u683C\u4E3A\u8BE5\u503C\uFF09\uFF0C\u5426\u5219 SheetJS \u4F1A\u7701\u7565\u7A7A\u5355\u5143\u683C\u5BF9\u5E94\u5B57\u6BB5\n */\n defval?: unknown;\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// replaceTo:tsx
|
|
2
|
-
import { UTC_FORMAT } from '../constants';
|
|
3
2
|
import { getIntl } from '@umijs/max';
|
|
4
3
|
import { Modal, Tag } from 'antd';
|
|
5
4
|
import dayjs from 'dayjs';
|
|
6
5
|
import { parse } from 'querystring';
|
|
7
6
|
import * as XLSX from 'xlsx';
|
|
7
|
+
import { UTC_FORMAT } from '../constants';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 提取括号中的值
|
|
@@ -22,6 +22,8 @@ export const getParenthesisValue = (str: string) => {
|
|
|
22
22
|
* @param max 最大读取行数
|
|
23
23
|
* @param header 哪行是表头,默认第一行
|
|
24
24
|
* @param rangeStart 开始读取行数{ c: 1, r: 2 } 从第2列第3行开始读取
|
|
25
|
+
* @param defval 缺省单元格占位值;传入后空单元格也会出现在每行对象中(如 `''` / `null`),不传则 SheetJS 默认会省略空字段的 key
|
|
26
|
+
* @param blankrows 是否输出完全空白的行,与 SheetJS `sheet_to_json` 的 `blankrows` 一致;不传则使用库默认
|
|
25
27
|
* @return Promise<T = any[]>
|
|
26
28
|
*/
|
|
27
29
|
export function importExexl<T = any>({
|
|
@@ -29,11 +31,17 @@ export function importExexl<T = any>({
|
|
|
29
31
|
max = 1,
|
|
30
32
|
rangeStart,
|
|
31
33
|
header,
|
|
34
|
+
defval = null,
|
|
35
|
+
blankrows,
|
|
32
36
|
}: {
|
|
33
37
|
file: any;
|
|
34
38
|
max?: number;
|
|
35
39
|
header?: number;
|
|
36
40
|
rangeStart?: { c: number; r: number };
|
|
41
|
+
/** 空单元格占位,传入后不过滤空字段(与表头对齐的 key 都会存在) */
|
|
42
|
+
defval?: unknown;
|
|
43
|
+
/** 是否输出空白行 */
|
|
44
|
+
blankrows?: boolean;
|
|
37
45
|
}): Promise<T[]> {
|
|
38
46
|
return new Promise((resolve, reject) => {
|
|
39
47
|
// 通过FileReader对象读取文件
|
|
@@ -61,6 +69,9 @@ export function importExexl<T = any>({
|
|
|
61
69
|
XLSX.utils.sheet_to_json(workbook.Sheets[sheet], {
|
|
62
70
|
header,
|
|
63
71
|
dateNF: 'YYYY-MM-DDTHH:mm:ss[Z]',
|
|
72
|
+
...(blankrows !== undefined ? { blankrows } : {}),
|
|
73
|
+
// 有 defval 时空单元格也会生成对应字段,否则缺省单元格不会出现在对象里
|
|
74
|
+
...(defval !== undefined ? { defval } : {}),
|
|
64
75
|
// 属性s从第1列第3行开始读取,属性c到最后一行最后一列结束(Excel 行号从1开始)
|
|
65
76
|
range: rangeStart
|
|
66
77
|
? {
|
|
@@ -145,23 +156,23 @@ function convertIndexedPropertiesToArrays(obj: Record<string, any>): any {
|
|
|
145
156
|
* @returns
|
|
146
157
|
*/
|
|
147
158
|
export const handleImportExeclCellValue = (value: unknown, type?: string) => {
|
|
148
|
-
if (!value && value !== 0 && value !== '0') return;
|
|
159
|
+
if (!value && value !== 0 && value !== '0') return value;
|
|
149
160
|
|
|
150
161
|
if (type === 'parenthesisCode') {
|
|
151
162
|
const newValue = getParenthesisValue(value as string);
|
|
152
163
|
return typeof newValue === 'string' ? newValue.trim() : newValue;
|
|
153
164
|
}
|
|
154
|
-
if (value instanceof Date || (type === 'date' && typeof value === 'string')) {
|
|
165
|
+
if (value instanceof Date || (type === 'date' && typeof value === 'string')) {
|
|
155
166
|
if (value instanceof Date) {
|
|
156
167
|
const corrected = new Date(value);
|
|
157
168
|
const seconds = corrected.getSeconds();
|
|
158
|
-
|
|
169
|
+
|
|
159
170
|
// 修正读取execl日期精度问题,如果秒数大于10,加1分钟并清零分钟和秒
|
|
160
171
|
if (seconds > 10) {
|
|
161
172
|
corrected.setMinutes(corrected.getMinutes() + 1);
|
|
162
173
|
corrected.setSeconds(0, 0); // 清零秒和毫秒
|
|
163
174
|
}
|
|
164
|
-
|
|
175
|
+
|
|
165
176
|
const dateStr = dayjs.utc(corrected).format(UTC_FORMAT);
|
|
166
177
|
return dateStr;
|
|
167
178
|
}
|
|
@@ -187,7 +198,7 @@ export const createNestedObjectAndSetValue = (
|
|
|
187
198
|
keys: string | string[],
|
|
188
199
|
value: any,
|
|
189
200
|
obj: Record<string, any>,
|
|
190
|
-
options: Omit<HandleImportListOptions, 'hasRowNum'
|
|
201
|
+
options: Omit<HandleImportListOptions, 'hasRowNum'>,
|
|
191
202
|
) => {
|
|
192
203
|
if (!keys.length) return obj;
|
|
193
204
|
// 过滤没有定义code的字段
|
|
@@ -207,7 +218,7 @@ export const createNestedObjectAndSetValue = (
|
|
|
207
218
|
const handleValue = needHandleCenterlineValue ? (value === '-' ? null : value) : value;
|
|
208
219
|
|
|
209
220
|
// 转为嵌套对象
|
|
210
|
-
newKeys.forEach((key) => {
|
|
221
|
+
newKeys.forEach((key, idx) => {
|
|
211
222
|
if (current[key] === undefined) {
|
|
212
223
|
current[key] = {};
|
|
213
224
|
}
|
|
@@ -887,7 +887,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
887
887
|
label: (
|
|
888
888
|
<ImportExecl key="importMultiLang" rangeStart={{ c: 0, r: 2 }} onChange={importMultiLang}>
|
|
889
889
|
<span>
|
|
890
|
-
<UploadOutlined style={{ marginRight:
|
|
890
|
+
<UploadOutlined style={{ marginRight: 6 }} />
|
|
891
891
|
{formatMessage({ id: 'cfmmUI.common.button.importMultiLang', defaultMessage: '导入多语言' })}
|
|
892
892
|
</span>
|
|
893
893
|
</ImportExecl>
|
|
@@ -926,7 +926,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
926
926
|
{...(importData?.attributes || {})}
|
|
927
927
|
>
|
|
928
928
|
<div style={{ color: !actionLoading ? 'rgba(0, 0, 0, 0.88)' : 'rgba(0, 0, 0, 0.25)' }}>
|
|
929
|
-
<UploadOutlined style={{ marginRight:
|
|
929
|
+
<UploadOutlined style={{ marginRight: 6 }} />
|
|
930
930
|
{formatMessage({ id: 'cfmmUI.common.button.importData', defaultMessage: '导入数据' })}
|
|
931
931
|
</div>
|
|
932
932
|
</ImportExecl>
|
|
@@ -14,6 +14,8 @@ const ImportExecl = <T,>(props: ImportExeclProps<T>) => {
|
|
|
14
14
|
max,
|
|
15
15
|
header,
|
|
16
16
|
rangeStart,
|
|
17
|
+
defval,
|
|
18
|
+
blankrows,
|
|
17
19
|
uploadProps,
|
|
18
20
|
buttonProps,
|
|
19
21
|
children,
|
|
@@ -36,7 +38,7 @@ const ImportExecl = <T,>(props: ImportExeclProps<T>) => {
|
|
|
36
38
|
0,
|
|
37
39
|
);
|
|
38
40
|
|
|
39
|
-
const data = await importExexl({ file: info.file, rangeStart, max, header });
|
|
41
|
+
const data = await importExexl({ file: info.file, rangeStart, max, header, defval, blankrows });
|
|
40
42
|
const result = await onChange?.(data as T, info.file as UploadFile);
|
|
41
43
|
|
|
42
44
|
hide?.();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
1
|
+
export declare const ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u7A7A\u5355\u5143\u683C\u5360\u4F4D\u503C\uFF1B\u4F20\u5165\u540E\u6BCF\u884C\u5BF9\u8C61\u4F1A\u5305\u542B\u4E0E\u8868\u5934\u5BF9\u9F50\u7684\u5168\u90E8 key\uFF08\u7A7A\u5355\u5143\u683C\u4E3A\u8BE5\u503C\uFF09\uFF0C\u5426\u5219 SheetJS \u4F1A\u7701\u7565\u7A7A\u5355\u5143\u683C\u5BF9\u5E94\u5B57\u6BB5\n */\n defval?: unknown;\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export var ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
1
|
+
export var ImportExeclTypes = "\nexport interface ImportExeclProps<T = any[]> {\n accept?: string;\n /**\n * \u4E0A\u4F20\u4E8B\u4EF6\uFF0C\u83B7\u53D6execl\u6570\u636E\u5217\u8868\uFF0C\u51FD\u6570\u8FD4\u56DEpromise\u5E76\u4E14showDefautlMessage\u4E0D\u662Ffalse\u65F6\u6709\u9ED8\u8BA4message\u63D0\u793A\n */\n onChange: (list: T, fileInfo: Pick<UploadFile, 'name' | 'size' | 'type' | 'uid'>) => Promise<{ success: boolean; failMsg?: string; data?: any } | void> | void;\n /**\n * \u663E\u793A\u9ED8\u8BA4\u7684\u63D0\u793A\n */\n showDefautlMessage?: boolean;\n /**\n * \u6309\u94AE\u6587\u672C\n */\n title?: string;\n /**\n * \u8BFB\u53D6\u5DE5\u4F5C\u7C3F\u6570\u91CF\uFF0C\u9ED8\u8BA41\n */\n max?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u884C\u4E3A\u8868\u5934\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\n */\n header?: number;\n /**\n * \u4EE5\u7B2C\u51E0\u5217\u7B2C\u51E0\u884C\u5F00\u59CB\u8BFB\u53D6\uFF0C\u9ED8\u8BA4\u7B2C\u4E00\u884C\u7B2C\u4E00\u5217\n */\n rangeStart?: { c: number; r: number };\n /**\n * \u7A7A\u5355\u5143\u683C\u5360\u4F4D\u503C\uFF1B\u4F20\u5165\u540E\u6BCF\u884C\u5BF9\u8C61\u4F1A\u5305\u542B\u4E0E\u8868\u5934\u5BF9\u9F50\u7684\u5168\u90E8 key\uFF08\u7A7A\u5355\u5143\u683C\u4E3A\u8BE5\u503C\uFF09\uFF0C\u5426\u5219 SheetJS \u4F1A\u7701\u7565\u7A7A\u5355\u5143\u683C\u5BF9\u5E94\u5B57\u6BB5\n */\n defval?: unknown;\n /**\n * \u4FDD\u7559\u7A7A\u884C\uFF0C\u9ED8\u8BA4false\n */\n blankrows?: boolean;\n /**\n * \u81EA\u5B9A\u4E49\u6309\u94AE\u5185\u5BB9\n */\n children?: React.ReactNode;\n /**\n * Upload\u7EC4\u4EF6\u5C5E\u6027\n */\n uploadProps?: UploadProps;\n /**\n * Button\u7EC4\u4EF6\u5C5E\u6027\n */\n buttonProps?: ButtonProps;\n}\n";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// replaceTo:tsx
|
|
2
|
-
import { UTC_FORMAT } from '../constants';
|
|
3
2
|
import { getIntl } from '@umijs/max';
|
|
4
3
|
import { Modal, Tag } from 'antd';
|
|
5
4
|
import dayjs from 'dayjs';
|
|
6
5
|
import { parse } from 'querystring';
|
|
7
6
|
import * as XLSX from 'xlsx';
|
|
7
|
+
import { UTC_FORMAT } from '../constants';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 提取括号中的值
|
|
@@ -22,6 +22,8 @@ export const getParenthesisValue = (str: string) => {
|
|
|
22
22
|
* @param max 最大读取行数
|
|
23
23
|
* @param header 哪行是表头,默认第一行
|
|
24
24
|
* @param rangeStart 开始读取行数{ c: 1, r: 2 } 从第2列第3行开始读取
|
|
25
|
+
* @param defval 缺省单元格占位值;传入后空单元格也会出现在每行对象中(如 `''` / `null`),不传则 SheetJS 默认会省略空字段的 key
|
|
26
|
+
* @param blankrows 是否输出完全空白的行,与 SheetJS `sheet_to_json` 的 `blankrows` 一致;不传则使用库默认
|
|
25
27
|
* @return Promise<T = any[]>
|
|
26
28
|
*/
|
|
27
29
|
export function importExexl<T = any>({
|
|
@@ -29,11 +31,17 @@ export function importExexl<T = any>({
|
|
|
29
31
|
max = 1,
|
|
30
32
|
rangeStart,
|
|
31
33
|
header,
|
|
34
|
+
defval = null,
|
|
35
|
+
blankrows,
|
|
32
36
|
}: {
|
|
33
37
|
file: any;
|
|
34
38
|
max?: number;
|
|
35
39
|
header?: number;
|
|
36
40
|
rangeStart?: { c: number; r: number };
|
|
41
|
+
/** 空单元格占位,传入后不过滤空字段(与表头对齐的 key 都会存在) */
|
|
42
|
+
defval?: unknown;
|
|
43
|
+
/** 是否输出空白行 */
|
|
44
|
+
blankrows?: boolean;
|
|
37
45
|
}): Promise<T[]> {
|
|
38
46
|
return new Promise((resolve, reject) => {
|
|
39
47
|
// 通过FileReader对象读取文件
|
|
@@ -61,6 +69,9 @@ export function importExexl<T = any>({
|
|
|
61
69
|
XLSX.utils.sheet_to_json(workbook.Sheets[sheet], {
|
|
62
70
|
header,
|
|
63
71
|
dateNF: 'YYYY-MM-DDTHH:mm:ss[Z]',
|
|
72
|
+
...(blankrows !== undefined ? { blankrows } : {}),
|
|
73
|
+
// 有 defval 时空单元格也会生成对应字段,否则缺省单元格不会出现在对象里
|
|
74
|
+
...(defval !== undefined ? { defval } : {}),
|
|
64
75
|
// 属性s从第1列第3行开始读取,属性c到最后一行最后一列结束(Excel 行号从1开始)
|
|
65
76
|
range: rangeStart
|
|
66
77
|
? {
|
|
@@ -145,23 +156,23 @@ function convertIndexedPropertiesToArrays(obj: Record<string, any>): any {
|
|
|
145
156
|
* @returns
|
|
146
157
|
*/
|
|
147
158
|
export const handleImportExeclCellValue = (value: unknown, type?: string) => {
|
|
148
|
-
if (!value && value !== 0 && value !== '0') return;
|
|
159
|
+
if (!value && value !== 0 && value !== '0') return value;
|
|
149
160
|
|
|
150
161
|
if (type === 'parenthesisCode') {
|
|
151
162
|
const newValue = getParenthesisValue(value as string);
|
|
152
163
|
return typeof newValue === 'string' ? newValue.trim() : newValue;
|
|
153
164
|
}
|
|
154
|
-
if (value instanceof Date || (type === 'date' && typeof value === 'string')) {
|
|
165
|
+
if (value instanceof Date || (type === 'date' && typeof value === 'string')) {
|
|
155
166
|
if (value instanceof Date) {
|
|
156
167
|
const corrected = new Date(value);
|
|
157
168
|
const seconds = corrected.getSeconds();
|
|
158
|
-
|
|
169
|
+
|
|
159
170
|
// 修正读取execl日期精度问题,如果秒数大于10,加1分钟并清零分钟和秒
|
|
160
171
|
if (seconds > 10) {
|
|
161
172
|
corrected.setMinutes(corrected.getMinutes() + 1);
|
|
162
173
|
corrected.setSeconds(0, 0); // 清零秒和毫秒
|
|
163
174
|
}
|
|
164
|
-
|
|
175
|
+
|
|
165
176
|
const dateStr = dayjs.utc(corrected).format(UTC_FORMAT);
|
|
166
177
|
return dateStr;
|
|
167
178
|
}
|
|
@@ -187,7 +198,7 @@ export const createNestedObjectAndSetValue = (
|
|
|
187
198
|
keys: string | string[],
|
|
188
199
|
value: any,
|
|
189
200
|
obj: Record<string, any>,
|
|
190
|
-
options: Omit<HandleImportListOptions, 'hasRowNum'
|
|
201
|
+
options: Omit<HandleImportListOptions, 'hasRowNum'>,
|
|
191
202
|
) => {
|
|
192
203
|
if (!keys.length) return obj;
|
|
193
204
|
// 过滤没有定义code的字段
|
|
@@ -207,7 +218,7 @@ export const createNestedObjectAndSetValue = (
|
|
|
207
218
|
const handleValue = needHandleCenterlineValue ? (value === '-' ? null : value) : value;
|
|
208
219
|
|
|
209
220
|
// 转为嵌套对象
|
|
210
|
-
newKeys.forEach((key) => {
|
|
221
|
+
newKeys.forEach((key, idx) => {
|
|
211
222
|
if (current[key] === undefined) {
|
|
212
223
|
current[key] = {};
|
|
213
224
|
}
|