From 3e6c05c4ac2ba5bf0fcbd965008aad5738f9c883 Mon Sep 17 00:00:00 2001 From: imeepos Date: Wed, 16 Jul 2025 14:05:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E7=BB=93=E6=9E=9C=E7=9B=B8=E5=85=B3=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 修复list_matching_results接口'Invalid column type Integer at index: 18, name: is_active'错误 - 修正template_matching_result_repository.rs中row_to_matching_result函数的is_active字段处理 - 使用rusqlite::types::Value枚举正确处理多种数据类型 2. 修复数据插入和读取的类型不一致问题 - 修正数据插入时将INTEGER字段转换为字符串的错误 - 统一数据类型:数字字段直接使用原始类型而非字符串 3. 实现应用匹配结果功能 - 修复ProjectDetails.tsx中handleApplyMatchingResult函数 - 调用save_matching_result API保存匹配结果到数据库 - 添加成功/失败通知提示 修复的具体问题: - template_matching_results表的is_active字段类型处理 - 数字字段(total_segments, matched_segments等)的类型转换 - quality_score字段的NULL值处理 - 前端应用匹配结果后保存到数据库的逻辑 --- .../template_matching_result_repository.rs | 44 ++++++++++--------- apps/desktop/src/pages/ProjectDetails.tsx | 40 ++++++++++++++--- 2 files changed, 58 insertions(+), 26 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 1f5cc26..4c4a006 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 @@ -53,19 +53,19 @@ impl TemplateMatchingResultRepository { &final_result.binding_id, &final_result.result_name, &final_result.description, - &final_result.total_segments.to_string(), - &final_result.matched_segments.to_string(), - &final_result.failed_segments.to_string(), - &final_result.success_rate.to_string(), - &final_result.used_materials.to_string(), - &final_result.used_models.to_string(), - &final_result.matching_duration_ms.to_string(), - &final_result.quality_score.map(|s| s.to_string()), + &final_result.total_segments, + &final_result.matched_segments, + &final_result.failed_segments, + &final_result.success_rate, + &final_result.used_materials, + &final_result.used_models, + &final_result.matching_duration_ms, + &final_result.quality_score, &serde_json::to_string(&final_result.status).unwrap(), &final_result.metadata, &final_result.created_at.to_rfc3339(), &final_result.updated_at.to_rfc3339(), - &(final_result.is_active as i32).to_string(), + &(final_result.is_active as i32), ], )?; @@ -458,8 +458,7 @@ impl TemplateMatchingResultRepository { let status: MatchingResultStatus = serde_json::from_str(&status_str) .unwrap_or(MatchingResultStatus::Success); - let quality_score_str: Option = row.get("quality_score")?; - let quality_score = quality_score_str.and_then(|s| s.parse::().ok()); + let quality_score: Option = row.get("quality_score")?; let created_at_str: String = row.get("created_at")?; let updated_at_str: String = row.get("updated_at")?; @@ -470,8 +469,13 @@ impl TemplateMatchingResultRepository { .unwrap_or_else(|_| Utc::now().into()) .with_timezone(&Utc); - let is_active_str: String = row.get("is_active")?; - let is_active = is_active_str.parse::().unwrap_or(1) != 0; + // 正确处理 is_active 字段,支持多种数据类型 + let is_active = match row.get::<_, rusqlite::types::Value>("is_active")? { + rusqlite::types::Value::Integer(i) => i != 0, + rusqlite::types::Value::Text(s) => s == "1" || s.to_lowercase() == "true", + rusqlite::types::Value::Real(f) => f != 0.0, + _ => true, // 默认为 true + }; Ok(TemplateMatchingResult { id: row.get("id")?, @@ -480,13 +484,13 @@ impl TemplateMatchingResultRepository { binding_id: row.get("binding_id")?, result_name: row.get("result_name")?, description: row.get("description")?, - total_segments: row.get::<_, String>("total_segments")?.parse().unwrap_or(0), - matched_segments: row.get::<_, String>("matched_segments")?.parse().unwrap_or(0), - failed_segments: row.get::<_, String>("failed_segments")?.parse().unwrap_or(0), - success_rate: row.get::<_, String>("success_rate")?.parse().unwrap_or(0.0), - used_materials: row.get::<_, String>("used_materials")?.parse().unwrap_or(0), - used_models: row.get::<_, String>("used_models")?.parse().unwrap_or(0), - matching_duration_ms: row.get::<_, String>("matching_duration_ms")?.parse().unwrap_or(0), + total_segments: row.get("total_segments")?, + matched_segments: row.get("matched_segments")?, + failed_segments: row.get("failed_segments")?, + success_rate: row.get("success_rate")?, + used_materials: row.get("used_materials")?, + used_models: row.get("used_models")?, + matching_duration_ms: row.get("matching_duration_ms")?, quality_score, status, metadata: row.get("metadata")?, diff --git a/apps/desktop/src/pages/ProjectDetails.tsx b/apps/desktop/src/pages/ProjectDetails.tsx index f68ab5a..fe9503b 100644 --- a/apps/desktop/src/pages/ProjectDetails.tsx +++ b/apps/desktop/src/pages/ProjectDetails.tsx @@ -34,6 +34,7 @@ import { zhCN } from 'date-fns/locale'; import { MaterialSegmentStats } from '../components/MaterialSegmentStats'; import { MaterialSegmentViewMode } from '../types/materialSegmentView'; import { TemplateMatchingResultManager } from '../components/TemplateMatchingResultManager'; +import { useNotifications } from '../components/NotificationSystem'; // 格式化时间 const formatTime = (dateString: string) => { @@ -78,6 +79,7 @@ export const ProjectDetails: React.FC = () => { queueStats, getProjectQueueStatus } = useVideoClassificationStore(); + const { success: addNotification } = useNotifications(); // 模板绑定状态管理 const { @@ -362,20 +364,46 @@ export const ProjectDetails: React.FC = () => { const handleApplyMatchingResult = async (result: MaterialMatchingResult) => { try { - // 这里可以添加应用匹配结果的逻辑 - // 例如更新模板绑定的匹配状态等 - console.log('应用匹配结果:', result); + if (!currentMatchingBinding) { + throw new Error('没有找到当前匹配绑定信息'); + } + + // 生成结果名称 + const resultName = `匹配结果_${new Date().toLocaleString('zh-CN')}`; + const description = `模板 ${currentMatchingBinding.template_name} 的匹配结果,成功匹配 ${result.statistics.matched_segments} 个片段`; + + // 调用后端API保存匹配结果 + await invoke('save_matching_result', { + serviceResult: { + project_id: project?.id, + template_id: currentMatchingBinding.binding.template_id, + binding_id: currentMatchingBinding.binding.id, + matches: result.matches, + failed_segments: result.failed_segments, + statistics: result.statistics, + matching_duration_ms: 0 // MaterialMatchingResult 没有这个字段,使用默认值 + }, + resultName, + description, + matchingDurationMs: 0 // 使用默认值 + }); // 关闭对话框 setShowMatchingResultDialog(false); setMatchingResult(null); setCurrentMatchingBinding(null); - // 可以显示成功提示 - alert('匹配结果已应用'); + // 显示成功提示 + addNotification('匹配结果已保存', `已成功保存匹配结果"${resultName}",可在匹配记录页面查看。`); + + // 如果当前在匹配记录选项卡,刷新数据 + if (activeTab === 'matching-results') { + // 触发匹配记录列表刷新 + window.location.reload(); + } } catch (error) { console.error('应用匹配结果失败:', error); - alert(`应用匹配结果失败: ${error}`); + addNotification('保存匹配结果失败', `保存匹配结果时发生错误: ${error}`); } };