162 lines
6.7 KiB
TypeScript
162 lines
6.7 KiB
TypeScript
|
|
import React from 'react';
|
||
|
|
import { Box, Grid, Paper, Typography, IconButton, TextField, Tabs, Tab } from '@mui/material';
|
||
|
|
import { DataGrid, type GridColDef } from '@mui/x-data-grid';
|
||
|
|
import FilterListIcon from '@mui/icons-material/FilterList';
|
||
|
|
import SearchIcon from '@mui/icons-material/Search';
|
||
|
|
import { useTranslation } from 'react-i18next';
|
||
|
|
import { useParams } from 'react-router-dom';
|
||
|
|
import { useKnowledgeOverview } from '@/hooks/knowledge-hooks';
|
||
|
|
import type { IDocumentLog, IFileLogItem } from '@/interfaces/database/knowledge';
|
||
|
|
import logger from '@/utils/logger';
|
||
|
|
import i18n, { LanguageAbbreviation } from '@/locales';
|
||
|
|
import { enUS, zhCN } from '@mui/x-data-grid/locales';
|
||
|
|
|
||
|
|
|
||
|
|
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);
|
||
|
|
|
||
|
|
// 同步分页模型到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]);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Box sx={{ p: 3 }}>
|
||
|
|
{/* 顶部统计卡片占位 */}
|
||
|
|
<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)}>
|
||
|
|
<Tab value="file" label={t('knowledgeDetails.file')} />
|
||
|
|
<Tab value="dataset" label={t('knowledgeDetails.dataset')} />
|
||
|
|
</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>
|
||
|
|
</Box>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export default KnowledgeLogsPage;
|