108 lines
3.4 KiB
TypeScript
108 lines
3.4 KiB
TypeScript
|
|
import { Carousel } from '@web/src/components/common/element/Carousel';
|
|
import LeaderCard from '@web/src/components/common/element/LeaderCard';
|
|
import React, { useState, useCallback } from 'react';
|
|
import * as tus from 'tus-js-client';
|
|
interface TusUploadProps {
|
|
onSuccess?: (response: any) => void;
|
|
onError?: (error: Error) => void;
|
|
}
|
|
const carouselItems = [
|
|
{
|
|
id: 1,
|
|
image: 'https://th.bing.com/th/id/OIP.PEtRTLQwIX54HGFX5xNDYwHaE7?rs=1&pid=ImgDetMain',
|
|
title: '自然风光',
|
|
description: '壮丽的山川河流'
|
|
},
|
|
{
|
|
id: 2,
|
|
image: 'https://eskipaper.com/images/scenery-pictures-15.jpg',
|
|
title: '城市景观',
|
|
description: '现代化的都市风貌'
|
|
}
|
|
];
|
|
const TusUploader: React.FC<TusUploadProps> = ({
|
|
onSuccess,
|
|
onError
|
|
}) => {
|
|
const [progress, setProgress] = useState<number>(0);
|
|
const [isUploading, setIsUploading] = useState<boolean>(false);
|
|
const [uploadError, setUploadError] = useState<string | null>(null);
|
|
const handleFileUpload = useCallback((file: File) => {
|
|
if (!file) return;
|
|
setIsUploading(true);
|
|
setProgress(0);
|
|
setUploadError(null);
|
|
// Extract file extension
|
|
const extension = file.name.split('.').pop() || '';
|
|
const upload = new tus.Upload(file, {
|
|
endpoint: "http://localhost:3000/upload",
|
|
retryDelays: [0, 1000, 3000, 5000],
|
|
metadata: {
|
|
filename: file.name,
|
|
size: file.size.toString(),
|
|
mimeType: file.type,
|
|
extension: extension,
|
|
modifiedAt: new Date(file.lastModified).toISOString(),
|
|
},
|
|
onProgress: (bytesUploaded, bytesTotal) => {
|
|
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
|
|
setProgress(Number(percentage));
|
|
},
|
|
onSuccess: () => {
|
|
setIsUploading(false);
|
|
setProgress(100);
|
|
onSuccess && onSuccess(upload);
|
|
},
|
|
onError: (error) => {
|
|
setIsUploading(false);
|
|
setUploadError(error.message);
|
|
onError && onError(error);
|
|
}
|
|
});
|
|
|
|
upload.start();
|
|
},
|
|
[onSuccess, onError]
|
|
);
|
|
|
|
return (
|
|
<div className=' flex flex-col gap-4'>
|
|
<Carousel
|
|
slides={carouselItems}
|
|
|
|
autoplayDelay={5000}
|
|
className="shadow-xl"
|
|
/>
|
|
<LeaderCard
|
|
name="张三"
|
|
title="技术总监"
|
|
description={
|
|
"负责公司技术战略规划"
|
|
}
|
|
imageUrl="https://th.bing.com/th/id/OIP.ea0spF2OAgI4I1KzgZFtTgHaHX?rs=1&pid=ImgDetMain"
|
|
/>
|
|
<input
|
|
type="file"
|
|
onChange={(e) => {
|
|
const file = e.target.files?.[0];
|
|
if (file) handleFileUpload(file);
|
|
}}
|
|
/>
|
|
{isUploading && (
|
|
<div>
|
|
<progress value={progress} max="100" />
|
|
<span>{progress}%</span>
|
|
</div>
|
|
)}
|
|
{uploadError && (
|
|
<div style={{ color: 'red' }}>
|
|
上传错误: {uploadError}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default TusUploader;
|