diff --git a/src/upload/_example/request-method.jsx b/src/upload/_example/request-method.jsx
new file mode 100644
index 000000000..3d682628e
--- /dev/null
+++ b/src/upload/_example/request-method.jsx
@@ -0,0 +1,67 @@
+import React, { useCallback, useState } from 'react';
+import { Radio, Upload } from 'tdesign-react';
+
+const RequestMethod = () => {
+ const [files, setFiles] = useState([]);
+ const [uploadMethod, setUploadMethod] = useState('requestSuccessMethod');
+
+ // customize upload `file`, if success, return url
+ const requestSuccessMethod = useCallback(
+ (file) =>
+ new Promise((resolve) => {
+ // set file.percent for mock upload progress
+ // eslint-disable-next-line no-param-reassign
+ file.percent = 0;
+ let timer = setTimeout(() => {
+ // resolve 参数为关键代码
+ resolve({
+ status: 'success',
+ response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' },
+ });
+ // eslint-disable-next-line no-param-reassign
+ file.percent = 100;
+ clearTimeout(timer);
+ timer = null;
+ }, 520);
+ }),
+ [],
+ );
+
+ // customize upload `file`, if fail, return error message
+ const requestFailMethod = useCallback(
+ () =>
+ new Promise((resolve) => {
+ // resolve 参数为关键代码
+ resolve({
+ status: 'fail',
+ error: 'for some reason, upload fail',
+ });
+ }),
+ [],
+ );
+
+ const onChangeUploadMethod = useCallback((value) => {
+ setUploadMethod(value);
+ setFiles([]);
+ }, []);
+
+ return (
+
+
+
+ 上传成功示例
+ 上传失败示例
+
+
+
+
+
+ );
+};
+
+export default RequestMethod;
diff --git a/src/upload/type.ts b/src/upload/type.ts
index 214dfb873..8507d0663 100644
--- a/src/upload/type.ts
+++ b/src/upload/type.ts
@@ -258,8 +258,8 @@ export interface UploadRemoveContext {
}
export interface SuccessContext {
- e: ProgressEvent;
+ e?: ProgressEvent;
file: UploadFile;
- fileList: UploadFile[];
+ fileList?: UploadFile[];
response: any;
}
diff --git a/src/upload/upload.tsx b/src/upload/upload.tsx
index 446f9a1e8..de05d9278 100644
--- a/src/upload/upload.tsx
+++ b/src/upload/upload.tsx
@@ -13,7 +13,14 @@ import FlowList from './themes/flow-list/index';
import BooleanRender from './boolean-render';
import { finishUpload, isSingleFile, updateFileList } from './util';
import { FlowRemoveContext, TdUploadFile, UploadProps } from './types';
-import { ProgressContext, SuccessContext, TdUploadProps, UploadFile, UploadRemoveContext } from './type';
+import {
+ ProgressContext,
+ RequestMethodResponse,
+ SuccessContext,
+ TdUploadProps,
+ UploadFile,
+ UploadRemoveContext,
+} from './type';
import useDefaultValue from './hooks/useDefaultValue';
const urlCreator = window.webkitURL || window.URL;
@@ -45,6 +52,7 @@ const Upload: React.ForwardRefRenderFunction = (props, ref
onRemove,
onDragenter,
onDragleave,
+ requestMethod,
files: fileList = [],
} = useDefaultValue, UploadProps>(props, []);
@@ -92,7 +100,7 @@ const Upload: React.ForwardRefRenderFunction = (props, ref
};
const onError = useCallback(
- (options: { event: ProgressEvent; file: TdUploadFile; response?: any }) => {
+ (options: { event?: ProgressEvent; file: TdUploadFile; response?: any }) => {
const { event, file, response } = options;
file.status = 'fail';
let res = response;
@@ -156,19 +164,41 @@ const Upload: React.ForwardRefRenderFunction = (props, ref
[fileList, onChange, onProgress],
);
+ const handleRequestMethod = useCallback(
+ (file: UploadFile) => {
+ if (typeof requestMethod !== 'function') {
+ console.warn('TDesign Upload Warn: `requestMethod` must be a function.');
+ return;
+ }
+ requestMethod(file).then((res: RequestMethodResponse) => {
+ if (!handleRequestMethodResponse(res)) return;
+ if (res.status === 'success') {
+ return handleSuccess({ file, response: res.response });
+ }
+ if (res.status === 'fail') {
+ const r = res.response || {};
+ onError({ file, response: { ...r, error: res.error } });
+ }
+ });
+ },
+ [handleSuccess, onError, requestMethod],
+ );
const upload = useCallback(
- (uploadFile: TdUploadFile): Promise => {
+ async (uploadFile: TdUploadFile): Promise => {
const file = { ...uploadFile };
if (file.status !== 'waiting') {
return;
}
- if (!action) {
- console.error('TDesign Upload Error: action is required.');
+ if (!action && !requestMethod) {
+ console.error('TDesign Upload Error: action or requestMethod is required.');
return;
}
setErrorMsg('');
// eslint-disable-next-line no-param-reassign
file.status = 'progress';
+ if (requestMethod) {
+ return handleRequestMethod(file);
+ }
request({
action,
data,
@@ -181,9 +211,41 @@ const Upload: React.ForwardRefRenderFunction = (props, ref
onSuccess: handleSuccess,
});
},
- [action, data, handleProgress, handleSuccess, headers, name, onError, withCredentials],
+ [
+ action,
+ data,
+ handleProgress,
+ handleRequestMethod,
+ handleSuccess,
+ headers,
+ name,
+ onError,
+ requestMethod,
+ withCredentials,
+ ],
);
+ function handleRequestMethodResponse(res: RequestMethodResponse) {
+ if (!res) {
+ console.error('TDesign Upload Error: `requestMethodResponse` is required.');
+ return false;
+ }
+ if (!res.status) {
+ console.error(
+ 'TDesign Upload Error: `requestMethodResponse.status` is missing, which value is `success` or `fail`',
+ );
+ return false;
+ }
+ if (!['success', 'fail'].includes(res.status)) {
+ console.error('TDesign Upload Error: `requestMethodResponse.status` must be `success` or `fail`');
+ return false;
+ }
+ if (res.status === 'success' && (!res.response || !res.response.url)) {
+ console.warn('TDesign Upload Warn: `requestMethodResponse.response.url` is required, when `status` is `success`');
+ }
+ return true;
+ }
+
const formatFiles = (files: File[] = []): TdUploadFile[] =>
files.map((fileRaw) => {
const file = typeof format === 'function' ? format(fileRaw) : fileRaw;