Fix: Add video preview #9869 (#10748)

### What problem does this PR solve?

Fix: Add video preview

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
chanx
2025-10-23 14:25:05 +08:00
committed by GitHub
parent ac188b0486
commit 6d333ec4bc
4 changed files with 101 additions and 5 deletions

View File

@ -2,7 +2,7 @@ import message from '@/components/ui/message';
import { Spin } from '@/components/ui/spin';
import request from '@/utils/request';
import classNames from 'classnames';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
interface ImagePreviewerProps {
className?: string;
@ -17,7 +17,7 @@ export const ImagePreviewer: React.FC<ImagePreviewerProps> = ({
const [imageSrc, setImageSrc] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const fetchImage = async () => {
const fetchImage = useCallback(async () => {
setIsLoading(true);
const res = await request(url, {
method: 'GET',
@ -30,12 +30,13 @@ export const ImagePreviewer: React.FC<ImagePreviewerProps> = ({
const objectUrl = URL.createObjectURL(res.data);
setImageSrc(objectUrl);
setIsLoading(false);
};
}, [url]);
useEffect(() => {
if (url) {
fetchImage();
}
}, [url]);
}, [url, fetchImage]);
useEffect(() => {
return () => {

View File

@ -8,6 +8,7 @@ import styles from './index.less';
import PdfPreviewer, { IProps } from './pdf-preview';
import { PptPreviewer } from './ppt-preview';
import { TxtPreviewer } from './txt-preview';
import { VideoPreviewer } from './video-preview';
type PreviewProps = {
fileType: string;
@ -42,11 +43,30 @@ const Preview = ({
<TxtPreviewer className={className} url={url} />
</section>
)}
{['visual'].indexOf(fileType) > -1 && (
{['jpg', 'png', 'gif', 'jpeg', 'svg', 'bmp', 'ico', 'tif'].indexOf(
fileType,
) > -1 && (
<section>
<ImagePreviewer className={className} url={url} />
</section>
)}
{[
'mp4',
'avi',
'mov',
'mkv',
'wmv',
'flv',
'mpeg',
'mpg',
'asf',
'rm',
'rmvb',
].indexOf(fileType) > -1 && (
<section>
<VideoPreviewer className={className} url={url} />
</section>
)}
{['pptx'].indexOf(fileType) > -1 && (
<section>
<PptPreviewer className={className} url={url} />

View File

@ -0,0 +1,74 @@
import message from '@/components/ui/message';
import { Spin } from '@/components/ui/spin';
import request from '@/utils/request';
import classNames from 'classnames';
import { useCallback, useEffect, useState } from 'react';
interface VideoPreviewerProps {
className?: string;
url: string;
}
export const VideoPreviewer: React.FC<VideoPreviewerProps> = ({
className,
url,
}) => {
// const url = useGetDocumentUrl();
const [videoSrc, setVideoSrc] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const fetchVideo = useCallback(async () => {
setIsLoading(true);
const res = await request(url, {
method: 'GET',
responseType: 'blob',
onError: () => {
message.error('Failed to load video');
setIsLoading(false);
},
});
const objectUrl = URL.createObjectURL(res.data);
setVideoSrc(objectUrl);
setIsLoading(false);
}, [url]);
useEffect(() => {
if (url) {
fetchVideo();
}
}, [url, fetchVideo]);
useEffect(() => {
return () => {
if (videoSrc) {
URL.revokeObjectURL(videoSrc);
}
};
}, [videoSrc]);
return (
<div
className={classNames(
'relative w-full h-full p-4 bg-background-paper border border-border-normal rounded-md video-previewer',
className,
)}
>
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center">
<Spin />
</div>
)}
{!isLoading && videoSrc && (
<div className="max-h-[80vh] overflow-auto p-2">
<video
src={videoSrc}
controls
className="w-full h-auto max-w-full object-contain"
onLoadedData={() => URL.revokeObjectURL(videoSrc!)}
/>
</div>
)}
</div>
);
};

View File

@ -166,6 +166,7 @@ const Chunk = () => {
case 'doc':
return documentInfo?.name.split('.').pop() || 'doc';
case 'visual':
return documentInfo?.name.split('.').pop() || 'visual';
case 'docx':
case 'txt':
case 'md':