diff --git a/package.json b/package.json index 0a606f7..32145ba 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "js-base64": "^3.7.8", "jsencrypt": "^3.5.4", "lodash": "^4.17.21", + "loglevel": "^1.9.2", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.64.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d399311..21a6cf2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 + loglevel: + specifier: ^1.9.2 + version: 1.9.2 react: specifier: ^18.3.1 version: 18.3.1 @@ -1434,6 +1437,10 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3164,6 +3171,8 @@ snapshots: lodash@4.17.21: {} + loglevel@1.9.2: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 diff --git a/src/hooks/document-hooks.ts b/src/hooks/document-hooks.ts index a8cd0e5..94bdf02 100644 --- a/src/hooks/document-hooks.ts +++ b/src/hooks/document-hooks.ts @@ -17,8 +17,8 @@ export interface UseDocumentListState { // 文档列表Hook返回值接口 export interface UseDocumentListReturn extends UseDocumentListState { - fetchDocuments: (params?: IFetchKnowledgeListRequestParams) => Promise; - fetchDocumentsFilter: () => Promise; + fetchDocuments: (params?: IFetchKnowledgeListRequestParams, body?: IFetchDocumentListRequestBody) => Promise; + fetchDocumentsFilter: () => Promise<{ filter?: IDocumentInfoFilter, total?: number } | undefined>; setKeywords: (keywords: string) => void; setCurrentPage: (page: number) => void; setPageSize: (size: number) => void; @@ -44,7 +44,9 @@ export const useDocumentList = ( /** * 获取文档列表 */ - const fetchDocuments = useCallback(async (params?: IFetchKnowledgeListRequestParams) => { + const fetchDocuments = useCallback(async ( + params?: IFetchKnowledgeListRequestParams, + body?: IFetchDocumentListRequestBody) => { if (!kbId) return; try { @@ -61,6 +63,13 @@ export const useDocumentList = ( // 构建请求体 const requestBody: IFetchDocumentListRequestBody = {}; + if (body?.suffix) { + requestBody.suffix = body.suffix; + } + if (body?.run_status) { + requestBody.run_status = body.run_status; + } + // 构建查询参数 const requestParams: IFetchKnowledgeListRequestParams = { kb_id: kbId, @@ -108,7 +117,7 @@ export const useDocumentList = ( kb_id: kbId, }); if (response.data.code === 0) { - const data: IDocumentInfoFilter = response.data.data; + const data: { filter?: IDocumentInfoFilter, total?: number } = response.data.data; return data; } else { throw new Error(response.data.message || '获取文档过滤器失败'); @@ -189,7 +198,7 @@ export const useDocumentOperations = () => { const formData = new FormData(); formData.append('kb_id', kbId); - + files.forEach((file) => { formData.append('file', file); }); @@ -221,7 +230,7 @@ export const useDocumentOperations = () => { const formData = new FormData(); formData.append('kb_id', kbId); - + files.forEach((file) => { formData.append('file', file); }); diff --git a/src/pages/knowledge/components/DocumentListComponent.tsx b/src/pages/knowledge/components/DocumentListComponent.tsx index d81be76..38e9d8b 100644 --- a/src/pages/knowledge/components/DocumentListComponent.tsx +++ b/src/pages/knowledge/components/DocumentListComponent.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, @@ -54,6 +54,7 @@ import type { IDocumentInfoFilter } from '@/interfaces/database/document'; import { RUNNING_STATUS_KEYS, type RunningStatus } from '@/constants/knowledge'; import { LanguageAbbreviation } from '@/locales'; import dayjs from 'dayjs'; +import logger from '@/utils/logger'; interface DocumentListComponentProps { @@ -75,7 +76,11 @@ interface DocumentListComponentProps { onPageSizeChange: (pageSize: number) => void; // 筛选器相关props documentFilter?: IDocumentInfoFilter; - onFetchFilter?: () => Promise; + // filter 变化时触发 + onSelectedFilterChange?: (filter: { + run_status: Array, + suffix: Array, + }) => void; // 新增操作功能props onRename: (fileId: string, newName: string) => void; onChangeStatus: (fileIds: string[], status: string) => void; @@ -183,7 +188,7 @@ const DocumentListComponent: React.FC = ({ onPageChange, onPageSizeChange, documentFilter, - onFetchFilter, + onSelectedFilterChange, onRename, onChangeStatus, onCancelRun, @@ -199,7 +204,6 @@ const DocumentListComponent: React.FC = ({ const [selectedFileId, setSelectedFileId] = useState(''); const [selectedFile, setSelectedFile] = useState(undefined); - const [filter, setFilter] = useState(documentFilter); const [selectedRunStatus, setSelectedRunStatus] = useState([]); const [selectedSuffix, setSelectedSuffix] = useState([]); const [renameDialogOpen, setRenameDialogOpen] = useState(false); @@ -213,21 +217,16 @@ const DocumentListComponent: React.FC = ({ return currentLanguage === LanguageAbbreviation.Zh ? zhCN : enUS; }; - // 获取筛选器数据 - useEffect(() => { - const fetchFilter = async () => { - try { - const filterData = await onFetchFilter?.(); - setFilter(filterData); - } catch (error) { - console.error('Failed to fetch document filter:', error); - } + const handleFilterSubmit = useCallback(() => { + const filter = { + run_status: selectedRunStatus, + suffix: selectedSuffix, }; - if (!filter) { - fetchFilter(); + if (onSelectedFilterChange) { + onSelectedFilterChange(filter); } - }, [onFetchFilter, filter]); + }, [selectedRunStatus, selectedSuffix]) const handleMenuClick = (event: React.MouseEvent, file: IKnowledgeFile) => { event.stopPropagation(); @@ -334,10 +333,10 @@ const DocumentListComponent: React.FC = ({ minWidth: 200, cellClassName: 'grid-center-cell', renderCell: (params) => ( - = ({ return ( {/* 筛选器 */} - {filter && ( + {documentFilter && ( 筛选器 @@ -490,7 +489,7 @@ const DocumentListComponent: React.FC = ({ )} > - {Object.entries(filter.run_status).map(([status, count]) => ( + {Object.entries(documentFilter.run_status).map(([status, count]) => ( {getRunStatusLabel(status)} ({count}) @@ -514,20 +513,33 @@ const DocumentListComponent: React.FC = ({ )} > - {Object.entries(filter.suffix).map(([suffix, count]) => ( + {Object.entries(documentFilter.suffix).map(([suffix, count]) => ( {suffix.toUpperCase()} ({count}) ))} - - + {/* submit filter */} + )} diff --git a/src/pages/knowledge/detail.tsx b/src/pages/knowledge/detail.tsx index ea44531..a6b2314 100644 --- a/src/pages/knowledge/detail.tsx +++ b/src/pages/knowledge/detail.tsx @@ -33,11 +33,12 @@ import KnowledgeGraphView from './components/KnowledgeGraphView'; import { useDocumentList, useDocumentOperations } from '@/hooks/document-hooks'; import { RUNNING_STATUS_KEYS } from '@/constants/knowledge'; import { useKnowledgeDetail } from '@/hooks/knowledge-hooks'; +import logger from '@/utils/logger'; function KnowledgeBaseDetail() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); - + // 状态管理 const [error, setError] = useState(null); const [searchKeyword, setSearchKeyword] = useState(''); @@ -47,17 +48,27 @@ function KnowledgeBaseDetail() { }); const [uploadDialogOpen, setUploadDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); - + const [processDetailsDialogOpen, setProcessDetailsDialogOpen] = useState(false); const [selectedFileDetails, setSelectedFileDetails] = useState(null); - + // 标签页状态 const [currentTab, setCurrentTab] = useState(0); - + // 轮询相关状态 const pollingIntervalRef = useRef(null); const [isPolling, setIsPolling] = useState(false); + // documents filter + const [documentsFilter, setDocumentsFilter] = useState(undefined); + + const { + knowledge: knowledgeBase, + refresh: fetchKnowledgeDetail, + loading, showKnowledgeGraph, + knowledgeGraph + } = useKnowledgeDetail(id || ''); + // 使用新的document hooks const { documents: files, @@ -70,6 +81,8 @@ function KnowledgeBaseDetail() { setKeywords, setCurrentPage, setPageSize, + fetchDocuments, + fetchDocumentsFilter, } = useDocumentList(id || ''); const { @@ -79,17 +92,19 @@ function KnowledgeBaseDetail() { renameDocument, changeDocumentStatus, cancelRunDocuments, - loading: operationLoading, error: operationError, } = useDocumentOperations(); - const { knowledge: knowledgeBase, refresh: fetchKnowledgeDetail, loading, showKnowledgeGraph, knowledgeGraph } = useKnowledgeDetail(id || ''); - console.log('showKnowledgeGraph:', showKnowledgeGraph, knowledgeGraph); + const refreshDetailData = async () => { + await fetchKnowledgeDetail(); + await refreshFiles(); + }; + // 删除文件 const handleDeleteFiles = async () => { - try { + try { await deleteDocuments(Array.from(rowSelectionModel.ids) as string[]); setDeleteDialogOpen(false); setRowSelectionModel({ @@ -176,7 +191,7 @@ function KnowledgeBaseDetail() { if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current); } - + setIsPolling(true); pollingIntervalRef.current = setInterval(() => { refreshFiles(); @@ -215,7 +230,20 @@ function KnowledgeBaseDetail() { // 初始化数据 useEffect(() => { - fetchKnowledgeDetail(); + fetchDocumentsFilter().then(filterData => { + if (filterData?.filter) { + // setKeywords(filter.keywords || ''); + logger.debug('filter:', filterData.filter); + const filter = filterData.filter || {}; + const showFilter = Object.keys(filter.run_status || {}).length > 0 || Object.keys(filter.suffix || {}).length > 0; + if (showFilter) { + setDocumentsFilter({ + run_status: filterData.filter?.run_status || {}, + suffix: filterData.filter?.suffix || {}, + }); + } + } + }); }, [id]); // 搜索文件 @@ -230,7 +258,7 @@ function KnowledgeBaseDetail() { // 合并错误状态 const combinedError = error || filesError || operationError; - if (loading) { + if (loading || !knowledgeBase) { return ( @@ -247,22 +275,10 @@ function KnowledgeBaseDetail() { ); } - if (!knowledgeBase) { - return ( - - 知识库不存在 - - ); - } - - function fetchDocumentsFilter(): Promise { - throw new Error('Function not implemented.'); - } - return ( {/* 面包屑导航 */} - - setCurrentTab(newValue)} sx={{ borderBottom: 1, borderColor: 'divider' }} > - + {/* Document List 标签页内容 */} {currentTab === 0 && ( @@ -300,7 +316,6 @@ function KnowledgeBaseDetail() { onSearchChange={setSearchKeyword} onReparse={(fileIds) => handleReparse(fileIds)} onDelete={(fileIds) => { - console.log('删除文件:', fileIds); setRowSelectionModel({ type: 'include', ids: new Set(fileIds) @@ -314,12 +329,15 @@ function KnowledgeBaseDetail() { }} rowSelectionModel={rowSelectionModel} onRowSelectionModelChange={(newModel) => { - console.log('新的选择模型:', newModel); setRowSelectionModel(newModel); }} total={total} page={currentPage} pageSize={pageSize} + documentFilter={documentsFilter} + onSelectedFilterChange={(filterBody) => { + fetchDocuments({}, filterBody); + }} onPageChange={setCurrentPage} onPageSizeChange={setPageSize} onRename={handleRename} @@ -330,7 +348,7 @@ function KnowledgeBaseDetail() { /> )} - + {/* Graph 标签页内容 */} {currentTab === 1 && ( @@ -367,6 +385,10 @@ function KnowledgeBaseDetail() { total={total} page={currentPage} pageSize={pageSize} + documentFilter={documentsFilter} + onSelectedFilterChange={(filterBody) => { + fetchDocuments({}, filterBody); + }} onPageChange={setCurrentPage} onPageSizeChange={setPageSize} onRename={handleRename} @@ -477,14 +499,14 @@ function KnowledgeBaseDetail() { 进度 - - diff --git a/src/services/knowledge_service.ts b/src/services/knowledge_service.ts index b69aafe..fe4be0f 100644 --- a/src/services/knowledge_service.ts +++ b/src/services/knowledge_service.ts @@ -68,7 +68,7 @@ const knowledgeService = { params?: IFetchKnowledgeListRequestParams, body?: IFetchDocumentListRequestBody ) => { - return request.post(api.get_document_list, { data: body || {} }, { params }); + return request.post(api.get_document_list, body || {}, { params }); }, // 创建文档 diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 0000000..cf57ad8 --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,17 @@ +import log from 'loglevel'; + +// 根据环境设置日志级别 +if (import.meta.env.DEV) { + log.setLevel('debug'); +} else { + log.setLevel('warn'); +} + +const logger = { + debug: log.debug.bind(log), + info: log.info.bind(log), + warn: log.warn.bind(log), + error: log.error.bind(log), +} + +export default logger;