修复导览楼层默认进入与模型复位状态
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-17 11:54:08 +08:00
parent 19ecca84e8
commit 122013ccfb
7 changed files with 407 additions and 69 deletions

View File

@@ -3430,6 +3430,8 @@ const restoreCameraSnapshot = (snapshot: CameraSnapshot) => {
}
}
export type ResetViewBaselineResult = 'applied' | 'not-ready' | 'invalid-target' | 'failed' | 'stale'
const applyReferenceOverviewCameraState = () => {
restoreCameraSnapshot(referenceOverviewCameraState)
}
@@ -3652,6 +3654,49 @@ const getVisualFocusReport = () => {
}
}
const getVisiblePoiScreenPositions = () => {
if (!renderer || !camera) return []
const rect = renderer.domElement.getBoundingClientRect()
return getPoiSprites().flatMap((sprite) => {
const poi = sprite.userData.poi as RenderPoi | undefined
const screen = getProjectedScreenPosition(sprite)
let ancestor: THREE.Object3D | null = sprite
while (ancestor) {
if (!ancestor.visible) return []
ancestor = ancestor.parent
}
if (
!poi
|| !screen
|| screen.x < 0
|| screen.x > rect.width
|| screen.y < 0
|| screen.y > rect.height
) return []
// Match the production fallback hit-test so diagnostics only expose coordinates
// that a tap can resolve to this exact current marker.
const hit = findNearestPoiMarkerByScreenPoint({
clientX: rect.left + screen.x,
clientY: rect.top + screen.y
} as PointerEvent, rect)
if (hit !== sprite) return []
return [{
poiId: poi.id,
floorId: poi.floorId,
name: poi.name,
kind: poi.kind,
primaryCategory: poi.primaryCategory,
screen: {
x: rect.left + screen.x,
y: rect.top + screen.y
}
}]
})
}
const getVisualStabilityReport = () => ({
camera: serializeCameraSnapshot(captureCameraSnapshot()),
modelRoot: getModelRootTransformAudit(activeModel),
@@ -3674,6 +3719,8 @@ const installVisualStabilityDiagnostics = () => {
}
diagnosticsWindow.__GUIDE_3D_VISUAL_STABILITY__ = {
getReport: getVisualStabilityReport,
isInitialModelReady: () => initialModelSettled && Boolean(initialGuideState && activeModel),
getVisiblePoiScreenPositions,
getFloors: () => floorIndex.value.map((floor) => ({
floorId: floor.floorId,
label: floor.label,
@@ -3696,6 +3743,8 @@ const installVisualStabilityDiagnostics = () => {
poiId: poi.id,
floorId: poi.floorId,
name: poi.name,
kind: poi.kind,
primaryCategory: poi.primaryCategory,
positionGltf: poi.positionGltf!
}))
},
@@ -5610,6 +5659,18 @@ 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 resetToViewBaseline = async (options: ResetViewBaselineOptions) => {
// Do not invalidate the first model load while the renderer is still being initialized.
// The page-level guide model state will replay only its latest not-ready request.
const baseline = initialGuideState
if (!baseline || !scene || !camera || !controls) return 'not-ready' as const
if (loadError.value) return 'failed' as const
if (options.view === 'floor') {
if (!options.floorId || !floorIndex.value.some((item) => item.floorId === options.floorId)) {
return 'invalid-target' as const
}
}
clearTargetFocus()
invalidateModelLoads()
adjacentPreloadSeq += 1
@@ -5627,25 +5688,22 @@ const resetToViewBaseline = async (options: ResetViewBaselineOptions) => {
autoSwitchStateMachine.reset(options.view)
resetInteractionGateState()
const baseline = initialGuideState
if (!baseline || !scene || !camera || !controls || loadError.value) return false
isLoading.value = true
try {
if (options.view === 'floor') {
const floorId = options.floorId
if (!floorId) return false
if (!floorId) return 'invalid-target' as const
const floor = floorIndex.value.find((item) => item.floorId === floorId)
if (!floor) return false
if (!floor) return 'invalid-target' as const
if (activeView.value !== 'floor' || currentFloor.value !== floorId || activeModel?.userData.floorId !== floorId) {
await loadFloor(floorId, { applyFloorBaseline: true, detachPoiBeforeLoad: true })
} else {
const floorBaseline = getFloorViewBaseline(floorId, activeModel, floor.modelUrl)
if (!floorBaseline) return false
if (!floorBaseline) return 'failed' as const
restoreCameraSnapshot(floorBaseline.camera)
}
if (!scene || !isCurrentModelLoad(modelLoadVersion)) return false
if (!scene || !isCurrentModelLoad(modelLoadVersion)) return 'stale' as const
activeView.value = 'floor'
currentFloor.value = floorId
autoSwitchStateMachine.reset('floor')
@@ -5654,7 +5712,7 @@ const resetToViewBaseline = async (options: ResetViewBaselineOptions) => {
if (activeView.value !== 'overview') {
await loadOverview({ cameraSnapshot: baseline.camera })
}
if (!scene || !isCurrentModelLoad(modelLoadVersion)) return false
if (!scene || !isCurrentModelLoad(modelLoadVersion)) return 'stale' as const
restoreCameraSnapshot(baseline.camera)
currentFloor.value = baseline.floorId
activeView.value = 'overview'
@@ -5665,12 +5723,13 @@ const resetToViewBaseline = async (options: ResetViewBaselineOptions) => {
autoSwitchStateMachine.setFloorInitialDistance(controls.getDistance())
}
refreshPoiVisibilityByDistance()
return true
return 'applied' as const
} catch (error) {
if (isStaleModelLoadError(error)) return 'stale' as const
if (!isStaleModelLoadError(error)) {
console.error('恢复馆内导览初始状态失败:', error)
}
return false
return 'failed' as const
} finally {
isLoading.value = false
}

View File

@@ -240,6 +240,7 @@ import { computed, ref, watch } from 'vue'
import TencentMap from '@/components/map/TencentMap.vue'
// #ifdef H5
import ThreeMap from '@/components/map/ThreeMap.vue'
import type { ResetViewBaselineResult } from '@/components/map/ThreeMap.vue'
// #endif
import type {
GuideModelSource,
@@ -464,8 +465,8 @@ const indoorRendererRef = ref<{
view: 'overview' | 'floor'
floorId?: string
reason: 'poi-detail-close' | 'manual-reset' | 'floor-reset'
}) => Promise<boolean> | boolean
resetToInitialState?: () => Promise<boolean> | boolean
}) => Promise<ResetViewBaselineResult> | ResetViewBaselineResult
resetToInitialState?: () => Promise<ResetViewBaselineResult> | ResetViewBaselineResult
disableAutoSwitchTemporarily?: (durationMs: number) => void
} | null>(null)
@@ -790,8 +791,8 @@ defineExpose({
view: 'overview' | 'floor'
floorId?: string
reason: 'poi-detail-close' | 'manual-reset' | 'floor-reset'
}) => indoorRendererRef.value?.resetToViewBaseline?.(options) || false,
resetToInitialState: () => indoorRendererRef.value?.resetToInitialState?.() || false
}) => indoorRendererRef.value?.resetToViewBaseline?.(options) || 'not-ready',
resetToInitialState: () => indoorRendererRef.value?.resetToInitialState?.() || 'not-ready'
})
</script>