import { onBeforeUnmount } from 'vue'; import axios from 'axios'; import type { AxiosRequestConfig, AxiosResponse } from 'axios'; import type { MessageReactive } from 'naive-ui'; import type { MessageApiInjection } from 'naive-ui/es/message/src/MessageProvider'; import { useLoading } from '@sa/hooks'; import { getAuthorization } from '@/service/request/shared'; interface MimeMap { xlsx: string; zip: string; oss: string; } const mimeMap: MimeMap = { xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', zip: 'application/zip', oss: 'application/octet-stream' }; const baseUrl = import.meta.env.VITE_SERVICE_BASE_URL; export function useDownLoadFile() { let messageReactive: MessageReactive | undefined | null; const { loading, startLoading, endLoading } = useLoading(); function paramsGetToUrl(url: string, params: Record | null): string { let urlparams = url; if (params) { urlparams = `${url}?`; for (const propName of Object.keys(params)) { const value = params[propName]; const part = `${encodeURIComponent(propName)}=`; if (value !== null && typeof value !== 'undefined') { if (typeof value === 'object') { // eslint-disable-next-line max-depth for (const key of Object.keys(value)) { // eslint-disable-next-line max-depth if (value[key] !== null && typeof value[key] !== 'undefined') { const par = `${propName}[${key}]`; const subPart = `${encodeURIComponent(par)}=`; urlparams += `${subPart + encodeURIComponent(value[key])}&`; } } } else { urlparams += `${part + encodeURIComponent(value)}&`; } } } urlparams = urlparams.slice(0, -1); } return baseUrl + urlparams; } function getPostParams(params: Record | null) { const dataParams: Record = {}; // 用于存放请求体数据 // get请求映射params参数 if (params) { for (const propName of Object.keys(params)) { const value = params[propName]; if (value !== null && typeof value !== 'undefined') { if (typeof value === 'object') { // eslint-disable-next-line max-depth for (const key of Object.keys(value)) { // eslint-disable-next-line max-depth if (value[key] !== null && typeof value[key] !== 'undefined') { const nestedKey = `${propName}[${key}]`; dataParams[nestedKey] = value[key]; } } } else { dataParams[propName] = value; } } } } return dataParams; } function handleRequest(config: AxiosRequestConfig, mine: keyof MimeMap, filename: string) { createMessage('warning', '正在导出中,请稍后...'); axios(config) .then(res => { resolveBlob(res, mine, filename); }) .catch(err => { createMessage('error', err.message); endLoading(); }); } function downLoadOss(ossId: string | number = '', filename: string = '') { handleRequest( { method: 'get', url: `${baseUrl}/system/oss/download/${ossId}`, responseType: 'blob', headers: { Authorization: getAuthorization() } }, 'oss', filename ); } function downLoadZip(url: string, filename: string = '') { handleRequest( { method: 'get', url: baseUrl + url, responseType: 'blob', headers: { Authorization: getAuthorization() } }, 'zip', filename ); } function downLoadZipPost(url: string, params: Record | null = null, filename: string = '') { handleRequest( { method: 'post', url: baseUrl + url, data: getPostParams(params), responseType: 'blob', headers: { Authorization: getAuthorization(), 'Content-Type': 'application/json;charset=utf-8' // 设置请求体类型 } }, 'zip', filename ); } function downLoadExcel(url: string, params: Record | null = null, filename: string = '') { handleRequest( { method: 'get', url: paramsGetToUrl(url, params), responseType: 'blob', headers: { Authorization: getAuthorization() } }, 'xlsx', filename ); } function downLoadExcelPost(url: string, params: Record | null = null, filename: string = '') { handleRequest( { method: 'post', url: baseUrl + url, data: getPostParams(params), responseType: 'blob', headers: { Authorization: getAuthorization(), 'Content-Type': 'application/json;charset=utf-8' // 设置请求体类型 } }, 'xlsx', filename ); } function resolveBlob(res: AxiosResponse, mime: keyof MimeMap, filename: string) { const mimeType = mimeMap[mime]; if (res.headers['content-type'].includes('application/json')) { const fileReader = new FileReader(); fileReader.readAsText(new Blob([res.data], { type: 'application/octet-stream' }), 'utf-8'); fileReader.onload = () => { try { const result = JSON.parse(fileReader.result as string); if (result.code === 500) { removeMessage(); messageReactive = window.$message?.error(`导出失败:${result.msg}`, { duration: 0 }); } } catch { removeMessage(); messageReactive = window.$message?.error(`系统错误,请联系管理员`, { duration: 0 }); } }; endLoading(); setTimeout(() => { removeMessage(); }, 3000); return; } const aLink = document.createElement('a'); const blob = new Blob([res.data], { type: mimeType }); // //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名; const patt = /filename=([^;]+\.[^.;]+);*/; const contentDisposition = decodeURI(res.headers['content-disposition']); const result = patt.exec(contentDisposition); // var fileName = result[1] // fileName = fileName.replace(/\"/g, '') let fileName: string | undefined = ''; if (filename) { fileName = filename; } else { fileName = result?.[1]; fileName = fileName?.replace(/"/g, ''); } aLink.style.display = 'none'; aLink.href = URL.createObjectURL(blob); aLink.setAttribute('download', decodeURI(typeof fileName === 'string' ? fileName : '')); // 设置下载文件名称 document.body.appendChild(aLink); aLink.click(); URL.revokeObjectURL(aLink.href); // 清除引用 document.body.removeChild(aLink); createMessage('success', '导出成功'); endLoading(); setTimeout(() => { removeMessage(); }, 3000); } // 创建消息框 function createMessage(type: keyof MessageApiInjection, message: string) { startLoading(); removeMessage(); messageReactive = window.$message?.[type](message, { duration: 0 }) as MessageReactive; } // 移出消息框 function removeMessage() { if (messageReactive) { messageReactive.destroy(); messageReactive = null; } } onBeforeUnmount(() => { removeMessage(); }); return { loading, downLoadOss, downLoadZip, downLoadZipPost, downLoadExcel, downLoadExcelPost }; }