2025-11-04 15:32:55 +08:00
|
|
|
import React from 'react';
|
2025-11-07 13:30:59 +08:00
|
|
|
import { Box, Grid, Paper, Typography, IconButton, TextField, Tabs, Tab, Fab } from '@mui/material';
|
2025-11-04 15:32:55 +08:00
|
|
|
import { DataGrid, type GridColDef } from '@mui/x-data-grid';
|
2025-11-07 13:30:59 +08:00
|
|
|
import {
|
|
|
|
|
ArrowBack as ArrowBackIcon,
|
|
|
|
|
Search as SearchIcon,
|
|
|
|
|
} from '@mui/icons-material';
|
2025-11-04 15:32:55 +08:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2025-11-07 13:30:59 +08:00
|
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
|
|
|
import { useKnowledgeOverview, useKnowledgeDetail } from '@/hooks/knowledge-hooks';
|
2025-11-04 15:32:55 +08:00
|
|
|
import logger from '@/utils/logger';
|
2025-11-14 17:42:10 +08:00
|
|
|
import i18n from '@/locales';
|
2025-11-04 15:32:55 +08:00
|
|
|
import { enUS, zhCN } from '@mui/x-data-grid/locales';
|
2025-11-07 13:30:59 +08:00
|
|
|
import KnowledgeBreadcrumbs from './components/KnowledgeBreadcrumbs';
|
2025-11-14 17:42:10 +08:00
|
|
|
import { LanguageAbbreviation } from '@/constants/common';
|
2025-11-04 15:32:55 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
const PROCESSING_TYPES = {
|
|
|
|
|
knowledgeGraph: 'GraphRAG',
|
|
|
|
|
raptor: 'RAPTOR',
|
|
|
|
|
} as const
|
|
|
|
|
|
|
|
|
|
type ProcessingType = typeof PROCESSING_TYPES[keyof typeof PROCESSING_TYPES]
|
|
|
|
|
|
|
|
|
|
const ProcessingTypeMap = {
|
|
|
|
|
[PROCESSING_TYPES.knowledgeGraph]: 'Knowledge Graph',
|
|
|
|
|
[PROCESSING_TYPES.raptor]: 'RAPTOR',
|
|
|
|
|
} as const
|
|
|
|
|
|
|
|
|
|
function KnowledgeLogsPage() {
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const [paginationModel, setPaginationModel] = React.useState({ page: 0, pageSize: 50 });
|
|
|
|
|
|
|
|
|
|
// 根据当前语言获取DataGrid的localeText
|
|
|
|
|
const getDataGridLocale = () => {
|
|
|
|
|
const currentLanguage = i18n.language;
|
|
|
|
|
return currentLanguage === LanguageAbbreviation.Zh ? zhCN : enUS;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 路由参数与数据Hook
|
|
|
|
|
const { id: kbId = '' } = useParams();
|
|
|
|
|
const {
|
|
|
|
|
overview,
|
|
|
|
|
fileLogs,
|
|
|
|
|
datasetLogs,
|
|
|
|
|
loading,
|
|
|
|
|
currentPage,
|
|
|
|
|
pageSize,
|
|
|
|
|
setCurrentPage,
|
|
|
|
|
setPageSize,
|
|
|
|
|
activeTab,
|
|
|
|
|
keywords,
|
|
|
|
|
setActiveTab,
|
|
|
|
|
setKeywords,
|
|
|
|
|
} = useKnowledgeOverview(kbId);
|
|
|
|
|
|
2025-11-07 13:30:59 +08:00
|
|
|
// 获取知识库详情以用于面包屑显示名称
|
|
|
|
|
const { knowledge } = useKnowledgeDetail(kbId);
|
|
|
|
|
|
2025-11-04 15:32:55 +08:00
|
|
|
// 同步分页模型到Hook
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
|
setPaginationModel({ page: Math.max(currentPage - 1, 0), pageSize });
|
|
|
|
|
}, [currentPage, pageSize]);
|
|
|
|
|
|
|
|
|
|
const columnsFile: GridColDef[] = [
|
|
|
|
|
{ field: 'id', headerName: 'ID', width: 100 },
|
|
|
|
|
{
|
|
|
|
|
field: 'document_name', headerName: t('knowledgeDetails.fileName'), flex: 1, minWidth: 160, valueGetter: (params) => {
|
|
|
|
|
logger.info('params', params)
|
|
|
|
|
return ''
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{ field: 'source_from', headerName: t('knowledgeDetails.source'), flex: 1, minWidth: 140 },
|
|
|
|
|
{ field: 'pipeline_title', headerName: t('knowledgeDetails.ingestionPipeline'), flex: 1, minWidth: 180 },
|
|
|
|
|
{ field: 'create_date', headerName: t('knowledgeDetails.startDate') || 'Start Date', flex: 0.8, minWidth: 160, sortable: true },
|
|
|
|
|
{ field: 'task_type', headerName: t('knowledgeDetails.task') || 'Task', flex: 0.8, minWidth: 140 },
|
|
|
|
|
{ field: 'status', headerName: t('knowledgeDetails.status'), flex: 0.7, minWidth: 120 },
|
|
|
|
|
{ field: 'operations', headerName: t('knowledgeDetails.operations') || 'Operations', flex: 0.8, minWidth: 160, sortable: false, filterable: false, align: 'center', headerAlign: 'center' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const columnsDataset: GridColDef[] = [
|
|
|
|
|
{ field: 'id', headerName: 'ID', width: 100 },
|
|
|
|
|
{ field: 'create_date', headerName: t('knowledgeDetails.startDate') || 'Start Date', flex: 1, minWidth: 160, sortable: true },
|
|
|
|
|
{ field: 'task_type', headerName: 'Processing Type', flex: 1, minWidth: 180 },
|
|
|
|
|
{ field: 'status', headerName: t('knowledgeDetails.status'), flex: 0.8, minWidth: 120 },
|
|
|
|
|
{ field: 'operations', headerName: t('knowledgeDetails.operations') || 'Operations', flex: 0.8, minWidth: 160, sortable: false, filterable: false, align: 'center', headerAlign: 'center' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const columns = React.useMemo(() => (activeTab === 'fileLogs' ?
|
|
|
|
|
columnsFile :
|
|
|
|
|
columnsDataset),
|
|
|
|
|
[activeTab]);
|
|
|
|
|
const rows = React.useMemo(() => (activeTab === 'fileLogs' ?
|
|
|
|
|
(fileLogs?.logs || []) :
|
|
|
|
|
(datasetLogs?.logs || [])),
|
|
|
|
|
[activeTab, fileLogs, datasetLogs]);
|
|
|
|
|
const rowCount = React.useMemo(() => (activeTab === 'fileLogs' ?
|
|
|
|
|
(fileLogs?.total || 0) :
|
|
|
|
|
(datasetLogs?.total || 0)),
|
|
|
|
|
[activeTab, fileLogs, datasetLogs]);
|
|
|
|
|
|
2025-11-07 13:30:59 +08:00
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const handleNavigateBack = () => {
|
|
|
|
|
navigate(`/knowledge/${kbId}`);
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-04 15:32:55 +08:00
|
|
|
return (
|
|
|
|
|
<Box sx={{ p: 3 }}>
|
2025-11-07 13:30:59 +08:00
|
|
|
{/* 面包屑导航 */}
|
|
|
|
|
<KnowledgeBreadcrumbs
|
|
|
|
|
kbItems={[
|
|
|
|
|
{
|
|
|
|
|
label: t('knowledgeSettings.knowledgeBase'),
|
|
|
|
|
path: '/knowledge'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: knowledge?.name || t('knowledgeSettings.knowledgeBaseDetail'),
|
|
|
|
|
path: `/knowledge/${kbId}`
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: t('knowledgeSettings.fileLogs')
|
|
|
|
|
}
|
|
|
|
|
]}
|
|
|
|
|
/>
|
2025-11-04 15:32:55 +08:00
|
|
|
{/* 顶部统计卡片占位 */}
|
|
|
|
|
<Grid container spacing={2} sx={{ mb: 2 }}>
|
|
|
|
|
<Grid size={{ xs: 12, md: 4 }}>
|
|
|
|
|
<Paper sx={{ p: 2 }}>
|
|
|
|
|
<Typography variant="subtitle2">{t('datasetOverview.totalFiles')}</Typography>
|
|
|
|
|
<Typography variant="h4" sx={{ mt: 1 }}>{fileLogs?.total ?? 0}</Typography>
|
|
|
|
|
<Typography variant="caption" color="text.secondary">0% from last week</Typography>
|
|
|
|
|
</Paper>
|
|
|
|
|
</Grid>
|
|
|
|
|
<Grid size={{ xs: 12, md: 4 }}>
|
|
|
|
|
<Paper sx={{ p: 2 }}>
|
|
|
|
|
<Typography variant="subtitle2">{t('datasetOverview.downloading')}</Typography>
|
|
|
|
|
<Typography variant="h4" sx={{ mt: 1 }}>0</Typography>
|
|
|
|
|
<Typography variant="caption" color="text.secondary">{t('knowledgeDetails.success')} {overview?.finished ?? 0} · {t('knowledgeDetails.failed')} {overview?.failed ?? 0}</Typography>
|
|
|
|
|
</Paper>
|
|
|
|
|
</Grid>
|
|
|
|
|
<Grid size={{ xs: 12, md: 4 }}>
|
|
|
|
|
<Paper sx={{ p: 2 }}>
|
|
|
|
|
<Typography variant="subtitle2">{t('datasetOverview.processing')}</Typography>
|
|
|
|
|
<Typography variant="h4" sx={{ mt: 1 }}>{overview?.processing ?? 0}</Typography>
|
|
|
|
|
<Typography variant="caption" color="text.secondary">{t('knowledgeDetails.success')} {overview?.finished ?? 0} · {t('knowledgeDetails.failed')} {overview?.failed ?? 0}</Typography>
|
|
|
|
|
</Paper>
|
|
|
|
|
</Grid>
|
|
|
|
|
</Grid>
|
|
|
|
|
|
|
|
|
|
{/* Tabs & Filter/Search */}
|
|
|
|
|
<Box display="flex" alignItems="center" gap={2} sx={{ mb: 2 }}>
|
|
|
|
|
<Tabs value={activeTab} onChange={(_, v) => setActiveTab(v)}>
|
2025-11-07 13:30:59 +08:00
|
|
|
<Tab value="fileLogs" label={t('knowledgeDetails.file')} />
|
|
|
|
|
<Tab value="datasetLogs" label={t('knowledgeDetails.dataset')} />
|
2025-11-04 15:32:55 +08:00
|
|
|
</Tabs>
|
|
|
|
|
{/* <IconButton aria-label="filter"><FilterListIcon /></IconButton> */}
|
|
|
|
|
<Box display="flex" alignItems="center" gap={1} sx={{ ml: 'auto' }}>
|
|
|
|
|
<SearchIcon color="action" />
|
|
|
|
|
<TextField size="small" placeholder={t('common.search')} value={keywords} onChange={(e) => setKeywords(e.target.value)} />
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
|
|
{/* DataGrid 表格占位 */}
|
|
|
|
|
<Paper variant="outlined" sx={{ height: 420 }}>
|
|
|
|
|
<DataGrid
|
|
|
|
|
columns={columns}
|
|
|
|
|
rows={rows}
|
|
|
|
|
getRowId={(row) => row.id}
|
|
|
|
|
density="comfortable"
|
|
|
|
|
pageSizeOptions={[20, 50, 100]}
|
|
|
|
|
paginationMode="server"
|
|
|
|
|
rowCount={rowCount}
|
|
|
|
|
paginationModel={paginationModel}
|
|
|
|
|
onPaginationModelChange={(model) => {
|
|
|
|
|
setPaginationModel(model);
|
|
|
|
|
setCurrentPage(model.page + 1);
|
|
|
|
|
setPageSize(model.pageSize);
|
|
|
|
|
}}
|
|
|
|
|
loading={loading}
|
|
|
|
|
disableColumnMenu
|
|
|
|
|
localeText={getDataGridLocale().components.MuiDataGrid.defaultProps.localeText}
|
|
|
|
|
/>
|
|
|
|
|
</Paper>
|
2025-11-07 13:30:59 +08:00
|
|
|
|
|
|
|
|
{/* 返回按钮 */}
|
|
|
|
|
<Fab
|
|
|
|
|
color="primary"
|
|
|
|
|
aria-label={t('knowledgeSettings.backToKnowledgeDetail')}
|
|
|
|
|
onClick={handleNavigateBack}
|
|
|
|
|
sx={{
|
|
|
|
|
position: 'fixed',
|
|
|
|
|
bottom: 128,
|
|
|
|
|
right: 64,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<ArrowBackIcon />
|
|
|
|
|
</Fab>
|
2025-11-04 15:32:55 +08:00
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default KnowledgeLogsPage;
|