Files
TERES_web_frontend/src/pages/knowledge/overview.tsx

202 lines
7.7 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { Box, Grid, Paper, Typography, IconButton, TextField, Tabs, Tab, Fab } from '@mui/material';
import { DataGrid, type GridColDef } from '@mui/x-data-grid';
import {
ArrowBack as ArrowBackIcon,
Search as SearchIcon,
} from '@mui/icons-material';
import { useTranslation } from 'react-i18next';
import { useNavigate, useParams } from 'react-router-dom';
import { useKnowledgeOverview, useKnowledgeDetail } from '@/hooks/knowledge-hooks';
import logger from '@/utils/logger';
import i18n from '@/locales';
import { enUS, zhCN } from '@mui/x-data-grid/locales';
import KnowledgeBreadcrumbs from './components/KnowledgeBreadcrumbs';
import { LanguageAbbreviation } from '@/constants/common';
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);
// 获取知识库详情以用于面包屑显示名称
const { knowledge } = useKnowledgeDetail(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]);
const navigate = useNavigate();
const handleNavigateBack = () => {
navigate(`/knowledge/${kbId}`);
};
return (
<Box sx={{ p: 3 }}>
{/* 面包屑导航 */}
<KnowledgeBreadcrumbs
kbItems={[
{
label: t('knowledgeSettings.knowledgeBase'),
path: '/knowledge'
},
{
label: knowledge?.name || t('knowledgeSettings.knowledgeBaseDetail'),
path: `/knowledge/${kbId}`
},
{
label: t('knowledgeSettings.fileLogs')
}
]}
/>
{/* 顶部统计卡片占位 */}
<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="fileLogs" label={t('knowledgeDetails.file')} />
<Tab value="datasetLogs" 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>
{/* 返回按钮 */}
<Fab
color="primary"
aria-label={t('knowledgeSettings.backToKnowledgeDetail')}
onClick={handleNavigateBack}
sx={{
position: 'fixed',
bottom: 128,
right: 64,
}}
>
<ArrowBackIcon />
</Fab>
</Box>
);
}
export default KnowledgeLogsPage;