diff --git a/web/src/components/new-document-link.tsx b/web/src/components/new-document-link.tsx index e64ef142460..0e7620de3e0 100644 --- a/web/src/components/new-document-link.tsx +++ b/web/src/components/new-document-link.tsx @@ -1,22 +1,24 @@ -import { api_host } from '@/utils/api'; import React from 'react'; interface IProps extends React.PropsWithChildren { - documentId: string; + link: string; preventDefault?: boolean; + color?: string; } const NewDocumentLink = ({ children, - documentId, + link, preventDefault = false, + color = 'rgb(15, 79, 170)', }: IProps) => { return ( e.preventDefault()} - href={`${api_host}/document/get/${documentId}`} + href={link} rel="noreferrer" + style={{ color }} > {children} diff --git a/web/src/constants/common.ts b/web/src/constants/common.ts index a356d015c66..882c22ffe5a 100644 --- a/web/src/constants/common.ts +++ b/web/src/constants/common.ts @@ -68,3 +68,23 @@ export const FileMimeTypeMap = { xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', mp4: 'video/mp4', }; + +//#region file preview +export const Images = [ + 'jpg', + 'jpeg', + 'png', + 'gif', + 'bmp', + 'tif', + 'tiff', + 'webp', + // 'svg', + 'ico', +]; + +// Without FileViewer +export const ExceptiveType = ['xlsx', 'xls', 'pdf', ...Images]; + +export const SupportedPreviewDocumentTypes = ['docx', 'csv', ...ExceptiveType]; +//#endregion diff --git a/web/src/hooks/documentHooks.ts b/web/src/hooks/documentHooks.ts index cc74a5fa8ff..ffa524ff304 100644 --- a/web/src/hooks/documentHooks.ts +++ b/web/src/hooks/documentHooks.ts @@ -9,12 +9,15 @@ import { useDispatch, useSelector } from 'umi'; import { useGetKnowledgeSearchParams } from './routeHook'; import { useOneNamespaceEffectsLoading } from './storeHooks'; -export const useGetDocumentUrl = (documentId: string) => { - const url = useMemo(() => { - return `${api_host}/document/get/${documentId}`; - }, [documentId]); +export const useGetDocumentUrl = (documentId?: string) => { + const getDocumentUrl = useCallback( + (id?: string) => { + return `${api_host}/document/get/${documentId || id}`; + }, + [documentId], + ); - return url; + return getDocumentUrl; }; export const useGetChunkHighlights = (selectedChunk: IChunk) => { diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 46ae5428ded..5a202bdad92 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -505,6 +505,7 @@ export default { 'Support for a single or bulk upload. Strictly prohibited from uploading company data or other banned files.', local: 'Local uploads', s3: 'S3 uploads', + preview: 'Preview', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/locales/zh-traditional.ts b/web/src/locales/zh-traditional.ts index 1f6a73c1dec..9538e54f07b 100644 --- a/web/src/locales/zh-traditional.ts +++ b/web/src/locales/zh-traditional.ts @@ -468,6 +468,7 @@ export default { directory: '文件夾', local: '本地上傳', s3: 'S3 上傳', + preview: '預覽', }, footer: { profile: '“保留所有權利 @ react”', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index ab0a0fbc741..dc6572058a2 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -486,6 +486,7 @@ export default { directory: '文件夹', local: '本地上传', s3: 'S3 上传', + preview: '预览', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx index 47a63cc30ea..6ad33210a53 100644 --- a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx @@ -106,8 +106,8 @@ const KnowledgeFile = () => { }, { title: t('uploadDate'), - dataIndex: 'create_date', - key: 'create_date', + dataIndex: 'create_time', + key: 'create_time', render(value) { return formatDate(value); }, diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx index a0e2816e1d4..20b823154b2 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx @@ -1,5 +1,6 @@ import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg'; import NewDocumentLink from '@/components/new-document-link'; +import { useGetDocumentUrl } from '@/hooks/documentHooks'; import { ITestingDocument } from '@/interfaces/database/knowledge'; import { isPdf } from '@/utils/documentUtils'; import { Table, TableProps } from 'antd'; @@ -15,6 +16,7 @@ const SelectFiles = ({ handleTesting }: IProps) => { ); const dispatch = useDispatch(); + const getDocumentUrl = useGetDocumentUrl(); const columns: TableProps['columns'] = [ { @@ -35,7 +37,10 @@ const SelectFiles = ({ handleTesting }: IProps) => { key: 'view', width: 50, render: (_, { doc_id, doc_name }) => ( - + ), diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index e57599a65d4..f2e465b8c86 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -30,6 +30,7 @@ import MarkdownContent from '../markdown-content'; import SvgIcon from '@/components/svg-icon'; import { useTranslate } from '@/hooks/commonHooks'; +import { useGetDocumentUrl } from '@/hooks/documentHooks'; import { getExtension, isPdf } from '@/utils/documentUtils'; import styles from './index.less'; @@ -44,6 +45,7 @@ const MessageItem = ({ }) => { const userInfo = useSelectUserInfo(); const fileThumbnails = useSelectFileThumbnails(); + const getDocumentUrl = useGetDocumentUrl(); const isAssistant = item.role === MessageType.Assistant; @@ -113,7 +115,7 @@ const MessageItem = ({ )} {item.doc_name} diff --git a/web/src/pages/document-viewer/index.less b/web/src/pages/document-viewer/index.less index 333e67c92a3..8389f1aa9ea 100644 --- a/web/src/pages/document-viewer/index.less +++ b/web/src/pages/document-viewer/index.less @@ -1,8 +1,13 @@ .viewerWrapper { width: 100%; + height: 100%; :global { .pdf-canvas { text-align: center; } } + .image { + width: 100%; + height: 100%; + } } diff --git a/web/src/pages/document-viewer/index.tsx b/web/src/pages/document-viewer/index.tsx index 961591774ad..39c7befcf87 100644 --- a/web/src/pages/document-viewer/index.tsx +++ b/web/src/pages/document-viewer/index.tsx @@ -1,10 +1,17 @@ +import { ExceptiveType, Images } from '@/constants/common'; import { api_host } from '@/utils/api'; +import { Flex, Image } from 'antd'; import FileViewer from 'react-file-viewer'; import { useParams, useSearchParams } from 'umi'; import Excel from './excel'; +import Pdf from './pdf'; import styles from './index.less'; +// TODO: The interface returns an incorrect content-type for the SVG. + +const isNotExceptiveType = (ext: string) => ExceptiveType.indexOf(ext) === -1; + const DocumentViewer = () => { const { id: documentId } = useParams(); const api = `${api_host}/file/get/${documentId}`; @@ -17,8 +24,14 @@ const DocumentViewer = () => { return (
- {ext === 'xlsx' && } - {ext !== 'xlsx' && ( + {Images.includes(ext!) && ( + + + + )} + {ext === 'pdf' && } + {(ext === 'xlsx' || ext === 'xls') && } + {isNotExceptiveType(ext!) && ( )}
diff --git a/web/src/pages/document-viewer/pdf/index.tsx b/web/src/pages/document-viewer/pdf/index.tsx new file mode 100644 index 00000000000..176c08b2060 --- /dev/null +++ b/web/src/pages/document-viewer/pdf/index.tsx @@ -0,0 +1,38 @@ +import { Skeleton } from 'antd'; +import { PdfHighlighter, PdfLoader } from 'react-pdf-highlighter'; + +interface IProps { + url: string; +} + +const DocumentPreviewer = ({ url }: IProps) => { + const resetHash = () => {}; + + return ( +
+ } + workerSrc="/pdfjs-dist/pdf.worker.min.js" + > + {(pdfDocument) => { + return ( + event.altKey} + onScrollChange={resetHash} + scrollRef={() => {}} + onSelectionFinished={() => null} + highlightTransform={() => { + return
; + }} + highlights={[]} + /> + ); + }} +
+
+ ); +}; + +export default DocumentPreviewer; diff --git a/web/src/pages/file-manager/action-cell/index.tsx b/web/src/pages/file-manager/action-cell/index.tsx index d03aa75dcc8..86d3d5afae6 100644 --- a/web/src/pages/file-manager/action-cell/index.tsx +++ b/web/src/pages/file-manager/action-cell/index.tsx @@ -6,13 +6,21 @@ import { DeleteOutlined, DownloadOutlined, EditOutlined, + EyeOutlined, LinkOutlined, } from '@ant-design/icons'; import { Button, Space, Tooltip } from 'antd'; -import { useHandleDeleteFile, useNavigateToDocument } from '../hooks'; +import { useHandleDeleteFile } from '../hooks'; +import NewDocumentLink from '@/components/new-document-link'; +import { SupportedPreviewDocumentTypes } from '@/constants/common'; +import { getExtension } from '@/utils/documentUtils'; import styles from './index.less'; +const isSupportedPreviewDocumentType = (fileExtension: string) => { + return SupportedPreviewDocumentTypes.includes(fileExtension); +}; + interface IProps { record: IFile; setCurrentRecord: (record: any) => void; @@ -35,7 +43,7 @@ const ActionCell = ({ [documentId], setSelectedRowKeys, ); - const navigateToDocument = useNavigateToDocument(record.id, record.name); + const extension = getExtension(record.name); const onDownloadDocument = () => { downloadFile({ @@ -59,15 +67,6 @@ const ActionCell = ({ return ( - {/* - - */} + +
+ )} ); }; diff --git a/web/src/pages/file-manager/hooks.ts b/web/src/pages/file-manager/hooks.ts index 4023b30b542..dc95043276c 100644 --- a/web/src/pages/file-manager/hooks.ts +++ b/web/src/pages/file-manager/hooks.ts @@ -13,7 +13,6 @@ import { import { useGetPagination, useSetPagination } from '@/hooks/logicHooks'; import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import { IFile } from '@/interfaces/database/file-manager'; -import { getExtension } from '@/utils/documentUtils'; import { PaginationProps } from 'antd'; import { UploadFile } from 'antd/lib'; import { useCallback, useEffect, useMemo, useState } from 'react'; @@ -339,12 +338,3 @@ export const useHandleBreadcrumbClick = () => { return { handleBreadcrumbClick }; }; - -export const useNavigateToDocument = (documentId: string, name: string) => { - const navigate = useNavigate(); - const navigateToDocument = () => { - navigate(`/document/${documentId}?ext=${getExtension(name)}`); - }; - - return navigateToDocument; -}; diff --git a/web/src/pages/file-manager/index.tsx b/web/src/pages/file-manager/index.tsx index 051f684687a..a7bb98ac8d2 100644 --- a/web/src/pages/file-manager/index.tsx +++ b/web/src/pages/file-manager/index.tsx @@ -96,8 +96,8 @@ const FileManager = () => { }, { title: t('uploadDate'), - dataIndex: 'create_date', - key: 'create_date', + dataIndex: 'create_time', + key: 'create_time', render(text) { return formatDate(text); }, diff --git a/web/src/pages/knowledge/knowledge-card/index.tsx b/web/src/pages/knowledge/knowledge-card/index.tsx index b94ef27bc6e..9970f91802b 100644 --- a/web/src/pages/knowledge/knowledge-card/index.tsx +++ b/web/src/pages/knowledge/knowledge-card/index.tsx @@ -100,7 +100,7 @@ const KnowledgeCard = ({ item }: IProps) => {
- {formatDate(item.update_date)} + {formatDate(item.update_time)}
{/* diff --git a/web/src/routes.ts b/web/src/routes.ts index d2d7e0d7a22..4ab6134bde7 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -88,12 +88,13 @@ const routes = [ path: '/flow', component: '@/pages/flow', }, - { - path: 'document/:id', - component: '@/pages/document-viewer', - }, ], }, + { + path: 'document/:id', + component: '@/pages/document-viewer', + layout: false, + }, { path: '/*', component: '@/pages/404', diff --git a/web/src/utils/date.ts b/web/src/utils/date.ts index 90aee0aa467..93472d25bee 100644 --- a/web/src/utils/date.ts +++ b/web/src/utils/date.ts @@ -16,5 +16,5 @@ export function formatDate(date: any) { if (!date) { return ''; } - return dayjs(date).format('DD/MM/YYYY'); + return dayjs(date).format('DD/MM/YYYY HH:mm:ss'); }