122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
import { useCallback, useState } from "react";
|
|
import api from "@/lib/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 [debugData, setDebugData] = useState<string>("");
|
|
const [isUploading, setIsUploading] = useState(false);
|
|
const [uploadProgress, setUploadProgress] = useState(0);
|
|
const [uploadError, setUploadError] = useState<string | null>(null);
|
|
const [uploadData, setUploadData] = useState<string>("");
|
|
|
|
const fetchMaterials = useCallback(async () => {
|
|
try {
|
|
setFetchError(null);
|
|
setDebugData("Loading...");
|
|
|
|
const { data } = await api.get(`/api/materials?t=${new Date().getTime()}`);
|
|
setDebugData(JSON.stringify(data).substring(0, 200));
|
|
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));
|
|
setDebugData(`Error: ${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();
|
|
setUploadData("");
|
|
} 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,
|
|
debugData,
|
|
isUploading,
|
|
uploadProgress,
|
|
uploadError,
|
|
uploadData,
|
|
setUploadError,
|
|
fetchMaterials,
|
|
deleteMaterial,
|
|
handleUpload,
|
|
};
|
|
};
|