This commit is contained in:
禺狨 2023-03-07 11:47:25 +08:00
commit 5ea6c8399d
3 changed files with 140 additions and 42 deletions

View File

@ -25,7 +25,6 @@ export function createResource(type: string) {
}
export function storeResource(
type: string,
categoryId: number,
name: string,
extension: string,
@ -33,18 +32,24 @@ export function storeResource(
disk: string,
fileId: string,
path: string,
url: string
url: string,
extra: object
) {
return client.post("/backend/v1/resource/create", {
category_id: categoryId,
name,
extension,
size,
disk,
file_id: fileId,
path,
url,
});
let data = Object.assign(
{},
{
category_id: categoryId,
name,
extension,
size,
disk,
file_id: fileId,
path,
url,
},
extra
);
return client.post("/backend/v1/resource/create", data);
}
export function destroyResource(id: number) {

View File

@ -7,13 +7,15 @@ import {
Progress,
Row,
Table,
Tag,
Upload,
} from "antd";
import Dragger from "antd/es/upload/Dragger";
import { useEffect, useState } from "react";
import { generateUUID, getToken } from "../../utils";
import { useRef, useState } from "react";
import { generateUUID } from "../../utils";
import { minioUploadId } from "../../api/upload";
import { UploadChunk } from "../../js/minio-upload-chunk";
import { storeResource } from "../../api/resource";
interface PropsInterface {
categoryId: number;
@ -27,13 +29,18 @@ interface FileItem {
size: number;
progress: number;
file: File;
resource_type: string;
resourceType: string;
loading: boolean;
run: UploadChunk;
isSuc: boolean;
isErr: boolean;
errMsg: string;
remoteName: string;
}
export const UploadVideoButton = (props: PropsInterface) => {
const [showModal, setShowModal] = useState(false);
const localFileList = useRef<FileItem[]>([]);
const [fileList, setFileList] = useState<FileItem[]>([]);
const getMinioUploadId = async () => {
@ -47,6 +54,7 @@ export const UploadVideoButton = (props: PropsInterface) => {
if (file.type === "video/mp4") {
//添加到本地待上传
let data = await getMinioUploadId();
let run = new UploadChunk(file, data["upload_id"], data["filename"]);
let item: FileItem = {
id: generateUUID(),
duration: 0,
@ -54,16 +62,54 @@ export const UploadVideoButton = (props: PropsInterface) => {
size: file.size,
progress: 0,
file: file,
resource_type: data["resource_type"],
resourceType: data["resource_type"],
loading: true,
run: new UploadChunk(
file,
data["upload_id"],
data["filename"]
),
run: run,
isSuc: false,
isErr: false,
errMsg: "",
remoteName: data["filename"],
};
item.run.start();
setFileList([item, ...fileList]);
item.run.on("success", (url: string) => {
item.isSuc = true;
setFileList([...localFileList.current]);
// 创建上传记录
storeResource(
props.categoryId,
item.file.name,
"mp4",
item.file.size,
"minio",
"",
item.remoteName,
url,
{
duration: item.duration,
}
).then(() => {
message.success(`${item.file.name} 上传成功`);
});
});
item.run.on("retry", () => {
item.isErr = false;
item.errMsg = "";
setFileList([...localFileList.current]);
});
item.run.on("progress", (progress: number) => {
item.progress = progress;
setFileList([...localFileList.current]);
});
item.run.on("error", (msg: string) => {
item.isErr = true;
item.errMsg = msg;
setFileList([...localFileList.current]);
});
setTimeout(() => {
item.run.start();
}, 500);
localFileList.current.push(item);
setFileList([...localFileList.current]);
} else {
message.error(`${file.name} 并不是 mp4 视频文件`);
}
@ -103,6 +149,13 @@ export const UploadVideoButton = (props: PropsInterface) => {
open={true}
onCancel={() => {
setShowModal(false);
props.onUpdate();
}}
maskClosable={false}
closable={false}
onOk={() => {
setShowModal(false);
props.onUpdate();
}}
>
<Row gutter={[0, 10]}>
@ -145,7 +198,7 @@ export const UploadVideoButton = (props: PropsInterface) => {
{record.progress > 0 && (
<Progress
size="small"
steps={10}
steps={20}
percent={record.progress}
/>
)}
@ -155,16 +208,33 @@ export const UploadVideoButton = (props: PropsInterface) => {
{
title: "操作",
key: "action",
render: (index, record) => (
render: (_, record) => (
<>
{record.progress === 0 && (
<Button
onClick={() => {
fileList.splice(index, 1);
}}
>
</Button>
{record.progress > 0 &&
record.isSuc === false &&
record.isErr === false && (
<Button
type="link"
onClick={() => {
record.run.cancel();
}}
>
</Button>
)}
{record.isErr && (
<>
<Tag color="red">{record.errMsg}</Tag>
<Button
type="link"
onClick={() => {
record.run.retry();
}}
>
</Button>
</>
)}
</>
),

View File

@ -13,7 +13,8 @@ export class UploadChunk {
filename: string;
onError: ((err: string) => void | undefined) | undefined;
onSuccess: (() => void | undefined) | undefined;
onSuccess: ((url: string) => void | undefined) | undefined;
onRetry: (() => void | undefined) | undefined;
onProgress: ((progress: number) => void) | undefined;
constructor(file: File, uploadId: string, filename: string) {
@ -32,22 +33,41 @@ export class UploadChunk {
this.filename = filename;
}
on(event: string, handle: any) {
if (event === "error") {
this.onError = handle;
} else if (event === "success") {
this.onSuccess = handle;
} else if (event === "progress") {
this.onProgress = handle;
} else if (event === "retry") {
this.onRetry = handle;
}
}
start() {
if (this.isStop) {
return;
}
let start = (this.chunkIndex - 1) * this.chunkSize;
if (start > this.file.size) {
if (this.chunkIndex > this.chunkNumber) {
//上传完成
minioMerge(this.filename, this.uploadId)
.then((res) => {
console.log("合并成功", res);
.then((res: any) => {
let url = res.data.url;
this.onSuccess && this.onSuccess(url);
})
.catch((e) => {
console.error("合并失败", e);
console.error("文件合并失败", e);
this.onError && this.onError("失败.3");
});
return;
}
this.onProgress &&
this.onProgress(
parseInt((this.chunkIndex / this.chunkNumber) * 100 + "")
);
let start = (this.chunkIndex - 1) * this.chunkSize;
const chunkData = this.file.slice(start, start + this.chunkSize);
const boolname = this.file.name + "-" + this.chunkIndex;
const tmpFile = new File([chunkData], boolname);
@ -65,16 +85,19 @@ export class UploadChunk {
this.start();
})
.catch((e) => {
console.error("获取签名url失败", e);
console.error("文件分片上传失败", e);
this.onError && this.onError("失败.2");
});
}
stop() {
cancel() {
this.isStop = true;
this.onError && this.onError("已取消");
}
resume() {
retry() {
this.isStop = false;
this.start();
this.onRetry && this.onRetry();
}
}