|
|
@@ -84,17 +84,33 @@ function useFetchLoader(url) {
|
|
|
}
|
|
|
|
|
|
function Loader({ customState }) {
|
|
|
- // 优先使用传入的 customState,否则回退到 useProgress (用于纹理加载等后续过程)
|
|
|
- const { active, progress: dreiProgress } = useProgress();
|
|
|
-
|
|
|
- // 合并状态:如果是下载阶段(customState.loading),用 customState;否则用 drei
|
|
|
- const isLoading = customState?.loading || active;
|
|
|
- if (!isLoading) return null;
|
|
|
+ // 只负责显示手动下载的进度
|
|
|
+ // 如果没有在下载,直接返回 null
|
|
|
+ if (!customState || !customState.loading) return null;
|
|
|
|
|
|
- const loaded = customState?.loading ? customState.loaded : 0;
|
|
|
- const total = customState?.loading ? customState.total : 0;
|
|
|
- const progress = customState?.loading ? customState.progress : (dreiProgress || 0);
|
|
|
-
|
|
|
+ return (
|
|
|
+ <LoaderUI
|
|
|
+ progress={customState.progress}
|
|
|
+ loaded={customState.loaded}
|
|
|
+ total={customState.total}
|
|
|
+ status="downloading"
|
|
|
+ />
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+// 专门用于 Suspense fallback 的解析状态提示
|
|
|
+function ParsingLoader() {
|
|
|
+ return (
|
|
|
+ <LoaderUI
|
|
|
+ progress={100}
|
|
|
+ loaded={0}
|
|
|
+ total={0}
|
|
|
+ status="parsing"
|
|
|
+ />
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function LoaderUI({ progress, loaded, total, status }) {
|
|
|
// 格式化文件大小
|
|
|
const formatBytes = (bytes) => {
|
|
|
if (bytes === 0) return '0 B';
|
|
|
@@ -105,13 +121,13 @@ function Loader({ customState }) {
|
|
|
};
|
|
|
|
|
|
// 判断是否无法计算总大小
|
|
|
- const isIndeterminate = customState?.loading && total === 0 && loaded > 0;
|
|
|
+ const isIndeterminate = status === 'downloading' && total === 0 && loaded > 0;
|
|
|
|
|
|
const progressText = isIndeterminate
|
|
|
? `已下载 ${formatBytes(loaded)}`
|
|
|
: `${progress.toFixed(0)}%`;
|
|
|
|
|
|
- const statusText = customState?.loading
|
|
|
+ const statusText = status === 'downloading'
|
|
|
? (total > 0 ? `下载中 ${formatBytes(loaded)} / ${formatBytes(total)}` : '下载中...')
|
|
|
: '解析模型中...';
|
|
|
|
|
|
@@ -679,7 +695,7 @@ export default function Scene({ url, zoomMin, zoomMax }) {
|
|
|
{url ? (
|
|
|
<>
|
|
|
{fetchState.blobUrl && (
|
|
|
- <Suspense fallback={null}>
|
|
|
+ <Suspense fallback={<ParsingLoader />}>
|
|
|
<SceneContent url={fetchState.blobUrl} zoomMin={zoomMin} zoomMax={zoomMax} fileType={fileType} />
|
|
|
</Suspense>
|
|
|
)}
|