fix: 统一馆内三维模型返回初始状态
This commit is contained in:
@@ -478,6 +478,7 @@ let resizeObserver: ResizeObserver | null = null
|
||||
let isDisposed = false
|
||||
let pendingTargetFocus: TargetPoiFocusRequest | null = null
|
||||
let targetFocusQueue: Promise<unknown> = Promise.resolve()
|
||||
let targetFocusGeneration = 0
|
||||
let modelLoadVersion = 0
|
||||
let pendingRequestedFloorId = ''
|
||||
let floorSwitchLoadToken = 0
|
||||
@@ -515,6 +516,7 @@ let defaultFloorPreloadSeq = 0
|
||||
let firstModelLoadStartedAt = 0
|
||||
let firstModelVisibleReported = false
|
||||
let initialModelSettled = false
|
||||
let initialGuideState: { floorId: string; camera: CameraSnapshot } | null = null
|
||||
|
||||
const cameraTweenEnabled = true
|
||||
const cameraTweenDurationMs = 480
|
||||
@@ -3519,6 +3521,8 @@ const getVisualStabilityReport = () => ({
|
||||
anchors: getProjectedBuildingAnchors(),
|
||||
activeView: activeView.value,
|
||||
floorId: currentFloor.value,
|
||||
activeFocusPoiId: activeFocusPoiId.value,
|
||||
hasPendingTargetFocus: Boolean(pendingTargetFocus),
|
||||
isCameraTweening: Boolean(cameraTween),
|
||||
poiFocusCameraAnimationCount,
|
||||
cameraSnapshotRestoreCount,
|
||||
@@ -3558,7 +3562,8 @@ const installVisualStabilityDiagnostics = () => {
|
||||
queueTargetFocus(request)
|
||||
return targetFocusQueue
|
||||
},
|
||||
clearTargetFocus
|
||||
clearTargetFocus,
|
||||
resetToInitialState
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5144,6 +5149,7 @@ const emitTargetFocus = (
|
||||
}
|
||||
|
||||
const clearTargetFocus = () => {
|
||||
targetFocusGeneration += 1
|
||||
pendingTargetFocus = null
|
||||
clearMapSelection(false)
|
||||
}
|
||||
@@ -5176,7 +5182,10 @@ const focusCameraOnPoi = (poi: RenderPoi) => {
|
||||
moveCameraTo(nextPosition, target, { reason: 'poi-focus' })
|
||||
}
|
||||
|
||||
const focusTargetPoi = async (request: TargetPoiFocusRequest) => {
|
||||
const isCurrentTargetFocus = (generation: number) => generation === targetFocusGeneration
|
||||
|
||||
const focusTargetPoi = async (request: TargetPoiFocusRequest, generation: number) => {
|
||||
if (!isCurrentTargetFocus(generation)) return false
|
||||
if (!request.poiId || !request.floorId) {
|
||||
emitTargetFocus(request, 'missing', '目标位置数据不完整')
|
||||
return false
|
||||
@@ -5198,12 +5207,15 @@ const focusTargetPoi = async (request: TargetPoiFocusRequest) => {
|
||||
suppressProgress: true,
|
||||
detachPoiBeforeLoad: true
|
||||
})
|
||||
if (!isCurrentTargetFocus(generation)) return false
|
||||
isLoading.value = false
|
||||
emit('floorChange', request.floorId)
|
||||
} else if (shouldRenderPoiMarkers.value && !getPoiSprites().length) {
|
||||
await loadFloorPOIs(floor, modelLoadVersion)
|
||||
if (!isCurrentTargetFocus(generation)) return false
|
||||
}
|
||||
|
||||
if (!isCurrentTargetFocus(generation)) return false
|
||||
const poi = findLoadedPoi(request.poiId) || addFocusMarkerFromRequest(request) || createPoiFromFocusRequest(request)
|
||||
|
||||
if (!poi?.positionGltf) {
|
||||
@@ -5244,11 +5256,12 @@ const queueTargetFocus = (request: TargetPoiFocusRequest | null) => {
|
||||
if (!isSceneReadyForTargetFocus()) return
|
||||
|
||||
const nextRequest = pendingTargetFocus
|
||||
const requestGeneration = targetFocusGeneration
|
||||
if (!nextRequest) return
|
||||
|
||||
pendingTargetFocus = null
|
||||
targetFocusQueue = targetFocusQueue
|
||||
.then(() => focusTargetPoi(nextRequest))
|
||||
.then(() => focusTargetPoi(nextRequest, requestGeneration))
|
||||
.finally(() => {
|
||||
if (pendingTargetFocus) {
|
||||
queueTargetFocus(pendingTargetFocus)
|
||||
@@ -5321,6 +5334,12 @@ const init3DScene = async () => {
|
||||
installVisualStabilityDiagnostics()
|
||||
await loadModelPackage()
|
||||
|
||||
// The package, not a hard-coded floor, determines the stable first-ready baseline.
|
||||
initialGuideState = {
|
||||
floorId: currentFloor.value,
|
||||
camera: captureCameraSnapshot()
|
||||
}
|
||||
|
||||
setProgress(100, '馆内三维模型加载完成')
|
||||
initialModelSettled = true
|
||||
isLoading.value = false
|
||||
@@ -5440,6 +5459,52 @@ const showMultiFloor = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Restores business and camera state on the existing scene. It never initializes WebGL or
|
||||
// reloads the model package, so closing a detail page cannot remount ThreeMap.
|
||||
const resetToInitialState = async () => {
|
||||
clearTargetFocus()
|
||||
invalidateModelLoads()
|
||||
adjacentPreloadSeq += 1
|
||||
defaultFloorPreloadSeq += 1
|
||||
cancelCameraTween()
|
||||
clearProgrammaticCameraTimer()
|
||||
clearRoutePreview()
|
||||
selectedPOI.value = null
|
||||
activeFocusPoiId.value = ''
|
||||
disposeFocusLabel()
|
||||
disposeFocusPulse()
|
||||
disposeFocusBase()
|
||||
clearFocusHallHighlight()
|
||||
updatePoiMarkerFocus()
|
||||
autoSwitchStateMachine.reset('overview')
|
||||
resetInteractionGateState()
|
||||
|
||||
const baseline = initialGuideState
|
||||
if (!baseline || !scene || !camera || !controls || loadError.value) return false
|
||||
|
||||
isLoading.value = true
|
||||
try {
|
||||
currentFloor.value = baseline.floorId
|
||||
if (activeView.value !== 'overview') {
|
||||
await loadOverview({ cameraSnapshot: baseline.camera })
|
||||
}
|
||||
if (!scene || !isCurrentModelLoad(modelLoadVersion)) return false
|
||||
restoreCameraSnapshot(baseline.camera)
|
||||
currentFloor.value = baseline.floorId
|
||||
activeView.value = 'overview'
|
||||
autoSwitchStateMachine.reset('overview')
|
||||
refreshPoiVisibilityByDistance()
|
||||
return true
|
||||
} catch (error) {
|
||||
if (!isStaleModelLoadError(error)) {
|
||||
console.error('恢复馆内导览初始状态失败:', error)
|
||||
}
|
||||
return false
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const retryLoad = () => {
|
||||
init3DScene()
|
||||
}
|
||||
@@ -5530,6 +5595,7 @@ defineExpose({
|
||||
},
|
||||
clearSelection: clearMapSelection,
|
||||
clearRoute: clearRoutePreview,
|
||||
resetToInitialState,
|
||||
clearNavigation: () => clearMapSelection(false),
|
||||
disableAutoSwitchTemporarily
|
||||
})
|
||||
|
||||
@@ -460,6 +460,7 @@ const indoorRendererRef = ref<{
|
||||
zoomCamera?: (direction: 'in' | 'out', options?: { source?: 'button' | 'gesture' }) => void
|
||||
clearSelection?: (shouldEmit?: boolean) => void
|
||||
clearRoute?: () => Promise<void> | void
|
||||
resetToInitialState?: () => Promise<boolean> | boolean
|
||||
disableAutoSwitchTemporarily?: (durationMs: number) => void
|
||||
} | null>(null)
|
||||
|
||||
@@ -779,7 +780,8 @@ defineExpose({
|
||||
clearRoute: () => {
|
||||
indoorRendererRef.value?.clearRoute?.()
|
||||
},
|
||||
showOverview: handleShowOverview
|
||||
showOverview: handleShowOverview,
|
||||
resetToInitialState: () => indoorRendererRef.value?.resetToInitialState?.() || false
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user