mirror of
https://github.com/PlayEdu/backend
synced 2025-06-24 08:02:48 +08:00
minio分片上传
This commit is contained in:
parent
6649aa8cfa
commit
709027df50
@ -7,8 +7,26 @@ export function image(categoryId: number, file: File) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function minioToken(extension: string) {
|
export function minioUploadId(extension: string) {
|
||||||
return client.get("/backend/v1/upload/minio-token", {
|
return client.get("/backend/v1/upload/minio-upload-id", {
|
||||||
extension,
|
extension,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
export function minioPreSignUrl(
|
||||||
|
uploadId: string,
|
||||||
|
filename: string,
|
||||||
|
partNumber: number
|
||||||
|
) {
|
||||||
|
return client.get("/backend/v1/upload/minio-pre-sign-url", {
|
||||||
|
upload_id: uploadId,
|
||||||
|
filename,
|
||||||
|
part_number: partNumber,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function minioMerge(filename: string, uploadId: string) {
|
||||||
|
return client.get("/backend/v1/upload/minio-merge", {
|
||||||
|
filename,
|
||||||
|
upload_id: uploadId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -12,8 +12,8 @@ import {
|
|||||||
import Dragger from "antd/es/upload/Dragger";
|
import Dragger from "antd/es/upload/Dragger";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { generateUUID, getToken } from "../../utils";
|
import { generateUUID, getToken } from "../../utils";
|
||||||
import { minioToken } from "../../api/upload";
|
import { minioUploadId } from "../../api/upload";
|
||||||
import Resumable from "resumablejs";
|
import { UploadChunk } from "../../js/minio-upload-chunk";
|
||||||
|
|
||||||
interface PropsInterface {
|
interface PropsInterface {
|
||||||
categoryId: number;
|
categoryId: number;
|
||||||
@ -29,30 +29,24 @@ interface FileItem {
|
|||||||
file: File;
|
file: File;
|
||||||
resource_type: string;
|
resource_type: string;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
R: Resumable | undefined;
|
run: UploadChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UploadVideoButton = (props: PropsInterface) => {
|
export const UploadVideoButton = (props: PropsInterface) => {
|
||||||
const [showModal, setShowModal] = useState(false);
|
const [showModal, setShowModal] = useState(false);
|
||||||
const [fileList, setFileList] = useState<FileItem[]>([]);
|
const [fileList, setFileList] = useState<FileItem[]>([]);
|
||||||
|
|
||||||
const getMinioConfig = async () => {
|
const getMinioUploadId = async () => {
|
||||||
let resp: any = await minioToken("mp4");
|
let resp: any = await minioUploadId("mp4");
|
||||||
return resp.data;
|
return resp.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const r = new Resumable({
|
|
||||||
chunkSize: 1 * 1024 * 1024,
|
|
||||||
fileParameterName: "file",
|
|
||||||
uploadMethod: "POST",
|
|
||||||
});
|
|
||||||
|
|
||||||
const uploadProps = {
|
const uploadProps = {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
beforeUpload: async (file: File) => {
|
beforeUpload: async (file: File) => {
|
||||||
if (file.type === "video/mp4") {
|
if (file.type === "video/mp4") {
|
||||||
//添加到本地待上传
|
//添加到本地待上传
|
||||||
let data = await getMinioConfig();
|
let data = await getMinioUploadId();
|
||||||
let item: FileItem = {
|
let item: FileItem = {
|
||||||
id: generateUUID(),
|
id: generateUUID(),
|
||||||
duration: 0,
|
duration: 0,
|
||||||
@ -62,38 +56,13 @@ export const UploadVideoButton = (props: PropsInterface) => {
|
|||||||
file: file,
|
file: file,
|
||||||
resource_type: data["resource_type"],
|
resource_type: data["resource_type"],
|
||||||
loading: true,
|
loading: true,
|
||||||
R: undefined,
|
run: new UploadChunk(
|
||||||
|
file,
|
||||||
|
data["upload_id"],
|
||||||
|
data["filename"]
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
item.run.start();
|
||||||
// 初始化上传对象
|
|
||||||
let r = new Resumable({
|
|
||||||
target: data["url"],
|
|
||||||
chunkSize: 6 * 1024 * 1024,
|
|
||||||
simultaneousUploads: 1,
|
|
||||||
uploadMethod: "PUT",
|
|
||||||
method: "octet",
|
|
||||||
testChunks: false, //不校验已上传的chunks
|
|
||||||
chunkNumberParameterName: "partNumber",
|
|
||||||
query: {
|
|
||||||
uploadId: item.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
r.on("fileProgress", (file: Resumable.ResumableFile) => {
|
|
||||||
item.progress = file.progress(false) * 100;
|
|
||||||
console.log("进度", item.progress);
|
|
||||||
});
|
|
||||||
r.on("error", (e) => {
|
|
||||||
console.log("错误", e);
|
|
||||||
});
|
|
||||||
r.addFile(item.file);
|
|
||||||
|
|
||||||
item.R = r;
|
|
||||||
setTimeout(() => {
|
|
||||||
if (item.R) {
|
|
||||||
item.R.upload();
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
setFileList([item, ...fileList]);
|
setFileList([item, ...fileList]);
|
||||||
} else {
|
} else {
|
||||||
message.error(`${file.name} 并不是 mp4 视频文件`);
|
message.error(`${file.name} 并不是 mp4 视频文件`);
|
||||||
|
80
src/js/minio-upload-chunk.ts
Normal file
80
src/js/minio-upload-chunk.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import axios, { Axios } from "axios";
|
||||||
|
import { minioMerge, minioPreSignUrl } from "../api/upload";
|
||||||
|
|
||||||
|
export class UploadChunk {
|
||||||
|
client: Axios;
|
||||||
|
file: File;
|
||||||
|
progress: number;
|
||||||
|
chunkNumber: number;
|
||||||
|
isStop: boolean;
|
||||||
|
chunkSize: number;
|
||||||
|
chunkIndex: number;
|
||||||
|
uploadId: string;
|
||||||
|
filename: string;
|
||||||
|
|
||||||
|
onError: ((err: string) => void | undefined) | undefined;
|
||||||
|
onSuccess: (() => void | undefined) | undefined;
|
||||||
|
onProgress: ((progress: number) => void) | undefined;
|
||||||
|
|
||||||
|
constructor(file: File, uploadId: string, filename: string) {
|
||||||
|
this.client = axios.create({
|
||||||
|
timeout: 15000,
|
||||||
|
withCredentials: false,
|
||||||
|
});
|
||||||
|
this.file = file;
|
||||||
|
this.progress = 0;
|
||||||
|
this.isStop = false;
|
||||||
|
this.chunkIndex = 1;
|
||||||
|
this.chunkSize = 6 * 1024 * 1024;
|
||||||
|
this.chunkNumber = Math.ceil(file.size / this.chunkSize);
|
||||||
|
|
||||||
|
this.uploadId = uploadId;
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (this.isStop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let start = (this.chunkIndex - 1) * this.chunkSize;
|
||||||
|
if (start > this.file.size) {
|
||||||
|
//上传完成
|
||||||
|
minioMerge(this.filename, this.uploadId)
|
||||||
|
.then((res) => {
|
||||||
|
console.log("合并成功", res);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error("合并失败", e);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const chunkData = this.file.slice(start, start + this.chunkSize);
|
||||||
|
const boolname = this.file.name + "-" + this.chunkIndex;
|
||||||
|
const tmpFile = new File([chunkData], boolname);
|
||||||
|
|
||||||
|
minioPreSignUrl(this.uploadId, this.filename, this.chunkIndex)
|
||||||
|
.then((res: any) => {
|
||||||
|
return this.client.put(res.data.url, tmpFile, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "multipart/form-data",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.chunkIndex += 1;
|
||||||
|
this.start();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error("获取签名url失败", e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.isStop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
resume() {
|
||||||
|
this.isStop = false;
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user