'use client'; import { useState } from 'react'; import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Box, Typography, CircularProgress, List, ListItem, ListItemText, ListItemSecondaryAction, IconButton, Alert, Paper, useTheme, Tooltip } from '@mui/material'; import WarningAmberIcon from '@mui/icons-material/WarningAmber'; import FolderOpenIcon from '@mui/icons-material/FolderOpen'; import DeleteIcon from '@mui/icons-material/Delete'; import { useTranslation } from 'react-i18next'; /** * 项目迁移对话框组件 * @param {Object} props - 组件属性 * @param {boolean} props.open - 对话框是否打开 * @param {Function} props.onClose - 关闭对话框的回调函数 * @param {Array} props.projectIds - 需要迁移的项目ID列表 */ export default function MigrationDialog({ open, onClose, projectIds = [] }) { const { t } = useTranslation(); const theme = useTheme(); const [migrating, setMigrating] = useState(false); const [success, setSuccess] = useState(false); const [error, setError] = useState(null); const [migratedCount, setMigratedCount] = useState(0); const [taskId, setTaskId] = useState(null); const [progress, setProgress] = useState(0); const [statusText, setStatusText] = useState(''); const [processingIds, setProcessingIds] = useState([]); // 打开项目目录 const handleOpenDirectory = async projectId => { try { setProcessingIds(prev => [...prev, projectId]); const response = await fetch('/api/projects/open-directory', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ projectId }) }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || t('migration.openDirectoryFailed')); } // 成功打开目录,不需要特别处理 } catch (err) { console.error('打开目录错误:', err); setError(err.message); } finally { setProcessingIds(prev => prev.filter(id => id !== projectId)); } }; // 删除项目目录 const handleDeleteDirectory = async projectId => { try { if (!window.confirm(t('migration.confirmDelete'))) { return; } setProcessingIds(prev => [...prev, projectId]); const response = await fetch('/api/projects/delete-directory', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ projectId }) }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || t('migration.deleteDirectoryFailed')); } // 从列表中移除已删除的项目 const updatedProjectIds = projectIds.filter(id => id !== projectId); // 这里我们不能直接修改 projectIds,因为它是从父组件传入的 // 但我们可以通知用户界面刷新 window.location.reload(); } catch (err) { console.error('删除目录错误:', err); setError(err.message); } finally { setProcessingIds(prev => prev.filter(id => id !== projectId)); } }; // 处理迁移操作 const handleMigration = async () => { try { setMigrating(true); setError(null); setSuccess(false); setProgress(0); setStatusText(t('migration.starting')); // 调用异步迁移接口启动迁移任务 const response = await fetch('/api/projects/migrate', { method: 'POST' }); if (!response.ok) { throw new Error(t('migration.failed')); } const { success, taskId: newTaskId } = await response.json(); if (!success || !newTaskId) { throw new Error(t('migration.startFailed')); } // 保存任务ID setTaskId(newTaskId); setStatusText(t('migration.processing')); // 开始轮询任务状态 await pollMigrationStatus(newTaskId); } catch (err) { console.error('迁移错误:', err); setError(err.message); setMigrating(false); } }; // 轮询迁移任务状态 const pollMigrationStatus = async id => { try { // 定义轮询间隔(毫秒) const pollInterval = 1000; // 发送请求获取任务状态 const response = await fetch(`/api/projects/migrate?taskId=${id}`); if (!response.ok) { throw new Error(t('migration.statusFailed')); } const { success, task } = await response.json(); if (!success || !task) { throw new Error(t('migration.taskNotFound')); } // 更新进度 setProgress(task.progress || 0); // 根据任务状态更新UI if (task.status === 'completed') { // 任务完成 setMigratedCount(task.completed); setSuccess(true); setMigrating(false); setStatusText(t('migration.completed')); // 迁移成功后,延迟关闭对话框并刷新页面 setTimeout(() => { onClose(); window.location.reload(); }, 2000); } else if (task.status === 'failed') { // 任务失败 throw new Error(task.error || t('migration.failed')); } else { // 任务仍在进行中,继续轮询 setTimeout(() => pollMigrationStatus(id), pollInterval); // 更新状态文本 if (task.total > 0) { setStatusText( t('migration.progressStatus', { completed: task.completed || 0, total: task.total }) ); } } } catch (err) { console.error('获取迁移状态错误:', err); setError(err.message); setMigrating(false); } }; return ( {t('migration.title')} {success ? ( {t('migration.success', { count: migratedCount })} ) : error ? ( {error} ) : null} {t('migration.description')} {projectIds.length > 0 && ( {t('migration.projectsList')}: {projectIds.map(id => ( handleOpenDirectory(id)} disabled={processingIds.includes(id)} size="small" > handleDeleteDirectory(id)} disabled={processingIds.includes(id)} size="small" sx={{ ml: 1, color: 'error.main' }} > ))} )} {migrating && ( 0 ? 'determinate' : 'indeterminate'} value={progress} /> {statusText || t('migration.migrating')} {progress > 0 && ( {progress}% )} )} ); }