Merge pull request #98 from zstar1003/dev
feat(知识块管理): 实现chunk关联图片预览显示功能
This commit is contained in:
commit
16b2c75dfe
|
@ -1,6 +1,5 @@
|
||||||
import i18n from '@/locales/config';
|
import i18n from '@/locales/config';
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
|
||||||
import { App, ConfigProvider, ConfigProviderProps, theme } from 'antd';
|
import { App, ConfigProvider, ConfigProviderProps, theme } from 'antd';
|
||||||
import pt_BR from 'antd/lib/locale/pt_BR';
|
import pt_BR from 'antd/lib/locale/pt_BR';
|
||||||
import deDE from 'antd/locale/de_DE';
|
import deDE from 'antd/locale/de_DE';
|
||||||
|
@ -68,7 +67,7 @@ function Root({ children }: React.PropsWithChildren) {
|
||||||
>
|
>
|
||||||
<App>{children}</App>
|
<App>{children}</App>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
<ReactQueryDevtools buttonPosition={'top-left'} />
|
{/* <ReactQueryDevtools buttonPosition={'top-left'} /> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
.primitiveImg {
|
||||||
|
display: inline-block;
|
||||||
|
max-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
max-width: 100px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imagePreview {
|
||||||
|
display: block;
|
||||||
|
max-width: 45vw;
|
||||||
|
max-height: 40vh;
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Popover } from 'antd';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
interface IImage {
|
||||||
|
id: string;
|
||||||
|
className: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChunkImage = ({ id, className, ...props }: IImage) => {
|
||||||
|
const imgSrc = id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
{...props}
|
||||||
|
src={imgSrc}
|
||||||
|
alt=""
|
||||||
|
className={classNames(styles.primitiveImg, className)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChunkImage;
|
||||||
|
|
||||||
|
export const ImageWithPopover = ({ id }: { id: string }) => {
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
placement="left"
|
||||||
|
content={
|
||||||
|
<ChunkImage id={id} className={styles.imagePreview}></ChunkImage>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ChunkImage id={id} className={styles.image}></ChunkImage>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
|
@ -90,3 +90,39 @@
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.imagePreviewPane {
|
||||||
|
width: 200px;
|
||||||
|
min-width: 200px;
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imagePreviewContainer {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.fullSizeImage {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import ChunkImage from '@/components/chunk_image';
|
||||||
import { useFetchNextChunkList, useSwitchChunk } from '@/hooks/chunk-hooks';
|
import { useFetchNextChunkList, useSwitchChunk } from '@/hooks/chunk-hooks';
|
||||||
import type { PaginationProps } from 'antd';
|
import type { PaginationProps } from 'antd';
|
||||||
import { Divider, Flex, Pagination, Space, Spin, message } from 'antd';
|
import { Divider, Flex, Pagination, Space, Spin, message } from 'antd';
|
||||||
|
@ -46,6 +47,14 @@ const Chunk = () => {
|
||||||
documentId,
|
documentId,
|
||||||
} = useUpdateChunk();
|
} = useUpdateChunk();
|
||||||
|
|
||||||
|
// 获取选中的chunk
|
||||||
|
const selectedChunk = data.find((item) => item.chunk_id === selectedChunkId);
|
||||||
|
|
||||||
|
// 获取图片ID,兼容两种字段名
|
||||||
|
const getImageId = (chunk: any) => {
|
||||||
|
return chunk?.image_id || chunk?.img_id;
|
||||||
|
};
|
||||||
|
|
||||||
const onPaginationChange: PaginationProps['onShowSizeChange'] = (
|
const onPaginationChange: PaginationProps['onShowSizeChange'] = (
|
||||||
page,
|
page,
|
||||||
size,
|
size,
|
||||||
|
@ -134,6 +143,35 @@ const Chunk = () => {
|
||||||
></ChunkToolBar>
|
></ChunkToolBar>
|
||||||
<Divider></Divider>
|
<Divider></Divider>
|
||||||
<Flex flex={1} gap={'middle'}>
|
<Flex flex={1} gap={'middle'}>
|
||||||
|
{/* 左侧图片预览窗格 */}
|
||||||
|
<div className={styles.imagePreviewPane}>
|
||||||
|
<h4>{t('关联图片显示区域')}</h4>
|
||||||
|
{selectedChunk ? (
|
||||||
|
getImageId(selectedChunk) ? (
|
||||||
|
<div className={styles.imagePreviewContainer}>
|
||||||
|
<ChunkImage
|
||||||
|
id={getImageId(selectedChunk)}
|
||||||
|
className={styles.fullSizeImage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className={styles.placeholderContainer}>
|
||||||
|
{' '}
|
||||||
|
<p>{t('chunk.noImageAssociated', '此区块没有关联图片')}</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<div className={styles.placeholderContainer}>
|
||||||
|
{' '}
|
||||||
|
<p>
|
||||||
|
{t(
|
||||||
|
'chunk.selectChunkToViewImage',
|
||||||
|
'请选择一个块以查看其图片',
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<Flex
|
<Flex
|
||||||
vertical
|
vertical
|
||||||
className={isPdf ? styles.pagePdfWrapper : styles.pageWrapper}
|
className={isPdf ? styles.pagePdfWrapper : styles.pageWrapper}
|
||||||
|
|
|
@ -1,16 +1,7 @@
|
||||||
import { useInfiniteFetchKnowledgeList } from '@/hooks/knowledge-hooks';
|
import { useInfiniteFetchKnowledgeList } from '@/hooks/knowledge-hooks';
|
||||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||||
import { PlusOutlined, SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import {
|
import { Divider, Empty, Flex, Input, Skeleton, Space, Spin } from 'antd';
|
||||||
Button,
|
|
||||||
Divider,
|
|
||||||
Empty,
|
|
||||||
Flex,
|
|
||||||
Input,
|
|
||||||
Skeleton,
|
|
||||||
Space,
|
|
||||||
Spin,
|
|
||||||
} from 'antd';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import InfiniteScroll from 'react-infinite-scroll-component';
|
import InfiniteScroll from 'react-infinite-scroll-component';
|
||||||
import { useSaveKnowledge } from './hooks';
|
import { useSaveKnowledge } from './hooks';
|
||||||
|
@ -26,7 +17,6 @@ const KnowledgeList = () => {
|
||||||
const {
|
const {
|
||||||
visible,
|
visible,
|
||||||
hideModal,
|
hideModal,
|
||||||
showModal,
|
|
||||||
onCreateOk,
|
onCreateOk,
|
||||||
loading: creatingLoading,
|
loading: creatingLoading,
|
||||||
} = useSaveKnowledge();
|
} = useSaveKnowledge();
|
||||||
|
@ -67,15 +57,6 @@ const KnowledgeList = () => {
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
prefix={<SearchOutlined />}
|
prefix={<SearchOutlined />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<PlusOutlined />}
|
|
||||||
onClick={showModal}
|
|
||||||
className={styles.topButton}
|
|
||||||
>
|
|
||||||
{t('createKnowledgeBase')}
|
|
||||||
</Button>*/}
|
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
|
|
Loading…
Reference in New Issue