first-update

This commit is contained in:
2026-03-17 14:36:31 +08:00
parent 72f08aee7c
commit 4eddf05e79
516 changed files with 115270 additions and 1 deletions

View File

@@ -0,0 +1,400 @@
'use client';
import { Box, Typography, Checkbox, Button, Select, MenuItem, Tooltip, Menu, IconButton, Badge } from '@mui/material';
import QuizIcon from '@mui/icons-material/Quiz';
import DownloadIcon from '@mui/icons-material/Download';
import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
import CleaningServicesIcon from '@mui/icons-material/CleaningServices';
import AssessmentIcon from '@mui/icons-material/Assessment';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';
import FilterListIcon from '@mui/icons-material/FilterList';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import axios from 'axios';
import { toast } from 'sonner';
import { useTranslation } from 'react-i18next';
import { useState } from 'react';
import ChunkFilterDialog from './ChunkFilterDialog';
export default function ChunkListHeader({
projectId,
totalChunks,
selectedChunks,
onSelectAll,
onBatchGenerateQuestions,
onBatchEditChunks,
onBatchDeleteChunks,
questionFilter,
setQuestionFilter,
chunks = [], // 添加chunks参数用于导出文本块
selectedModel = {},
onFilterChange = null,
activeFilterCount = 0
}) {
const { t, i18n } = useTranslation();
// 添加更多菜单的状态和锚点
const [moreMenuAnchorEl, setMoreMenuAnchorEl] = useState(null);
const isMoreMenuOpen = Boolean(moreMenuAnchorEl);
// 添加筛选对话框状态
const [filterDialogOpen, setFilterDialogOpen] = useState(false);
// 自动任务菜单状态
const [autoTasksMenuAnchorEl, setAutoTasksMenuAnchorEl] = useState(null);
const isAutoTasksMenuOpen = Boolean(autoTasksMenuAnchorEl);
const handleAutoTasksClick = event => {
setAutoTasksMenuAnchorEl(event.currentTarget);
};
const handleAutoTasksClose = () => {
setAutoTasksMenuAnchorEl(null);
};
// 打开更多菜单
const handleMoreMenuClick = event => {
setMoreMenuAnchorEl(event.currentTarget);
};
// 关闭更多菜单
const handleMoreMenuClose = () => {
setMoreMenuAnchorEl(null);
};
// 处理批量编辑,关闭菜单并调用原有函数
const handleBatchEdit = () => {
handleMoreMenuClose();
onBatchEditChunks();
};
// 处理批量删除,关闭菜单并调用原有函数
const handleBatchDelete = () => {
handleMoreMenuClose();
onBatchDeleteChunks();
};
// 处理导出文本块,关闭菜单并调用原有函数
const handleExport = () => {
handleMoreMenuClose();
handleExportChunks();
};
// 创建自动提取问题任务
const handleCreateAutoQuestionTask = async () => {
if (!projectId || !selectedModel?.id) {
toast.error(t('textSplit.selectModelFirst', { defaultValue: '请先选择模型' }));
return;
}
try {
// 调用创建任务接口
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
taskType: 'question-generation',
modelInfo: selectedModel,
language: i18n.language,
detail: '批量生成问题任务'
});
if (response.data?.code === 0) {
toast.success(t('tasks.createSuccess', { defaultValue: '后台任务已创建,系统将自动处理未生成问题的文本块' }));
} else {
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + response.data?.message);
}
} catch (error) {
console.error('创建自动提取问题任务失败:', error);
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
}
};
// 创建自动数据清洗任务
const handleCreateAutoDataCleaningTask = async () => {
if (!projectId || !selectedModel?.id) {
toast.error(t('textSplit.selectModelFirst', { defaultValue: '请先选择模型' }));
return;
}
try {
// 调用创建任务接口
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
taskType: 'data-cleaning',
modelInfo: selectedModel,
language: i18n.language,
detail: '批量数据清洗任务'
});
if (response.data?.code === 0) {
toast.success(
t('tasks.createSuccess', { defaultValue: '后台任务已创建,系统将自动处理所有文本块进行数据清洗' })
);
} else {
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + response.data?.message);
}
} catch (error) {
console.error('创建自动数据清洗任务失败:', error);
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
}
};
// 创建自动生成评估数据集任务
const handleCreateAutoEvalGenerationTask = async () => {
if (!projectId || !selectedModel?.id) {
toast.error(t('textSplit.selectModelFirst', { defaultValue: '请先选择模型' }));
return;
}
try {
// 调用创建任务接口
const response = await axios.post(`/api/projects/${projectId}/tasks`, {
taskType: 'eval-generation',
modelInfo: selectedModel,
language: i18n.language,
detail: '批量生成评估数据集任务'
});
if (response.data?.code === 0) {
toast.success(
t('tasks.createSuccess', {
defaultValue: '后台任务已创建,系统将自动为所有未生成评估题目的文本块生成评估数据集'
})
);
} else {
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + response.data?.message);
}
} catch (error) {
console.error('创建自动生成评估数据集任务失败:', error);
toast.error(t('tasks.createFailed', { defaultValue: '创建任务失败' }) + ': ' + error.message);
}
};
// 导出文本块为JSON文件的函数
const handleExportChunks = () => {
if (!chunks || chunks.length === 0) return;
// 创建要导出的数据对象
const exportData = chunks.map(chunk => ({
name: chunk.name,
projectId: chunk.projectId,
fileName: chunk.fileName,
content: chunk.content,
summary: chunk.summary,
size: chunk.size
}));
// 将数据转换为JSON字符串
const jsonString = JSON.stringify(exportData, null, 2);
// 创建Blob对象
const blob = new Blob([jsonString], { type: 'application/json' });
// 创建下载链接
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `text-chunks-export-${new Date().toISOString().split('T')[0]}.json`;
// 触发下载
document.body.appendChild(a);
a.click();
// 清理
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
return (
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
justifyContent: 'space-between',
alignItems: { xs: 'flex-start', md: 'center' },
gap: 2,
mb: 3
}}
>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Checkbox
checked={selectedChunks.length === totalChunks}
indeterminate={selectedChunks.length > 0 && selectedChunks.length < totalChunks}
onChange={onSelectAll}
/>
<Typography variant="body1">{t('textSplit.selectedCount', { count: selectedChunks.length })}</Typography>
</Box>
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', sm: 'row' },
alignItems: { xs: 'flex-start', sm: 'center' },
flexWrap: 'wrap',
gap: 1.5,
width: { xs: '100%', md: 'auto' }
}}
>
{/* 更多筛选按钮 */}
<Tooltip title={t('datasets.moreFilters', { defaultValue: '更多筛选' })}>
<Badge badgeContent={activeFilterCount} color="error" overlap="circular">
<Button
variant="outlined"
startIcon={<FilterListIcon />}
onClick={() => setFilterDialogOpen(true)}
size="small"
sx={{ borderRadius: 1 }}
>
{t('datasets.moreFilters', { defaultValue: '更多筛选' })}
</Button>
</Badge>
</Tooltip>
<Box
sx={{
display: 'flex',
flexWrap: 'wrap',
gap: 1.5,
mt: { xs: 1, sm: 0 },
width: { xs: '100%', sm: 'auto' }
}}
>
<Button
variant="contained"
color="primary"
startIcon={<QuizIcon />}
disabled={selectedChunks.length === 0}
onClick={onBatchGenerateQuestions}
size="medium"
sx={{ minWidth: { xs: '48%', sm: 'auto' } }}
>
{t('textSplit.batchGenerateQuestions')}
</Button>
{/* 自动任务下拉菜单 */}
<Button
variant="outlined"
color="secondary"
startIcon={<AutoFixHighIcon />}
endIcon={<KeyboardArrowDownIcon />}
onClick={handleAutoTasksClick}
disabled={!projectId || !selectedModel?.id}
size="medium"
sx={{ minWidth: { xs: '48%', sm: 'auto' } }}
>
{t('textSplit.autoTasks', { defaultValue: '自动任务' })}
</Button>
<Menu
anchorEl={autoTasksMenuAnchorEl}
open={isAutoTasksMenuOpen}
onClose={handleAutoTasksClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right'
}}
>
<Tooltip
title={t('textSplit.autoGenerateQuestionsTip', {
defaultValue: '创建后台批量处理任务:自动查询待生成问题的文本块并提取问题'
})}
placement="left"
>
<MenuItem
onClick={() => {
handleCreateAutoQuestionTask();
handleAutoTasksClose();
}}
>
<QuizIcon fontSize="small" sx={{ mr: 1, color: 'secondary.main' }} />
{t('textSplit.autoGenerateQuestions')}
</MenuItem>
</Tooltip>
<Tooltip
title={t('textSplit.autoEvalGenerationTip', {
defaultValue: '创建后台批量处理任务:自动为所有未生成评估题目的文本块生成评估数据集'
})}
placement="left"
>
<MenuItem
onClick={() => {
handleCreateAutoEvalGenerationTask();
handleAutoTasksClose();
}}
>
<AssessmentIcon fontSize="small" sx={{ mr: 1, color: 'secondary.main' }} />
{t('textSplit.autoEvalGeneration', { defaultValue: '自动生成评估集' })}
</MenuItem>
</Tooltip>
<Tooltip
title={t('textSplit.autoDataCleaningTip', {
defaultValue: '创建后台批量处理任务:自动对所有文本块进行数据清洗'
})}
placement="left"
>
<MenuItem
onClick={() => {
handleCreateAutoDataCleaningTask();
handleAutoTasksClose();
}}
>
<CleaningServicesIcon fontSize="small" sx={{ mr: 1, color: 'success.main' }} />
{t('textSplit.autoDataCleaning', { defaultValue: '自动数据清洗' })}
</MenuItem>
</Tooltip>
</Menu>
{/* 更多菜单按钮 */}
<Tooltip title={t('common.more', { defaultValue: '更多操作' })}>
<IconButton
onClick={handleMoreMenuClick}
color="primary"
size="medium"
sx={{
border: '1px solid',
borderColor: 'divider'
}}
>
<MoreVertIcon />
</IconButton>
</Tooltip>
{/* 更多操作下拉菜单 */}
<Menu
anchorEl={moreMenuAnchorEl}
open={isMoreMenuOpen}
onClose={handleMoreMenuClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right'
}}
>
<MenuItem onClick={handleBatchEdit} disabled={selectedChunks.length === 0}>
<EditIcon fontSize="small" sx={{ mr: 1 }} />
{t('batchEdit.batchEdit', { defaultValue: '批量编辑' })}
</MenuItem>
<MenuItem onClick={handleBatchDelete} disabled={selectedChunks.length === 0}>
<DeleteIcon fontSize="small" sx={{ mr: 1, color: 'error.main' }} />
{t('textSplit.batchDeleteChunks', { defaultValue: '批量删除' })}
</MenuItem>
<MenuItem onClick={handleExport} disabled={chunks.length === 0}>
<DownloadIcon fontSize="small" sx={{ mr: 1 }} />
{t('textSplit.exportChunks', { defaultValue: '导出文本块' })}
</MenuItem>
</Menu>
</Box>
</Box>
{/* 筛选对话框 */}
<ChunkFilterDialog open={filterDialogOpen} onClose={() => setFilterDialogOpen(false)} onApply={onFilterChange} />
</Box>
);
}