同步移动端源码并修复小程序嵌入标题
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-28 18:37:40 +08:00
parent 06ad609e1f
commit 540bb8627f
62 changed files with 4196 additions and 1410 deletions

View File

@@ -164,6 +164,10 @@ import {
createGuideObliqueReturnPose,
createGuideTopViewPose
} from '@/domain/guideTopView'
import {
hasReachedOutdoorExitBoundary,
OUTDOOR_OUTWARD_INTENT_GRACE_MS
} from '@/domain/guideSemanticZoom'
import {
getOverviewMapLabelDefinition,
isOverviewMapLabelMatch,
@@ -193,6 +197,7 @@ import {
type PoiVisibilityTier
} from '@/domain/poiDisplay'
import {
ensurePoiIconSprite,
getPoiIconHref,
resolvePoiIconKey,
type PoiIconKey
@@ -306,7 +311,9 @@ const SGS_VISUAL_RENDER_CONFIG = {
framing: {
overviewScreenOffsetRatio: new THREE.Vector2(-0.045, -0.095),
overviewReferenceVerticalOffset: 44,
overviewMaxDistanceFactor: 1.35,
// Keep two to three zoom-out levels of the 3D building overview before
// the semantic boundary hands the visitor to the Tencent outdoor map.
overviewMaxDistanceFactor: 1.85,
// The left floor rail and right zoom tools make the geometric center look
// left-biased. Shift the floor framing right into the visible map area.
floorScreenOffsetRatio: new THREE.Vector2(-0.05, -0.055)
@@ -712,6 +719,7 @@ const props = withDefaults(defineProps<{
autoSwitch?: boolean
disableAutoExit?: boolean
autoSwitchCooldown?: number
semanticZoomEnabled?: boolean
}>(), {
assetBaseUrl: '',
activeFloor: '',
@@ -735,7 +743,8 @@ const props = withDefaults(defineProps<{
sceneViewport: null,
autoSwitch: true,
disableAutoExit: false,
autoSwitchCooldown: 1500
autoSwitchCooldown: 1500,
semanticZoomEnabled: false
})
const emit = defineEmits<{
@@ -760,6 +769,7 @@ const emit = defineEmits<{
sceneRevision: number
}]
autoSwitchBlocked: [reason: { reason: 'loading-locked' | 'cooldown' | 'disabled' }]
semanticExteriorExit: []
initialModelProgress: [event: InitialModelProgressEvent]
initialModelReady: [event: { view: ViewMode; floorId?: string; elapsedMs?: number }]
initialModelFailed: [event: {
@@ -983,6 +993,9 @@ let hasPendingManualModelAdjustment = false
let activeAutoSwitchInputSource: GuideAutoSwitchInputSource = 'gesture'
let isProgrammaticCameraChange = false
let hasActiveUserCameraGesture = false
let overviewGestureStartDistance = 0
let semanticOutwardZoomIntentAt = 0
let semanticExteriorExitRequested = false
let programmaticCameraTimer: ReturnType<typeof setTimeout> | null = null
let cameraTween: CameraTweenState | null = null
let buttonAutoSwitchTimer: ReturnType<typeof setTimeout> | null = null
@@ -2572,6 +2585,7 @@ const handleControlStart = () => {
const distance = controls?.getDistance()
if (!isProgrammaticCameraChange && typeof distance === 'number' && Number.isFinite(distance)) {
hasActiveUserCameraGesture = true
overviewGestureStartDistance = activeView.value === 'overview' ? distance : 0
autoSwitchStateMachine.beginInput(distance, activeAutoSwitchInputSource)
}
if (!isProgrammaticCameraChange) {
@@ -2582,7 +2596,9 @@ const handleControlStart = () => {
}
const handleControlEnd = () => {
requestSemanticExteriorExitFromGesture()
hasActiveUserCameraGesture = false
overviewGestureStartDistance = 0
activeAutoSwitchInputSource = 'gesture'
scheduleModelAdjustIdleReport()
}
@@ -2797,6 +2813,7 @@ const waitForContainer = async () => {
}
const initThree = async () => {
ensurePoiIconSprite()
const container = await waitForContainer()
if (!container) {
throw new Error('3D 容器未就绪')
@@ -5144,9 +5161,46 @@ const handleWheelIntent = (event: WheelEvent) => {
if (!Number.isFinite(distance)) return
activeAutoSwitchInputSource = 'wheel'
if (event.deltaY > 0) semanticOutwardZoomIntentAt = Date.now()
autoSwitchStateMachine.beginInput(distance, 'wheel')
}
const canRequestSemanticExteriorExit = () => (
props.semanticZoomEnabled
&& !semanticExteriorExitRequested
&& !weakNetworkFallbackActive.value
&& !isLoading.value
&& !isProgrammaticCameraChange
&& Boolean(controls)
&& activeView.value === 'overview'
&& !props.showRoute
&& !props.routeNavigationActive
&& !props.routeStartSelectionActive
&& !props.targetFocus
&& !selectedPOI.value
)
const requestSemanticExteriorExit = () => {
if (!canRequestSemanticExteriorExit()) return false
semanticExteriorExitRequested = true
emit('semanticExteriorExit')
return true
}
const requestSemanticExteriorExitFromGesture = () => {
if (!canRequestSemanticExteriorExit() || !controls || !overviewGestureStartDistance) return
const currentDistance = controls.getDistance()
const maxDistance = controls.maxDistance
const outwardGesture = currentDistance > overviewGestureStartDistance * 1.025
const atExteriorBoundary = hasReachedOutdoorExitBoundary(currentDistance, maxDistance)
const recentWheelIntent = Date.now() - semanticOutwardZoomIntentAt < OUTDOOR_OUTWARD_INTENT_GRACE_MS
if (atExteriorBoundary && (outwardGesture || recentWheelIntent)) {
requestSemanticExteriorExit()
}
}
const canRunAutoSwitch = (direction: GuideAutoSwitchDirection) => {
if (
!props.autoSwitch
@@ -6262,15 +6316,24 @@ const handleWeakNetworkZoomIntent = async (event: {
boundaryAttempt: boolean
referenceVisibleWorldSpan: number | null
thresholdReached: boolean
outdoorExitReached: boolean
viewport: GuideViewportState
}) => {
if (
!weakNetworkFallbackActive.value
|| isLoading.value
|| !props.autoSwitch
|| weakNetworkSceneTransitionInFlight
) return
const from = activeView.value
if (
from === 'overview'
&& event.direction === 'out'
&& event.outdoorExitReached
&& requestWeakNetworkSemanticExteriorExit()
) return
if (!props.autoSwitch) return
const shouldEnterFloor = from === 'overview' && event.direction === 'in'
const shouldExitOverview = from === 'floor' && event.direction === 'out'
if (!shouldEnterFloor && !shouldExitOverview) return
@@ -6340,6 +6403,26 @@ const handleWeakNetworkZoomIntent = async (event: {
}
}
const canRequestWeakNetworkSemanticExteriorExit = () => (
props.semanticZoomEnabled
&& !semanticExteriorExitRequested
&& weakNetworkFallbackActive.value
&& !isLoading.value
&& activeView.value === 'overview'
&& !props.showRoute
&& !props.routeNavigationActive
&& !props.routeStartSelectionActive
&& !props.targetFocus
&& !selectedPOI.value
)
const requestWeakNetworkSemanticExteriorExit = () => {
if (!canRequestWeakNetworkSemanticExteriorExit()) return false
semanticExteriorExitRequested = true
emit('semanticExteriorExit')
return true
}
const zoomCamera = (direction: 'in' | 'out', options: { source?: ZoomCameraSource } = {}) => {
if (weakNetworkFallbackActive.value) {
const source = options.source || 'button'
@@ -6369,6 +6452,13 @@ const zoomCamera = (direction: 'in' | 'out', options: { source?: ZoomCameraSourc
if (!Number.isFinite(nextDistance) || nextDistance <= 0) return
if (
direction === 'out'
&& activeView.value === 'overview'
&& hasReachedOutdoorExitBoundary(nextDistance, maxDistance)
&& requestSemanticExteriorExit()
) return
const shouldTrackUserZoom = options.source === 'button'
if (shouldTrackUserZoom) {
trackButtonZoomForAutoSwitch(currentDistance, nextDistance)
@@ -7115,7 +7205,9 @@ const createPoiDomLabelIcon = (iconKey: PoiIconKey) => {
svg.setAttribute('data-poi-icon', iconKey)
const use = document.createElementNS('http://www.w3.org/2000/svg', 'use')
use.setAttribute('href', getPoiIconHref(iconKey))
const iconHref = getPoiIconHref(iconKey)
use.setAttribute('href', iconHref)
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', iconHref)
svg.appendChild(use)
return svg
}