import React, { useCallback, useEffect, useState } from 'react'; import { scanDinsarResults } from './api/dinsar'; import { extractDispResults } from './api/idl'; import { clearTaskLogs, deleteTaskLog, getActiveTasks, getRecentTasks, getTaskLogs } from './api/tasks'; import DinsarCatalogPanel from './components/DinsarCatalogPanel'; const card = { background: '#fff', padding: '12px', borderRadius: '8px', border: '1px solid #e2e8f0', marginBottom: '12px', }; const PRODUCT_TASK_TYPES = [ 'SCAN_DINSAR', 'PUBLISH_DINSAR_PRODUCTS', 'REBUILD_DINSAR_CATALOG', ]; const TASK_TYPE_LABEL = { SCAN_DINSAR: 'D-InSAR结果扫描', PUBLISH_DINSAR_PRODUCTS: 'D-InSAR产物发布', REBUILD_DINSAR_CATALOG: 'D-InSAR目录重建', }; const STATUS_LABEL = { PENDING: '等待中', RUNNING: '运行中', COMPLETED: '已完成', FAILED: '失败', CANCELLED: '已取消', CANCELED: '已取消', }; function formatTaskType(taskType) { return TASK_TYPE_LABEL[taskType] || taskType || '-'; } function formatStatus(status) { return STATUS_LABEL[status] || status || '-'; } export default function DinsarProductsPanel({ readOnly = false, onJobQueued }) { const [extractRootDir, setExtractRootDir] = useState(''); const [extractDestDir, setExtractDestDir] = useState(''); const [extractResult, setExtractResult] = useState(null); const [extracting, setExtracting] = useState(false); const [actionMessage, setActionMessage] = useState(''); const [actionError, setActionError] = useState(false); const [scanning, setScanning] = useState(false); const [activeTask, setActiveTask] = useState(null); const [recentTask, setRecentTask] = useState(null); const [taskLogs, setTaskLogs] = useState([]); const [taskLogsLoading, setTaskLogsLoading] = useState(false); const [taskLogActionLoading, setTaskLogActionLoading] = useState(false); const [taskLogDeletingId, setTaskLogDeletingId] = useState(null); const monitoredTask = activeTask || recentTask; const logTaskId = monitoredTask?.task_id || ''; const showingRecentTask = !activeTask && !!recentTask; const loadActiveTask = useCallback(async () => { try { const data = await getActiveTasks(); const tasks = Array.isArray(data) ? data : (data?.tasks || []); const relevantTask = tasks.find(task => PRODUCT_TASK_TYPES.includes(task.task_type)) || null; setActiveTask(relevantTask); return relevantTask; } catch { setActiveTask(null); return null; } }, []); const loadRecentTask = useCallback(async () => { try { const tasks = await getRecentTasks(PRODUCT_TASK_TYPES, [], 1, 0); const nextTask = Array.isArray(tasks) ? (tasks[0] || null) : null; setRecentTask(nextTask); return nextTask; } catch { setRecentTask(null); return null; } }, []); const loadTaskLogs = useCallback(async taskId => { if (!taskId) { setTaskLogs([]); return; } setTaskLogsLoading(true); try { const data = await getTaskLogs(taskId, 50, 0); setTaskLogs(data?.logs || []); } catch { setTaskLogs([]); } finally { setTaskLogsLoading(false); } }, []); const handleDeleteTaskLog = useCallback(async logId => { const taskId = logTaskId; if (!taskId || !logId || taskLogActionLoading) return; if (!window.confirm('确定要删除这条任务日志吗?')) return; setTaskLogDeletingId(logId); setTaskLogActionLoading(true); try { await deleteTaskLog(taskId, logId); await loadTaskLogs(taskId); } catch (error) { setActionMessage(`删除日志失败:${error?.response?.data?.detail || error.message}`); setActionError(true); } finally { setTaskLogDeletingId(null); setTaskLogActionLoading(false); } }, [logTaskId, loadTaskLogs, taskLogActionLoading]); const handleClearTaskLogs = useCallback(async () => { const taskId = logTaskId; if (!taskId || taskLogActionLoading || taskLogs.length === 0) return; if (!window.confirm(`确定要清空任务 ${taskId} 的全部日志吗?`)) return; setTaskLogActionLoading(true); try { await clearTaskLogs(taskId); await loadTaskLogs(taskId); } catch (error) { setActionMessage(`清空日志失败:${error?.response?.data?.detail || error.message}`); setActionError(true); } finally { setTaskLogActionLoading(false); } }, [logTaskId, loadTaskLogs, taskLogActionLoading, taskLogs.length]); const refreshMonitor = useCallback(async () => { const [nextActiveTask, nextRecentTask] = await Promise.all([ loadActiveTask(), loadRecentTask(), ]); const nextTaskId = nextActiveTask?.task_id || nextRecentTask?.task_id || ''; await loadTaskLogs(nextTaskId); }, [loadActiveTask, loadRecentTask, loadTaskLogs]); useEffect(() => { refreshMonitor(); }, [refreshMonitor]); const handleExtract = async () => { if (!extractRootDir.trim()) return; setExtracting(true); setExtractResult(null); setActionMessage(''); setActionError(false); try { const result = await extractDispResults(extractRootDir.trim(), extractDestDir.trim() || null); setExtractResult(result); } catch (err) { setExtractResult({ error: err?.response?.data?.detail || err.message }); } finally { setExtracting(false); } }; const handleScan = async () => { if (readOnly) return; setScanning(true); setActionMessage(''); setActionError(false); try { const result = await scanDinsarResults(); setActionMessage(result?.message || `D-InSAR结果扫描任务已入队:${result?.task_id || '-'}`); if (result?.task_id) { onJobQueued?.(result.task_id); } await refreshMonitor(); } catch (err) { setActionError(true); setActionMessage(err?.response?.data?.detail || err.message || 'D-InSAR结果扫描失败'); } finally { setScanning(false); } }; return (