Files
TJWaterFrontend_Refine/public/three-dimensional/zjb/v29/loadingProgress.mjs
T
jiang d013f34493
Generic Container CI/CD / test-build-publish (push) Successful in 1m4s
Frontend CI/CD v2 / build-test-publish-and-deploy (push) Successful in 1m4s
fix(scene): resume chunk downloads after proxy interruptions
Whole-file loading still failed after adding caching because the public proxy interrupted large GLB response bodies. Download validated 1 MiB ranges, retry transient failures up to three attempts, and persist completed chunks so reloads resume from their last boundary.

Add regression cases observed failing before the change for interrupted downloads, cross-reload resume, and temporary HTTP failures. Verify range integrity, full-cache reuse, permanent errors, and storage fallback.
2026-10-16 18:37:24 +08:00

62 lines
2.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const boot = document.getElementById('boot');
const title = document.getElementById('boot-title');
const detail = document.getElementById('boot-detail');
const progress = document.getElementById('boot-progress');
const retry = document.getElementById('boot-retry');
const formatBytes = bytes => (bytes / 1024 / 1024).toFixed(1) + ' MB';
let entries = new Map();
let failed = false;
let lastPaint = 0;
export function beginLoading(files, message = '正在载入三维场景') {
entries = new Map(files.map(file => [file, {stage:'waiting', loaded:0, total:0}]));
failed = false;
boot.hidden = false;
boot.dataset.state = 'loading';
boot.setAttribute('aria-busy', 'true');
title.textContent = message;
detail.textContent = '正在检查本地资源缓存';
progress.hidden = false;
progress.removeAttribute('value');
retry.hidden = true;
lastPaint = 0;
}
export function reportProgress(update) {
if (failed || !entries.has(update.file)) return;
entries.set(update.file, update);
// Large streamed files can emit hundreds of chunks in a frame.
if (update.stage === 'download' && performance.now() - lastPaint < 100) return;
lastPaint = performance.now();
const values = [...entries.values()];
const done = values.filter(item => item.stage === 'ready').length;
const loaded = values.reduce((sum, item) => sum + item.loaded, 0);
const cached = values.filter(item => item.stage === 'cache').length;
const retrying = values.some(item => item.stage === 'retry');
const parsing = values.some(item => item.stage === 'parse');
const downloading = values.some(item => item.stage === 'download');
progress.max = Math.max(1, values.length);
progress.value = done;
title.textContent = `正在载入场景资源 ${done} / ${values.length}`;
detail.textContent = `${retrying ? '连接中断,正在从断点重试' : parsing ? '正在解析模型' : downloading ? '正在下载资源' : cached ? '正在读取本地缓存' : '正在准备场景'} · 已读取 ${formatBytes(loaded)}`;
}
export function finishLoading() {
if (failed) return;
boot.setAttribute('aria-busy', 'false');
boot.hidden = true;
}
export function failLoading(error) {
failed = true;
boot.hidden = false;
boot.dataset.state = 'error';
boot.setAttribute('aria-busy', 'false');
title.textContent = '场景资源加载失败';
detail.textContent = '部分资源未能载入,请检查网络后重试。' + (error?.message ? '(' + error.message + ')' : '');
progress.hidden = true;
retry.hidden = false;
}
retry.addEventListener('click', () => window.location.reload());