mps-platform/cds-fontend-2025.V1/src/hooks/business/download.ts

166 lines
5.2 KiB
TypeScript
Raw Normal View History

2025-07-14 10:47:35 +08:00
import StreamSaver from 'streamsaver';
import { errorCodeRecord } from '@/constants/common';
import { localStg } from '@/utils/storage';
import { getServiceBaseURL } from '@/utils/service';
import { transformToURLSearchParams } from '@/utils/common';
import { WritableStream } from 'web-streams-polyfill/ponyfill';
2025-07-14 10:47:35 +08:00
interface RequestConfig {
method: 'GET' | 'POST';
url: string;
params?: Record<string, any>;
filename?: string;
contentType?: string;
}
export function useDownload() {
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
/** 获取通用请求头 */
const getCommonHeaders = (contentType = 'application/octet-stream') => ({
Authorization: `Bearer ${localStg.get('token')}`,
Clientid: import.meta.env.VITE_APP_CLIENT_ID!,
'Content-Type': contentType
});
/** 通用下载方法 */
function downloadByData(data: BlobPart, filename: string, type = 'application/octet-stream') {
const blob = new Blob([data], { type });
const blobURL = window.URL.createObjectURL(blob);
const tempLink = Object.assign(document.createElement('a'), {
style: { display: 'none' },
href: blobURL,
download: filename
});
if (typeof tempLink.download === 'undefined') {
tempLink.setAttribute('target', '_blank');
}
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
}
/** 流式下载 */
async function downloadByStream(
readableStream: ReadableStream<Uint8Array>,
filename: string,
contentLength?: number
): Promise<void> {
window.$loading?.endLoading();
// 检查浏览器是否原生支持 WritableStream若不支持则使用polyfill
if (typeof window.WritableStream === 'undefined') {
window.WritableStream = WritableStream;
// 确保StreamSaver也使用相同的Polyfill
StreamSaver.WritableStream = WritableStream;
}
StreamSaver.mitm = '/mitm.html' // 增加此行代码
2025-07-14 10:47:35 +08:00
const fileStream = StreamSaver.createWriteStream(filename, { size: contentLength });
if (window.WritableStream && readableStream?.pipeTo) {
await readableStream.pipeTo(fileStream);
window.$message?.success('下载完成');
return;
}
// 降级处理
const writer = fileStream.getWriter();
const reader = readableStream.getReader();
const pump = async (): Promise<void> => {
const { done, value } = await reader.read();
if (done) return writer.close();
await writer.write(value);
return pump();
};
await pump();
}
/** 处理响应 */
async function handleResponse(response: Response) {
if (response.headers.get('Content-Type')?.includes('application/json')) {
const res = await response.json();
const code = res.code as CommonType.ErrorCode;
throw new Error(errorCodeRecord[code] || res.msg || errorCodeRecord.default);
}
}
/** 核心下载逻辑 */
async function executeDownload(config: RequestConfig): Promise<void> {
const { method, url, params, filename, contentType } = config;
const timestamp = Date.now();
const fullUrl = `${baseURL}${url}${url.includes('?') ? '&' : '?'}t=${timestamp}`;
window.$loading?.startLoading('正在下载数据,请稍候...');
try {
const requestOptions: RequestInit = {
method,
headers: getCommonHeaders(contentType)
};
if (method === 'POST' && params) {
requestOptions.body = transformToURLSearchParams(params);
requestOptions.headers = {
...requestOptions.headers,
'Content-Type': 'application/x-www-form-urlencoded'
};
}
const response = await fetch(fullUrl, requestOptions);
await handleResponse(response);
const finalFilename = filename || response.headers.get('Download-Filename') || `download-${timestamp}`;
/*老旧浏览器还是存在流式传输兼容问题,暂时屏蔽,只使用普通传输*/
/*if (response.body) {
2025-07-14 10:47:35 +08:00
const contentLength = Number(response.headers.get('Content-Length'));
await downloadByStream(response.body, finalFilename, contentLength);
return;
}*/
2025-07-14 10:47:35 +08:00
const responseContentType = response.headers.get('Content-Type');
const mainType = responseContentType?.split(';')[0]?.trim() || 'application/octet-stream';
downloadByData(await response.blob(), finalFilename, mainType);
} catch (error: any) {
window.$message?.error(error.message);
} finally {
window.$loading?.endLoading();
}
}
/** 公共下载接口 */
const download = (url: string, params: Record<string, any>, filename: string) =>
executeDownload({ method: 'POST', url, params, filename });
/** OSS文件下载 */
const oss = (ossId: CommonType.IdType) =>
executeDownload({
method: 'GET',
url: `/resource/oss/download/${ossId}`
});
/** ZIP文件下载 */
const zip = (url: string, filename: string) =>
executeDownload({
method: 'GET',
url,
filename,
contentType: 'application/octet-stream'
});
return {
oss,
zip,
download
};
}