导出表格表单组件
import { storage } from '@/utils';
import { codeMessage } from '@/utils/request';
import { history } from '@umijs/max';
import { message, notification } from 'antd';
import React, { useState } from 'react';
import { extend } from 'umi-request';
interface IDownloadProps {
params?: any;
accept?: string;
method?: string;
data?: any;
action: string;
isToken?: boolean; // 是否带token
beforeDownload?: () => any; // 下载前回调
callback?: () => void; // 成功后回调
children?: (loading: boolean) => React.ReactElement<any>; // 下载组件子组件
}
/**
* @class 下载组件
*/
const Download: React.FC<IDownloadProps> = (props) => {
const [loading, setLoading] = useState<boolean>(false);
const {
params = {},
accept = '*/*',
method = 'get',
action,
isToken = true,
callback,
children,
data,
beforeDownload,
} = props;
const errorHandler = (error: any) => {
const { response = {} } = error;
const errortext = codeMessage[response.status] || response.statusText;
const { status, url } = response;
let errorMessage;
notification.destroy();
if (status === 401 && url.indexOf('user/signout') === -1) {
errorMessage = '未登录或登录已过期,请重新登录。';
notification.error({
message: errorMessage,
});
window?.g_app?._store?.dispatch({
type: 'login/logout',
});
} else {
errorMessage = `${errortext}`;
}
message.error(errorMessage);
throw error;
};
// 浏览器保存本地
const downFile = (blob: any, fileName: string) => {
if (window?.navigator && window.navigator?.msSaveOrOpenBlob) {
window?.navigator.msSaveBlob(blob, fileName);
} else {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
window?.URL?.revokeObjectURL(link.href);
}
};
/**
* 下载
*/
const downloadTmpl = async () => {
const token = storage.get('token');
if (!token) {
message.error('未登录或登录已过期,请重新登录。');
storage.clear();
history.replace('/login');
return;
}
const headers: any = {
...(isToken ? { 'x-Token': token } : null),
Accept: accept,
};
const request = extend({
errorHandler,
credentials: 'include',
timeout: 600000,
});
setLoading(true);
return request(action, {
method,
headers,
responseType: 'arrayBuffer',
getResponse: true,
params,
data,
...(Object.keys(params).length ? { data: JSON.stringify(params) } : null),
})
.then((props: any) => {
const { data, response } = props;
if (data?.code === 1000) {
const { code, msg } = data;
const errorDesc = {
message: `请求错误 ${code}`,
description: msg,
};
notification.error(errorDesc);
return;
}
const contentDisposition = response?.headers?.get(
'content-disposition',
);
if (contentDisposition) {
let [fileName]: any = contentDisposition?.split('=').slice(-1);
fileName = fileName.replace(`utf-8''`, '');
const blob = new Blob([data]);
downFile(blob, decodeURI(fileName));
} else {
return notification.error({ message: '请求错误' });
}
})
.then(() => callback && callback())
.finally(() => {
setLoading(false);
});
};
const start = () => {
beforeDownload
? beforeDownload()
.then(() => downloadTmpl())
.catch((e: any) => message.error(e.message))
: downloadTmpl();
};
return (
<div onClick={start} style={{ display: 'inline-block' }}>
{children && children(loading)}
</div>
);
};
export default Download;
使用方法
<Download
isToken={true}
action={}//接口地址
params={}//get方式的参数,post使用data
>
{(option: any) => (
<Button
className={styles.exportBtn}
icon={<DownloadOutlined />}
{...option}
>
{useLocale('导出')}
</Button>
)}
</Download>