diff --git a/apps/desktop/src/components/MaterialCard.tsx b/apps/desktop/src/components/MaterialCard.tsx index 7c6ff91..919bcd6 100644 --- a/apps/desktop/src/components/MaterialCard.tsx +++ b/apps/desktop/src/components/MaterialCard.tsx @@ -1,17 +1,20 @@ import React, { useState, useEffect } from 'react'; import { FileVideo, FileAudio, FileImage, File, Clock, ExternalLink, ChevronDown, ChevronUp, - Monitor, Volume2, Palette, Calendar, Hash, Zap, HardDrive, Film, Eye, Brain, Loader2, User, Edit2 + Monitor, Volume2, Palette, Calendar, Hash, Zap, HardDrive, Film, Eye, Brain, Loader2, User, Edit2, Trash2, RefreshCw } from 'lucide-react'; import { Material, MaterialSegment } from '../types/material'; import { useMaterialStore } from '../store/materialStore'; import { useVideoClassificationStore } from '../store/videoClassificationStore'; import { Model } from '../types/model'; import { invoke } from '@tauri-apps/api/core'; +import { DeleteConfirmDialog } from './DeleteConfirmDialog'; interface MaterialCardProps { material: Material; onEdit?: (material: Material) => void; + onDelete?: (materialId: string, materialName: string) => void; + onReprocess?: (materialId: string) => void; } // 格式化时间(秒转为 mm:ss 格式) @@ -60,7 +63,7 @@ const formatDate = (dateString: string): string => { * 素材卡片组件 * 显示素材信息和切分片段 */ -export const MaterialCard: React.FC = ({ material, onEdit }) => { +export const MaterialCard: React.FC = ({ material, onEdit, onDelete, onReprocess }) => { const { getMaterialSegments } = useMaterialStore(); const { startClassification, isLoading: classificationLoading } = useVideoClassificationStore(); const [segments, setSegments] = useState([]); @@ -69,6 +72,9 @@ export const MaterialCard: React.FC = ({ material, onEdit }) const [isClassifying, setIsClassifying] = useState(false); const [associatedModel, setAssociatedModel] = useState(null); const [loadingModel, setLoadingModel] = useState(false); + const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); + const [isReprocessing, setIsReprocessing] = useState(false); // 获取素材类型图标 const getTypeIcon = (type: string) => { @@ -209,6 +215,43 @@ export const MaterialCard: React.FC = ({ material, onEdit }) } }; + // 处理删除素材 + const handleDeleteClick = () => { + setShowDeleteConfirm(true); + }; + + const handleDeleteConfirm = async () => { + if (!onDelete) return; + + setIsDeleting(true); + try { + await onDelete(material.id, material.name); + setShowDeleteConfirm(false); + } catch (error) { + console.error('删除素材失败:', error); + } finally { + setIsDeleting(false); + } + }; + + const handleDeleteCancel = () => { + setShowDeleteConfirm(false); + }; + + // 处理重新处理素材 + const handleReprocessClick = async () => { + if (!onReprocess) return; + + setIsReprocessing(true); + try { + await onReprocess(material.id); + } catch (error) { + console.error('重新处理素材失败:', error); + } finally { + setIsReprocessing(false); + } + }; + return (
{/* 素材基本信息 */} @@ -218,6 +261,22 @@ export const MaterialCard: React.FC = ({ material, onEdit })

{material.name}

+ {/* 重新处理按钮 - 仅在状态为 Pending 时显示 */} + {material.processing_status === 'Pending' && onReprocess && ( + + )} + {onEdit && ( )} + + {onDelete && ( + + )} + {material.processing_status} @@ -471,6 +541,17 @@ export const MaterialCard: React.FC = ({ material, onEdit }) )}
)} + + {/* 删除确认对话框 */} + ); }; diff --git a/apps/desktop/src/pages/ProjectDetails.tsx b/apps/desktop/src/pages/ProjectDetails.tsx index 5937aed..e325aa4 100644 --- a/apps/desktop/src/pages/ProjectDetails.tsx +++ b/apps/desktop/src/pages/ProjectDetails.tsx @@ -39,6 +39,8 @@ export const ProjectDetails: React.FC = () => { stats, loadMaterials, loadMaterialStats, + deleteMaterial, + processMaterials, isLoading: materialsLoading } = useMaterialStore(); const { @@ -287,6 +289,36 @@ export const ProjectDetails: React.FC = () => { } }; + // 素材删除处理函数 + const handleDeleteMaterial = async (materialId: string, _materialName: string) => { + try { + await deleteMaterial(materialId); + + // 重新加载素材列表 + if (project) { + loadMaterials(project.id); + } + } catch (error) { + console.error('删除素材失败:', error); + throw error; + } + }; + + // 素材重新处理函数 + const handleReprocessMaterial = async (materialId: string) => { + try { + await processMaterials([materialId]); + + // 重新加载素材列表 + if (project) { + loadMaterials(project.id); + } + } catch (error) { + console.error('重新处理素材失败:', error); + throw error; + } + }; + if (isLoading) { return (
@@ -527,7 +559,13 @@ export const ProjectDetails: React.FC = () => { ) : materials.length > 0 ? (
{materials.map((material) => ( - + ))}
) : (