doctor-mail/apps/web/src/hooks/useTusUpload.ts

113 lines
2.6 KiB
TypeScript

import { useState } from "react";
import * as tus from "tus-js-client";
// useTusUpload.ts
interface UploadProgress {
fileId: string;
progress: number;
}
interface UploadResult {
url: string;
fileId: string;
}
export function useTusUpload() {
const [uploadProgress, setUploadProgress] = useState<
Record<string, number>
>({});
const [isUploading, setIsUploading] = useState(false);
const [uploadError, setUploadError] = useState<string | null>(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 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://localhost:3000/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 () => {
try {
if (upload.url) {
const fileId = getFileId(upload.url);
setIsUploading(false);
setUploadProgress((prev) => ({
...prev,
[fileKey]: 100,
}));
onSuccess({
url: upload.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,
};
}