chore: expose SGS hall POI diagnostics
This commit is contained in:
24
.superpowers/sdd/task-3-report.md
Normal file
24
.superpowers/sdd/task-3-report.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Task 3 Report
|
||||
|
||||
Status: DONE
|
||||
|
||||
Files changed:
|
||||
- `src/repositories/GuideModelRepository.ts`
|
||||
|
||||
Commands run:
|
||||
- `node scripts/check-sgs-hall-poi-adapter.mjs`
|
||||
- Output: `SGS hall POI adapter smoke check passed`
|
||||
- `pnpm type-check`
|
||||
- Output summary: `vue-tsc --noEmit` completed successfully in the main workspace.
|
||||
|
||||
Commits created:
|
||||
- Main workspace commit will be created by controller after validation.
|
||||
|
||||
Self-review notes:
|
||||
- Added dev-only SGS guide model diagnostics helper.
|
||||
- Replaced silent floor endpoint catches with guarded diagnostics while preserving empty-array fallback behavior.
|
||||
- Added hall-generation diagnostics for eligible spaces producing no renderable hall POIs and render filtering removing all hall POIs.
|
||||
- No page/component SGS payload parsing was added.
|
||||
|
||||
Concerns:
|
||||
- None after main workspace validation.
|
||||
@@ -12,7 +12,9 @@ import {
|
||||
isIndoorNavigableFloor
|
||||
} from '@/domain/guideFloor'
|
||||
import {
|
||||
createSgsHallPoiDiagnostics,
|
||||
formatSgsFloorLabel,
|
||||
toMuseumHallPoisFromSgs,
|
||||
toMuseumPoiFromSgs
|
||||
} from '@/data/adapters/sgsSdkGuideAdapter'
|
||||
import {
|
||||
@@ -38,7 +40,9 @@ const toRenderPoi = (poi: StaticNavPoiPayload): GuideRenderPoi => ({
|
||||
primaryCategoryZh: poi.primaryCategoryZh,
|
||||
iconType: poi.iconType || poi.primaryCategory,
|
||||
positionGltf: poi.positionGltf,
|
||||
sourceObjectName: poi.sourceObjectName
|
||||
sourceObjectName: poi.sourceObjectName,
|
||||
kind: poi.primaryCategory === 'touring_poi' ? 'hall' : 'facility',
|
||||
hallName: poi.primaryCategory === 'touring_poi' ? poi.name : undefined
|
||||
})
|
||||
|
||||
const toSgsRenderPoi = (
|
||||
@@ -51,9 +55,22 @@ const toSgsRenderPoi = (
|
||||
primaryCategoryZh: poi.primaryCategory.label,
|
||||
iconType: poi.primaryCategory.iconType || poi.primaryCategory.id,
|
||||
positionGltf: poi.positionGltf,
|
||||
sourceObjectName: poi.sourceObjectName
|
||||
sourceObjectName: poi.sourceObjectName,
|
||||
kind: poi.kind,
|
||||
hallId: poi.hallId,
|
||||
hallName: poi.hallName,
|
||||
entrances: poi.entrances
|
||||
})
|
||||
|
||||
const dedupeRenderPoisById = (pois: GuideRenderPoi[]) => {
|
||||
const seen = new Set<string>()
|
||||
return pois.filter((poi) => {
|
||||
if (!poi.id || seen.has(poi.id)) return false
|
||||
seen.add(poi.id)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
const trimTrailingSlash = (value: string) => value.replace(/\/+$/, '')
|
||||
|
||||
const resolveSgsAssetUrl = (url?: string | null) => {
|
||||
@@ -100,6 +117,14 @@ const isSharedSgsModelAsset = (
|
||||
return modelUrl === overviewModelUrl || allModelUrls.filter((url) => url === modelUrl).length > 1
|
||||
}
|
||||
|
||||
const warnSgsGuideModelDiagnostics = (
|
||||
message: string,
|
||||
payload: Record<string, unknown>
|
||||
) => {
|
||||
if (!import.meta.env.DEV) return
|
||||
console.warn(`[SGS guide model] ${message}`, payload)
|
||||
}
|
||||
|
||||
const getSgsFloorModelMatchKeys = (floor: SgsSdkFloorSummaryPayload, label: string) => (
|
||||
[
|
||||
String(floor.floorId),
|
||||
@@ -210,10 +235,55 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
|
||||
))
|
||||
if (!matchedFloor) return []
|
||||
|
||||
const pois = await this.provider.getFloorPois(String(matchedFloor.floorId))
|
||||
return pois
|
||||
.map((poi) => toSgsRenderPoi(toMuseumPoiFromSgs(poi, manifest.floors)))
|
||||
const resolvedFloorId = String(matchedFloor.floorId)
|
||||
const loadFloorData = async <T>(
|
||||
endpoint: 'pois' | 'spaces' | 'navigablePlaces',
|
||||
loader: () => Promise<T[]>
|
||||
) => {
|
||||
try {
|
||||
return await loader()
|
||||
} catch (error) {
|
||||
warnSgsGuideModelDiagnostics('floor data request failed', {
|
||||
floorId: resolvedFloorId,
|
||||
endpoint,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
})
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const [pois, spaces, navigablePlaces] = await Promise.all([
|
||||
loadFloorData('pois', () => this.provider.getFloorPois(resolvedFloorId)),
|
||||
loadFloorData('spaces', () => this.provider.getFloorSpaces(resolvedFloorId)),
|
||||
loadFloorData('navigablePlaces', () => this.provider.getNavigablePlaces(resolvedFloorId))
|
||||
])
|
||||
const ordinaryPois = pois.map((poi) => toSgsRenderPoi(toMuseumPoiFromSgs(poi, manifest.floors)))
|
||||
const museumHallPois = toMuseumHallPoisFromSgs(spaces, navigablePlaces, manifest.floors, resolvedFloorId)
|
||||
const hallDiagnostics = createSgsHallPoiDiagnostics(spaces, navigablePlaces, museumHallPois)
|
||||
|
||||
if (hallDiagnostics.eligibleSpaceCount > 0 && hallDiagnostics.hallPoiWithPositionCount === 0) {
|
||||
warnSgsGuideModelDiagnostics('eligible hall spaces produced no renderable hall POIs', {
|
||||
floorId: resolvedFloorId,
|
||||
...hallDiagnostics
|
||||
})
|
||||
}
|
||||
|
||||
const hallPois = museumHallPois.map(toSgsRenderPoi)
|
||||
const renderPois = dedupeRenderPoisById([
|
||||
...hallPois,
|
||||
...ordinaryPois
|
||||
])
|
||||
.filter((poi) => Array.isArray(poi.positionGltf) && poi.positionGltf.length === 3)
|
||||
|
||||
if (hallDiagnostics.hallPoiWithPositionCount > 0 && !renderPois.some((poi) => poi.primaryCategory === 'exhibition_hall')) {
|
||||
warnSgsGuideModelDiagnostics('render POI filter removed all hall POIs', {
|
||||
floorId: resolvedFloorId,
|
||||
...hallDiagnostics,
|
||||
renderPoiCount: renderPois.length
|
||||
})
|
||||
}
|
||||
|
||||
return renderPois
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user