Files
ViGent2/frontend/src/features/home/model/useMaterials.ts
Kevin Wong b2c1042c5c 更新
2026-02-04 18:04:17 +08:00

114 lines
3.2 KiB
TypeScript

import { useCallback, useState } from "react";
import api from "@/shared/api/axios";
interface Material {
id: string;
name: string;
scene: string;
size_mb: number;
path: string;
}
interface UseMaterialsOptions {
selectedMaterial: string;
setSelectedMaterial: React.Dispatch<React.SetStateAction<string>>;
}
export const useMaterials = ({
selectedMaterial,
setSelectedMaterial,
}: UseMaterialsOptions) => {
const [materials, setMaterials] = useState<Material[]>([]);
const [fetchError, setFetchError] = useState<string | null>(null);
const [isUploading, setIsUploading] = useState(false);
const [uploadProgress, setUploadProgress] = useState(0);
const [uploadError, setUploadError] = useState<string | null>(null);
const fetchMaterials = useCallback(async () => {
try {
setFetchError(null);
const { data } = await api.get(`/api/materials?t=${new Date().getTime()}`);
const nextMaterials = data.materials || [];
setMaterials(nextMaterials);
const nextSelected = nextMaterials.find((item: Material) => item.id === selectedMaterial)?.id
|| nextMaterials[0]?.id
|| "";
if (nextSelected !== selectedMaterial) {
setSelectedMaterial(nextSelected);
}
} catch (error) {
console.error("获取素材失败:", error);
setFetchError(String(error));
}
}, [selectedMaterial, setSelectedMaterial]);
const deleteMaterial = useCallback(async (materialId: string) => {
if (!confirm("确定要删除这个素材吗?")) return;
try {
await api.delete(`/api/materials/${materialId}`);
fetchMaterials();
if (selectedMaterial === materialId) {
setSelectedMaterial("");
}
} catch (error) {
alert("删除失败: " + error);
}
}, [fetchMaterials, selectedMaterial, setSelectedMaterial]);
const handleUpload = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const validTypes = ['.mp4', '.mov', '.avi'];
const ext = file.name.toLowerCase().slice(file.name.lastIndexOf('.'));
if (!validTypes.includes(ext)) {
setUploadError('仅支持 MP4、MOV、AVI 格式');
return;
}
setIsUploading(true);
setUploadProgress(0);
setUploadError(null);
try {
const formData = new FormData();
formData.append('file', file);
await api.post('/api/materials', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (progressEvent) => {
if (progressEvent.total) {
const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
setUploadProgress(progress);
}
},
});
setUploadProgress(100);
setIsUploading(false);
fetchMaterials();
} catch (err: any) {
console.error("Upload failed:", err);
setIsUploading(false);
const errorMsg = err.response?.data?.detail || err.message || String(err);
setUploadError(`上传失败: ${errorMsg}`);
}
e.target.value = '';
}, [fetchMaterials]);
return {
materials,
fetchError,
isUploading,
uploadProgress,
uploadError,
setUploadError,
fetchMaterials,
deleteMaterial,
handleUpload,
};
};