@cfmm/umi-plugins-ui-v2 0.0.16 → 0.0.18
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 +27 -6
- package/dist/cjs/components/ImportExecl.tpl +53 -5
- package/dist/cjs/hooks/useAction.tpl +38 -23
- package/dist/cjs/locales/en-US.d.ts +3 -0
- package/dist/cjs/locales/enUS/File.d.ts +3 -0
- package/dist/cjs/locales/enUS/File.js +3 -0
- package/dist/cjs/locales/enUS/index.d.ts +3 -0
- package/dist/cjs/locales/th-TH.d.ts +3 -0
- package/dist/cjs/locales/zh-CN.d.ts +3 -0
- package/dist/cjs/locales/zh-TW.d.ts +3 -0
- package/dist/cjs/locales/zhCN/File.d.ts +3 -0
- package/dist/cjs/locales/zhCN/File.js +3 -0
- package/dist/cjs/locales/zhCN/index.d.ts +3 -0
- package/dist/cjs/locales/zhTW/File.d.ts +3 -0
- package/dist/cjs/locales/zhTW/File.js +3 -0
- package/dist/cjs/locales/zhTW/index.d.ts +3 -0
- package/dist/cjs/types/CrudTableTypes.d.ts +1 -1
- package/dist/cjs/types/CrudTableTypes.js +1 -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 +27 -6
- package/dist/esm/components/ImportExecl.tpl +53 -5
- package/dist/esm/hooks/useAction.tpl +38 -23
- package/dist/esm/locales/en-US.d.ts +3 -0
- package/dist/esm/locales/enUS/File.d.ts +3 -0
- package/dist/esm/locales/enUS/File.js +3 -0
- package/dist/esm/locales/enUS/index.d.ts +3 -0
- package/dist/esm/locales/th-TH.d.ts +3 -0
- package/dist/esm/locales/zh-CN.d.ts +3 -0
- package/dist/esm/locales/zh-TW.d.ts +3 -0
- package/dist/esm/locales/zhCN/File.d.ts +3 -0
- package/dist/esm/locales/zhCN/File.js +3 -0
- package/dist/esm/locales/zhCN/index.d.ts +3 -0
- package/dist/esm/locales/zhTW/File.d.ts +3 -0
- package/dist/esm/locales/zhTW/File.js +3 -0
- package/dist/esm/locales/zhTW/index.d.ts +3 -0
- package/dist/esm/types/CrudTableTypes.d.ts +1 -1
- package/dist/esm/types/CrudTableTypes.js +1 -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
|
@@ -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<{
|
|
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<{\n success: boolean; failMsg?: string; data?: {\n success: boolean;\n insertCount: number;\n updateCount: number;\n deleteCount: number;\n } | number\n } | 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<{
|
|
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<{\n success: boolean; failMsg?: string; data?: {\n success: boolean;\n insertCount: number;\n updateCount: number;\n deleteCount: number;\n } | number\n } | 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
|
}
|
|
@@ -2,7 +2,7 @@ import { CloudDownloadOutlined, DownloadOutlined, PlusOutlined, UploadOutlined }
|
|
|
2
2
|
import { ActionType, ColumnsState, ProColumns, ProFormInstance, ProTable } from '@ant-design/pro-components';
|
|
3
3
|
import { cfmmUtils, ImportExecl, useFormatLocale, useIntl, useModel } from '@umijs/max';
|
|
4
4
|
import { Button, Drawer, Dropdown, MenuProps, message, Modal, Progress, Radio } from 'antd';
|
|
5
|
-
import React, { ForwardedRef, forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
5
|
+
import React, { ForwardedRef, forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
6
6
|
import useAction from '../hooks/useAction';
|
|
7
7
|
import useAuthority from '../hooks/useAuthority';
|
|
8
8
|
import useMemoizedFn from '../hooks/useMemoizedFn';
|
|
@@ -716,6 +716,11 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
716
716
|
];
|
|
717
717
|
}, [rowKey, columns, multiLang, defaultAuthCodes, actionColumnConfig, updateFormRef]);
|
|
718
718
|
|
|
719
|
+
const viewColumns = useMemo<ProColumns<T>[]>(() => {
|
|
720
|
+
// 如果没有配置hideInExport,说明是正常的表格字段,配置了hideInExport,说明是导出隐藏的列
|
|
721
|
+
return columns.filter((column) => (column as any).hideInExport ?? true);
|
|
722
|
+
}, [columns]);
|
|
723
|
+
|
|
719
724
|
const editColumns = useMemo<ProColumns<T>[]>(() => {
|
|
720
725
|
return columns.map((column) => {
|
|
721
726
|
if (updateConfig.disabledColumnKeys?.includes(column.dataIndex as keyof T)) {
|
|
@@ -764,6 +769,11 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
764
769
|
onDelete: handleDelete,
|
|
765
770
|
updateModalOpen: () => updateDrawerRef.current?.show(),
|
|
766
771
|
updateModalClose: () => updateDrawerRef.current?.close(),
|
|
772
|
+
handlePercentChange,
|
|
773
|
+
downloadButtonLoading,
|
|
774
|
+
setDownloadButtonLoading,
|
|
775
|
+
percent,
|
|
776
|
+
setPercent,
|
|
767
777
|
}),
|
|
768
778
|
[
|
|
769
779
|
actionRef,
|
|
@@ -788,6 +798,11 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
788
798
|
setEditLangModalOpen,
|
|
789
799
|
setCurrentLangInfo,
|
|
790
800
|
handleDelete,
|
|
801
|
+
handlePercentChange,
|
|
802
|
+
downloadButtonLoading,
|
|
803
|
+
setDownloadButtonLoading,
|
|
804
|
+
percent,
|
|
805
|
+
setPercent,
|
|
791
806
|
],
|
|
792
807
|
);
|
|
793
808
|
|
|
@@ -866,7 +881,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
866
881
|
}
|
|
867
882
|
key="add"
|
|
868
883
|
>
|
|
869
|
-
<PlusOutlined style={{ marginRight:
|
|
884
|
+
<PlusOutlined style={{ marginRight: 8 }} />
|
|
870
885
|
{formatMessage({ id: 'cfmmUI.common.button.add', defaultMessage: '新增' })}
|
|
871
886
|
</a>
|
|
872
887
|
),
|
|
@@ -876,7 +891,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
876
891
|
key: 'exportMultiLang',
|
|
877
892
|
label: (
|
|
878
893
|
<a onClick={handleExportMultiLang} key="exportMultiLang">
|
|
879
|
-
<CloudDownloadOutlined style={{ marginRight:
|
|
894
|
+
<CloudDownloadOutlined style={{ marginRight: 8 }} />
|
|
880
895
|
{formatMessage({ id: 'cfmmUI.common.button.exportMultiLang', defaultMessage: '导出多语言' })}
|
|
881
896
|
</a>
|
|
882
897
|
),
|
|
@@ -898,7 +913,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
898
913
|
key: 'templateDownload',
|
|
899
914
|
label: (
|
|
900
915
|
<a onClick={handleDownloadTemplate} key="templateDownload">
|
|
901
|
-
<DownloadOutlined style={{ marginRight:
|
|
916
|
+
<DownloadOutlined style={{ marginRight: 8 }} />
|
|
902
917
|
{formatMessage({ id: 'cfmmUI.common.button.templateDownload', defaultMessage: '下载模板' })}
|
|
903
918
|
</a>
|
|
904
919
|
),
|
|
@@ -909,7 +924,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
909
924
|
disabled: !tableList.length || loading,
|
|
910
925
|
label: (
|
|
911
926
|
<a onClick={handleDownloadExcel} key="export">
|
|
912
|
-
<CloudDownloadOutlined style={{ marginRight:
|
|
927
|
+
<CloudDownloadOutlined style={{ marginRight: 8 }} />
|
|
913
928
|
{formatMessage({ id: 'cfmmUI.common.button.exportData', defaultMessage: '导出数据' })}
|
|
914
929
|
</a>
|
|
915
930
|
),
|
|
@@ -940,6 +955,12 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
940
955
|
return allButtons!.filter((button) => button.auth).map(({ auth, ...rest }) => rest);
|
|
941
956
|
}, [tableList, loading, columnsStateMap]);
|
|
942
957
|
|
|
958
|
+
useEffect(() => {
|
|
959
|
+
return () => {
|
|
960
|
+
timer.current && clearTimeout(timer.current);
|
|
961
|
+
};
|
|
962
|
+
}, []);
|
|
963
|
+
|
|
943
964
|
return (
|
|
944
965
|
<>
|
|
945
966
|
{downloadButtonLoading ? <Progress percent={percent} size="small" /> : null}
|
|
@@ -1149,7 +1170,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
|
|
|
1149
1170
|
/>
|
|
1150
1171
|
|
|
1151
1172
|
{/* 查看详情 */}
|
|
1152
|
-
<ViewTableItemDrawer<T> row={viewRow} onClose={useMemoizedFn(() => setViewRow(undefined))} columns={
|
|
1173
|
+
<ViewTableItemDrawer<T> row={viewRow} onClose={useMemoizedFn(() => setViewRow(undefined))} columns={viewColumns} />
|
|
1153
1174
|
|
|
1154
1175
|
{/* 操作日志 */}
|
|
1155
1176
|
<ActionLogDrawer row={actionLogRow} onClose={useMemoizedFn(() => setActionLogRow(undefined))} />
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import { importExexl } from '../utils/importHelper';
|
|
2
1
|
import { UploadOutlined } from '@ant-design/icons';
|
|
3
2
|
import { useIntl } from '@umijs/max';
|
|
4
3
|
import type { UploadFile, UploadProps } from 'antd';
|
|
5
|
-
import { Button, message, Upload } from 'antd';
|
|
4
|
+
import { Button, message, Modal, Upload } from 'antd';
|
|
6
5
|
import React from 'react';
|
|
7
6
|
import { ImportExeclProps } from '../types';
|
|
7
|
+
import { importExexl } from '../utils/importHelper';
|
|
8
8
|
import styles from './ImportExecl.less';
|
|
9
9
|
|
|
10
10
|
const ImportExecl = <T,>(props: ImportExeclProps<T>) => {
|
|
11
11
|
const {
|
|
12
|
-
accept =
|
|
12
|
+
accept = '.xlsx, .xls',
|
|
13
13
|
title,
|
|
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?.();
|
|
@@ -52,6 +54,52 @@ const ImportExecl = <T,>(props: ImportExeclProps<T>) => {
|
|
|
52
54
|
{ count: result.data },
|
|
53
55
|
),
|
|
54
56
|
);
|
|
57
|
+
} else if (
|
|
58
|
+
result.data &&
|
|
59
|
+
typeof result.data === 'object' &&
|
|
60
|
+
(result.data.insertCount || result.data.updateCount || result.data.deleteCount)
|
|
61
|
+
) {
|
|
62
|
+
const { insertCount = 0, updateCount = 0, deleteCount = 0 } = result.data;
|
|
63
|
+
Modal.info({
|
|
64
|
+
title: formatMessage(
|
|
65
|
+
{
|
|
66
|
+
id: 'cfmmUI.File.import.exceed.success',
|
|
67
|
+
defaultMessage: '成功导入 {count} 条数据',
|
|
68
|
+
},
|
|
69
|
+
{ count: insertCount + updateCount + deleteCount },
|
|
70
|
+
),
|
|
71
|
+
content: (
|
|
72
|
+
<div>
|
|
73
|
+
<p>
|
|
74
|
+
{formatMessage(
|
|
75
|
+
{
|
|
76
|
+
id: 'cfmmUI.File.import.add.success',
|
|
77
|
+
defaultMessage: '新增 {insertCount} 条数据',
|
|
78
|
+
},
|
|
79
|
+
{ count: insertCount },
|
|
80
|
+
)}
|
|
81
|
+
</p>
|
|
82
|
+
<p>
|
|
83
|
+
{formatMessage(
|
|
84
|
+
{
|
|
85
|
+
id: 'cfmmUI.File.import.update.success',
|
|
86
|
+
defaultMessage: '更新 {updateCount} 条数据',
|
|
87
|
+
},
|
|
88
|
+
{ count: updateCount },
|
|
89
|
+
)}
|
|
90
|
+
</p>
|
|
91
|
+
<p>
|
|
92
|
+
{formatMessage(
|
|
93
|
+
{
|
|
94
|
+
id: 'cfmmUI.File.import.delete.success',
|
|
95
|
+
defaultMessage: '删除 {deleteCount} 条数据',
|
|
96
|
+
},
|
|
97
|
+
{ count: deleteCount },
|
|
98
|
+
)}
|
|
99
|
+
</p>
|
|
100
|
+
</div>
|
|
101
|
+
),
|
|
102
|
+
});
|
|
55
103
|
} else {
|
|
56
104
|
message.success(
|
|
57
105
|
formatMessage({
|
|
@@ -105,4 +153,4 @@ const ImportExecl = <T,>(props: ImportExeclProps<T>) => {
|
|
|
105
153
|
);
|
|
106
154
|
};
|
|
107
155
|
|
|
108
|
-
export default React.memo(ImportExecl) as <T
|
|
156
|
+
export default React.memo(ImportExecl) as <T>(props: ImportExeclProps<T>) => React.ReactElement;
|
|
@@ -4,10 +4,16 @@ import { useState } from 'react';
|
|
|
4
4
|
import { API } from '../types';
|
|
5
5
|
import useActionLocales from './useActionLocales';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/** 与 queryList 中 queryFn 一致:用泛型 K 绑定接口返回的 data/rows 载荷类型 */
|
|
8
|
+
type ListOrBasePromise<K> = Promise<API.Result_Base<K>> | Promise<API.Result_Base_List<K>>;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 支持多种 service 签名;K 由返回的 Result_Base<K> / Result_Base_List<K> 推断(与 useQueryTableList 思路一致)
|
|
12
|
+
*/
|
|
8
13
|
export type ActionFn<T, K> =
|
|
9
|
-
| ((
|
|
10
|
-
| ((
|
|
14
|
+
| (() => ListOrBasePromise<K>)
|
|
15
|
+
| ((params: T, url?: string) => ListOrBasePromise<K>)
|
|
16
|
+
| ((method: API.MethodTypes, params: T, url?: string) => ListOrBasePromise<K>);
|
|
11
17
|
|
|
12
18
|
type Options<T, K> = {
|
|
13
19
|
// loading时的提示内容,false时不显示
|
|
@@ -24,6 +30,13 @@ type Options<T, K> = {
|
|
|
24
30
|
showMsg?: boolean;
|
|
25
31
|
};
|
|
26
32
|
|
|
33
|
+
/** doAction 返回值:`data` 恒为 `K | null`(无 undefined),便于多项目复用 */
|
|
34
|
+
export type DoActionResult<K> = {
|
|
35
|
+
success: boolean;
|
|
36
|
+
data: K | null;
|
|
37
|
+
error: AxiosError | null;
|
|
38
|
+
};
|
|
39
|
+
|
|
27
40
|
interface IProps {
|
|
28
41
|
baseLocalCode?: string;
|
|
29
42
|
baseLocalName?: string;
|
|
@@ -38,24 +51,20 @@ const useAction = (props: IProps = {}) => {
|
|
|
38
51
|
const [error, setError] = useState<AxiosError>();
|
|
39
52
|
|
|
40
53
|
/**
|
|
41
|
-
*
|
|
42
|
-
* @param method 请求方式
|
|
43
|
-
* @param params 传给后端的参数
|
|
44
|
-
* @param {Options} options
|
|
45
|
-
* @returns {{success: boolean; data?: K | null}}
|
|
54
|
+
* 列表的操作方法;`data` 的泛型 K 由 `options.actionFn` 的返回类型推断(未标注返回类型时 K 回退为 any,与旧行为一致)
|
|
46
55
|
*/
|
|
47
|
-
async function doAction<
|
|
56
|
+
async function doAction<TParams = API.TableListParams, KData = any>(
|
|
48
57
|
method: API.AllMethodTypes,
|
|
49
|
-
params:
|
|
50
|
-
options:
|
|
58
|
+
params: TParams,
|
|
59
|
+
options: Options<TParams, KData>,
|
|
51
60
|
url?: string,
|
|
52
|
-
): Promise<
|
|
61
|
+
): Promise<DoActionResult<KData>> {
|
|
53
62
|
setLoading(true);
|
|
54
63
|
|
|
55
64
|
const { actionFn, waitingMsg, successMsg, failMsg, showMsg = true, errCallback } = options;
|
|
56
65
|
|
|
57
66
|
let success: boolean = false;
|
|
58
|
-
let data:
|
|
67
|
+
let data: KData | null = null;
|
|
59
68
|
let fnError: AxiosError | null = null;
|
|
60
69
|
let hide;
|
|
61
70
|
|
|
@@ -76,14 +85,13 @@ const useAction = (props: IProps = {}) => {
|
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
try {
|
|
79
|
-
|
|
80
|
-
let result:
|
|
88
|
+
type AnyResult = API.Result_Base<KData> | API.Result_Base_List<KData>;
|
|
89
|
+
let result: AnyResult;
|
|
90
|
+
const callFn = actionFn as (...args: unknown[]) => Promise<AnyResult>;
|
|
81
91
|
if (actionFn.length === 1 || (actionFn.length === 2 && url)) {
|
|
82
|
-
|
|
83
|
-
result = await (actionFn as (params: T, url?: string) => Promise<API.Result_Base<K>>)(params, url);
|
|
92
|
+
result = await (callFn as (p: TParams, u?: string) => Promise<AnyResult>)(params, url);
|
|
84
93
|
} else {
|
|
85
|
-
|
|
86
|
-
result = await (actionFn as (method: API.MethodTypes, params: T, url?: string) => Promise<API.Result_Base<K>>)(
|
|
94
|
+
result = await (callFn as (m: API.MethodTypes, p: TParams, u?: string) => Promise<AnyResult>)(
|
|
87
95
|
requestMethod,
|
|
88
96
|
params,
|
|
89
97
|
url,
|
|
@@ -92,16 +100,23 @@ const useAction = (props: IProps = {}) => {
|
|
|
92
100
|
|
|
93
101
|
// 返回数据处理
|
|
94
102
|
if (result && result.code === 200) {
|
|
95
|
-
if(requestMethod === 'GET' && successMsg && showMsg) {
|
|
103
|
+
if (requestMethod === 'GET' && successMsg && showMsg) {
|
|
96
104
|
message.success(successMsg);
|
|
97
105
|
}
|
|
98
|
-
if(requestMethod !== 'GET' && showMsg && successMsg !== false) {
|
|
106
|
+
if (requestMethod !== 'GET' && showMsg && successMsg !== false) {
|
|
99
107
|
const { successMsg: successMessage } = getActionLocales(method);
|
|
100
108
|
message.success(successMsg || successMessage);
|
|
101
109
|
}
|
|
102
110
|
success = true;
|
|
103
|
-
if (result
|
|
104
|
-
|
|
111
|
+
if ('rows' in result) {
|
|
112
|
+
const r = result as API.Result_Base_List<KData>;
|
|
113
|
+
const raw = r.data != null ? r.data : r.rows;
|
|
114
|
+
// 与历史逻辑一致:仅 truthy 时写入(0 / false / 空串 等仍不写入,避免行为变化)
|
|
115
|
+
if (raw) {
|
|
116
|
+
data = raw as KData;
|
|
117
|
+
}
|
|
118
|
+
} else if ((result as API.Result_Base<KData>).data) {
|
|
119
|
+
data = (result as API.Result_Base<KData>).data;
|
|
105
120
|
}
|
|
106
121
|
}
|
|
107
122
|
|
|
@@ -52,6 +52,9 @@ declare const _default: {
|
|
|
52
52
|
'cfmmUI.File.import': string;
|
|
53
53
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
54
54
|
'cfmmUI.File.import.exceed.success': string;
|
|
55
|
+
'cfmmUI.File.import.add.success': string;
|
|
56
|
+
'cfmmUI.File.import.update.success': string;
|
|
57
|
+
'cfmmUI.File.import.delete.success': string;
|
|
55
58
|
'cfmmUI.File.button.excel.download': string;
|
|
56
59
|
'cfmmUI.File.check.type.failMessage': string;
|
|
57
60
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -35,6 +35,9 @@ declare const _default: {
|
|
|
35
35
|
'cfmmUI.File.import': string;
|
|
36
36
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
37
37
|
'cfmmUI.File.import.exceed.success': string;
|
|
38
|
+
'cfmmUI.File.import.add.success': string;
|
|
39
|
+
'cfmmUI.File.import.update.success': string;
|
|
40
|
+
'cfmmUI.File.import.delete.success': string;
|
|
38
41
|
'cfmmUI.File.button.excel.download': string;
|
|
39
42
|
'cfmmUI.File.check.type.failMessage': string;
|
|
40
43
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -35,6 +35,9 @@ export default {
|
|
|
35
35
|
'cfmmUI.File.import': 'Import',
|
|
36
36
|
'cfmmUI.File.import.exceed.error.title': 'Import Failed, Reason',
|
|
37
37
|
'cfmmUI.File.import.exceed.success': 'Successfully Imported {count} Pieces Of Data',
|
|
38
|
+
'cfmmUI.File.import.add.success': 'Added {count} Pieces Of Data',
|
|
39
|
+
'cfmmUI.File.import.update.success': 'Updated {count} Pieces Of Data',
|
|
40
|
+
'cfmmUI.File.import.delete.success': 'Deleted {count} Pieces Of Data',
|
|
38
41
|
'cfmmUI.File.button.excel.download': 'Download As Excel',
|
|
39
42
|
'cfmmUI.File.check.type.failMessage': 'This File Type Is Not Supported, It Can Only Be {type} Type',
|
|
40
43
|
'cfmmUI.File.check.size.failMessage': 'The File Cannot Be Larger Than {size}',
|
|
@@ -52,6 +52,9 @@ declare const _default: {
|
|
|
52
52
|
'cfmmUI.File.import': string;
|
|
53
53
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
54
54
|
'cfmmUI.File.import.exceed.success': string;
|
|
55
|
+
'cfmmUI.File.import.add.success': string;
|
|
56
|
+
'cfmmUI.File.import.update.success': string;
|
|
57
|
+
'cfmmUI.File.import.delete.success': string;
|
|
55
58
|
'cfmmUI.File.button.excel.download': string;
|
|
56
59
|
'cfmmUI.File.check.type.failMessage': string;
|
|
57
60
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -52,6 +52,9 @@ declare const _default: {
|
|
|
52
52
|
'cfmmUI.File.import': string;
|
|
53
53
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
54
54
|
'cfmmUI.File.import.exceed.success': string;
|
|
55
|
+
'cfmmUI.File.import.add.success': string;
|
|
56
|
+
'cfmmUI.File.import.update.success': string;
|
|
57
|
+
'cfmmUI.File.import.delete.success': string;
|
|
55
58
|
'cfmmUI.File.button.excel.download': string;
|
|
56
59
|
'cfmmUI.File.check.type.failMessage': string;
|
|
57
60
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -52,6 +52,9 @@ declare const _default: {
|
|
|
52
52
|
'cfmmUI.File.import': string;
|
|
53
53
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
54
54
|
'cfmmUI.File.import.exceed.success': string;
|
|
55
|
+
'cfmmUI.File.import.add.success': string;
|
|
56
|
+
'cfmmUI.File.import.update.success': string;
|
|
57
|
+
'cfmmUI.File.import.delete.success': string;
|
|
55
58
|
'cfmmUI.File.button.excel.download': string;
|
|
56
59
|
'cfmmUI.File.check.type.failMessage': string;
|
|
57
60
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -51,6 +51,9 @@ declare const _default: {
|
|
|
51
51
|
'cfmmUI.File.import': string;
|
|
52
52
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
53
53
|
'cfmmUI.File.import.exceed.success': string;
|
|
54
|
+
'cfmmUI.File.import.add.success': string;
|
|
55
|
+
'cfmmUI.File.import.update.success': string;
|
|
56
|
+
'cfmmUI.File.import.delete.success': string;
|
|
54
57
|
'cfmmUI.File.button.excel.download': string;
|
|
55
58
|
'cfmmUI.File.check.type.failMessage': string;
|
|
56
59
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -35,6 +35,9 @@ declare const _default: {
|
|
|
35
35
|
'cfmmUI.File.import': string;
|
|
36
36
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
37
37
|
'cfmmUI.File.import.exceed.success': string;
|
|
38
|
+
'cfmmUI.File.import.add.success': string;
|
|
39
|
+
'cfmmUI.File.import.update.success': string;
|
|
40
|
+
'cfmmUI.File.import.delete.success': string;
|
|
38
41
|
'cfmmUI.File.button.excel.download': string;
|
|
39
42
|
'cfmmUI.File.check.type.failMessage': string;
|
|
40
43
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -35,6 +35,9 @@ export default {
|
|
|
35
35
|
'cfmmUI.File.import': '导入',
|
|
36
36
|
'cfmmUI.File.import.exceed.error.title': '导入失败,原因如下',
|
|
37
37
|
'cfmmUI.File.import.exceed.success': '成功导入 {count} 条数据',
|
|
38
|
+
'cfmmUI.File.import.add.success': '新增 {count} 条数据',
|
|
39
|
+
'cfmmUI.File.import.update.success': '更新 {count} 条数据',
|
|
40
|
+
'cfmmUI.File.import.delete.success': '删除 {count} 条数据',
|
|
38
41
|
'cfmmUI.File.button.excel.download': '下载为Excel',
|
|
39
42
|
'cfmmUI.File.check.type.failMessage': '不支持该文件类型,只能是 {type} 类型',
|
|
40
43
|
'cfmmUI.File.check.size.failMessage': '文件不能大于 {size}',
|
|
@@ -52,6 +52,9 @@ declare const _default: {
|
|
|
52
52
|
'cfmmUI.File.import': string;
|
|
53
53
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
54
54
|
'cfmmUI.File.import.exceed.success': string;
|
|
55
|
+
'cfmmUI.File.import.add.success': string;
|
|
56
|
+
'cfmmUI.File.import.update.success': string;
|
|
57
|
+
'cfmmUI.File.import.delete.success': string;
|
|
55
58
|
'cfmmUI.File.button.excel.download': string;
|
|
56
59
|
'cfmmUI.File.check.type.failMessage': string;
|
|
57
60
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -34,6 +34,9 @@ declare const _default: {
|
|
|
34
34
|
'cfmmUI.File.import': string;
|
|
35
35
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
36
36
|
'cfmmUI.File.import.exceed.success': string;
|
|
37
|
+
'cfmmUI.File.import.add.success': string;
|
|
38
|
+
'cfmmUI.File.import.update.success': string;
|
|
39
|
+
'cfmmUI.File.import.delete.success': string;
|
|
37
40
|
'cfmmUI.File.button.excel.download': string;
|
|
38
41
|
'cfmmUI.File.check.type.failMessage': string;
|
|
39
42
|
'cfmmUI.File.check.size.failMessage': string;
|
|
@@ -34,6 +34,9 @@ export default {
|
|
|
34
34
|
'cfmmUI.File.import': '導入',
|
|
35
35
|
'cfmmUI.File.import.exceed.error.title': '導入失敗,原因如下',
|
|
36
36
|
'cfmmUI.File.import.exceed.success': '成功導入 {count} 條數據',
|
|
37
|
+
'cfmmUI.File.import.add.success': '新增 {count} 條數據',
|
|
38
|
+
'cfmmUI.File.import.update.success': '更新 {count} 條數據',
|
|
39
|
+
'cfmmUI.File.import.delete.success': '刪除 {count} 條數據',
|
|
37
40
|
'cfmmUI.File.button.excel.download': '下載為Excel',
|
|
38
41
|
'cfmmUI.File.check.type.failMessage': '不支持該檔案類型,只能是 {type} 類型',
|
|
39
42
|
'cfmmUI.File.check.size.failMessage': '文件不能大於 {size}',
|
|
@@ -51,6 +51,9 @@ declare const _default: {
|
|
|
51
51
|
'cfmmUI.File.import': string;
|
|
52
52
|
'cfmmUI.File.import.exceed.error.title': string;
|
|
53
53
|
'cfmmUI.File.import.exceed.success': string;
|
|
54
|
+
'cfmmUI.File.import.add.success': string;
|
|
55
|
+
'cfmmUI.File.import.update.success': string;
|
|
56
|
+
'cfmmUI.File.import.delete.success': string;
|
|
54
57
|
'cfmmUI.File.button.excel.download': string;
|
|
55
58
|
'cfmmUI.File.check.type.failMessage': string;
|
|
56
59
|
'cfmmUI.File.check.size.failMessage': string;
|