From 6d333ec4bcec9fd8fd4936ef81730b32971d87d3 Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Thu, 23 Oct 2025 14:25:05 +0800 Subject: [PATCH] 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) --- .../document-preview/image-preview.tsx | 9 ++- .../components/document-preview/index.tsx | 22 +++++- .../document-preview/video-preview.tsx | 74 +++++++++++++++++++ .../components/knowledge-chunk/index.tsx | 1 + 4 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/video-preview.tsx diff --git a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/image-preview.tsx b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/image-preview.tsx index 80e796a54..bec4ae75e 100644 --- a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/image-preview.tsx +++ b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/image-preview.tsx @@ -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 = ({ const [imageSrc, setImageSrc] = useState(null); const [isLoading, setIsLoading] = useState(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 = ({ const objectUrl = URL.createObjectURL(res.data); setImageSrc(objectUrl); setIsLoading(false); - }; + }, [url]); + useEffect(() => { if (url) { fetchImage(); } - }, [url]); + }, [url, fetchImage]); useEffect(() => { return () => { diff --git a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/index.tsx b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/index.tsx index dd7b35348..b778067a6 100644 --- a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/index.tsx +++ b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/index.tsx @@ -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 = ({ )} - {['visual'].indexOf(fileType) > -1 && ( + {['jpg', 'png', 'gif', 'jpeg', 'svg', 'bmp', 'ico', 'tif'].indexOf( + fileType, + ) > -1 && (
)} + {[ + 'mp4', + 'avi', + 'mov', + 'mkv', + 'wmv', + 'flv', + 'mpeg', + 'mpg', + 'asf', + 'rm', + 'rmvb', + ].indexOf(fileType) > -1 && ( +
+ +
+ )} {['pptx'].indexOf(fileType) > -1 && (
diff --git a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/video-preview.tsx b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/video-preview.tsx new file mode 100644 index 000000000..2b21ed528 --- /dev/null +++ b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/components/document-preview/video-preview.tsx @@ -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 = ({ + className, + url, +}) => { + // const url = useGetDocumentUrl(); + const [videoSrc, setVideoSrc] = useState(null); + const [isLoading, setIsLoading] = useState(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 ( +
+ {isLoading && ( +
+ +
+ )} + + {!isLoading && videoSrc && ( +
+
+ )} +
+ ); +}; diff --git a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/index.tsx b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/index.tsx index 033e83d5b..7aff9e993 100644 --- a/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/index.tsx +++ b/web/src/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk/index.tsx @@ -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':