diff --git a/src/compenents/upload-video-button/index.tsx b/src/compenents/upload-video-button/index.tsx index 02934a2..5371e0a 100644 --- a/src/compenents/upload-video-button/index.tsx +++ b/src/compenents/upload-video-button/index.tsx @@ -21,30 +21,10 @@ interface PropsInterface { onUpdate: () => void; } -interface FileItem { - id: string; - filename: string; - uploadId: string; - name: string; - duration: number; - size: number; - progress: number; - file: File; - resourceType: string; - loading: boolean; - run: UploadChunk; - isSuc: boolean; - isErr: boolean; - errMsg: string; - remoteName: string; - poster: string; -} - export const UploadVideoButton = (props: PropsInterface) => { const [showModal, setShowModal] = useState(false); const localFileList = useRef([]); const [fileList, setFileList] = useState([]); - const upRef = useRef(0); const getMinioUploadId = async () => { let resp: any = await minioUploadId("mp4"); @@ -55,7 +35,6 @@ export const UploadVideoButton = (props: PropsInterface) => { multiple: true, beforeUpload: async (file: File) => { if (file.type === "video/mp4") { - upRef.current++; // 视频封面解析 || 视频时长解析 let videoInfo = await parseVideo(file); // 添加到本地待上传 @@ -63,58 +42,50 @@ export const UploadVideoButton = (props: PropsInterface) => { let run = new UploadChunk(file, data["upload_id"], data["filename"]); let item: FileItem = { id: generateUUID(), - duration: videoInfo.duration, - filename: data["filename"], - uploadId: data["upload_id"], - name: file.name, - size: file.size, - progress: 0, file: file, - resourceType: data["resource_type"], - loading: true, - run: run, - isSuc: false, - isErr: false, - errMsg: "", - remoteName: data["filename"], - poster: videoInfo.poster, + upload: { + handler: run, + progress: 0, + status: 0, + remark: "", + }, + video: { + duration: videoInfo.duration, + poster: videoInfo.poster, + }, }; - item.run.on("success", () => { + item.upload.handler.on("success", () => { minioMergeVideo( - item.filename, - item.uploadId, + data["filename"], + data["upload_id"], props.categoryIds.join(","), - item.name, + item.file.name, "mp4", - item.size, - item.duration, - item.poster + item.file.size, + item.video?.duration || 0, + item.video?.poster || "" ).then(() => { - item.isSuc = true; + item.upload.status = item.upload.handler.getUploadStatus(); setFileList([...localFileList.current]); - message.success(`${item.file.name} 上传成功`); - upRef.current--; }); }); - item.run.on("retry", () => { - item.isErr = false; - item.errMsg = ""; + item.upload.handler.on("progress", (p: number) => { + item.upload.status = item.upload.handler.getUploadStatus(); + item.upload.progress = p; + console.log("状态,进度", item.upload.status, item.upload.progress); setFileList([...localFileList.current]); }); - item.run.on("progress", (progress: number) => { - item.progress = progress; + item.upload.handler.on("error", (msg: string) => { + item.upload.status = item.upload.handler.getUploadStatus(); + item.upload.remark = msg; setFileList([...localFileList.current]); }); - item.run.on("error", (msg: string) => { - item.isErr = true; - item.errMsg = msg; - setFileList([...localFileList.current]); - upRef.current--; - }); setTimeout(() => { - item.run.start(); + item.upload.handler.start(); }, 500); + // 先插入到ref localFileList.current.push(item); + // 再更新list setFileList([...localFileList.current]); } else { message.error(`${file.name} 并不是 mp4 视频文件`); @@ -124,11 +95,6 @@ export const UploadVideoButton = (props: PropsInterface) => { }; const closeWin = () => { - // if (upRef.current > 0) { - // message.error(`等待上传成功后才能关闭`); - // return; - // } - if (fileList.length > 0) { let i = 0; fileList.map((item: any) => { @@ -195,13 +161,16 @@ export const UploadVideoButton = (props: PropsInterface) => { title: "视频", dataIndex: "name", key: "name", + render: (_, record) => {record.file.name}, }, { title: "大小", dataIndex: "size", key: "size", render: (_, record) => ( - {(record.size / 1024 / 1024).toFixed(2)} M + + {(record.file.size / 1024 / 1024).toFixed(2)}M + ), }, { @@ -210,12 +179,13 @@ export const UploadVideoButton = (props: PropsInterface) => { key: "progress", render: (_, record: FileItem) => ( <> - {record.progress === 0 && "等待上传"} - {record.progress > 0 && ( + {record.upload.status === 0 ? ( + "等待上传" + ) : ( )} @@ -226,32 +196,13 @@ export const UploadVideoButton = (props: PropsInterface) => { key: "action", render: (_, record) => ( <> - {record.progress > 0 && - record.isSuc === false && - record.isErr === false && ( - - )} + {record.upload.status === 5 ? ( + {record.upload.remark} + ) : null} - {record.isErr && ( - <> - {record.errMsg} - - - )} + {record.upload.status === 7 ? ( + 上传成功 + ) : null} ), }, diff --git a/src/js/minio-upload-chunk.ts b/src/js/minio-upload-chunk.ts index 2698fec..170f2da 100644 --- a/src/js/minio-upload-chunk.ts +++ b/src/js/minio-upload-chunk.ts @@ -11,11 +11,14 @@ export class UploadChunk { chunkIndex: number; uploadId: string; filename: string; + // 上传状态[0:等待上传,3:上传中,5:上传失败,7:上传成功] + uploadStatus: number; + uploadRemark: string; - onError: ((err: string) => void | undefined) | undefined; - onSuccess: (() => void | undefined) | undefined; - onRetry: (() => void | undefined) | undefined; - onProgress: ((progress: number) => void) | undefined; + onError?: (err: string) => void | undefined; + onSuccess?: () => void | undefined; + onRetry?: () => void | undefined; + onProgress?: (progress: number) => void; constructor(file: File, uploadId: string, filename: string) { this.client = axios.create({ @@ -31,6 +34,9 @@ export class UploadChunk { this.uploadId = uploadId; this.filename = filename; + + this.uploadStatus = 0; + this.uploadRemark = ""; } on(event: string, handle: any) { @@ -49,23 +55,25 @@ export class UploadChunk { if (this.isStop) { return; } + + // 检测是否上传完成 if (this.chunkIndex > this.chunkNumber) { - //上传完成 - this.onSuccess && this.onSuccess(); + this.uploadCompleted(); return; } - this.onProgress && - this.onProgress( - parseInt((this.chunkIndex / this.chunkNumber) * 100 + "") - ); + + // 进度更新 + this.uploadProgressUpdated(); 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); + // 首先获取上传minio的签名 minioPreSignUrl(this.uploadId, this.filename, this.chunkIndex) .then((res: any) => { + // 拿到签名之后将分块内容上传到minio return this.client.put(res.data.url, tmpFile, { headers: { "Content-Type": "multipart/form-data", @@ -76,12 +84,15 @@ export class UploadChunk { this.chunkIndex += 1; this.start(); }) - .catch((e) => { - console.error("文件分片上传失败", e); - this.onError && this.onError("失败.2"); + .catch((e: any) => { + this.uploadedFail(e); }); } + isOver() { + return this.uploadStatus === 5 || this.uploadStatus === 7; + } + cancel() { this.isStop = true; this.onError && this.onError("已取消"); @@ -92,4 +103,40 @@ export class UploadChunk { this.start(); this.onRetry && this.onRetry(); } + + uploadProgressUpdated() { + if (this.uploadStatus === 0) { + this.uploadStatus = 3; + } + this.onProgress && + this.onProgress( + parseInt((this.chunkIndex / this.chunkNumber) * 100 + "") + ); + } + + uploadCompleted() { + this.uploadStatus = 7; + this.onSuccess && this.onSuccess(); + } + + uploadedFail(e: any) { + console.log("上传失败,错误信息:", e); + this.uploadStatus = 5; + this.onError && this.onError("失败.2"); + } + + getUploadStatus(): number { + return this.uploadStatus; + } + + getUploadProgress(): number { + if (this.chunkNumber === 0) { + return 0; + } + return (this.chunkIndex / this.chunkNumber) * 100; + } + + getUploadRemark(): string { + return this.uploadRemark; + } } diff --git a/src/playedu.d.ts b/src/playedu.d.ts new file mode 100644 index 0000000..feb1b6a --- /dev/null +++ b/src/playedu.d.ts @@ -0,0 +1,20 @@ +declare global { + interface FileItem { + id: string; //上传文件的唯一id + file: File; //上传的文件资源 + // 上传实际执行者 + upload: { + handler: UploadChunk; + progress: number; + status: number; + remark: string; + }; + // 视频文件信息 + video?: { + duration: number; //时长 + poster: string; //视频帧 + }; + } +} + +export {};