feat: 添加素材删除和重新处理功能
- 在MaterialCard组件中添加删除按钮,使用DeleteConfirmDialog替代window.confirm - 在MaterialCard组件中添加重新处理按钮,当素材状态为Pending时显示 - 在ProjectDetails页面中添加删除和重新处理的处理函数 - 遵循Tauri开发规范和前端开发规范 - 实现了统一的删除确认对话框UI交互
This commit is contained in:
parent
3f90013a47
commit
9aa2cdd49f
|
|
@ -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<MaterialCardProps> = ({ material, onEdit }) => {
|
||||
export const MaterialCard: React.FC<MaterialCardProps> = ({ material, onEdit, onDelete, onReprocess }) => {
|
||||
const { getMaterialSegments } = useMaterialStore();
|
||||
const { startClassification, isLoading: classificationLoading } = useVideoClassificationStore();
|
||||
const [segments, setSegments] = useState<MaterialSegment[]>([]);
|
||||
|
|
@ -69,6 +72,9 @@ export const MaterialCard: React.FC<MaterialCardProps> = ({ material, onEdit })
|
|||
const [isClassifying, setIsClassifying] = useState(false);
|
||||
const [associatedModel, setAssociatedModel] = useState<Model | null>(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<MaterialCardProps> = ({ 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 (
|
||||
<div className="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
{/* 素材基本信息 */}
|
||||
|
|
@ -218,6 +261,22 @@ export const MaterialCard: React.FC<MaterialCardProps> = ({ material, onEdit })
|
|||
<h4 className="font-medium text-gray-900 truncate">{material.name}</h4>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
{/* 重新处理按钮 - 仅在状态为 Pending 时显示 */}
|
||||
{material.processing_status === 'Pending' && onReprocess && (
|
||||
<button
|
||||
onClick={handleReprocessClick}
|
||||
disabled={isReprocessing}
|
||||
className="text-gray-400 hover:text-green-500 transition-colors disabled:opacity-50"
|
||||
title="重新处理"
|
||||
>
|
||||
{isReprocessing ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
) : (
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{onEdit && (
|
||||
<button
|
||||
onClick={() => onEdit(material)}
|
||||
|
|
@ -227,6 +286,17 @@ export const MaterialCard: React.FC<MaterialCardProps> = ({ material, onEdit })
|
|||
<Edit2 className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
{onDelete && (
|
||||
<button
|
||||
onClick={handleDeleteClick}
|
||||
className="text-gray-400 hover:text-red-500 transition-colors"
|
||||
title="删除素材"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<span className={`px-2 py-1 text-xs rounded-full ${getStatusColor(material.processing_status)}`}>
|
||||
{material.processing_status}
|
||||
</span>
|
||||
|
|
@ -471,6 +541,17 @@ export const MaterialCard: React.FC<MaterialCardProps> = ({ material, onEdit })
|
|||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 删除确认对话框 */}
|
||||
<DeleteConfirmDialog
|
||||
isOpen={showDeleteConfirm}
|
||||
title="删除素材"
|
||||
message="确定要删除这个素材吗?此操作不可撤销。"
|
||||
itemName={material.name}
|
||||
deleting={isDeleting}
|
||||
onConfirm={handleDeleteConfirm}
|
||||
onCancel={handleDeleteCancel}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className="flex items-center justify-center min-h-[400px]">
|
||||
|
|
@ -527,7 +559,13 @@ export const ProjectDetails: React.FC = () => {
|
|||
) : materials.length > 0 ? (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-3 md:gap-4">
|
||||
{materials.map((material) => (
|
||||
<MaterialCard key={material.id} material={material} onEdit={handleEditMaterial} />
|
||||
<MaterialCard
|
||||
key={material.id}
|
||||
material={material}
|
||||
onEdit={handleEditMaterial}
|
||||
onDelete={handleDeleteMaterial}
|
||||
onReprocess={handleReprocessMaterial}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
Loading…
Reference in New Issue