修复 SGS SDK 导览数据源与模型加载

升级 SDK API 数据契约,补齐 guideStops、业务 POI、诊断与路线数据接口。

修复 SDK 模式下 POI/模型/楼层混用静态数据的问题,并为 ThreeMap 模型加载增加短退避重试。
This commit is contained in:
lyf
2026-07-02 10:26:52 +08:00
parent 9efcef5190
commit 7cda427de9
13 changed files with 966 additions and 104 deletions

View File

@@ -255,7 +255,6 @@ export class SgsSdkGuideRepository implements GuideRepository {
private floorsCache: MuseumFloor[] | null = null
private poiCache: MuseumPoi[] | null = null
private floorAliases: Map<string, string> | null = null
private readonly staticFallback = new StaticGuideRepository()
constructor(private readonly provider: SgsSdkApiProvider = defaultSgsSdkApiProvider) {}
@@ -331,7 +330,7 @@ export class SgsSdkGuideRepository implements GuideRepository {
const pois = await this.listPois()
return pois.find((poi) => poi.id === id)
|| findPoiByNavIdNameFallback(pois, id)
|| this.staticFallback.getPoiById(id)
|| null
}
async searchPois(keyword = '') {

View File

@@ -14,6 +14,7 @@ import {
} from '@/repositories/GuideRouteRepository'
import {
defaultSgsSdkApiProvider,
type SgsFloorDiagnosticsPayload,
type SgsNavigablePlacePayload,
type SgsSdkApiProvider
} from '@/data/providers/sgsSdkApiProvider'
@@ -29,13 +30,40 @@ const createUnavailableReadiness = (message: string): GuideRouteReadiness => ({
})
const logSdkRouteReadinessIssue = (message: string, payload: Record<string, unknown>) => {
console.error(`[SDKRouteReadiness] ${message}`, payload)
console.warn(`[SDKRouteReadiness] ${message}`, payload)
}
const toNumber = (value: unknown) => (
Number.isFinite(Number(value)) ? Number(value) : undefined
)
const isPositiveNumber = (value: unknown) => {
const numberValue = toNumber(value)
return typeof numberValue === 'number' && numberValue > 0
}
const hasRouteNodeId = (place: SgsNavigablePlacePayload) => (
place.nodeId !== null && place.nodeId !== undefined && place.nodeId !== ''
)
const hasRouteGraphEvidence = (floor: Pick<SgsFloorDiagnosticsPayload, 'routePlanningReady' | 'routeNodeCount' | 'routeEdgeCount'>) => (
floor.routePlanningReady === true
|| (isPositiveNumber(floor.routeNodeCount) && isPositiveNumber(floor.routeEdgeCount))
)
const hasRouteTargetEvidence = (
floor: Pick<SgsFloorDiagnosticsPayload, 'navigablePlaceCount'>,
routeTargetCount?: number
) => {
if (typeof routeTargetCount === 'number') return routeTargetCount > 0
return floor.navigablePlaceCount === undefined || isPositiveNumber(floor.navigablePlaceCount)
}
const isRouteReadyFromDiagnostics = (
floor: Pick<SgsFloorDiagnosticsPayload, 'routePlanningReady' | 'routeNodeCount' | 'routeEdgeCount' | 'navigablePlaceCount'>,
routeTargetCount?: number
) => hasRouteGraphEvidence(floor) && hasRouteTargetEvidence(floor, routeTargetCount)
const positionFromPlace = (place: SgsNavigablePlacePayload): [number, number, number] | undefined => {
const source = place.position || {
x: place.x,
@@ -70,36 +98,42 @@ export class SdkGuideRouteRepository {
return createUnavailableReadiness('SDK 地图楼层数据为空')
}
// 收集有路线数据的楼层
const readyFloors = floors.filter(
(floor) =>
floor.routePlanningReady &&
floor.routeNodeCount &&
floor.routeNodeCount > 0 &&
floor.routeEdgeCount &&
floor.routeEdgeCount > 0
)
// 地图级 diagnostics 的楼层摘要只保证 routePlanningReady/navigablePlaceCount
// routeNodeCount/routeEdgeCount 可能只出现在 floor diagnostics 或 summary 中。
let readyFloors = floors.filter((floor) => isRouteReadyFromDiagnostics(floor))
let notReadyFloors = floors.filter((floor) => !isRouteReadyFromDiagnostics(floor))
if (readyFloors.length === 0) {
const floorEvidence = await Promise.all(
floors.map((floor) => this.loadFloorRouteEvidence(floor))
)
readyFloors = floorEvidence
.filter((item) => item.ready)
.map((item) => item.floor)
notReadyFloors = floorEvidence
.filter((item) => !item.ready)
.map((item) => item.floor)
}
// 没有楼层有路线数据时不可用
if (readyFloors.length === 0) {
logSdkRouteReadinessIssue('SDK 路线数据不完整', {
logSdkRouteReadinessIssue('SDK 路线数据未达到位置关系生成条件', {
floorCount: floors.length,
readyFloorCount: readyFloors.length,
summary: diagnostics.summary,
floors: floors.map((floor) => ({
floorId: floor.floorId,
floorName: floor.floorName,
floorCode: floor.floorCode,
routePlanningReady: floor.routePlanningReady,
routeNodeCount: floor.routeNodeCount,
routeEdgeCount: floor.routeEdgeCount
routeEdgeCount: floor.routeEdgeCount,
navigablePlaceCount: floor.navigablePlaceCount
}))
})
return createUnavailableReadiness('无法定位,当前仅支持点位位置预览')
}
// 收集未就绪的楼层
const notReadyFloors = floors.filter((floor) => !floor.routePlanningReady)
// 如果有楼层未就绪,给出警告但仍然可用
if (notReadyFloors.length > 0) {
const floorLabels = notReadyFloors
@@ -125,6 +159,25 @@ export class SdkGuideRouteRepository {
}
}
private async loadFloorRouteEvidence(floor: SgsFloorDiagnosticsPayload) {
const rawFloorId = stringifyId(floor.floorId)
const [floorDiagnostics, navigablePlaces] = await Promise.all([
this.sdkApiProvider.getFloorDiagnostics(rawFloorId).catch(() => null),
this.sdkApiProvider.getNavigablePlaces(rawFloorId).catch(() => [])
])
const routeTargetCount = navigablePlaces.filter(hasRouteNodeId).length
const evidence = floorDiagnostics || floor
return {
floor: {
...floor,
...floorDiagnostics
},
ready: isRouteReadyFromDiagnostics(evidence, routeTargetCount),
routeTargetCount
}
}
async listRouteTargets(): Promise<GuideRouteTarget[]> {
if (this.targetsCache) return this.targetsCache
@@ -141,7 +194,7 @@ export class SdkGuideRouteRepository {
for (const place of places) {
// 过滤掉没有 nodeId 的点位,这些无法用于路线规划
if (place.nodeId === null || place.nodeId === undefined || place.nodeId === '') {
if (!hasRouteNodeId(place)) {
continue
}