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); }; }); };