feat: save the selected parser to the backend on the upload file page and upload document (#54)
* feat: add pagination to document table * feat: fetch document list by page * feat: poll the document list * feat: upload document * feat: save the selected parser to the backend on the upload file page
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import { KnowledgeRouteKey } from '@/constants/knowledge';
|
||||
import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
|
||||
import {
|
||||
useDeleteDocumentById,
|
||||
useKnowledgeBaseId,
|
||||
} from '@/hooks/knowledgeHook';
|
||||
import { Pagination } from '@/interfaces/common';
|
||||
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
|
||||
import { PlusOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
@@ -15,8 +19,8 @@ import {
|
||||
Tag,
|
||||
} from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { PaginationProps } from 'antd/lib';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useDispatch, useNavigate, useSelector } from 'umi';
|
||||
import CreateEPModal from './createEFileModal';
|
||||
import styles from './index.less';
|
||||
@@ -30,50 +34,90 @@ const KnowledgeFile = () => {
|
||||
const dispatch = useDispatch();
|
||||
const kFModel = useSelector((state: any) => state.kFModel);
|
||||
const effects = useSelector((state: any) => state.loading.effects);
|
||||
const { data } = kFModel;
|
||||
const { data, total } = kFModel;
|
||||
const knowledgeBaseId = useKnowledgeBaseId();
|
||||
const { removeDocument } = useDeleteDocumentById();
|
||||
|
||||
const loading = getOneNamespaceEffectsLoading('kFModel', effects, [
|
||||
'getKfList',
|
||||
'updateDocumentStatus',
|
||||
]);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [doc_id, setDocId] = useState('0');
|
||||
const [parser_id, setParserId] = useState('0');
|
||||
let navigate = useNavigate();
|
||||
|
||||
const getKfList = (keywords?: string) => {
|
||||
const getKfList = () => {
|
||||
const payload = {
|
||||
kb_id: knowledgeBaseId,
|
||||
keywords,
|
||||
};
|
||||
if (!keywords) {
|
||||
delete payload.keywords;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'kFModel/getKfList',
|
||||
payload,
|
||||
});
|
||||
};
|
||||
|
||||
const throttledGetDocumentList = () => {
|
||||
dispatch({
|
||||
type: 'kFModel/throttledGetDocumentList',
|
||||
payload: knowledgeBaseId,
|
||||
});
|
||||
};
|
||||
|
||||
const setPagination = (pageNumber = 1, pageSize?: number) => {
|
||||
const pagination: Pagination = {
|
||||
current: pageNumber,
|
||||
} as Pagination;
|
||||
if (pageSize) {
|
||||
pagination.pageSize = pageSize;
|
||||
}
|
||||
dispatch({
|
||||
type: 'kFModel/setPagination',
|
||||
payload: pagination,
|
||||
});
|
||||
};
|
||||
|
||||
const onPageChange: PaginationProps['onChange'] = (pageNumber, pageSize) => {
|
||||
setPagination(pageNumber, pageSize);
|
||||
getKfList();
|
||||
};
|
||||
|
||||
const pagination: PaginationProps = useMemo(() => {
|
||||
return {
|
||||
showQuickJumper: true,
|
||||
total,
|
||||
showSizeChanger: true,
|
||||
current: kFModel.pagination.currentPage,
|
||||
pageSize: kFModel.pagination.pageSize,
|
||||
pageSizeOptions: [1, 2, 10, 20, 50, 100],
|
||||
onChange: onPageChange,
|
||||
};
|
||||
}, [total, kFModel.pagination]);
|
||||
|
||||
useEffect(() => {
|
||||
if (knowledgeBaseId) {
|
||||
getKfList();
|
||||
dispatch({
|
||||
type: 'kFModel/pollGetDocumentList-start',
|
||||
payload: knowledgeBaseId,
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
dispatch({
|
||||
type: 'kFModel/pollGetDocumentList-stop',
|
||||
});
|
||||
};
|
||||
}, [knowledgeBaseId]);
|
||||
|
||||
const debounceChange = debounce(getKfList, 300);
|
||||
const debounceCallback = useCallback(
|
||||
(value: string) => debounceChange(value),
|
||||
[],
|
||||
);
|
||||
const handleInputChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
const value = e.target.value;
|
||||
setInputValue(value);
|
||||
debounceCallback(e.target.value);
|
||||
dispatch({ type: 'kFModel/setSearchString', payload: value });
|
||||
setPagination();
|
||||
throttledGetDocumentList();
|
||||
};
|
||||
|
||||
const onChangeStatus = (e: boolean, doc_id: string) => {
|
||||
dispatch({
|
||||
type: 'kFModel/updateDocumentStatus',
|
||||
@@ -85,13 +129,7 @@ const KnowledgeFile = () => {
|
||||
});
|
||||
};
|
||||
const onRmDocument = () => {
|
||||
dispatch({
|
||||
type: 'kFModel/document_rm',
|
||||
payload: {
|
||||
doc_id,
|
||||
kb_id: knowledgeBaseId,
|
||||
},
|
||||
});
|
||||
removeDocument(doc_id);
|
||||
};
|
||||
const showCEFModal = () => {
|
||||
dispatch({
|
||||
@@ -226,7 +264,6 @@ const KnowledgeFile = () => {
|
||||
key: 'action',
|
||||
render: (_, record) => (
|
||||
<ParsingActionCell
|
||||
documentId={doc_id}
|
||||
knowledgeBaseId={knowledgeBaseId}
|
||||
setDocumentAndParserId={setDocumentAndParserId(record)}
|
||||
record={record}
|
||||
@@ -248,12 +285,12 @@ const KnowledgeFile = () => {
|
||||
<div className={styles.filter}>
|
||||
<Space>
|
||||
<h3>Total</h3>
|
||||
<Tag color="purple">100 files</Tag>
|
||||
<Tag color="purple">{total} files</Tag>
|
||||
</Space>
|
||||
<Space>
|
||||
<Input
|
||||
placeholder="Seach your files"
|
||||
value={inputValue}
|
||||
value={kFModel.searchString}
|
||||
style={{ width: 220 }}
|
||||
allowClear
|
||||
onChange={handleInputChange}
|
||||
@@ -272,7 +309,7 @@ const KnowledgeFile = () => {
|
||||
columns={finalColumns}
|
||||
dataSource={data}
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
pagination={pagination}
|
||||
scroll={{ scrollToFirstRowOnChange: true, x: true, y: 'fill' }}
|
||||
/>
|
||||
<CreateEPModal getKfList={getKfList} kb_id={knowledgeBaseId} />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { BaseState } from '@/interfaces/common';
|
||||
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||
import kbService from '@/services/kbService';
|
||||
import { message } from 'antd';
|
||||
@@ -6,14 +7,16 @@ import pick from 'lodash/pick';
|
||||
import { Nullable } from 'typings';
|
||||
import { DvaModel } from 'umi';
|
||||
|
||||
export interface KFModelState {
|
||||
export interface KFModelState extends BaseState {
|
||||
isShowCEFwModal: boolean;
|
||||
isShowTntModal: boolean;
|
||||
isShowSegmentSetModal: boolean;
|
||||
isShowRenameModal: boolean;
|
||||
tenantIfo: any;
|
||||
data: IKnowledgeFile[];
|
||||
total: number;
|
||||
currentRecord: Nullable<IKnowledgeFile>;
|
||||
searchString: string;
|
||||
}
|
||||
|
||||
const model: DvaModel<KFModelState> = {
|
||||
@@ -25,7 +28,13 @@ const model: DvaModel<KFModelState> = {
|
||||
isShowRenameModal: false,
|
||||
tenantIfo: {},
|
||||
data: [],
|
||||
total: 0,
|
||||
currentRecord: null,
|
||||
searchString: '',
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
updateState(state, { payload }) {
|
||||
@@ -40,6 +49,12 @@ const model: DvaModel<KFModelState> = {
|
||||
setCurrentRecord(state, { payload }) {
|
||||
return { ...state, currentRecord: payload };
|
||||
},
|
||||
setSearchString(state, { payload }) {
|
||||
return { ...state, searchString: payload };
|
||||
},
|
||||
setPagination(state, { payload }) {
|
||||
return { ...state, pagination: { ...state.pagination, ...payload } };
|
||||
},
|
||||
},
|
||||
subscriptions: {
|
||||
setup({ dispatch, history }) {
|
||||
@@ -69,22 +84,41 @@ const model: DvaModel<KFModelState> = {
|
||||
callback && callback(res);
|
||||
}
|
||||
},
|
||||
*getKfList({ payload = {} }, { call, put }) {
|
||||
const { data, response } = yield call(
|
||||
kbService.get_document_list,
|
||||
payload,
|
||||
);
|
||||
const { retcode, data: res, retmsg } = data;
|
||||
*getKfList({ payload = {} }, { call, put, select }) {
|
||||
const state: KFModelState = yield select((state: any) => state.kFModel);
|
||||
const requestBody = {
|
||||
...payload,
|
||||
page: state.pagination.current,
|
||||
page_size: state.pagination.pageSize,
|
||||
};
|
||||
if (state.searchString) {
|
||||
requestBody['keywords'] = state.searchString;
|
||||
}
|
||||
const { data } = yield call(kbService.get_document_list, requestBody);
|
||||
const { retcode, data: res } = data;
|
||||
|
||||
if (retcode === 0) {
|
||||
yield put({
|
||||
type: 'updateState',
|
||||
payload: {
|
||||
data: res,
|
||||
data: res.docs,
|
||||
total: res.total,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
throttledGetDocumentList: [
|
||||
function* ({ payload }, { call, put }) {
|
||||
yield put({ type: 'getKfList', payload: { kb_id: payload } });
|
||||
},
|
||||
{ type: 'throttle', ms: 1000 }, // TODO: Provide type support for this effect
|
||||
],
|
||||
pollGetDocumentList: [
|
||||
function* ({ payload }, { call, put }) {
|
||||
yield put({ type: 'getKfList', payload: { kb_id: payload } });
|
||||
},
|
||||
{ type: 'poll', delay: 5000 }, // TODO: Provide type support for this effect
|
||||
],
|
||||
*updateDocumentStatus({ payload = {} }, { call, put }) {
|
||||
const { data, response } = yield call(
|
||||
kbService.document_change_status,
|
||||
@@ -106,11 +140,12 @@ const model: DvaModel<KFModelState> = {
|
||||
const { retcode, data: res, retmsg } = data;
|
||||
if (retcode === 0) {
|
||||
message.success('删除成功!');
|
||||
put({
|
||||
yield put({
|
||||
type: 'getKfList',
|
||||
payload: { kb_id: payload.kb_id },
|
||||
});
|
||||
}
|
||||
return retcode;
|
||||
},
|
||||
*document_rename({ payload = {} }, { call, put }) {
|
||||
const { data } = yield call(
|
||||
|
||||
@@ -5,19 +5,18 @@ import { Button, Dropdown, MenuProps, Space, Tooltip } from 'antd';
|
||||
import { useDispatch } from 'umi';
|
||||
|
||||
interface IProps {
|
||||
documentId: string;
|
||||
knowledgeBaseId: string;
|
||||
record: IKnowledgeFile;
|
||||
setDocumentAndParserId: () => void;
|
||||
}
|
||||
|
||||
const ParsingActionCell = ({
|
||||
documentId,
|
||||
knowledgeBaseId,
|
||||
record,
|
||||
setDocumentAndParserId,
|
||||
}: IProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const documentId = record.id;
|
||||
|
||||
const removeDocument = () => {
|
||||
dispatch({
|
||||
|
||||
@@ -18,8 +18,7 @@ const SegmentSetModal: React.FC<kFProps> = ({
|
||||
const kFModel = useSelector((state: any) => state.kFModel);
|
||||
const settingModel = useSelector((state: any) => state.settingModel);
|
||||
const [selectedTag, setSelectedTag] = useState('');
|
||||
const { tenantIfo = {} } = settingModel;
|
||||
const { parser_ids = '' } = tenantIfo;
|
||||
const parser_ids = settingModel?.tenantIfo?.parser_ids ?? '';
|
||||
const { isShowSegmentSetModal } = kFModel;
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
|
||||
import uploadService from '@/services/uploadService';
|
||||
import type { UploadProps } from 'antd';
|
||||
import { Button, Upload } from 'antd';
|
||||
import React from 'react';
|
||||
import { Link } from 'umi';
|
||||
interface PropsType {
|
||||
kb_id: string;
|
||||
getKfList: () => void;
|
||||
@@ -12,6 +13,8 @@ type UploadRequestOption = Parameters<
|
||||
>[0];
|
||||
|
||||
const FileUpload: React.FC<PropsType> = ({ kb_id, getKfList }) => {
|
||||
const knowledgeBaseId = useKnowledgeBaseId();
|
||||
|
||||
const createRequest: (props: UploadRequestOption) => void = async function ({
|
||||
file,
|
||||
onSuccess,
|
||||
@@ -30,9 +33,9 @@ const FileUpload: React.FC<PropsType> = ({ kb_id, getKfList }) => {
|
||||
showUploadList: false,
|
||||
};
|
||||
return (
|
||||
<Upload {...uploadProps}>
|
||||
<Button type="link">导入文件</Button>
|
||||
</Upload>
|
||||
// <Upload {...uploadProps}>
|
||||
<Link to={`/knowledge/dataset/upload?id=${knowledgeBaseId}`}>导入文件</Link>
|
||||
// </Upload>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user