Checkpoint production workflow updates
This commit is contained in:
@@ -9,6 +9,7 @@ export default function useGlobalTaskControl({
|
||||
licenseOk,
|
||||
activeTasks,
|
||||
setActiveTasks,
|
||||
setRuntimeSummary,
|
||||
pendingTaskIds,
|
||||
setPendingTaskIds,
|
||||
setIsCheckingTasks,
|
||||
@@ -21,8 +22,11 @@ export default function useGlobalTaskControl({
|
||||
const pendingTaskIdsRef = useRef(pendingTaskIds);
|
||||
useEffect(() => { pendingTaskIdsRef.current = pendingTaskIds; }, [pendingTaskIds]);
|
||||
|
||||
const handleTasksUpdate = useCallback(async (tasks) => {
|
||||
const handleTasksUpdate = useCallback(async (tasks, runtimeSummary = null) => {
|
||||
setActiveTasks(tasks);
|
||||
if (setRuntimeSummary) {
|
||||
setRuntimeSummary(runtimeSummary);
|
||||
}
|
||||
const hasRunningTasks = tasks.length > 0;
|
||||
|
||||
// 首次检查完成,清除检查状态
|
||||
@@ -93,21 +97,45 @@ export default function useGlobalTaskControl({
|
||||
|
||||
}, [
|
||||
setActiveTasks,
|
||||
setRuntimeSummary,
|
||||
setIsCheckingTasks,
|
||||
handleTaskCompletionRef,
|
||||
setPendingTaskIds,
|
||||
]);
|
||||
|
||||
const normalizeRuntimeSummary = useCallback((payload) => {
|
||||
if (!payload || typeof payload !== 'object') return null;
|
||||
const items = payload.tasks?.items;
|
||||
return {
|
||||
...payload,
|
||||
tasks: {
|
||||
...(payload.tasks || {}),
|
||||
items: Array.isArray(items) ? items : [],
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Fallback polling (used when SSE is unavailable)
|
||||
const syncActiveTasks = useCallback(async () => {
|
||||
try {
|
||||
const response = await apiClient.get('/tasks/runtime-summary');
|
||||
const summary = normalizeRuntimeSummary(response.data);
|
||||
if (summary) {
|
||||
await handleTasksUpdate(summary.tasks.items, summary);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('同步任务运行概览失败:', error);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiClient.get('/tasks/active');
|
||||
const tasks = Array.isArray(response.data) ? response.data : [];
|
||||
await handleTasksUpdate(tasks);
|
||||
await handleTasksUpdate(tasks, null);
|
||||
} catch (error) {
|
||||
console.error('同步任务状态失败:', error);
|
||||
}
|
||||
}, [handleTasksUpdate]);
|
||||
}, [handleTasksUpdate, normalizeRuntimeSummary]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentUser || !licenseOk) return;
|
||||
@@ -121,12 +149,14 @@ export default function useGlobalTaskControl({
|
||||
|
||||
const startSSE = () => {
|
||||
const baseURL = apiClient.defaults.baseURL || '';
|
||||
es = new EventSource(`${baseURL}/tasks/active/stream`);
|
||||
es = new EventSource(`${baseURL}/tasks/runtime-summary/stream`);
|
||||
|
||||
es.onmessage = (event) => {
|
||||
try {
|
||||
const tasks = JSON.parse(event.data);
|
||||
handleTasksUpdate(Array.isArray(tasks) ? tasks : []);
|
||||
const summary = normalizeRuntimeSummary(JSON.parse(event.data));
|
||||
if (summary) {
|
||||
handleTasksUpdate(summary.tasks.items, summary);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('SSE parse error:', e);
|
||||
}
|
||||
|
||||
@@ -216,24 +216,46 @@ export default function usePairingLogic({
|
||||
}
|
||||
};
|
||||
|
||||
const createDinsarBatch = async () => {
|
||||
const createDinsarBatch = async (options = {}) => {
|
||||
if (!ensureCanOperate()) return;
|
||||
const chunkSize = Number(options?.chunkSize || 0);
|
||||
const foundPairs = usePairingStore.getState().foundPairs;
|
||||
const selectedPairs = foundPairs.filter(p => p.isSelected);
|
||||
if (selectedPairs.length === 0) {
|
||||
addLog('warn', '没有选中的配对可保存。');
|
||||
return;
|
||||
}
|
||||
if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
|
||||
addLog('warn', '每批条数必须是大于 0 的整数。');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const batchPairs = selectedPairs.map(compactDinsarBatchPair);
|
||||
const response = await apiClient.post('/task-batches/dinsar', {
|
||||
name: `DINSAR_${new Date().toISOString().slice(0, 10)}`,
|
||||
pairs: batchPairs,
|
||||
});
|
||||
const batchId = response.data?.batch_id || '';
|
||||
addLog('success', `已创建 D-InSAR 批次: ${batchId || 'OK'}`);
|
||||
if (batchId) {
|
||||
await focusBatchAfterCreate('dinsar', batchId);
|
||||
const createdBatchIds = [];
|
||||
const createdAt = new Date().toISOString().slice(0, 10);
|
||||
const totalChunks = Math.ceil(selectedPairs.length / chunkSize);
|
||||
for (let offset = 0; offset < selectedPairs.length; offset += chunkSize) {
|
||||
const chunkIndex = Math.floor(offset / chunkSize) + 1;
|
||||
const chunkPairs = selectedPairs
|
||||
.slice(offset, offset + chunkSize)
|
||||
.map(compactDinsarBatchPair);
|
||||
const response = await apiClient.post('/task-batches/dinsar', {
|
||||
name: totalChunks > 1
|
||||
? `DINSAR_${createdAt}_${String(chunkIndex).padStart(3, '0')}_of_${String(totalChunks).padStart(3, '0')}`
|
||||
: `DINSAR_${createdAt}`,
|
||||
pairs: chunkPairs,
|
||||
});
|
||||
const batchId = response.data?.batch_id || '';
|
||||
if (batchId) {
|
||||
createdBatchIds.push(batchId);
|
||||
}
|
||||
addLog(
|
||||
'success',
|
||||
`已创建 D-InSAR 批次 ${chunkIndex}/${totalChunks}: ${batchId || 'OK'} (${chunkPairs.length} 条)`
|
||||
);
|
||||
}
|
||||
if (createdBatchIds.length > 0) {
|
||||
addLog('info', `已按每批 ${chunkSize} 条拆分为 ${createdBatchIds.length} 个 D-InSAR 批次。`);
|
||||
await focusBatchAfterCreate('dinsar', createdBatchIds[0]);
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error.response?.data?.detail || error.message || '未知错误';
|
||||
|
||||
Reference in New Issue
Block a user