fix: fix upload bug 3d
This commit is contained in:
@@ -3,6 +3,78 @@ import { OrbitControls, Stage, useGLTF } from "@react-three/drei";
|
||||
import { useEffect, Suspense } from "react";
|
||||
import { Box, CircularProgress, Typography } from "@mui/material";
|
||||
|
||||
// Утилита для очистки кеша GLTF
|
||||
const clearGLTFCache = (url?: string) => {
|
||||
try {
|
||||
if (url) {
|
||||
// Если это blob URL, очищаем его из кеша
|
||||
if (url.startsWith("blob:")) {
|
||||
useGLTF.clear(url);
|
||||
console.log("🧹 clearGLTFCache: Очистка blob URL из кеша GLTF", {
|
||||
url,
|
||||
});
|
||||
} else {
|
||||
useGLTF.clear(url);
|
||||
console.log("🧹 clearGLTFCache: Очистка кеша для URL", { url });
|
||||
}
|
||||
} else {
|
||||
// Очищаем весь кеш GLTF
|
||||
useGLTF.clear();
|
||||
console.log("🧹 clearGLTFCache: Очистка всего кеша GLTF");
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("⚠️ clearGLTFCache: Ошибка при очистке кеша", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Утилита для проверки типа файла
|
||||
const isValid3DFile = (url: string): boolean => {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
const pathname = urlObj.pathname.toLowerCase();
|
||||
const searchParams = urlObj.searchParams;
|
||||
|
||||
// Проверяем расширение файла в пути
|
||||
const validExtensions = [".glb", ".gltf"];
|
||||
const hasValidExtension = validExtensions.some((ext) =>
|
||||
pathname.endsWith(ext)
|
||||
);
|
||||
|
||||
// Проверяем параметры запроса на наличие типа файла
|
||||
const fileType = searchParams.get("type") || searchParams.get("format");
|
||||
const hasValidType =
|
||||
fileType && ["glb", "gltf"].includes(fileType.toLowerCase());
|
||||
|
||||
// Если это blob URL, считаем его валидным (пользователь выбрал файл)
|
||||
const isBlobUrl = url.startsWith("blob:");
|
||||
|
||||
// Если это URL с токеном и нет явного расширения, считаем валидным
|
||||
// (предполагаем что сервер вернет правильный файл)
|
||||
const hasToken = searchParams.has("token");
|
||||
const isServerUrl = hasToken && !hasValidExtension;
|
||||
|
||||
const isValid =
|
||||
hasValidExtension || hasValidType || isBlobUrl || isServerUrl;
|
||||
|
||||
console.log("🔍 isValid3DFile: Проверка файла", {
|
||||
url,
|
||||
pathname,
|
||||
hasValidExtension,
|
||||
fileType,
|
||||
hasValidType,
|
||||
isBlobUrl,
|
||||
isServerUrl,
|
||||
isValid,
|
||||
});
|
||||
|
||||
return isValid;
|
||||
} catch (error) {
|
||||
console.warn("⚠️ isValid3DFile: Ошибка при проверке URL", error);
|
||||
// В случае ошибки парсинга URL, считаем валидным (пусть useGLTF сам разберется)
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
type ModelViewerProps = {
|
||||
width?: string;
|
||||
fileUrl: string;
|
||||
@@ -10,6 +82,18 @@ type ModelViewerProps = {
|
||||
};
|
||||
|
||||
const Model = ({ fileUrl }: { fileUrl: string }) => {
|
||||
// Очищаем кеш перед загрузкой новой модели
|
||||
useEffect(() => {
|
||||
// Очищаем кеш для текущего URL
|
||||
clearGLTFCache(fileUrl);
|
||||
}, [fileUrl]);
|
||||
|
||||
// Проверяем валидность файла перед загрузкой (только для blob URL)
|
||||
if (fileUrl.startsWith("blob:") && !isValid3DFile(fileUrl)) {
|
||||
console.warn("⚠️ Model: Попытка загрузить невалидный 3D файл", { fileUrl });
|
||||
throw new Error(`Файл не является корректной 3D моделью: ${fileUrl}`);
|
||||
}
|
||||
|
||||
const { scene } = useGLTF(fileUrl);
|
||||
return <primitive object={scene} />;
|
||||
};
|
||||
@@ -49,11 +133,26 @@ export const ThreeView = ({
|
||||
height = "100%",
|
||||
width = "100%",
|
||||
}: ModelViewerProps) => {
|
||||
// Очищаем кеш при размонтировании
|
||||
// Проверяем валидность файла (только для blob URL)
|
||||
useEffect(() => {
|
||||
if (fileUrl.startsWith("blob:") && !isValid3DFile(fileUrl)) {
|
||||
console.warn("⚠️ ThreeView: Невалидный 3D файл", { fileUrl });
|
||||
}
|
||||
}, [fileUrl]);
|
||||
|
||||
// Очищаем кеш при размонтировании и при смене URL
|
||||
useEffect(() => {
|
||||
// Очищаем кеш сразу при монтировании компонента
|
||||
clearGLTFCache(fileUrl);
|
||||
console.log("🧹 ThreeView: Очистка кеша модели при монтировании", {
|
||||
fileUrl,
|
||||
});
|
||||
|
||||
return () => {
|
||||
useGLTF.clear(fileUrl);
|
||||
console.log("🧹 ThreeView: Очистка кеша модели", { fileUrl });
|
||||
clearGLTFCache(fileUrl);
|
||||
console.log("🧹 ThreeView: Очистка кеша модели при размонтировании", {
|
||||
fileUrl,
|
||||
});
|
||||
};
|
||||
}, [fileUrl]);
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||
import { ThreeView } from "./ThreeView";
|
||||
import { ThreeViewErrorBoundary } from "./ThreeViewErrorBoundary";
|
||||
import { clearMediaTransitionCache } from "../../shared/lib/gltfCacheManager";
|
||||
|
||||
export interface MediaData {
|
||||
id: string | number;
|
||||
@@ -28,6 +29,30 @@ export function MediaViewer({
|
||||
}>) {
|
||||
const token = localStorage.getItem("token");
|
||||
const [resetKey, setResetKey] = useState(0);
|
||||
const [previousMediaId, setPreviousMediaId] = useState<
|
||||
string | number | null
|
||||
>(null);
|
||||
|
||||
// Сбрасываем ключ при смене медиа
|
||||
useEffect(() => {
|
||||
if (media?.id !== previousMediaId) {
|
||||
console.log("🔄 MediaViewer: Смена медиа, сброс ключа", {
|
||||
previousMediaId,
|
||||
newMediaId: media?.id,
|
||||
mediaType: media?.media_type,
|
||||
});
|
||||
|
||||
// Используем новый cache manager для очистки кеша
|
||||
clearMediaTransitionCache(
|
||||
previousMediaId,
|
||||
media?.id || null,
|
||||
media?.media_type
|
||||
);
|
||||
|
||||
setResetKey(0);
|
||||
setPreviousMediaId(media?.id || null);
|
||||
}
|
||||
}, [media?.id, media?.media_type, previousMediaId]);
|
||||
|
||||
const handleReset = () => {
|
||||
console.log("🔄 MediaViewer: handleReset вызван", {
|
||||
|
||||
Reference in New Issue
Block a user