From 66ceaf3274cac38de81b85d7ff6b5be213ee00fa Mon Sep 17 00:00:00 2001 From: imeepos Date: Fri, 18 Jul 2025 13:03:17 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=9C=80=E8=A6=81=E7=82=B9=E5=87=BB=E4=B8=A4?= =?UTF-8?q?=E6=AC=A1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题分析: - 第一次点击批量删除时,onConfirm回调中使用的batchDeleteConfirm.resultIds可能因为React状态更新的异步性而被清空 - handleBatchDelete函数内部会重置batchDeleteConfirm状态,导致竞态条件 解决方案: - 将对话框关闭逻辑从handleBatchDelete中移出 - 创建handleConfirmBatchDelete函数,在调用删除前先复制resultIds数组并立即关闭对话框 - 修复数据库查询中缺少is_exported和last_exported_at字段的问题 - 添加更好的loading状态管理和用户体验优化 修复内容: - 修复TemplateMatchingResultRepository中SELECT语句缺少新字段的问题 - 重构批量删除的状态管理逻辑,避免竞态条件 - 添加调试日志帮助问题诊断 - 改进loading状态的视觉反馈 --- .../template_matching_result_repository.rs | 6 +- .../components/TemplateMatchingResultCard.tsx | 9 ++- .../TemplateMatchingResultManager.tsx | 58 ++++++++++++++++--- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/apps/desktop/src-tauri/src/data/repositories/template_matching_result_repository.rs b/apps/desktop/src-tauri/src/data/repositories/template_matching_result_repository.rs index 60bf9ac..f3d6ff6 100644 --- a/apps/desktop/src-tauri/src/data/repositories/template_matching_result_repository.rs +++ b/apps/desktop/src-tauri/src/data/repositories/template_matching_result_repository.rs @@ -85,7 +85,8 @@ impl TemplateMatchingResultRepository { "SELECT id, project_id, template_id, binding_id, result_name, description, total_segments, matched_segments, failed_segments, success_rate, used_materials, used_models, matching_duration_ms, quality_score, - status, metadata, export_count, created_at, updated_at, is_active + status, metadata, export_count, is_exported, last_exported_at, + created_at, updated_at, is_active FROM template_matching_results WHERE id = ?1" )?; @@ -171,7 +172,8 @@ impl TemplateMatchingResultRepository { let mut query = "SELECT id, project_id, template_id, binding_id, result_name, description, total_segments, matched_segments, failed_segments, success_rate, used_materials, used_models, matching_duration_ms, quality_score, - status, metadata, export_count, created_at, updated_at, is_active + status, metadata, export_count, is_exported, last_exported_at, + created_at, updated_at, is_active FROM template_matching_results WHERE is_active = 1".to_string(); let mut params: Vec = Vec::new(); diff --git a/apps/desktop/src/components/TemplateMatchingResultCard.tsx b/apps/desktop/src/components/TemplateMatchingResultCard.tsx index eb6170e..09c5c0f 100644 --- a/apps/desktop/src/components/TemplateMatchingResultCard.tsx +++ b/apps/desktop/src/components/TemplateMatchingResultCard.tsx @@ -11,6 +11,7 @@ interface TemplateMatchingResultCardProps { isSelected?: boolean; onToggleSelect?: () => void; showExportStatus?: boolean; + disabled?: boolean; } export const TemplateMatchingResultCard: React.FC = ({ @@ -22,6 +23,7 @@ export const TemplateMatchingResultCard: React.FC { // 格式化时长显示 const formatDuration = (ms: number): string => { @@ -83,7 +85,7 @@ export const TemplateMatchingResultCard: React.FC +
{/* 卡片头部 */}
@@ -94,7 +96,10 @@ export const TemplateMatchingResultCard: React.FC e.stopPropagation()} />
diff --git a/apps/desktop/src/components/TemplateMatchingResultManager.tsx b/apps/desktop/src/components/TemplateMatchingResultManager.tsx index 5ba3c23..3d4895a 100644 --- a/apps/desktop/src/components/TemplateMatchingResultManager.tsx +++ b/apps/desktop/src/components/TemplateMatchingResultManager.tsx @@ -132,29 +132,41 @@ export const TemplateMatchingResultManager: React.FC { + console.log('开始批量删除,ID列表:', resultIds); setBatchOperationLoading(true); + try { const [deletedResults, deletedUsageRecords] = await invoke<[number, number]>( 'batch_soft_delete_matching_results_with_usage_reset', { resultIds } ); + console.log(`删除结果: ${deletedResults} 个匹配结果,${deletedUsageRecords} 条使用记录`); success(`成功删除 ${deletedResults} 个匹配结果,重置 ${deletedUsageRecords} 条使用记录`); // 重新加载列表 + console.log('重新加载列表...'); await loadResults(); await loadStatistics(); + console.log('列表重新加载完成'); // 清空选择 setSelectedResults(new Set()); - setBatchDeleteConfirm({ show: false, resultIds: [] }); } catch (err) { + console.error('批量删除失败:', err); setError(`批量删除失败: ${err}`); } finally { setBatchOperationLoading(false); } }; + // 确认批量删除 + const handleConfirmBatchDelete = async () => { + const resultIds = [...batchDeleteConfirm.resultIds]; // 复制数组避免状态变化影响 + setBatchDeleteConfirm({ show: false, resultIds: [] }); // 立即关闭对话框 + await handleBatchDelete(resultIds); + }; + // 切换选择状态 const handleToggleSelect = (resultId: string) => { const newSelected = new Set(selectedResults); @@ -291,7 +303,7 @@ export const TemplateMatchingResultManager: React.FC +
{/* 统计面板 */} {showStats && statistics && ( @@ -378,13 +390,20 @@ export const TemplateMatchingResultManager: React.FC + {batchOperationLoading && ( + + + + + )} {batchOperationLoading ? '删除中...' : `批量删除 (${selectedResults.size})`} @@ -423,12 +442,13 @@ export const TemplateMatchingResultManager: React.FC
-
@@ -527,9 +548,28 @@ export const TemplateMatchingResultManager: React.FC handleBatchDelete(batchDeleteConfirm.resultIds)} - onCancel={() => setBatchDeleteConfirm({ show: false, resultIds: [] })} + deleting={batchOperationLoading} + onConfirm={handleConfirmBatchDelete} + onCancel={() => !batchOperationLoading && setBatchDeleteConfirm({ show: false, resultIds: [] })} /> + + {/* 批量操作Loading遮罩 */} + {batchOperationLoading && ( +
+
+
+ + + + +
+

正在删除匹配结果

+

正在删除 {selectedResults.size} 个匹配结果并重置资源状态...

+
+
+
+
+ )}
); };