diff --git a/src/api/resource.ts b/src/api/resource.ts index ce4ae9f..34a29df 100644 --- a/src/api/resource.ts +++ b/src/api/resource.ts @@ -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) { diff --git a/src/compenents/upload-video-button/index.tsx b/src/compenents/upload-video-button/index.tsx index 8f04153..937c4ff 100644 --- a/src/compenents/upload-video-button/index.tsx +++ b/src/compenents/upload-video-button/index.tsx @@ -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([]); const [fileList, setFileList] = useState([]); 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(); }} > @@ -145,7 +198,7 @@ export const UploadVideoButton = (props: PropsInterface) => { {record.progress > 0 && ( )} @@ -155,16 +208,33 @@ export const UploadVideoButton = (props: PropsInterface) => { { title: "操作", key: "action", - render: (index, record) => ( + render: (_, record) => ( <> - {record.progress === 0 && ( - + {record.progress > 0 && + record.isSuc === false && + record.isErr === false && ( + + )} + + {record.isErr && ( + <> + {record.errMsg} + + )} ), diff --git a/src/js/minio-upload-chunk.ts b/src/js/minio-upload-chunk.ts index 5293755..b2778e8 100644 --- a/src/js/minio-upload-chunk.ts +++ b/src/js/minio-upload-chunk.ts @@ -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(); } }