114 lines
3.7 KiB
TypeScript
114 lines
3.7 KiB
TypeScript
import { randomId } from '../utils/random-id.ts';
|
||
import type { UploadOpts } from './upload-chunk.ts';
|
||
type ConvertOpts = {
|
||
appKey?: string;
|
||
version?: string;
|
||
username?: string;
|
||
directory?: string;
|
||
/**
|
||
* 文件大小限制
|
||
*/
|
||
maxSize?: number;
|
||
/**
|
||
* 文件数量限制
|
||
*/
|
||
maxCount?: number;
|
||
/**
|
||
* 是否不检查应用文件, 默认 true,默认不检测
|
||
*/
|
||
noCheckAppFiles?: boolean;
|
||
};
|
||
|
||
export const uploadFiles = async (files: File[], opts: ConvertOpts, opts2: UploadOpts) => {
|
||
const { directory, appKey, version, username, noCheckAppFiles = true } = opts;
|
||
const { uploadProgress, createEventSource, baseUrl = '', token, FormDataFn } = opts2 || {};
|
||
const length = files.length;
|
||
const maxSize = opts.maxSize || 20 * 1024 * 1024; // 20MB
|
||
const totalSize = files.reduce((acc, file) => acc + file.size, 0);
|
||
if (totalSize > maxSize) {
|
||
const maxSizeMB = maxSize / 1024 / 1024;
|
||
uploadProgress?.error('有文件大小不能超过' + maxSizeMB + 'MB');
|
||
return;
|
||
}
|
||
const maxCount = opts.maxCount || 10;
|
||
if (length > maxCount) {
|
||
uploadProgress?.error(`最多只能上传${maxCount}个文件`);
|
||
return;
|
||
}
|
||
uploadProgress?.info(`上传中,共${length}个文件`);
|
||
return new Promise((resolve, reject) => {
|
||
const formData = new FormDataFn();
|
||
const webkitRelativePath = files[0]?.webkitRelativePath;
|
||
const keepDirectory = webkitRelativePath !== '';
|
||
const root = keepDirectory ? webkitRelativePath.split('/')[0] : '';
|
||
for (let i = 0; i < files.length; i++) {
|
||
const file = files[i];
|
||
if (keepDirectory) {
|
||
// relativePath 去除第一级
|
||
const webkitRelativePath = file.webkitRelativePath.replace(root + '/', '');
|
||
formData.append('file', file, webkitRelativePath); // 保留文件夹路径
|
||
} else {
|
||
formData.append('file', files[i], files[i].name);
|
||
}
|
||
}
|
||
if (directory) {
|
||
formData.append('directory', directory);
|
||
}
|
||
if (appKey && version) {
|
||
formData.append('appKey', appKey);
|
||
formData.append('version', version);
|
||
}
|
||
if (username) {
|
||
formData.append('username', username);
|
||
}
|
||
const searchParams = new URLSearchParams();
|
||
const taskId = randomId();
|
||
searchParams.set('taskId', taskId);
|
||
|
||
if (noCheckAppFiles) {
|
||
searchParams.set('noCheckAppFiles', '1');
|
||
}
|
||
const eventSource = new EventSource('/api/s1/events?taskId=' + taskId);
|
||
|
||
uploadProgress?.start('上传中...');
|
||
eventSource.onopen = async function (event) {
|
||
const res = await fetch('/api/s1/resources/upload?' + searchParams.toString(), {
|
||
method: 'POST',
|
||
body: formData,
|
||
headers: {
|
||
'task-id': taskId,
|
||
Authorization: `Bearer ${token}`,
|
||
},
|
||
}).then((response) => response.json());
|
||
|
||
console.log('upload success', res);
|
||
fetch('/api/s1/events/close?taskId=' + taskId);
|
||
eventSource.close();
|
||
uploadProgress?.done();
|
||
resolve(res);
|
||
};
|
||
// 监听服务器推送的进度更新
|
||
eventSource.onmessage = function (event) {
|
||
console.log('Progress update:', event.data);
|
||
const parseIfJson = (data: string) => {
|
||
try {
|
||
return JSON.parse(data);
|
||
} catch (e) {
|
||
return data;
|
||
}
|
||
};
|
||
const receivedData = parseIfJson(event.data);
|
||
if (typeof receivedData === 'string') return;
|
||
const progress = Number(receivedData.progress);
|
||
const progressFixed = progress.toFixed(2);
|
||
console.log('progress', progress);
|
||
uploadProgress?.set(progress, { ...receivedData, taskId, progressFixed });
|
||
};
|
||
|
||
eventSource.onerror = function (event) {
|
||
console.log('eventSource.onerror', event);
|
||
reject(event);
|
||
};
|
||
});
|
||
};
|