import React, { useRef, useState } from "react"; import { Button, Card, message, Progress, Space, Tag } from "antd"; import TcVod from "vod-js-sdk-v6"; import { VodAPI } from "./api/vod.ts"; interface UploadTask { file: File; progress: number; status: "pending" | "uploading" | "success" | "error" | "canceled"; fileId?: string; videoUrl?: string; coverUrl?: string; cancel?: () => void; } export const VodUploadPage = () => { const videoInputRef = useRef(null); const coverInputRef = useRef(null); const [uploadTasks, setUploadTasks] = useState([]); const [selectedVideo, setSelectedVideo] = useState(null); const [selectedCover, setSelectedCover] = useState(null); // 获取上传签名 const getSignature = async () => { try { return await VodAPI.getSignature(); } catch (error) { message.error("获取上传签名失败"); throw error; } }; // 初始化VOD SDK const tcVod = new TcVod({ getSignature: getSignature, }); // 处理视频文件选择 const handleVideoSelect = (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { setSelectedVideo(e.target.files[0]); } }; // 处理封面文件选择 const handleCoverSelect = (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { setSelectedCover(e.target.files[0]); } }; // 开始上传 const startUpload = async () => { if (!selectedVideo) { message.warning("请先选择视频文件"); return; } const newTask: UploadTask = { file: selectedVideo, progress: 0, status: "pending", }; setUploadTasks((prev) => [...prev, newTask]); try { const uploader = tcVod.upload({ mediaFile: selectedVideo, coverFile: selectedCover || undefined, }); const updatedTask: UploadTask = { ...newTask, status: "uploading", cancel: () => { uploader.cancel(); setUploadTasks((prev) => prev.map((task) => task.file === newTask.file ? { ...task, status: "canceled" } : task ) ); }, }; setUploadTasks((prev) => prev.map((task) => task.file === newTask.file ? updatedTask : task) ); // 监听上传进度 uploader.on("media_progress", (info) => { setUploadTasks((prev) => prev.map((task) => task.file === newTask.file ? { ...task, progress: info.percent * 100 } : task ) ); }); // 监听上传完成 uploader.on("media_upload", (info) => { setUploadTasks((prev) => prev.map((task) => task.file === newTask.file ? { ...task, status: "success" } : task ) ); }); // 执行上传 const result = await uploader.done(); setUploadTasks((prev) => prev.map((task) => task.file === newTask.file ? { ...task, fileId: result.fileId, videoUrl: result.video.url, coverUrl: result.cover?.url, status: "success", } : task ) ); message.success("视频上传成功"); } catch (error) { setUploadTasks((prev) => prev.map((task) => task.file === newTask.file ? { ...task, status: "error" } : task ) ); message.error("视频上传失败"); } finally { setSelectedVideo(null); setSelectedCover(null); if (videoInputRef.current) videoInputRef.current.value = ""; if (coverInputRef.current) coverInputRef.current.value = ""; } }; // 渲染上传状态标签 const renderStatusTag = (status: UploadTask["status"]) => { switch (status) { case "pending": return 等待上传; case "uploading": return 上传中; case "success": return 上传成功; case "error": return 上传失败; case "canceled": return 已取消; default: return 未知状态; } }; return (
{uploadTasks.map((task, index) => (
{task.file.name} {renderStatusTag(task.status)} {task.status === "uploading" && task.cancel && ( )}
{task.status === "uploading" && ( )} {task.fileId && (
File ID: {task.fileId}
{task.videoUrl && (
视频地址:{" "} {task.videoUrl}
)} {task.coverUrl && (
封面地址:{" "} {task.coverUrl}
)}
)}
))}
); };