Fix BIM version model loading

This commit is contained in:
CODEX 2026-06-24 19:03:28 +03:00
parent 31bb673b44
commit bc8f70da9c
2 changed files with 43 additions and 6 deletions

View File

@ -319,9 +319,11 @@ let modelVersionHistoryLoading = false;
let modelVersionUploading = false; let modelVersionUploading = false;
let versionHistoryModal = null; let versionHistoryModal = null;
let loadModelAsyncRef = null; let loadModelAsyncRef = null;
let versionModelCounter = 0;
let emptyWheelNavigationRestoreTimer = null; let emptyWheelNavigationRestoreTimer = null;
let lastSurfaceDollyFactor = null; let lastSurfaceDollyFactor = null;
let lastSurfaceDollyFactorAt = 0; let lastSurfaceDollyFactorAt = 0;
const MODEL_LOAD_TIMEOUT_MS = 120000;
const GUEST_TOOLBAR_ACTIONS = new Set(["measure", "section", "projection"]); const GUEST_TOOLBAR_ACTIONS = new Set(["measure", "section", "projection"]);
const memoryStore = new Map(); // url -> ArrayBuffer const memoryStore = new Map(); // url -> ArrayBuffer
const blobUrls = []; const blobUrls = [];
@ -4700,6 +4702,13 @@ const uploadBuffer = async (bytes, filename, options = {}) => {
const getVersionKey = (version) => version?.versionId || `version-${version?.version || "unknown"}`; const getVersionKey = (version) => version?.versionId || `version-${version?.version || "unknown"}`;
const makeVersionModelId = (version) => {
versionModelCounter += 1;
const rawKey = version?.versionId || version?.version || version?.originalFilename || versionModelCounter;
const safeKey = String(rawKey).replace(/[^a-z0-9_-]+/gi, "-").replace(/^-+|-+$/g, "") || "version";
return `model-version-${safeKey}-${versionModelCounter}`;
};
const getModelVersionIdentity = (entry = getPrimaryModelEntry()) => { const getModelVersionIdentity = (entry = getPrimaryModelEntry()) => {
const meta = entry?.meta || {}; const meta = entry?.meta || {};
const direct = { const direct = {
@ -4896,13 +4905,18 @@ const openModelVersion = async (version) => {
if (settings?.viewerSettings) { if (settings?.viewerSettings) {
meta.viewerSettings = settings.viewerSettings; meta.viewerSettings = settings.viewerSettings;
} }
const previousModelId = previousEntry?.model?.id || null;
const nextModelId = makeVersionModelId(version);
if (previousModelId && transformStore[previousModelId]) {
transformStore[nextModelId] = safeClone(transformStore[previousModelId]);
}
await loadModelAsyncRef({ await loadModelAsyncRef({
type: viewerType, type: viewerType,
url: viewerSrc, url: viewerSrc,
name: version.originalFilename || previousEntry?.name || "model", name: version.originalFilename || previousEntry?.name || "model",
replace: true, replace: true,
preserveMeta: true, preserveMeta: true,
id: previousEntry?.model?.id || "model", id: nextModelId,
meta, meta,
}); });
modelVersionHistory = { modelVersionHistory = {
@ -6093,6 +6107,7 @@ const initViewer = async () => {
isMemory, isMemory,
name, name,
replace, replace,
requestedId: forcedId || null,
url, url,
}); });
const xktDataSource = inferredType === "xkt" const xktDataSource = inferredType === "xkt"
@ -6112,7 +6127,7 @@ const initViewer = async () => {
dataSource: xktDataSource || gltfDataSource || lasDataSource || stlDataSource || undefined, dataSource: xktDataSource || gltfDataSource || lasDataSource || stlDataSource || undefined,
}); });
const id = forcedId || (replace ? "model" : `model-${++modelCounter}`); const requestedId = forcedId || (replace ? "model" : `model-${++modelCounter}`);
let srcToLoad = url; let srcToLoad = url;
if (inferredType === "obj" && typeof url === "string" && url.startsWith("memory:") && memoryStore.has(url)) { if (inferredType === "obj" && typeof url === "string" && url.startsWith("memory:") && memoryStore.has(url)) {
const blobUrl = URL.createObjectURL(new Blob([memoryStore.get(url)], { type: "text/plain" })); const blobUrl = URL.createObjectURL(new Blob([memoryStore.get(url)], { type: "text/plain" }));
@ -6120,7 +6135,7 @@ const initViewer = async () => {
srcToLoad = blobUrl; srcToLoad = blobUrl;
} }
const loadOpts = { const loadOpts = {
id, id: requestedId,
src: srcToLoad, src: srcToLoad,
edges: edges ?? (inferredType === "gltf" || inferredType === "las" ? false : toggleEdges.checked), edges: edges ?? (inferredType === "gltf" || inferredType === "las" ? false : toggleEdges.checked),
}; };
@ -6129,12 +6144,17 @@ const initViewer = async () => {
if (inferredType === "stl") loadOpts.smoothNormals = true; if (inferredType === "stl") loadOpts.smoothNormals = true;
const currentModel = currentLoader.load(loadOpts); const currentModel = currentLoader.load(loadOpts);
const id = currentModel?.id || requestedId;
if (id !== requestedId && transformStore[requestedId] && !transformStore[id]) {
transformStore[id] = safeClone(transformStore[requestedId]);
}
sceneModels[id] = currentModel; sceneModels[id] = currentModel;
modelTypes[id] = inferredType; modelTypes[id] = inferredType;
currentModel.on("loaded", () => { currentModel.on("loaded", () => {
reportViewerEvent("model-loaded", { reportViewerEvent("model-loaded", {
id, id,
requestedId,
inferredType, inferredType,
name, name,
objectCount: Object.keys(viewer.scene.objects || {}).length, objectCount: Object.keys(viewer.scene.objects || {}).length,
@ -6180,6 +6200,7 @@ const initViewer = async () => {
currentModel.on("error", (err) => { currentModel.on("error", (err) => {
reportViewerEvent("model-error", { reportViewerEvent("model-error", {
id, id,
requestedId,
inferredType, inferredType,
name, name,
error: err?.message || String(err), error: err?.message || String(err),
@ -6225,8 +6246,24 @@ const initViewer = async () => {
reject(new Error("Не удалось инициировать загрузку модели")); reject(new Error("Не удалось инициировать загрузку модели"));
return; return;
} }
model.on("loaded", () => resolve(model)); let settled = false;
model.on("error", (err) => reject(new Error(err?.message || err))); let timer = null;
const settle = (handler, value) => {
if (settled) return;
settled = true;
if (timer) window.clearTimeout(timer);
handler(value);
};
model.on("loaded", () => settle(resolve, model));
model.on("error", (err) => settle(reject, new Error(err?.message || err)));
if (!settled) {
timer = window.setTimeout(() => {
setLoading(false);
updateNavCubeVisibility();
updatePanelsVisibility();
settle(reject, new Error("Загрузка модели заняла слишком много времени"));
}, MODEL_LOAD_TIMEOUT_MS);
}
}); });
loadModelAsyncRef = loadModelAsync; loadModelAsyncRef = loadModelAsync;

View File

@ -697,6 +697,6 @@
<input id="fileInput" class="hidden" type="file" <input id="fileInput" class="hidden" type="file"
accept=".xkt,.glb,.gltf,.bim,.las,.laz,.obj,.stl"> accept=".xkt,.glb,.gltf,.bim,.las,.laz,.obj,.stl">
<script type="module" src="/dcViewer.js?v=58"></script> <script type="module" src="/dcViewer.js?v=59"></script>
</body> </body>
</html> </html>