Files
yudao-ui-admin-vben/apps/web-antd/src/components/upload/use-upload.ts

181 lines
4.5 KiB
TypeScript
Raw Normal View History

2025-04-17 23:30:34 +08:00
import type { Ref } from 'vue';
import type { AxiosProgressEvent, InfraFileApi } from '#/api/infra/file';
2025-04-17 23:30:34 +08:00
import { computed, unref } from 'vue';
import { useAppConfig } from '@vben/hooks';
2025-04-17 23:30:34 +08:00
import { $t } from '@vben/locales';
import { createFile, getFilePresignedUrl, uploadFile } from '#/api/infra/file';
import { baseRequestClient } from '#/api/request';
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
/**
*
*/
enum UPLOAD_TYPE {
// 客户端直接上传只支持S3服务
CLIENT = 'client',
// 客户端发送到后端上传
SERVER = 'server',
}
2025-04-17 23:30:34 +08:00
/**
*
* @param acceptRef
* @param helpTextRef
* @param maxNumberRef
* @param maxSizeRef
* @returns
*/
2025-04-17 23:30:34 +08:00
export function useUploadType({
acceptRef,
helpTextRef,
maxNumberRef,
maxSizeRef,
}: {
acceptRef: Ref<string[]>;
helpTextRef: Ref<string>;
maxNumberRef: Ref<number>;
maxSizeRef: Ref<number>;
}) {
// 文件类型限制
const getAccept = computed(() => {
const accept = unref(acceptRef);
if (accept && accept.length > 0) {
return accept;
}
return [];
});
const getStringAccept = computed(() => {
return unref(getAccept)
.map((item) => {
return item.indexOf('/') > 0 || item.startsWith('.')
? item
: `.${item}`;
})
.join(',');
});
// 支持jpg、jpeg、png格式不超过2M最多可选择10张图片
const getHelpText = computed(() => {
const helpText = unref(helpTextRef);
if (helpText) {
return helpText;
}
const helpTexts: string[] = [];
const accept = unref(acceptRef);
if (accept.length > 0) {
helpTexts.push($t('ui.upload.accept', [accept.join(',')]));
}
const maxSize = unref(maxSizeRef);
if (maxSize) {
helpTexts.push($t('ui.upload.maxSize', [maxSize]));
}
const maxNumber = unref(maxNumberRef);
if (maxNumber && maxNumber !== Infinity) {
helpTexts.push($t('ui.upload.maxNumber', [maxNumber]));
}
return helpTexts.join('');
});
return { getAccept, getStringAccept, getHelpText };
}
/**
*
* @param directory
* @returns URL
*/
2025-05-26 18:46:06 +08:00
export function useUpload(directory?: string) {
// 后端上传地址
const uploadUrl = getUploadUrl();
// 是否使用前端直连上传
const isClientUpload =
UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE;
// 重写ElUpload上传方法
2025-05-26 18:46:06 +08:00
async function httpRequest(
file: File,
onUploadProgress?: AxiosProgressEvent,
2025-05-26 18:46:06 +08:00
) {
// 模式一:前端上传
if (isClientUpload) {
// 1.1 生成文件名称
const fileName = await generateFileName(file);
// 1.2 获取文件预签名地址
const presignedInfo = await getFilePresignedUrl(fileName, directory);
// 1.3 上传文件
return baseRequestClient
.put(presignedInfo.uploadUrl, file, {
headers: {
'Content-Type': file.type,
},
})
.then(() => {
// 1.4. 记录文件信息到后端(异步)
createFile0(presignedInfo, file);
// 通知成功,数据格式保持与后端上传的返回结果一致
return { url: presignedInfo.url };
});
} else {
// 模式二:后端上传
return uploadFile({ file, directory }, onUploadProgress);
}
2025-05-26 18:46:06 +08:00
}
return {
uploadUrl,
httpRequest,
};
2025-05-26 18:46:06 +08:00
}
/**
* URL
*/
2025-05-26 18:46:06 +08:00
export function getUploadUrl(): string {
return `${apiURL}/infra/file/upload`;
2025-05-26 18:46:06 +08:00
}
/**
*
*
* @param vo
* @param file
*/
2025-05-26 18:46:06 +08:00
function createFile0(
vo: InfraFileApi.FilePresignedUrlRespVO,
2025-05-26 18:46:06 +08:00
file: File,
): InfraFileApi.File {
const fileVO = {
configId: vo.configId,
url: vo.url,
path: vo.path,
name: file.name,
type: file.type,
size: file.size,
};
createFile(fileVO);
return fileVO;
}
/**
* 使SHA256
*
* @param file
*/
async function generateFileName(file: File) {
// // 读取文件内容
// const data = await file.arrayBuffer();
// const wordArray = CryptoJS.lib.WordArray.create(data);
// // 计算SHA256
// const sha256 = CryptoJS.SHA256(wordArray).toString();
// // 拼接后缀
// const ext = file.name.slice(Math.max(0, file.name.lastIndexOf('.')));
// return `${sha256}${ext}`;
return file.name;
2025-04-22 22:10:33 +08:00
}