修复馆内三维点位显示异常
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-04 23:42:05 +08:00
parent f03783201d
commit 39f1fc1198
5 changed files with 629 additions and 47 deletions

View File

@@ -38,6 +38,12 @@ import {
const SDK_FLOOR_BUNDLE_CONCURRENCY = 2
const getNow = () => (
typeof performance !== 'undefined' && typeof performance.now === 'function'
? performance.now()
: Date.now()
)
const toRenderPoi = (poi: StaticNavPoiPayload): GuideRenderPoi => ({
id: poi.id,
name: poi.name,
@@ -77,6 +83,26 @@ const dedupeRenderPoisById = (pois: GuideRenderPoi[]) => {
})
}
const countByValue = <T>(
items: T[],
selector: (item: T) => string | number | null | undefined
) => items.reduce<Record<string, number>>((counts, item) => {
const key = String(selector(item) || '<missing>')
counts[key] = (counts[key] || 0) + 1
return counts
}, {})
const countDroppedRenderPoiCategories = (
sourcePois: GuideRenderPoi[],
keptPois: GuideRenderPoi[]
) => {
const keptIds = new Set(keptPois.map((poi) => poi.id))
return countByValue(
sourcePois.filter((poi) => !keptIds.has(poi.id)),
(poi) => poi.primaryCategory
)
}
const trimTrailingSlash = (value: string) => value.replace(/\/+$/, '')
const resolveSgsAssetUrl = (url?: string | null) => {
@@ -135,6 +161,37 @@ const warnSgsGuideModelDiagnostics = (
console.warn(`[SGS guide model] ${message}`, payload)
}
const stringifyDiagnosticPayload = (payload: Record<string, unknown>) => {
try {
return JSON.stringify(payload)
} catch {
return '[unserializable]'
}
}
const logSgsGuideModelDiagnostics = (
message: string,
payload: Record<string, unknown>
) => {
if (!import.meta.env.DEV) return
if (typeof window !== 'undefined') {
const diagnosticsWindow = window as unknown as {
__GUIDE_3D_DIAGNOSTIC_EVENTS__?: Array<{
source: string
event: string
payload: Record<string, unknown>
}>
}
diagnosticsWindow.__GUIDE_3D_DIAGNOSTIC_EVENTS__ ||= []
diagnosticsWindow.__GUIDE_3D_DIAGNOSTIC_EVENTS__.push({
source: 'SGS guide model',
event: message,
payload
})
}
console.debug(`[SGS guide model] ${message} ${stringifyDiagnosticPayload(payload)}`)
}
const summarizeYValues = (pois: GuideRenderPoi[]) => {
const values = pois
.map((poi) => poi.positionGltf?.[1])
@@ -228,9 +285,22 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
constructor(private readonly provider: SgsSdkApiProvider = defaultSgsSdkApiProvider) {}
async loadPackage(): Promise<GuideModelRenderPackage> {
const startedAt = getNow()
const manifest = await this.provider.getManifest()
const allFloors = sortSgsFloors(manifest.floors)
const floors = allFloors.filter(isIndoorNavigableFloor)
const overviewFloor = allFloors.find((floor) => !isIndoorNavigableFloor(floor))
const overviewBundleRequest = overviewFloor
? this.provider.getFloorBundle(String(overviewFloor.floorId)).catch((error) => {
warnSgsGuideModelDiagnostics('overview bundle request failed', {
floorId: String(overviewFloor.floorId),
floorCode: overviewFloor.floorCode,
error: error instanceof Error ? error.message : String(error)
})
return null
})
: Promise.resolve(null)
this.floorsCache = floors
const bundleResults = await mapWithConcurrency(
@@ -291,10 +361,7 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
})
.filter((asset): asset is GuideModelFloorAsset => Boolean(asset?.modelUrl))
const overviewFloor = allFloors.find((floor) => !isIndoorNavigableFloor(floor))
const overviewBundle = overviewFloor
? await this.provider.getFloorBundle(String(overviewFloor.floorId)).catch(() => null)
: null
const overviewBundle = await overviewBundleRequest
const overviewModelUrls = uniqueModelUrls([
overviewBundle?.model?.modelUrl,
overviewBundle?.model?.fallbackModelUrl,
@@ -306,6 +373,15 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
...asset,
sharedModelAsset: isSharedSgsModelAsset(asset.modelUrl, overviewModelUrl, floorModelUrls)
}))
logSgsGuideModelDiagnostics('render package ready', {
elapsedMs: Math.round(getNow() - startedAt),
mapId: manifest.mapId,
mode: dataSourceConfig.mode,
overviewFloorId: overviewFloor ? String(overviewFloor.floorId) : '',
overviewModelUrl,
floorCount: floorAssets.length,
floorBundleCount: bundleResults.filter((result) => Boolean(result.bundle)).length
})
return {
overviewModelUrl,
@@ -377,14 +453,28 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
}
const hallPois = museumHallPois.map(toSgsRenderPoi)
const renderPois = dedupeRenderPoisById([
const adaptedPois = dedupeRenderPoisById([
...hallPois,
...ordinaryPois
])
.filter((poi) => poi.floorId === resolvedFloorId)
const floorMatchedPois = adaptedPois.filter((poi) => poi.floorId === resolvedFloorId)
const renderPois = floorMatchedPois
.filter((poi) => Array.isArray(poi.positionGltf) && poi.positionGltf.length === 3)
const renderHallPois = renderPois.filter((poi) => poi.kind === 'hall' || poi.primaryCategory === 'exhibition_hall')
logSgsGuideModelDiagnostics('floor POI category diagnostics', {
floorId: resolvedFloorId,
floorCode: matchedFloor.floorCode,
rawPoiCount: pois.length,
rawPoiTypeCounts: countByValue(pois, (poi) => poi.type),
rawPoiGroupCounts: countByValue(pois, (poi) => poi.poiGroup),
adaptedPoiCount: adaptedPois.length,
adaptedCategoryCounts: countByValue(adaptedPois, (poi) => poi.primaryCategory),
adaptedPoiCategoryCount: adaptedPois.filter((poi) => poi.primaryCategory === 'poi').length,
renderPoiCount: renderPois.length,
renderPoiCategoryCount: renderPois.filter((poi) => poi.primaryCategory === 'poi').length,
repositoryDroppedCategoryCounts: countDroppedRenderPoiCategories(adaptedPois, renderPois)
})
warnSgsGuideModelDiagnostics('floor render POI diagnostics', {
floorId: resolvedFloorId,
floorCode: matchedFloor.floorCode,