161 lines
5.0 KiB
JavaScript
161 lines
5.0 KiB
JavaScript
import { requestUtils,clientApi } from "../index";
|
||
let urlRule = 'https://api.deotaland.aiIMGURL'
|
||
export class FileServer {
|
||
//文件上传缓存映射 - 静态属性,所有实例共享
|
||
static fileCacheMap = new Map();
|
||
constructor() {
|
||
}
|
||
//文件拼接
|
||
concatUrl(url) {
|
||
return urlRule.replace('IMGURL',url)
|
||
}
|
||
/**
|
||
* 从URL中提取有效的文件名
|
||
* @param {*} url 文件URL
|
||
* @returns 有效的文件名
|
||
*/
|
||
extractFileName(url) {
|
||
// 如果是base64格式,根据MIME类型生成文件名
|
||
if (url.startsWith('data:')) {
|
||
const mimeType = url.match(/data:([^;]+)/)?.[1];
|
||
const extension = this.getExtensionFromMimeType(mimeType);
|
||
return `uploaded_file_${Date.now()}.${extension}`;
|
||
}
|
||
|
||
// 如果是普通URL,提取文件名并清理
|
||
try {
|
||
const urlObj = new URL(url);
|
||
const pathname = urlObj.pathname;
|
||
const fileName = pathname.split('/').pop() || 'uploaded_file';
|
||
|
||
// 移除查询参数和哈希
|
||
const cleanFileName = fileName.split('?')[0].split('#')[0];
|
||
|
||
// 如果没有扩展名,尝试从URL路径推断
|
||
if (!cleanFileName.includes('.')) {
|
||
const extension = this.inferExtensionFromPath(pathname);
|
||
return cleanFileName + (extension ? `.${extension}` : '');
|
||
}
|
||
|
||
return cleanFileName || `uploaded_file_${Date.now()}`;
|
||
} catch (error) {
|
||
// URL解析失败,使用默认文件名
|
||
return `uploaded_file_${Date.now()}`;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 从MIME类型获取文件扩展名
|
||
*/
|
||
getExtensionFromMimeType(mimeType) {
|
||
const mimeMap = {
|
||
'image/jpeg': 'jpg',
|
||
'image/jpg': 'jpg',
|
||
'image/png': 'png',
|
||
'image/gif': 'gif',
|
||
'image/bmp': 'bmp',
|
||
'image/webp': 'webp',
|
||
'image/svg+xml': 'svg',
|
||
'application/pdf': 'pdf',
|
||
'text/plain': 'txt',
|
||
'application/json': 'json'
|
||
};
|
||
return mimeMap[mimeType] || 'bin';
|
||
}
|
||
|
||
/**
|
||
* 从URL路径推断文件扩展名
|
||
*/
|
||
inferExtensionFromPath(pathname) {
|
||
// 常见的图片路径模式
|
||
if (pathname.includes('/image/') || pathname.includes('/img/')) return 'jpg';
|
||
if (pathname.includes('/photo/')) return 'jpg';
|
||
if (pathname.includes('/picture/')) return 'png';
|
||
return null;
|
||
}
|
||
//轮询获取并发时的线上文件映射
|
||
async pollFileCacheMap(cacheKey) {
|
||
return new Promise((resolve, reject) => {
|
||
const interval = setInterval(() => {
|
||
if (FileServer.fileCacheMap.get(cacheKey)!='loading') {
|
||
clearInterval(interval);
|
||
resolve(FileServer.fileCacheMap.get(cacheKey));
|
||
}
|
||
}, 1000); // 每1秒检查一次
|
||
});
|
||
}
|
||
//上传文件
|
||
async uploadFile(url) {
|
||
const cacheKey = url.slice(-8);
|
||
return new Promise(async (resolve, reject) => {
|
||
if(FileServer.fileCacheMap.has(cacheKey)&&FileServer.fileCacheMap.get(cacheKey)!='loading'){
|
||
resolve(this.concatUrl(FileServer.fileCacheMap.get(cacheKey)));
|
||
return;
|
||
}
|
||
if(FileServer.fileCacheMap.get(cacheKey)=='loading'){
|
||
const loadUrl = await this.pollFileCacheMap(cacheKey);
|
||
resolve(this.concatUrl(loadUrl));
|
||
return;
|
||
}
|
||
FileServer.fileCacheMap.set(cacheKey,'loading');
|
||
const file = await this.fileToBlob(url);//将文件或者base64文件转为blob对象
|
||
const formData = new FormData();
|
||
// 从URL中提取文件名,如果没有则使用默认文件名
|
||
const fileName = this.extractFileName(url);
|
||
formData.append('file', file, fileName);
|
||
try {
|
||
const response = await requestUtils.upload(clientApi.default.UPLOAD.url, formData);
|
||
if(response.code==0){
|
||
let data = response.data;
|
||
if(data.url){
|
||
// 截取后八位作为缓存 key
|
||
FileServer.fileCacheMap.set(cacheKey, data.url);
|
||
resolve(urlRule.replace('IMGURL',data.url));
|
||
}
|
||
}
|
||
} catch (error) {
|
||
reject(error);
|
||
console.error('上传文件失败:', error);
|
||
throw error;
|
||
}
|
||
})
|
||
}
|
||
//文件文件或者base64文件转为blob对象
|
||
fileToBlob(fileOrBase64) {
|
||
return new Promise((resolve, reject) => {
|
||
const xhr = new XMLHttpRequest();
|
||
xhr.open('GET', fileOrBase64);
|
||
xhr.responseType = 'blob';
|
||
xhr.onload = () => {
|
||
if (xhr.status === 200) {
|
||
resolve(xhr.response);
|
||
} else {
|
||
reject(new Error('文件转换失败'));
|
||
}
|
||
};
|
||
xhr.onerror = reject;
|
||
xhr.send();
|
||
});
|
||
}
|
||
//本地文件或者oss文件转为base64格式
|
||
async fileToBase64(url) {
|
||
return new Promise((resolve, reject) => {
|
||
const xhr = new XMLHttpRequest();
|
||
xhr.open('GET', url);
|
||
xhr.responseType = 'blob';
|
||
xhr.onload = () => {
|
||
if (xhr.status === 200) {
|
||
const reader = new FileReader();
|
||
reader.readAsDataURL(xhr.response);
|
||
reader.onloadend = () => {
|
||
resolve(reader.result);
|
||
};
|
||
} else {
|
||
reject(new Error('文件转换失败'));
|
||
}
|
||
};
|
||
xhr.onerror = reject;
|
||
xhr.send();
|
||
});
|
||
}
|
||
} |