import React, { useCallback, useState, useRef } from 'react'; import { Box, Card, IconButton, Flex, Button, Input, Grid } from '@chakra-ui/react'; import type { KbDataItemType } from '@/types/plugin'; import { usePagination } from '@/hooks/usePagination'; import { getKbDataList, getExportDataList, delOneKbDataByDataId, getTrainingData } from '@/api/plugins/kb'; import { DeleteIcon, RepeatIcon } from '@chakra-ui/icons'; import { fileDownload } from '@/utils/file'; import { useMutation, useQuery } from '@tanstack/react-query'; import { useToast } from '@/hooks/useToast'; import Papa from 'papaparse'; import InputModal, { FormData as InputDataType } from './InputDataModal'; import { debounce } from 'lodash'; import { getErrText } from '@/utils/tools'; import { useConfirm } from '@/hooks/useConfirm'; import { useTranslation } from 'react-i18next'; import MyIcon from '@/components/Icon'; import MyTooltip from '@/components/MyTooltip'; const DataCard = ({ kbId }: { kbId: string }) => { const BoxRef = useRef(null); const lastSearch = useRef(''); const { t } = useTranslation(); const [searchText, setSearchText] = useState(''); const { toast } = useToast(); const [isDeleting, setIsDeleting] = useState(false); const { openConfirm, ConfirmModal } = useConfirm({ content: t('dataset.Confirm to delete the data') }); const { data: kbDataList, isLoading, Pagination, total, getData, pageNum, pageSize } = usePagination({ api: getKbDataList, pageSize: 24, params: { kbId, searchText }, onChange() { if (BoxRef.current) { BoxRef.current.scrollTop = 0; } } }); const [editInputData, setEditInputData] = useState(); const { data: { qaListLen = 0, vectorListLen = 0 } = {}, refetch: refetchTrainingData } = useQuery(['getModelSplitDataList', kbId], () => getTrainingData({ kbId, init: false }), { onError(err) { console.log(err); } }); const refetchData = useCallback( (num = pageNum) => { getData(num); refetchTrainingData(); return null; }, [getData, pageNum, refetchTrainingData] ); // get al data and export csv const { mutate: onclickExport, isLoading: isLoadingExport = false } = useMutation({ mutationFn: () => getExportDataList(kbId), onSuccess(res) { const text = Papa.unparse({ fields: ['question', 'answer', 'source'], data: res }); fileDownload({ text, type: 'text/csv', filename: 'data.csv' }); toast({ title: '导出成功,下次导出需要半小时后', status: 'success' }); }, onError(err: any) { toast({ title: getErrText(err, '导出异常'), status: 'error' }); console.log(err); } }); const getFirstData = useCallback( debounce(() => { getData(1); lastSearch.current = searchText; }, 300), [] ); // interval get data useQuery(['refetchData'], () => refetchData(1), { refetchInterval: 5000, enabled: qaListLen > 0 || vectorListLen > 0 }); return ( 知识库数据: {total}组 } aria-label={'refresh'} variant={'base'} isLoading={isLoading} mr={[2, 4]} size={'sm'} onClick={() => { getData(pageNum); getTrainingData({ kbId, init: true }); }} /> {qaListLen > 0 || vectorListLen > 0 ? ( {qaListLen > 0 ? `${qaListLen}条数据正在拆分,` : ''} {vectorListLen > 0 ? `${vectorListLen}条数据正在生成索引,` : ''} 请耐心等待... ) : ( 所有数据已就绪~ )} { setSearchText(e.target.value); getFirstData(); }} onBlur={() => { if (searchText === lastSearch.current) return; getFirstData(); }} onKeyDown={(e) => { if (searchText === lastSearch.current) return; if (e.key === 'Enter') { getFirstData(); } }} /> {kbDataList.map((item) => ( setEditInputData({ dataId: item.id, q: item.q, a: item.a }) } > {item.q} {item.a} {item.source?.trim()} } variant={'base'} colorScheme={'gray'} aria-label={'delete'} size={'xs'} borderRadius={'md'} _hover={{ color: 'red.600' }} isLoading={isDeleting} onClick={(e) => { e.stopPropagation(); openConfirm(async () => { try { setIsDeleting(true); await delOneKbDataByDataId(item.id); refetchData(pageNum); } catch (error) { toast({ title: getErrText(error), status: 'error' }); } setIsDeleting(false); })(); }} /> ))} {total > pageSize && ( )} {total === 0 && ( 知识库空空如也 )} {editInputData !== undefined && ( setEditInputData(undefined)} onSuccess={() => refetchData()} /> )} ); }; export default React.memo(DataCard);