修复 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

@@ -26,6 +26,27 @@ export interface SgsSdkManifestPayload {
capabilities?: Record<string, boolean | undefined>
}
export type SgsPoiGroupPayload = 'SERVICE' | 'BUSINESS' | 'OTHER'
export type SgsBusinessPoiTypePayload =
| 'shop'
| 'restaurant'
| 'cafe'
| 'vending'
| 'bookstore'
| 'cultural_shop'
| 'photo_spot'
| string
export interface SgsPoiQueryParamsPayload {
mapId?: string | number
floorId?: string | number
group?: SgsPoiGroupPayload
types?: string[]
keyword?: string
limit?: number
}
export interface SgsPositionPayload {
x?: number | null
y?: number | null
@@ -47,6 +68,14 @@ export interface SgsPoiPayload {
anchorNodeName?: string | null
description?: string | null
iconUrl?: string | null
poiGroup?: SgsPoiGroupPayload | string | null
businessType?: SgsBusinessPoiTypePayload | null
coverImageUrl?: string | null
phone?: string | null
businessHours?: string | null
sortOrder?: number | null
spatialAreaId?: string | number | null
spatialAreaName?: string | null
}
export interface SgsSpacePayload {
@@ -79,6 +108,36 @@ export interface SgsNavigablePlacePayload {
ownerName?: string | null
}
export interface SgsGuideStopPayload {
id: string | number
name?: string | null
type?: string | null
typeName?: string | null
floorId?: string | number | null
position?: SgsPositionPayload | null
x?: number | null
y?: number | null
z?: number | null
targetType?: string | null
targetId?: string | number | null
audioUrl?: string | null
coverImageUrl?: string | null
description?: string | null
status?: string | null
located?: boolean | null
hasAudio?: boolean | null
poiId?: string | number | null
outlineId?: string | number | null
outlineName?: string | null
hallId?: string | number | null
hallName?: string | null
sort?: number | null
routeId?: string | number | null
routeName?: string | null
seqOrder?: number | null
stayMinutes?: number | null
}
export interface SgsFloorDiagnosticsPayload {
floorId: string | number
floorCode?: string | null
@@ -121,7 +180,7 @@ export interface SgsFloorBundlePayload {
model?: SgsModelInfoPayload | null
pois?: SgsPoiPayload[]
spaces?: SgsSpacePayload[]
guideStops?: unknown[]
guideStops?: SgsGuideStopPayload[]
routeSummary?: {
hasRouteNetwork?: boolean
nodeCount?: number
@@ -196,6 +255,54 @@ export interface SgsRoutePlanResponsePayload {
segments?: SgsRouteSegmentPayload[]
}
export interface SgsRouteEndpointPayload {
id?: string | number | null
name?: string | null
floorId?: string | number | null
floorCode?: string | null
floorName?: string | null
x?: number | null
y?: number | null
z?: number | null
}
export interface SgsFeaturedRouteSummaryPayload {
id: string | number
mapId?: string | number | null
routeName?: string | null
routeNameEn?: string | null
routeType?: string | null
theme?: string | null
description?: string | null
coverImageUrl?: string | null
estimatedDuration?: number | null
distanceMeters?: number | null
waypointCount?: number | null
sortOrder?: number | null
status?: string | number | null
}
export interface SgsFeaturedRouteWaypointPayload {
order?: number | null
spaceId?: string | number | null
spaceName?: string | null
guideStopId?: string | number | null
guideStopName?: string | null
floorId?: string | number | null
floorCode?: string | null
floorName?: string | null
x?: number | null
y?: number | null
z?: number | null
stayMinutes?: number | null
}
export interface SgsFeaturedRouteDetailPayload extends SgsFeaturedRouteSummaryPayload {
startEntrance?: SgsRouteEndpointPayload | null
endEntrance?: SgsRouteEndpointPayload | null
waypoints?: SgsFeaturedRouteWaypointPayload[]
}
interface CommonResult<T> {
code: number
msg?: string
@@ -209,7 +316,19 @@ export interface SgsSdkApiProvider {
getFloorBundle(floorId: string): Promise<SgsFloorBundlePayload>
getFloorPois(floorId: string): Promise<SgsPoiPayload[]>
getFloorSpaces(floorId: string): Promise<SgsSpacePayload[]>
getGuideStops(floorId: string): Promise<SgsGuideStopPayload[]>
getGuideStopsByHall(hallId: string): Promise<SgsGuideStopPayload[]>
getNavigablePlaces(floorId: string): Promise<SgsNavigablePlacePayload[]>
getFloorBusinessPois(
floorId: string,
options?: { types?: string[]; keyword?: string; limit?: number }
): Promise<SgsPoiPayload[]>
queryPois(params: SgsPoiQueryParamsPayload): Promise<SgsPoiPayload[]>
getFeaturedRoutes(
mapId?: string,
options?: { limit?: number }
): Promise<SgsFeaturedRouteSummaryPayload[]>
getFeaturedRoute(routeId: string): Promise<SgsFeaturedRouteDetailPayload>
planRoute(payload: SgsRoutePlanRequestPayload): Promise<SgsRoutePlanResponsePayload>
}
@@ -295,6 +414,21 @@ const requestJson = <T>(
})
})
const buildQueryString = (params: object) => {
const query = new URLSearchParams()
Object.entries(params as Record<string, unknown>).forEach(([key, value]) => {
if (value === null || typeof value === 'undefined' || value === '') return
query.set(key, Array.isArray(value) ? value.join(',') : String(value))
})
const queryString = query.toString()
return queryString ? `?${queryString}` : ''
}
const stableCacheKey = (value: unknown) => JSON.stringify(value)
export const createSgsSdkApiProvider = (): SgsSdkApiProvider => {
const manifestCache = new Map<string, SgsSdkManifestPayload>()
const mapDiagnosticsCache = new Map<string, SgsMapDiagnosticsPayload>()
@@ -302,10 +436,17 @@ export const createSgsSdkApiProvider = (): SgsSdkApiProvider => {
const floorBundleCache = new Map<string, SgsFloorBundlePayload>()
const floorPoiCache = new Map<string, SgsPoiPayload[]>()
const floorSpaceCache = new Map<string, SgsSpacePayload[]>()
const floorGuideStopCache = new Map<string, SgsGuideStopPayload[]>()
const hallGuideStopCache = new Map<string, SgsGuideStopPayload[]>()
const navigablePlaceCache = new Map<string, SgsNavigablePlacePayload[]>()
const floorBusinessPoiCache = new Map<string, SgsPoiPayload[]>()
const poiQueryCache = new Map<string, SgsPoiPayload[]>()
const featuredRoutesCache = new Map<string, SgsFeaturedRouteSummaryPayload[]>()
const featuredRouteDetailCache = new Map<string, SgsFeaturedRouteDetailPayload>()
const mapIdFor = (mapId?: string) => mapId || dataSourceConfig.sgsMapId
const floorIdFor = (floorId: string) => encodeURIComponent(floorId)
const hallIdFor = (hallId: string) => encodeURIComponent(hallId)
return {
async getManifest(mapId) {
@@ -370,6 +511,26 @@ export const createSgsSdkApiProvider = (): SgsSdkApiProvider => {
floorSpaceCache.set(floorId, spaces)
return spaces
},
async getGuideStops(floorId) {
const cached = floorGuideStopCache.get(floorId)
if (cached) return cached
const guideStops = await requestJson<SgsGuideStopPayload[]>(
`/gis/sdk/floors/${floorIdFor(floorId)}/guide-stops`
)
floorGuideStopCache.set(floorId, guideStops)
return guideStops
},
async getGuideStopsByHall(hallId) {
const cached = hallGuideStopCache.get(hallId)
if (cached) return cached
const guideStops = await requestJson<SgsGuideStopPayload[]>(
`/gis/sdk/halls/${hallIdFor(hallId)}/guide-stops`
)
hallGuideStopCache.set(hallId, guideStops)
return guideStops
},
async getNavigablePlaces(floorId) {
const cached = navigablePlaceCache.get(floorId)
if (cached) return cached
@@ -380,6 +541,50 @@ export const createSgsSdkApiProvider = (): SgsSdkApiProvider => {
navigablePlaceCache.set(floorId, places)
return places
},
async getFloorBusinessPois(floorId, options = {}) {
const cacheKey = `${floorId}:${stableCacheKey(options)}`
const cached = floorBusinessPoiCache.get(cacheKey)
if (cached) return cached
const pois = await requestJson<SgsPoiPayload[]>(
`/gis/sdk/floors/${floorIdFor(floorId)}/business-pois${buildQueryString(options)}`
)
floorBusinessPoiCache.set(cacheKey, pois)
return pois
},
async queryPois(params) {
const cacheKey = stableCacheKey(params)
const cached = poiQueryCache.get(cacheKey)
if (cached) return cached
const pois = await requestJson<SgsPoiPayload[]>(
`/gis/sdk/pois${buildQueryString(params)}`
)
poiQueryCache.set(cacheKey, pois)
return pois
},
async getFeaturedRoutes(mapId, options = {}) {
const normalizedMapId = mapIdFor(mapId)
const cacheKey = `${normalizedMapId}:${stableCacheKey(options)}`
const cached = featuredRoutesCache.get(cacheKey)
if (cached) return cached
const routes = await requestJson<SgsFeaturedRouteSummaryPayload[]>(
`/gis/sdk/maps/${encodeURIComponent(normalizedMapId)}/featured-routes${buildQueryString(options)}`
)
featuredRoutesCache.set(cacheKey, routes)
return routes
},
async getFeaturedRoute(routeId) {
const cached = featuredRouteDetailCache.get(routeId)
if (cached) return cached
const route = await requestJson<SgsFeaturedRouteDetailPayload>(
`/gis/sdk/featured-routes/${encodeURIComponent(routeId)}`
)
featuredRouteDetailCache.set(routeId, route)
return route
},
async planRoute(payload) {
return requestJson<SgsRoutePlanResponsePayload>(
'/gis/sdk/routes/plan',