feat: display all pdf pages
This commit is contained in:
parent
a6ae5b77d2
commit
82ea4ae6df
9 changed files with 133 additions and 40 deletions
40
web/package-lock.json
generated
40
web/package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
||||||
"@ant-design/icons": "^5.2.6",
|
"@ant-design/icons": "^5.2.6",
|
||||||
"@ant-design/pro-components": "^2.6.46",
|
"@ant-design/pro-components": "^2.6.46",
|
||||||
"@ant-design/pro-layout": "^7.17.16",
|
"@ant-design/pro-layout": "^7.17.16",
|
||||||
|
"ahooks": "^3.7.10",
|
||||||
"antd": "^5.12.7",
|
"antd": "^5.12.7",
|
||||||
"axios": "^1.6.3",
|
"axios": "^1.6.3",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
|
|
@ -4763,6 +4764,27 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ahooks": {
|
||||||
|
"version": "3.7.10",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.10.tgz",
|
||||||
|
"integrity": "sha512-/HLYif7sFA/5qSuWKrwvjDbf3bq+sdaMrUWS7XGCDRWdC2FrG/i+u5LZdakMYc6UIgJTMQ7tGiJCV7sdU4kSIw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.21.0",
|
||||||
|
"dayjs": "^1.9.1",
|
||||||
|
"intersection-observer": "^0.12.0",
|
||||||
|
"js-cookie": "^2.x.x",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
|
"screenfull": "^5.0.0",
|
||||||
|
"tslib": "^2.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||||
|
|
@ -9843,6 +9865,11 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/intersection-observer": {
|
||||||
|
"version": "0.12.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
|
||||||
|
"integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
|
||||||
|
},
|
||||||
"node_modules/intl": {
|
"node_modules/intl": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmmirror.com/intl/-/intl-1.2.5.tgz",
|
"resolved": "https://registry.npmmirror.com/intl/-/intl-1.2.5.tgz",
|
||||||
|
|
@ -10730,6 +10757,11 @@
|
||||||
"resolved": "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.5.tgz",
|
"resolved": "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.5.tgz",
|
||||||
"integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA=="
|
"integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/js-cookie": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
|
@ -15550,6 +15582,14 @@
|
||||||
"node": ">= 10.13.0"
|
"node": ">= 10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/screenfull": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/scroll-into-view-if-needed": {
|
"node_modules/scroll-into-view-if-needed": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
"@ant-design/icons": "^5.2.6",
|
"@ant-design/icons": "^5.2.6",
|
||||||
"@ant-design/pro-components": "^2.6.46",
|
"@ant-design/pro-components": "^2.6.46",
|
||||||
"@ant-design/pro-layout": "^7.17.16",
|
"@ant-design/pro-layout": "^7.17.16",
|
||||||
|
"ahooks": "^3.7.10",
|
||||||
"antd": "^5.12.7",
|
"antd": "^5.12.7",
|
||||||
"axios": "^1.6.3",
|
"axios": "^1.6.3",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { useSize } from 'ahooks';
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export const useDocumentResizeObserver = () => {
|
||||||
|
const [containerWidth, setContainerWidth] = useState<number>();
|
||||||
|
const [containerRef, setContainerRef] = useState<HTMLElement | null>(null);
|
||||||
|
const size = useSize(containerRef);
|
||||||
|
|
||||||
|
const onResize = useCallback((width?: number) => {
|
||||||
|
if (width) {
|
||||||
|
setContainerWidth(width);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onResize(size?.width);
|
||||||
|
}, [size?.width, onResize]);
|
||||||
|
|
||||||
|
return { containerWidth, setContainerRef };
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
.documentContainer {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100vh - 284px);
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
@ -1,59 +1,72 @@
|
||||||
import { useGetKnowledgeSearchParams } from '@/hooks/knowledgeHook';
|
import { useGetKnowledgeSearchParams } from '@/hooks/knowledgeHook';
|
||||||
import { getDocumentFile } from '@/services/kbService';
|
|
||||||
import { api_host } from '@/utils/api';
|
import { api_host } from '@/utils/api';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { Document, Page, pdfjs } from 'react-pdf';
|
import { Document, Page, pdfjs } from 'react-pdf';
|
||||||
import { useDispatch } from 'umi';
|
|
||||||
|
|
||||||
type PDFFile = string | File | null;
|
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
||||||
|
import 'react-pdf/dist/esm/Page/TextLayer.css';
|
||||||
|
import { useDocumentResizeObserver } from './hooks';
|
||||||
|
|
||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
// type PDFFile = string | File | null;
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||||
'pdfjs-dist/build/pdf.worker.min.js',
|
'pdfjs-dist/build/pdf.worker.min.js',
|
||||||
import.meta.url,
|
import.meta.url,
|
||||||
).toString();
|
).toString();
|
||||||
|
|
||||||
|
// const options = {
|
||||||
|
// cMapUrl: '/cmaps/',
|
||||||
|
// standardFontDataUrl: '/standard_fonts/',
|
||||||
|
// };
|
||||||
|
|
||||||
const DocumentPreview = () => {
|
const DocumentPreview = () => {
|
||||||
const [numPages, setNumPages] = useState<number>();
|
const [numPages, setNumPages] = useState<number>();
|
||||||
const [pageNumber, setPageNumber] = useState<number>(1);
|
|
||||||
const { documentId } = useGetKnowledgeSearchParams();
|
const { documentId } = useGetKnowledgeSearchParams();
|
||||||
const dispatch = useDispatch();
|
// const [file, setFile] = useState<PDFFile>(null);
|
||||||
const [file, setFile] = useState<PDFFile>(null);
|
const { containerWidth, setContainerRef } = useDocumentResizeObserver();
|
||||||
|
|
||||||
function onDocumentLoadSuccess({ numPages }: { numPages: number }): void {
|
function onDocumentLoadSuccess({ numPages }: { numPages: number }): void {
|
||||||
setNumPages(numPages);
|
setNumPages(numPages);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChange = (e: any) => {
|
// const handleChange = (e: any) => {
|
||||||
console.info(e.files);
|
// console.info(e.files);
|
||||||
setFile(e.target.files[0] || null);
|
// setFile(e.target.files[0] || null);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const url = `${api_host}/document/get/${documentId}`;
|
const url = useMemo(() => {
|
||||||
|
return `${api_host}/document/get/${documentId}`;
|
||||||
const fetch_document_file = useCallback(async () => {
|
|
||||||
const ret: Blob = await getDocumentFile(documentId);
|
|
||||||
console.info(ret);
|
|
||||||
const f = new File([ret], 'xx.pdf', { type: ret.type });
|
|
||||||
// console.info(f);
|
|
||||||
setFile(f);
|
|
||||||
}, [documentId]);
|
}, [documentId]);
|
||||||
|
|
||||||
useEffect(() => {
|
// const fetch_document_file = useCallback(async () => {
|
||||||
// dispatch({ type: 'kFModel/fetch_document_file', payload: documentId });
|
// const ret: Blob = await getDocumentFile(documentId);
|
||||||
fetch_document_file();
|
// console.info(ret);
|
||||||
}, [fetch_document_file]);
|
// const f = new File([ret], 'xx.pdf', { type: ret.type });
|
||||||
|
// setFile(f);
|
||||||
|
// }, [documentId]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// // dispatch({ type: 'kFModel/fetch_document_file', payload: documentId });
|
||||||
|
// fetch_document_file();
|
||||||
|
// }, [fetch_document_file]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div ref={setContainerRef} className={styles.documentContainer}>
|
||||||
{file && (
|
<Document
|
||||||
<Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
|
file={url}
|
||||||
<Page pageNumber={pageNumber} />
|
onLoadSuccess={onDocumentLoadSuccess}
|
||||||
</Document>
|
// options={options}
|
||||||
)}
|
>
|
||||||
|
{Array.from(new Array(numPages), (el, index) => (
|
||||||
<p>
|
<Page
|
||||||
Page {pageNumber} of {numPages}
|
key={`page_${index + 1}`}
|
||||||
</p>
|
pageNumber={index + 1}
|
||||||
|
width={containerWidth}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Document>
|
||||||
{/* <input type="file" onChange={handleChange} /> */}
|
{/* <input type="file" onChange={handleChange} /> */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||||
|
import { useSelector } from 'umi';
|
||||||
|
|
||||||
|
export const useSelectDocumentInfo = () => {
|
||||||
|
const documentInfo: IKnowledgeFile = useSelector(
|
||||||
|
(state: any) => state.chunkModel.documentInfo,
|
||||||
|
);
|
||||||
|
return documentInfo;
|
||||||
|
};
|
||||||
|
|
@ -24,8 +24,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.documentPreview {
|
.documentPreview {
|
||||||
width: 30%;
|
width: 40%;
|
||||||
overflow: auto;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { useDeleteChunkByIds } from '@/hooks/knowledgeHook';
|
||||||
import ChunkCard from './components/chunk-card';
|
import ChunkCard from './components/chunk-card';
|
||||||
import ChunkToolBar from './components/chunk-toolbar';
|
import ChunkToolBar from './components/chunk-toolbar';
|
||||||
import DocumentPreview from './components/document-preview';
|
import DocumentPreview from './components/document-preview';
|
||||||
|
import { useSelectDocumentInfo } from './hooks';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import { ChunkModelState } from './model';
|
import { ChunkModelState } from './model';
|
||||||
|
|
||||||
|
|
@ -34,6 +35,7 @@ const Chunk = () => {
|
||||||
const documentId: string = searchParams.get('doc_id') || '';
|
const documentId: string = searchParams.get('doc_id') || '';
|
||||||
const [chunkId, setChunkId] = useState<string | undefined>();
|
const [chunkId, setChunkId] = useState<string | undefined>();
|
||||||
const { removeChunk } = useDeleteChunkByIds();
|
const { removeChunk } = useDeleteChunkByIds();
|
||||||
|
const documentInfo = useSelectDocumentInfo();
|
||||||
|
|
||||||
const getChunkList = useCallback(() => {
|
const getChunkList = useCallback(() => {
|
||||||
const payload: PayloadType = {
|
const payload: PayloadType = {
|
||||||
|
|
@ -197,9 +199,12 @@ const Chunk = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
<section className={styles.documentPreview}>
|
|
||||||
<DocumentPreview></DocumentPreview>
|
{documentInfo.type === 'pdf' && (
|
||||||
</section>
|
<section className={styles.documentPreview}>
|
||||||
|
<DocumentPreview></DocumentPreview>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</div>
|
</div>
|
||||||
<CreatingModal doc_id={documentId} chunkId={chunkId} />
|
<CreatingModal doc_id={documentId} chunkId={chunkId} />
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export interface ChunkModelState extends BaseState {
|
||||||
chunk_id: string;
|
chunk_id: string;
|
||||||
doc_id: string;
|
doc_id: string;
|
||||||
chunkInfo: any;
|
chunkInfo: any;
|
||||||
documentInfo: Partial<IKnowledgeFile>;
|
documentInfo: IKnowledgeFile;
|
||||||
available?: number;
|
available?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ const model: DvaModel<ChunkModelState> = {
|
||||||
chunk_id: '',
|
chunk_id: '',
|
||||||
doc_id: '',
|
doc_id: '',
|
||||||
chunkInfo: {},
|
chunkInfo: {},
|
||||||
documentInfo: {},
|
documentInfo: {} as IKnowledgeFile,
|
||||||
pagination: {
|
pagination: {
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue