feat: 优化文件上传功能,支持上传进度显示和中止上传,更新封面和媒体项处理逻辑
This commit is contained in:
@@ -10,62 +10,84 @@ export const commonApi = {
|
||||
formData.append('type', type);
|
||||
return request('/upload', { method: 'POST', body: formData });
|
||||
},
|
||||
uploadMultipart: async (file, hash, onProgress) => {
|
||||
// 1. Check Hash
|
||||
try {
|
||||
const res = await commonApi.checkHash(hash);
|
||||
if (res) {
|
||||
if (onProgress) onProgress(100);
|
||||
return res;
|
||||
uploadMultipart: (file, hash, type, onProgress) => {
|
||||
const controller = new AbortController();
|
||||
const signal = controller.signal;
|
||||
|
||||
const promise = (async () => {
|
||||
// 1. Check Hash
|
||||
try {
|
||||
const res = await commonApi.checkHash(hash);
|
||||
if (res) {
|
||||
if (onProgress) onProgress(100);
|
||||
return res;
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore hash check errors
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
// 2. Init
|
||||
const initRes = await request('/upload/init', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
filename: file.name,
|
||||
size: file.size,
|
||||
mime_type: file.type,
|
||||
hash: hash
|
||||
if (signal.aborted) throw new Error('Aborted');
|
||||
|
||||
// 2. Init
|
||||
const initRes = await request('/upload/init', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
filename: file.name,
|
||||
size: file.size,
|
||||
mime_type: file.type,
|
||||
hash: hash,
|
||||
type: type
|
||||
},
|
||||
signal
|
||||
});
|
||||
|
||||
const { upload_id, chunk_size } = initRes;
|
||||
const totalChunks = Math.ceil(file.size / chunk_size);
|
||||
|
||||
// 3. Upload Parts
|
||||
for (let i = 0; i < totalChunks; i++) {
|
||||
if (signal.aborted) throw new Error('Aborted');
|
||||
|
||||
const start = i * chunk_size;
|
||||
const end = Math.min(start + chunk_size, file.size);
|
||||
const chunk = file.slice(start, end);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', chunk);
|
||||
formData.append('upload_id', upload_id);
|
||||
formData.append('part_number', i + 1);
|
||||
|
||||
// request helper with FormData handles content-type, but we need signal
|
||||
await request('/upload/part', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
signal
|
||||
});
|
||||
|
||||
if (onProgress) {
|
||||
const percent = Math.round(((i + 1) / totalChunks) * 100);
|
||||
onProgress(percent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const { upload_id, chunk_size } = initRes;
|
||||
const totalChunks = Math.ceil(file.size / chunk_size);
|
||||
// 4. Complete
|
||||
return request('/upload/complete', {
|
||||
method: 'POST',
|
||||
body: { upload_id },
|
||||
signal
|
||||
});
|
||||
})();
|
||||
|
||||
// 3. Upload Parts
|
||||
for (let i = 0; i < totalChunks; i++) {
|
||||
const start = i * chunk_size;
|
||||
const end = Math.min(start + chunk_size, file.size);
|
||||
const chunk = file.slice(start, end);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', chunk);
|
||||
formData.append('upload_id', upload_id);
|
||||
formData.append('part_number', i + 1);
|
||||
|
||||
await request('/upload/part', { method: 'POST', body: formData });
|
||||
|
||||
if (onProgress) {
|
||||
const percent = Math.round(((i + 1) / totalChunks) * 100);
|
||||
onProgress(percent);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Complete
|
||||
return request('/upload/complete', {
|
||||
method: 'POST',
|
||||
body: { upload_id }
|
||||
});
|
||||
return { promise, abort: () => controller.abort() };
|
||||
},
|
||||
uploadWithProgress: (file, type, onProgress) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr;
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('type', type);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/v1/upload');
|
||||
|
||||
const token = localStorage.getItem('token');
|
||||
@@ -94,7 +116,10 @@ export const commonApi = {
|
||||
};
|
||||
|
||||
xhr.onerror = () => reject(new Error('Network Error'));
|
||||
xhr.onabort = () => reject(new Error('Aborted'));
|
||||
xhr.send(formData);
|
||||
});
|
||||
|
||||
return { promise, abort: () => xhr.abort() };
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user