import { useState } from "react"; import * as tus from "tus-js-client"; import { env } from "../env"; import { getCompressedImageUrl } from "@nice/utils"; // useTusUpload.ts interface UploadProgress { fileId: string; progress: number; } interface UploadResult { compressedUrl: string; url: string; fileId: string; } export function useTusUpload() { const [uploadProgress, setUploadProgress] = useState< Record >({}); const [isUploading, setIsUploading] = useState(false); const [uploadError, setUploadError] = useState(null); const getFileId = (url: string) => { const parts = url.split("/"); const uploadIndex = parts.findIndex((part) => part === "upload"); if (uploadIndex === -1 || uploadIndex + 4 >= parts.length) { throw new Error("Invalid upload URL format"); } return parts.slice(uploadIndex + 1, uploadIndex + 5).join("/"); }; const getResourceUrl = (url: string) => { const parts = url.split("/"); const uploadIndex = parts.findIndex((part) => part === "upload"); if (uploadIndex === -1 || uploadIndex + 4 >= parts.length) { throw new Error("Invalid upload URL format"); } const resUrl = `http://${env.SERVER_IP}:${env.UOLOAD_PORT}/uploads/${parts.slice(uploadIndex + 1, uploadIndex + 6).join("/")}`; return resUrl; }; const handleFileUpload = async ( file: File, onSuccess: (result: UploadResult) => void, onError: (error: Error) => void, fileKey: string // 添加文件唯一标识 ) => { // if (!file || !file.name || !file.type) { // const error = new Error("不可上传该类型文件"); // setUploadError(error.message); // onError(error); // return; // } setIsUploading(true); setUploadProgress((prev) => ({ ...prev, [fileKey]: 0 })); setUploadError(null); try { const upload = new tus.Upload(file, { endpoint: `http://${env.SERVER_IP}:${env.SERVER_PORT}/upload`, retryDelays: [0, 1000, 3000, 5000], metadata: { filename: file.name, filetype: file.type, size: file.size as any, }, onProgress: (bytesUploaded, bytesTotal) => { const progress = Number( ((bytesUploaded / bytesTotal) * 100).toFixed(2) ); setUploadProgress((prev) => ({ ...prev, [fileKey]: progress, })); }, onSuccess: async (payload) => { try { if (upload.url) { const fileId = getFileId(upload.url); const url = getResourceUrl(upload.url); setIsUploading(false); setUploadProgress((prev) => ({ ...prev, [fileKey]: 100, })); onSuccess({ compressedUrl: getCompressedImageUrl(url), url, fileId, }); } } catch (error) { const err = error instanceof Error ? error : new Error("Unknown error"); setIsUploading(false); setUploadError(err.message); onError(err); } }, onError: (error) => { setIsUploading(false); setUploadError(error.message); onError(error); }, }); upload.start(); } catch (error) { const err = error instanceof Error ? error : new Error("Upload failed"); setIsUploading(false); setUploadError(err.message); onError(err); } }; return { uploadProgress, isUploading, uploadError, handleFileUpload, }; }