mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-04-20 05:00:01 +08:00
feat: set chunk to available state and select all chunk (#57)
* feat: set chunk to available state * feat: select all chunk
This commit is contained in:
parent
eb381963b3
commit
97d4387982
5
web/.eslintrc.js
Normal file
5
web/.eslintrc.js
Normal file
@ -0,0 +1,5 @@
|
||||
// .eslintrc.js
|
||||
module.exports = {
|
||||
// Umi 项目
|
||||
extends: [require.resolve('umi/eslint'), 'plugin:react-hooks/recommended'],
|
||||
};
|
103
web/package-lock.json
generated
103
web/package-lock.json
generated
@ -27,6 +27,7 @@
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/react": "^18.0.33",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@umijs/lint": "^4.1.1",
|
||||
"@umijs/plugins": "^4.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"prettier": "^3.2.4",
|
||||
@ -3479,16 +3480,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@umijs/lint": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@umijs/lint/-/lint-4.1.0.tgz",
|
||||
"integrity": "sha512-drXkAeBJGMLrPr/dDiOZ2Z+3VKkAf53MzoOIhwHy5atq+PFNG9Y7e6YuWrK3qVF75zg9culQzlHTvinCjDK97Q==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@umijs/lint/-/lint-4.1.1.tgz",
|
||||
"integrity": "sha512-fy2edKuYw42eM3LuH/2AiH0ZKdembFx3SR8dIGKxf7BmEQOSfUhskLiNGE8tSRubCiVzGUWvZQDw1YQcU0bsHg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "7.23.6",
|
||||
"@babel/eslint-parser": "7.23.3",
|
||||
"@stylelint/postcss-css-in-js": "^0.38.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@umijs/babel-preset-umi": "4.1.0",
|
||||
"@umijs/babel-preset-umi": "4.1.1",
|
||||
"eslint-plugin-jest": "27.2.3",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
@ -3501,6 +3503,7 @@
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.23.6.tgz",
|
||||
"integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.23.5",
|
||||
@ -3522,6 +3525,54 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@umijs/lint/node_modules/@babel/runtime": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.6.tgz",
|
||||
"integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@umijs/lint/node_modules/@umijs/babel-preset-umi": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@umijs/babel-preset-umi/-/babel-preset-umi-4.1.1.tgz",
|
||||
"integrity": "sha512-6pYZnF03euAJGZN3VLe8PKKRNMH6Zxj4GKNooLvJ0Wz0eMufmYDcA4CpbR6h8i1JpgcQ0Sngr8bqHLb7oMqrvw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.23.6",
|
||||
"@bloomberg/record-tuple-polyfill": "0.0.4",
|
||||
"@umijs/bundler-utils": "4.1.1",
|
||||
"@umijs/utils": "4.1.1",
|
||||
"core-js": "3.34.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@umijs/lint/node_modules/@umijs/bundler-utils": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@umijs/bundler-utils/-/bundler-utils-4.1.1.tgz",
|
||||
"integrity": "sha512-k1I1tjDePgB1XqpQHZiLJ/5gS4EykY8hqqzEzD1CSbd5KFE614+q6W/gcpFZ0YLJDWY1GdjOYpRokvuI/MSRfg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@umijs/utils": "4.1.1",
|
||||
"esbuild": "0.17.19",
|
||||
"regenerate": "^1.4.2",
|
||||
"regenerate-unicode-properties": "10.1.1",
|
||||
"spdy": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@umijs/lint/node_modules/@umijs/utils": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@umijs/utils/-/utils-4.1.1.tgz",
|
||||
"integrity": "sha512-hbnbJR3RA7fu4E7q4JFZ47XMYArr6Zn5bftr8YZ+o6hzJlomr4gzoOXE+XxM7rVMK4AFZoc+QZgNTJyISd08Pg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "3.5.3",
|
||||
"pino": "7.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@umijs/mfsu": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@umijs/mfsu/-/mfsu-4.1.0.tgz",
|
||||
@ -16319,6 +16370,31 @@
|
||||
"qs": "^6.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/umi/node_modules/@babel/core": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.23.6.tgz",
|
||||
"integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==",
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.23.5",
|
||||
"@babel/generator": "^7.23.6",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helpers": "^7.23.6",
|
||||
"@babel/parser": "^7.23.6",
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/traverse": "^7.23.6",
|
||||
"@babel/types": "^7.23.6",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
"json5": "^2.2.3",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/umi/node_modules/@babel/runtime": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.6.tgz",
|
||||
@ -16330,6 +16406,25 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/umi/node_modules/@umijs/lint": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@umijs/lint/-/lint-4.1.0.tgz",
|
||||
"integrity": "sha512-drXkAeBJGMLrPr/dDiOZ2Z+3VKkAf53MzoOIhwHy5atq+PFNG9Y7e6YuWrK3qVF75zg9culQzlHTvinCjDK97Q==",
|
||||
"dependencies": {
|
||||
"@babel/core": "7.23.6",
|
||||
"@babel/eslint-parser": "7.23.3",
|
||||
"@stylelint/postcss-css-in-js": "^0.38.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@umijs/babel-preset-umi": "4.1.0",
|
||||
"eslint-plugin-jest": "27.2.3",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-syntax": "0.36.2",
|
||||
"stylelint-config-standard": "25.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/umi/node_modules/fast-glob": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
|
@ -5,6 +5,7 @@
|
||||
"build": "umi build",
|
||||
"dev": "cross-env PORT=9000 umi dev",
|
||||
"postinstall": "umi setup",
|
||||
"lint": "umi lint --eslint-only",
|
||||
"setup": "umi setup",
|
||||
"start": "npm run dev"
|
||||
},
|
||||
@ -30,6 +31,7 @@
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/react": "^18.0.33",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@umijs/lint": "^4.1.1",
|
||||
"@umijs/plugins": "^4.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"prettier": "^3.2.4",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { ReactNode } from "react";
|
||||
import { Inspector } from "react-dev-inspector";
|
||||
import React, { ReactNode } from 'react';
|
||||
import { Inspector } from 'react-dev-inspector';
|
||||
|
||||
export function rootContainer(container: ReactNode) {
|
||||
return React.createElement(Inspector, null, container);
|
||||
|
@ -5,4 +5,5 @@ export interface Pagination {
|
||||
|
||||
export interface BaseState {
|
||||
pagination: Pagination;
|
||||
searchString: string;
|
||||
}
|
||||
|
@ -65,3 +65,13 @@ export interface ITenantInfo {
|
||||
chat_id: string;
|
||||
speech2text_id: string;
|
||||
}
|
||||
|
||||
export interface IChunk {
|
||||
available_int: number; // Whether to enable, 0: not enabled, 1: enabled
|
||||
chunk_id: string;
|
||||
content_with_weight: string;
|
||||
doc_id: string;
|
||||
docnm_kwd: string;
|
||||
img_id: string;
|
||||
important_kwd: any[];
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
.image {
|
||||
width: 100px !important;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.imagePreview {
|
||||
width: 600px;
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
import { IChunk } from '@/interfaces/database/knowledge';
|
||||
import { api_host } from '@/utils/api';
|
||||
import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd';
|
||||
import { useDispatch } from 'umi';
|
||||
|
||||
import { useState } from 'react';
|
||||
import styles from './index.less';
|
||||
|
||||
interface IProps {
|
||||
item: IChunk;
|
||||
checked: boolean;
|
||||
handleCheckboxClick: (chunkId: string, checked: boolean) => void;
|
||||
}
|
||||
|
||||
interface IImage {
|
||||
id: string;
|
||||
className: string;
|
||||
}
|
||||
// Pass onMouseEnter and onMouseLeave to img tag using props
|
||||
const Image = ({ id, className, ...props }: IImage) => {
|
||||
return (
|
||||
<img
|
||||
{...props}
|
||||
src={`${api_host}/document/image/${id}`}
|
||||
alt=""
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ChunkCard = ({ item, checked, handleCheckboxClick }: IProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const available = Number(item.available_int);
|
||||
const [enabled, setEnabled] = useState(available === 1);
|
||||
|
||||
const switchChunk = () => {
|
||||
dispatch({
|
||||
type: 'chunkModel/switch_chunk',
|
||||
payload: {
|
||||
chunk_ids: [item.chunk_id],
|
||||
available_int: available === 0 ? 1 : 0,
|
||||
doc_id: item.doc_id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const onChange = (checked: boolean) => {
|
||||
setEnabled(checked);
|
||||
switchChunk();
|
||||
};
|
||||
|
||||
const handleCheck: CheckboxProps['onChange'] = (e) => {
|
||||
handleCheckboxClick(item.chunk_id, e.target.checked);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card>
|
||||
<Flex gap={'middle'} justify={'space-between'}>
|
||||
<Checkbox onChange={handleCheck} checked={checked}></Checkbox>
|
||||
{item.img_id && (
|
||||
<Popover
|
||||
placement="topRight"
|
||||
content={
|
||||
<Image id={item.img_id} className={styles.imagePreview}></Image>
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={`${api_host}/document/image/${item.img_id}`}
|
||||
alt=""
|
||||
className={styles.image}
|
||||
/>
|
||||
<Image id={item.img_id} className={styles.image}></Image>
|
||||
</Popover>
|
||||
)}
|
||||
|
||||
<section>{item.content_with_weight}</section>
|
||||
<div>
|
||||
<Switch checked={enabled} onChange={onChange} />
|
||||
</div>
|
||||
</Flex>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChunkCard;
|
@ -1,4 +1,6 @@
|
||||
import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
|
||||
import { KnowledgeRouteKey } from '@/constants/knowledge';
|
||||
import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
CheckCircleOutlined,
|
||||
@ -9,17 +11,50 @@ import {
|
||||
PlusOutlined,
|
||||
SearchOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Button, Checkbox, Flex, Menu, MenuProps, Popover, Space } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Flex,
|
||||
Menu,
|
||||
MenuProps,
|
||||
Popover,
|
||||
Radio,
|
||||
RadioChangeEvent,
|
||||
Space,
|
||||
} from 'antd';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { Link, useDispatch, useSelector } from 'umi';
|
||||
import { ChunkModelState } from '../../model';
|
||||
|
||||
interface IProps {
|
||||
checked: boolean;
|
||||
getChunkList: () => void;
|
||||
selectAllChunk: (checked: boolean) => void;
|
||||
}
|
||||
|
||||
const ChunkToolBar = ({ getChunkList, selectAllChunk, checked }: IProps) => {
|
||||
const { documentInfo, available }: ChunkModelState = useSelector(
|
||||
(state: any) => state.chunkModel,
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const knowledgeBaseId = useKnowledgeBaseId();
|
||||
|
||||
const handleSelectAllCheck = useCallback(
|
||||
(e: any) => {
|
||||
// console.info(e.target.checked);
|
||||
selectAllChunk(e.target.checked);
|
||||
},
|
||||
[selectAllChunk],
|
||||
);
|
||||
|
||||
const ChunkToolBar = () => {
|
||||
const items: MenuProps['items'] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
key: '1',
|
||||
label: (
|
||||
<>
|
||||
<Checkbox>
|
||||
<Checkbox onChange={handleSelectAllCheck} checked={checked}>
|
||||
<b>Select All</b>
|
||||
</Checkbox>
|
||||
</>
|
||||
@ -55,47 +90,49 @@ const ChunkToolBar = () => {
|
||||
),
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
}, [checked, handleSelectAllCheck]);
|
||||
|
||||
const content = (
|
||||
<Menu style={{ width: 200 }} items={items} selectable={false} />
|
||||
);
|
||||
|
||||
const handleFilterChange = (e: RadioChangeEvent) => {
|
||||
dispatch({ type: 'chunkModel/setAvailable', payload: e.target.value });
|
||||
getChunkList();
|
||||
};
|
||||
|
||||
const filterContent = (
|
||||
<Radio.Group onChange={handleFilterChange} value={available}>
|
||||
<Space direction="vertical">
|
||||
<Radio value={undefined}>All</Radio>
|
||||
<Radio value={1}>Enabled</Radio>
|
||||
<Radio value={0}>Disabled</Radio>
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex justify="space-between" align="center">
|
||||
<Space>
|
||||
<Space size={'middle'}>
|
||||
<Link
|
||||
to={`/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`}
|
||||
>
|
||||
<ArrowLeftOutlined />
|
||||
</Link>
|
||||
<FilePdfOutlined />
|
||||
xxx.pdf
|
||||
{documentInfo.name}
|
||||
</Space>
|
||||
<Space>
|
||||
{/* <Select
|
||||
defaultValue="lucy"
|
||||
style={{ width: 100 }}
|
||||
popupMatchSelectWidth={false}
|
||||
optionRender={() => null}
|
||||
dropdownRender={(menu) => (
|
||||
<div style={{ width: 300 }}>
|
||||
{menu}
|
||||
<Menu
|
||||
// onClick={onClick}
|
||||
style={{ width: 256 }}
|
||||
// defaultSelectedKeys={['1']}
|
||||
// defaultOpenKeys={['sub1']}
|
||||
// mode="inline"
|
||||
items={actionItems}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
></Select> */}
|
||||
<Popover content={content} placement="bottomLeft" arrow={false}>
|
||||
<Popover content={content} placement="bottom" arrow={false}>
|
||||
<Button>
|
||||
Bulk
|
||||
<DownOutlined />
|
||||
</Button>
|
||||
</Popover>
|
||||
<Button icon={<SearchOutlined />} />
|
||||
<Popover content={filterContent} placement="bottom" arrow={false}>
|
||||
<Button icon={<FilterIcon />} />
|
||||
</Popover>
|
||||
<Button icon={<DeleteOutlined />} />
|
||||
<Button icon={<PlusOutlined />} type="primary" />
|
||||
</Space>
|
||||
|
@ -2,7 +2,7 @@
|
||||
padding: 24px;
|
||||
|
||||
display: flex;
|
||||
height: calc(100vh - 112px);
|
||||
// height: calc(100vh - 112px);
|
||||
flex-direction: column;
|
||||
|
||||
.filter {
|
||||
@ -66,5 +66,4 @@
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
}
|
@ -1,41 +1,36 @@
|
||||
import { api_host } from '@/utils/api';
|
||||
import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil';
|
||||
import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
|
||||
import type { PaginationProps } from 'antd';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Input,
|
||||
Pagination,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Select,
|
||||
Spin,
|
||||
Switch,
|
||||
} from 'antd';
|
||||
import { Button, Input, Pagination, Space, Spin } from 'antd';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
||||
import CreateModal from './components/createModal';
|
||||
|
||||
import ChunkCard from './components/chunk-card';
|
||||
import ChunkToolBar from './components/chunk-toolbar';
|
||||
import styles from './index.less';
|
||||
import { ChunkModelState } from './model';
|
||||
|
||||
interface PayloadType {
|
||||
doc_id: string;
|
||||
keywords?: string;
|
||||
available_int?: number;
|
||||
}
|
||||
|
||||
const Chunk = () => {
|
||||
const dispatch = useDispatch();
|
||||
const chunkModel = useSelector((state: any) => state.chunkModel);
|
||||
const chunkModel: ChunkModelState = useSelector(
|
||||
(state: any) => state.chunkModel,
|
||||
);
|
||||
const [keywords, SetKeywords] = useState('');
|
||||
const [available_int, setAvailableInt] = useState(-1);
|
||||
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
||||
const [searchParams] = useSearchParams();
|
||||
const [pagination, setPagination] = useState({ page: 1, size: 30 });
|
||||
const { data = [], total, chunk_id, isShowCreateModal } = chunkModel;
|
||||
const {
|
||||
data = [],
|
||||
total,
|
||||
chunk_id,
|
||||
isShowCreateModal,
|
||||
pagination,
|
||||
} = chunkModel;
|
||||
const effects = useSelector((state: any) => state.loading.effects);
|
||||
const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [
|
||||
'create_hunk',
|
||||
@ -44,23 +39,19 @@ const Chunk = () => {
|
||||
]);
|
||||
const documentId: string = searchParams.get('doc_id') || '';
|
||||
|
||||
const getChunkList = (value?: string) => {
|
||||
const getChunkList = () => {
|
||||
const payload: PayloadType = {
|
||||
doc_id: documentId,
|
||||
keywords: value || keywords,
|
||||
available_int,
|
||||
};
|
||||
if (payload.available_int === -1) {
|
||||
delete payload.available_int;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'chunkModel/chunk_list',
|
||||
payload: {
|
||||
...payload,
|
||||
...pagination,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const confirm = async (id: string) => {
|
||||
const retcode = await dispatch<any>({
|
||||
type: 'chunkModel/rm_chunk',
|
||||
@ -84,29 +75,55 @@ const Chunk = () => {
|
||||
getChunkList();
|
||||
};
|
||||
|
||||
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
|
||||
const onPaginationChange: PaginationProps['onShowSizeChange'] = (
|
||||
page,
|
||||
size,
|
||||
) => {
|
||||
setPagination({ page, size });
|
||||
};
|
||||
|
||||
const switchChunk = async (id: string, available_int: boolean) => {
|
||||
const retcode = await dispatch<any>({
|
||||
type: 'chunkModel/switch_chunk',
|
||||
setSelectedChunkIds([]);
|
||||
dispatch({
|
||||
type: 'chunkModel/setPagination',
|
||||
payload: {
|
||||
chunk_ids: [id],
|
||||
available_int: Number(available_int),
|
||||
doc_id: documentId,
|
||||
current: page,
|
||||
pageSize: size,
|
||||
},
|
||||
});
|
||||
|
||||
retcode === 0 && getChunkList();
|
||||
getChunkList();
|
||||
};
|
||||
|
||||
const selectAllChunk = useCallback(
|
||||
(checked: boolean) => {
|
||||
setSelectedChunkIds(checked ? data.map((x) => x.chunk_id) : []);
|
||||
// setSelectedChunkIds((previousIds) => {
|
||||
// return checked ? [...previousIds, ...data.map((x) => x.chunk_id)] : [];
|
||||
// });
|
||||
},
|
||||
[data],
|
||||
);
|
||||
|
||||
const handleSingleCheckboxClick = useCallback(
|
||||
(chunkId: string, checked: boolean) => {
|
||||
setSelectedChunkIds((previousIds) => {
|
||||
const idx = previousIds.findIndex((x) => x === chunkId);
|
||||
const nextIds = [...previousIds];
|
||||
if (checked && idx === -1) {
|
||||
nextIds.push(chunkId);
|
||||
} else if (!checked && idx !== -1) {
|
||||
nextIds.splice(idx, 1);
|
||||
}
|
||||
return nextIds;
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
getChunkList();
|
||||
}, [documentId, available_int, pagination]);
|
||||
return () => {
|
||||
dispatch({
|
||||
type: 'chunkModel/resetFilter', // TODO: need to reset state uniformly
|
||||
});
|
||||
};
|
||||
}, [documentId]);
|
||||
|
||||
const debounceChange = debounce(getChunkList, 300);
|
||||
const debounceCallback = useCallback(
|
||||
@ -117,17 +134,20 @@ const Chunk = () => {
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
setSelectedChunkIds([]);
|
||||
const value = e.target.value;
|
||||
SetKeywords(value);
|
||||
debounceCallback(value);
|
||||
};
|
||||
const handleSelectChange = (value: number) => {
|
||||
setAvailableInt(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.chunkPage}>
|
||||
<ChunkToolBar></ChunkToolBar>
|
||||
<ChunkToolBar
|
||||
getChunkList={getChunkList}
|
||||
selectAllChunk={selectAllChunk}
|
||||
checked={selectedChunkIds.length === data.length}
|
||||
></ChunkToolBar>
|
||||
<div className={styles.filter}>
|
||||
<div>
|
||||
<Input
|
||||
@ -137,28 +157,6 @@ const Chunk = () => {
|
||||
allowClear
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Select
|
||||
showSearch
|
||||
placeholder="是否启用"
|
||||
optionFilterProp="children"
|
||||
value={available_int}
|
||||
onChange={handleSelectChange}
|
||||
style={{ width: 220 }}
|
||||
options={[
|
||||
{
|
||||
value: -1,
|
||||
label: '全部',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '启用',
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
label: '未启用',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
@ -171,86 +169,16 @@ const Chunk = () => {
|
||||
</div>
|
||||
<div className={styles.pageContent}>
|
||||
<Spin spinning={loading} className={styles.spin} size="large">
|
||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }}>
|
||||
{data.map((item: any) => {
|
||||
return (
|
||||
<Col
|
||||
className="gutter-row"
|
||||
<Space direction="vertical" size={'middle'}>
|
||||
{data.map((item) => (
|
||||
<ChunkCard
|
||||
item={item}
|
||||
key={item.chunk_id}
|
||||
xs={24}
|
||||
sm={12}
|
||||
md={12}
|
||||
lg={8}
|
||||
>
|
||||
<Card
|
||||
className={styles.card}
|
||||
onClick={() => {
|
||||
handleEditchunk(item.chunk_id);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{ width: '50px' }}
|
||||
src={`${api_host}/document/image/${item.img_id}`}
|
||||
alt=""
|
||||
/>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<span className={styles.context}>
|
||||
{item.content_ltks}
|
||||
</span>
|
||||
<span className={styles.delete}>
|
||||
<Switch
|
||||
size="small"
|
||||
defaultValue={item.available_int == '1'}
|
||||
onChange={(checked: boolean, e: any) => {
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
switchChunk(item.chunk_id, checked);
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<span className={styles.text}>
|
||||
<MinusSquareOutlined />
|
||||
{item.doc_num}文档
|
||||
</span>
|
||||
<span className={styles.text}>
|
||||
<MinusSquareOutlined />
|
||||
{item.chunk_num}个
|
||||
</span>
|
||||
<span className={styles.text}>
|
||||
<MinusSquareOutlined />
|
||||
{item.token_num}千字符
|
||||
</span>
|
||||
<span style={{ float: 'right' }}>
|
||||
<Popconfirm
|
||||
title="Delete the task"
|
||||
description="Are you sure to delete this task?"
|
||||
onConfirm={(e: any) => {
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
console.log(confirm);
|
||||
confirm(item.chunk_id);
|
||||
}}
|
||||
okText="Yes"
|
||||
cancelText="No"
|
||||
>
|
||||
<DeleteOutlined
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
}}
|
||||
/>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
checked={selectedChunkIds.some((x) => x === item.chunk_id)}
|
||||
handleCheckboxClick={handleSingleCheckboxClick}
|
||||
></ChunkCard>
|
||||
))}
|
||||
</Space>
|
||||
</Spin>
|
||||
</div>
|
||||
<div className={styles.pageFooter}>
|
||||
@ -259,10 +187,10 @@ const Chunk = () => {
|
||||
showLessItems
|
||||
showQuickJumper
|
||||
showSizeChanger
|
||||
onChange={onShowSizeChange}
|
||||
defaultPageSize={30}
|
||||
pageSizeOptions={[30, 60, 90]}
|
||||
defaultCurrent={pagination.page}
|
||||
onChange={onPaginationChange}
|
||||
defaultPageSize={10}
|
||||
pageSizeOptions={[10, 30, 60, 90]}
|
||||
defaultCurrent={pagination.current}
|
||||
total={total}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,13 +1,19 @@
|
||||
import { BaseState } from '@/interfaces/common';
|
||||
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||
import kbService from '@/services/kbService';
|
||||
import { message } from 'antd';
|
||||
// import { delay } from '@/utils/storeUtil';
|
||||
import { DvaModel } from 'umi';
|
||||
|
||||
export interface ChunkModelState {
|
||||
export interface ChunkModelState extends BaseState {
|
||||
data: any[];
|
||||
total: number;
|
||||
isShowCreateModal: boolean;
|
||||
chunk_id: string;
|
||||
doc_id: string;
|
||||
chunkInfo: any;
|
||||
documentInfo: Partial<IKnowledgeFile>;
|
||||
available?: number;
|
||||
}
|
||||
|
||||
const model: DvaModel<ChunkModelState> = {
|
||||
@ -19,6 +25,13 @@ const model: DvaModel<ChunkModelState> = {
|
||||
chunk_id: '',
|
||||
doc_id: '',
|
||||
chunkInfo: {},
|
||||
documentInfo: {},
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
searchString: '',
|
||||
available: undefined, // set to undefined to select all
|
||||
},
|
||||
reducers: {
|
||||
updateState(state, { payload }) {
|
||||
@ -27,33 +40,56 @@ const model: DvaModel<ChunkModelState> = {
|
||||
...payload,
|
||||
};
|
||||
},
|
||||
setAvailable(state, { payload }) {
|
||||
return { ...state, available: payload };
|
||||
},
|
||||
setSearchString(state, { payload }) {
|
||||
return { ...state, searchString: payload };
|
||||
},
|
||||
setPagination(state, { payload }) {
|
||||
return { ...state, pagination: { ...state.pagination, ...payload } };
|
||||
},
|
||||
resetFilter(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
searchString: '',
|
||||
available: undefined,
|
||||
};
|
||||
},
|
||||
},
|
||||
// subscriptions: {
|
||||
// setup({ dispatch, history }) {
|
||||
// history.listen(location => {
|
||||
// console.log(location)
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
effects: {
|
||||
*chunk_list({ payload = {} }, { call, put }) {
|
||||
const { data, response } = yield call(kbService.chunk_list, payload);
|
||||
|
||||
const { retcode, data: res, retmsg } = data;
|
||||
*chunk_list({ payload = {} }, { call, put, select }) {
|
||||
const { available, searchString, pagination }: ChunkModelState =
|
||||
yield select((state: any) => state.chunkModel);
|
||||
const { data } = yield call(kbService.chunk_list, {
|
||||
...payload,
|
||||
available_int: available,
|
||||
keywords: searchString,
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
});
|
||||
const { retcode, data: res } = data;
|
||||
if (retcode === 0) {
|
||||
console.log(res);
|
||||
yield put({
|
||||
type: 'updateState',
|
||||
payload: {
|
||||
data: res.chunks,
|
||||
total: res.total,
|
||||
documentInfo: res.doc,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*switch_chunk({ payload = {} }, { call, put }) {
|
||||
const { data, response } = yield call(kbService.switch_chunk, payload);
|
||||
const { retcode, data: res, retmsg } = data;
|
||||
const { data } = yield call(kbService.switch_chunk, payload);
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
message.success('Modified successfully !');
|
||||
}
|
||||
return retcode;
|
||||
},
|
||||
*rm_chunk({ payload = {} }, { call, put }) {
|
||||
|
@ -16,7 +16,6 @@ export interface KFModelState extends BaseState {
|
||||
data: IKnowledgeFile[];
|
||||
total: number;
|
||||
currentRecord: Nullable<IKnowledgeFile>;
|
||||
searchString: string;
|
||||
}
|
||||
|
||||
const model: DvaModel<KFModelState> = {
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Avatar, Card, Dropdown, MenuProps, Space } from 'antd';
|
||||
import { MouseEvent } from 'react';
|
||||
import { useDispatch, useNavigate } from 'umi';
|
||||
|
||||
import showDeleteConfirm from '@/components/deleting-confirm';
|
||||
@ -23,6 +22,15 @@ const KnowledgeCard = ({ item }: IProps) => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const removeKnowledge = () => {
|
||||
return dispatch({
|
||||
type: 'knowledgeModel/rmKb',
|
||||
payload: {
|
||||
kb_id: item.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
showDeleteConfirm({ onOk: removeKnowledge });
|
||||
};
|
||||
@ -47,16 +55,7 @@ const KnowledgeCard = ({ item }: IProps) => {
|
||||
}
|
||||
};
|
||||
|
||||
const removeKnowledge = () => {
|
||||
return dispatch({
|
||||
type: 'knowledgeModel/rmKb',
|
||||
payload: {
|
||||
kb_id: item.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleCardClick = (e: MouseEvent<HTMLElement>) => {
|
||||
const handleCardClick = () => {
|
||||
navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${item.id}`);
|
||||
};
|
||||
|
||||
|
@ -7,3 +7,8 @@ export const getOneNamespaceEffectsLoading = (
|
||||
(effectName) => effects[`${namespace}/${effectName}`],
|
||||
);
|
||||
};
|
||||
|
||||
export const delay = (ms: number) =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user