修复 SGS SDK 导览数据源与模型加载
升级 SDK API 数据契约,补齐 guideStops、业务 POI、诊断与路线数据接口。 修复 SDK 模式下 POI/模型/楼层混用静态数据的问题,并为 ThreeMap 模型加载增加短退避重试。
This commit is contained in:
@@ -350,6 +350,7 @@ const floorExitConfirmThresholdMultiplier = 1.34
|
||||
const floorExitZoomOutIntentMinDeltaRatio = 0.015
|
||||
const floorExitAccumulatedZoomOutRatio = 0.26
|
||||
const floorExitCandidateHoldMs = 900
|
||||
const modelLoadRetryDelaysMs = [300, 900]
|
||||
|
||||
const syncControlInteractionOptions = () => {
|
||||
if (!controls) return
|
||||
@@ -2165,7 +2166,11 @@ const clearSceneData = () => {
|
||||
clearPoiGroupChildren()
|
||||
}
|
||||
|
||||
const loadModel = (
|
||||
const wait = (delayMs: number) => new Promise<void>((resolve) => {
|
||||
window.setTimeout(resolve, delayMs)
|
||||
})
|
||||
|
||||
const loadModelOnce = (
|
||||
url: string,
|
||||
label: string,
|
||||
loadToken?: number,
|
||||
@@ -2193,6 +2198,41 @@ const loadModel = (
|
||||
)
|
||||
})
|
||||
|
||||
const loadModel = async (
|
||||
url: string,
|
||||
label: string,
|
||||
loadToken?: number,
|
||||
options: LoadModelOptions = {}
|
||||
) => {
|
||||
let lastError: unknown = null
|
||||
|
||||
for (let attempt = 0; attempt <= modelLoadRetryDelaysMs.length; attempt += 1) {
|
||||
if (loadToken !== undefined && !isCurrentModelLoad(loadToken)) {
|
||||
throw createStaleModelLoadError()
|
||||
}
|
||||
|
||||
try {
|
||||
return await loadModelOnce(url, label, loadToken, options)
|
||||
} catch (error) {
|
||||
if (loadToken !== undefined && !isCurrentModelLoad(loadToken)) {
|
||||
throw createStaleModelLoadError()
|
||||
}
|
||||
|
||||
lastError = error
|
||||
const retryDelay = modelLoadRetryDelaysMs[attempt]
|
||||
if (retryDelay === undefined) break
|
||||
|
||||
if (!options.suppressProgress) {
|
||||
setProgress(18, `${label} 加载失败,正在重试 ${attempt + 1}/${modelLoadRetryDelaysMs.length}`)
|
||||
}
|
||||
|
||||
await wait(retryDelay)
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError instanceof Error ? lastError : new Error('模型资源加载失败')
|
||||
}
|
||||
|
||||
const prepareModel = (model: THREE.Object3D) => {
|
||||
model.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
|
||||
@@ -6,10 +6,12 @@ import type {
|
||||
GuideLocationPreview,
|
||||
GuideMapDiagnostics,
|
||||
GuideRouteReadiness,
|
||||
MuseumCategory,
|
||||
MuseumFloor,
|
||||
MuseumPoi
|
||||
} from '@/domain/museum'
|
||||
MuseumCategory,
|
||||
MuseumFloor,
|
||||
MuseumPoi,
|
||||
ExplainGuideStop,
|
||||
AudioPlayTargetType
|
||||
} from '@/domain/museum'
|
||||
import {
|
||||
NAV_ROUTE_UNAVAILABLE_MESSAGE
|
||||
} from '@/domain/guideReadiness'
|
||||
@@ -17,23 +19,30 @@ import {
|
||||
isIndoorNavigableFloor
|
||||
} from '@/domain/guideFloor'
|
||||
import type {
|
||||
SgsFloorDiagnosticsPayload,
|
||||
SgsMapDiagnosticsPayload,
|
||||
SgsNavigablePlacePayload,
|
||||
SgsPoiPayload,
|
||||
SgsFloorDiagnosticsPayload,
|
||||
SgsGuideStopPayload,
|
||||
SgsMapDiagnosticsPayload,
|
||||
SgsNavigablePlacePayload,
|
||||
SgsPoiPayload,
|
||||
SgsPositionPayload,
|
||||
SgsSdkFloorSummaryPayload,
|
||||
SgsSdkManifestPayload,
|
||||
SgsSpacePayload
|
||||
} from '@/data/providers/sgsSdkApiProvider'
|
||||
|
||||
const defaultCategory: MuseumCategory = {
|
||||
id: 'operation_experience',
|
||||
label: '导览点位',
|
||||
iconType: 'poi'
|
||||
}
|
||||
|
||||
const hallCategory: MuseumCategory = {
|
||||
const defaultCategory: MuseumCategory = {
|
||||
id: 'operation_experience',
|
||||
label: '导览点位',
|
||||
iconType: 'poi'
|
||||
}
|
||||
|
||||
const businessCategory: MuseumCategory = {
|
||||
id: 'business_poi',
|
||||
label: '运营服务',
|
||||
iconType: 'business'
|
||||
}
|
||||
|
||||
const hallCategory: MuseumCategory = {
|
||||
id: 'exhibition_hall',
|
||||
label: '展厅',
|
||||
iconType: 'exhibition_hall'
|
||||
@@ -45,7 +54,7 @@ const hallEntranceCategory: MuseumCategory = {
|
||||
iconType: 'hall_entrance'
|
||||
}
|
||||
|
||||
const categoryBySgsType: Record<string, MuseumCategory & { accessible?: boolean }> = {
|
||||
const categoryBySgsType: Record<string, MuseumCategory & { accessible?: boolean }> = {
|
||||
toilet: {
|
||||
id: 'basic_service_facility',
|
||||
label: '卫生间',
|
||||
@@ -237,6 +246,16 @@ export interface SgsHallPoiDiagnostics {
|
||||
skippedPlaceCount: number
|
||||
}
|
||||
|
||||
const businessTypeLabels: Record<string, string> = {
|
||||
shop: '商店',
|
||||
restaurant: '餐饮',
|
||||
cafe: '咖啡',
|
||||
vending: '售卖机',
|
||||
bookstore: '书店',
|
||||
cultural_shop: '文创商店',
|
||||
photo_spot: '打卡点'
|
||||
}
|
||||
|
||||
interface SgsHallPoiBuildOptions {
|
||||
fallbackY?: number
|
||||
}
|
||||
@@ -381,13 +400,23 @@ const normalizePlacePosition = (
|
||||
fallbackY
|
||||
)
|
||||
|
||||
const categoryFor = (poi: SgsPoiPayload): MuseumCategory & { accessible?: boolean } => {
|
||||
const normalizedType = poi.type?.trim()
|
||||
if (normalizedType && categoryBySgsType[normalizedType]) {
|
||||
return categoryBySgsType[normalizedType]
|
||||
}
|
||||
|
||||
if (poi.typeName) {
|
||||
const categoryFor = (poi: SgsPoiPayload): MuseumCategory & { accessible?: boolean } => {
|
||||
const normalizedType = poi.type?.trim().toLowerCase()
|
||||
const normalizedBusinessType = poi.businessType?.trim().toLowerCase()
|
||||
|
||||
if (String(poi.poiGroup || '').toUpperCase() === 'BUSINESS') {
|
||||
return {
|
||||
...businessCategory,
|
||||
label: normalizedBusinessType ? businessTypeLabels[normalizedBusinessType] || poi.typeName || businessCategory.label : poi.typeName || businessCategory.label,
|
||||
iconType: normalizedBusinessType || businessCategory.iconType
|
||||
}
|
||||
}
|
||||
|
||||
if (normalizedType && categoryBySgsType[normalizedType]) {
|
||||
return categoryBySgsType[normalizedType]
|
||||
}
|
||||
|
||||
if (poi.typeName) {
|
||||
return {
|
||||
...defaultCategory,
|
||||
label: poi.typeName,
|
||||
@@ -395,8 +424,15 @@ const categoryFor = (poi: SgsPoiPayload): MuseumCategory & { accessible?: boolea
|
||||
}
|
||||
}
|
||||
|
||||
return defaultCategory
|
||||
}
|
||||
return defaultCategory
|
||||
}
|
||||
|
||||
const kindForSgsPoi = (poi: SgsPoiPayload, category: MuseumCategory) => {
|
||||
if (category.id === 'business_poi') return 'facility'
|
||||
if (category.id === 'operation_experience') return 'guide'
|
||||
|
||||
return 'facility'
|
||||
}
|
||||
|
||||
export const toMuseumPoiFromSgs = (
|
||||
poi: SgsPoiPayload,
|
||||
@@ -425,12 +461,41 @@ export const toMuseumPoiFromSgs = (
|
||||
],
|
||||
positionGltf: normalizePosition(poi),
|
||||
sourceObjectName: poi.anchorNodeName || undefined,
|
||||
sourceConfidence: 'backend-sgs-sdk',
|
||||
navigationReadiness: '位置预览',
|
||||
accessible: category.accessible === true,
|
||||
kind: category.id === 'operation_experience' ? 'guide' : 'facility'
|
||||
}
|
||||
}
|
||||
sourceConfidence: 'backend-sgs-sdk',
|
||||
navigationReadiness: '位置预览',
|
||||
accessible: category.accessible === true,
|
||||
kind: kindForSgsPoi(poi, category)
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeAudioTargetType = (targetType?: string | null): AudioPlayTargetType | undefined => {
|
||||
const normalized = targetType?.toUpperCase()
|
||||
if (normalized === 'ITEM' || normalized === 'STOP') return normalized
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
export const toExplainGuideStopFromSgs = (stop: SgsGuideStopPayload): ExplainGuideStop | null => {
|
||||
const id = stringifyId(stop.id)
|
||||
if (!id) return null
|
||||
|
||||
return {
|
||||
id,
|
||||
name: normalizedText(stop.name) || `讲解点${id}`,
|
||||
hallId: stringifyId(stop.hallId) || undefined,
|
||||
hallName: normalizedText(stop.hallName) || undefined,
|
||||
floorId: stringifyId(stop.floorId) || undefined,
|
||||
targetType: normalizeAudioTargetType(stop.targetType) || 'STOP',
|
||||
targetId: stringifyId(stop.targetId) || id,
|
||||
coverImageUrl: normalizedText(stop.coverImageUrl) || undefined,
|
||||
description: normalizedText(stop.description) || undefined,
|
||||
hasAudio: stop.hasAudio === true || Boolean(normalizedText(stop.audioUrl)),
|
||||
poiId: stringifyId(stop.poiId) || undefined,
|
||||
outlineId: stringifyId(stop.outlineId || stop.routeId) || undefined,
|
||||
outlineName: normalizedText(stop.outlineName || stop.routeName) || undefined,
|
||||
sort: optionalNumber(stop.sort ?? stop.seqOrder)
|
||||
}
|
||||
}
|
||||
|
||||
export const toLocationPreviewFromPoi = (poi: MuseumPoi): GuideLocationPreview => ({
|
||||
poiId: poi.id,
|
||||
|
||||
@@ -10,17 +10,22 @@ import {
|
||||
import type {
|
||||
ExplainContentProvider
|
||||
} from '@/data/providers/staticMuseumContentProvider'
|
||||
import {
|
||||
defaultSgsSdkApiProvider,
|
||||
type SgsSdkApiProvider
|
||||
} from '@/data/providers/sgsSdkApiProvider'
|
||||
import {
|
||||
toBackendExplainTrack,
|
||||
toBackendGuideStop,
|
||||
toBackendHallFromList,
|
||||
toBackendMediaAsset,
|
||||
toBackendMuseumExhibit,
|
||||
groupGuideStopsByOutline,
|
||||
type BackendExhibit,
|
||||
type BackendGuideStop,
|
||||
type BackendHall
|
||||
} from '@/data/adapters/backendExplainDataAdapter'
|
||||
import {
|
||||
toExplainGuideStopFromSgs
|
||||
} from '@/data/adapters/sgsSdkGuideAdapter'
|
||||
|
||||
interface CommonResult<T> {
|
||||
code: number
|
||||
@@ -28,7 +33,14 @@ interface CommonResult<T> {
|
||||
data?: T
|
||||
}
|
||||
|
||||
const normalizeBaseUrl = (baseUrl: string) => baseUrl.replace(/\/+$/, '')
|
||||
const normalizeBaseUrl = (baseUrl: string) => {
|
||||
const trimmed = baseUrl.trim().replace(/\/+$/, '')
|
||||
if (!trimmed || /^https?:\/\//i.test(trimmed) || trimmed.startsWith('/')) {
|
||||
return trimmed
|
||||
}
|
||||
|
||||
return `/${trimmed}`
|
||||
}
|
||||
|
||||
const resolveAppApiBaseUrl = () => {
|
||||
const baseUrl = normalizeBaseUrl(dataSourceConfig.apiBaseUrl)
|
||||
@@ -77,7 +89,10 @@ export class BackendExplainContentProvider implements ExplainContentProvider {
|
||||
private readonly guideStopCache = new Map<string, ExplainGuideStop[]>()
|
||||
private readonly guideStopInflight = new Map<string, Promise<ExplainGuideStop[]>>()
|
||||
|
||||
constructor(private readonly fallbackProvider: ExplainContentProvider) {}
|
||||
constructor(
|
||||
private readonly fallbackProvider: ExplainContentProvider,
|
||||
private readonly sgsSdkApiProvider: SgsSdkApiProvider = defaultSgsSdkApiProvider
|
||||
) {}
|
||||
|
||||
private async requestStaticExplainExhibits() {
|
||||
const cached = this.searchCache.get('')
|
||||
@@ -223,14 +238,8 @@ export class BackendExplainContentProvider implements ExplainContentProvider {
|
||||
if (inflight) return inflight
|
||||
|
||||
const promise = (async () => {
|
||||
const url = `${resolveAppApiBaseUrl()}/gis/sdk/halls/${encodeURIComponent(normalizedHallId)}/guide-stops`
|
||||
const response = await requestJson<CommonResult<BackendGuideStop[]>>(url)
|
||||
if (response.code !== 0 || !Array.isArray(response.data)) {
|
||||
throw new Error(response.msg || '后端展厅讲解点加载失败')
|
||||
}
|
||||
|
||||
const stops = response.data
|
||||
.map(toBackendGuideStop)
|
||||
const stops = (await this.sgsSdkApiProvider.getGuideStopsByHall(normalizedHallId))
|
||||
.map(toExplainGuideStopFromSgs)
|
||||
.filter(Boolean) as ExplainGuideStop[]
|
||||
|
||||
this.guideStopCache.set(normalizedHallId, stops)
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -96,12 +96,8 @@ import type {
|
||||
GuideModelSource,
|
||||
GuideRenderPoi
|
||||
} from '@/domain/guideModel'
|
||||
import {
|
||||
StaticGuideModelRepository
|
||||
} from '@/repositories/GuideModelRepository'
|
||||
|
||||
const fallbackIndoorModelSource = new StaticGuideModelRepository()
|
||||
const indoorModelSource = ref<GuideModelSource>(fallbackIndoorModelSource)
|
||||
const indoorModelSource: GuideModelSource = guideUseCase.getModelSource()
|
||||
const guideFloors = ref<MuseumFloor[]>([])
|
||||
const normalizeGuideFloorId = (labelOrId: string) =>
|
||||
guideFloors.value.find((floor) => floor.id === labelOrId || floor.label === labelOrId)?.id
|
||||
@@ -123,19 +119,16 @@ const facility = ref<FacilityDetailViewModel>({
|
||||
|
||||
const loadGuideFloors = async () => {
|
||||
try {
|
||||
const modelPackage = await fallbackIndoorModelSource.loadPackage()
|
||||
guideFloors.value = modelPackage.floors.map((floor) => ({
|
||||
id: floor.floorId,
|
||||
label: floor.label,
|
||||
order: floor.order
|
||||
}))
|
||||
guideFloors.value = await guideUseCase.getFloors()
|
||||
const floors = guideFloors.value
|
||||
const defaultFloor = floors.find((floor) => floor.label === activeFloor.value)?.label
|
||||
|| floors.find((floor) => floor.id === 'L1')?.label
|
||||
|| floors[0]?.label
|
||||
const normalizedActiveFloorId = activeFloor.value
|
||||
? normalizeGuideFloorId(activeFloor.value)
|
||||
: ''
|
||||
const defaultFloor = floors.find((floor) => floor.id === normalizedActiveFloorId)?.id
|
||||
|| floors.find((floor) => floor.label === '1F')?.id
|
||||
|| floors[0]?.id
|
||||
|| activeFloor.value
|
||||
activeFloor.value = floors.find((floor) => floor.label === activeFloor.value)?.label
|
||||
|| defaultFloor
|
||||
activeFloor.value = defaultFloor
|
||||
} catch (error) {
|
||||
console.error('加载导览楼层失败:', error)
|
||||
guideFloors.value = []
|
||||
@@ -146,7 +139,7 @@ const focusFacilityPoi = (poi: MuseumPoi) => {
|
||||
if (!poi.floorId) return
|
||||
|
||||
activeMode.value = '3d'
|
||||
activeFloor.value = poi.floorLabel
|
||||
activeFloor.value = poi.floorId
|
||||
targetFocusRequestId.value += 1
|
||||
targetFocusRequest.value = toTargetFocusRequestViewModel({
|
||||
poiId: poi.id,
|
||||
@@ -164,7 +157,7 @@ const focusRenderPoi = (poi: GuideRenderPoi) => {
|
||||
|
||||
const floorLabel = guideFloors.value.find((floor) => floor.id === poi.floorId)?.label || poi.floorId
|
||||
activeMode.value = '3d'
|
||||
activeFloor.value = floorLabel
|
||||
activeFloor.value = poi.floorId
|
||||
targetFocusRequestId.value += 1
|
||||
targetFocusRequest.value = toTargetFocusRequestViewModel({
|
||||
poiId: poi.id,
|
||||
@@ -242,10 +235,10 @@ const resolveRenderPoiByName = async () => {
|
||||
const normalizedTarget = normalizePoiName(facility.value.name)
|
||||
if (!normalizedTarget) return null
|
||||
|
||||
const modelPackage = await indoorModelSource.value.loadPackage()
|
||||
const modelPackage = await indoorModelSource.loadPackage()
|
||||
for (const floor of modelPackage.floors) {
|
||||
const floorId = floor.floorId
|
||||
const pois = await indoorModelSource.value.loadFloorPois(floorId).catch(() => [])
|
||||
const pois = await indoorModelSource.loadFloorPois(floorId).catch(() => [])
|
||||
const matchedPoi = pois.find((poi) => {
|
||||
const poiName = normalizePoiName(poi.name)
|
||||
const hallName = normalizePoiName(poi.hallName || '')
|
||||
|
||||
@@ -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 = '') {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type SgsMapNode =
|
||||
| { type: 'coord'; floorId: string | number; x: number; z: number; y?: number }
|
||||
| { type: 'poiId'; value: number }
|
||||
| { type: 'nodeName'; value: string }
|
||||
| { type: 'poiId'; value: string | number; floorId?: string | number }
|
||||
| { type: 'nodeName'; value: string; floorId?: string | number }
|
||||
|
||||
export interface SgsSnapDetail {
|
||||
original: { x: number; z: number }
|
||||
@@ -14,13 +14,14 @@ export interface SgsRouteResult {
|
||||
distance: number
|
||||
duration: number
|
||||
pathPoints: Array<{ x: number; y: number; z: number }>
|
||||
startSnap: SgsSnapDetail
|
||||
endSnap: SgsSnapDetail
|
||||
computeTimeMs: number
|
||||
polyCount: number
|
||||
startSnap?: SgsSnapDetail
|
||||
endSnap?: SgsSnapDetail
|
||||
computeTimeMs?: number
|
||||
polyCount?: number
|
||||
warnings: string[]
|
||||
errorCode?: string
|
||||
message?: string
|
||||
segments?: SgsRouteSegment[]
|
||||
}
|
||||
|
||||
export interface SgsMapSDKOptions {
|
||||
@@ -28,17 +29,39 @@ export interface SgsMapSDKOptions {
|
||||
sdkUrl?: string
|
||||
targetOrigin?: string
|
||||
floorId?: string | number
|
||||
mapId?: string | number
|
||||
timeout?: number
|
||||
readyTimeout?: number
|
||||
}
|
||||
|
||||
export interface SgsMapEvents {
|
||||
ready: { engineVersion: string; protocolVersion: number }
|
||||
poiClick: { id?: number; poiId?: number; name: string; type: string; floorId?: string | number; description?: string }
|
||||
poiClick: { id: string | number; poiId?: string | number; name: string; type: string; floorId?: string | number; description?: string }
|
||||
floorChanged: { floorId: string | number }
|
||||
error: { code: string; message: string }
|
||||
loadError: { type: string; detail: string }
|
||||
routeTransfer: {
|
||||
currentFloorId: string | number
|
||||
targetFloorId: string | number
|
||||
fromFloorId: string | number
|
||||
fromNodeName: string
|
||||
toNodeName: string
|
||||
transferType: SgsRouteTransferType
|
||||
connectorName?: string
|
||||
segmentIndex: number
|
||||
totalSegments: number
|
||||
routeId?: string
|
||||
}
|
||||
modelLoading: { floorId: string | number; modelUrl: string }
|
||||
modelReady: { floorId: string | number; parseTimeMs: number }
|
||||
modelError: { floorId: string | number; error: string; fallbackUsed: boolean }
|
||||
floorBundleReady: { floorId: string | number; dataVersion: string }
|
||||
routeReady: { routeId: string; distance: number; duration: number; segmentCount?: number; hasTransfer?: boolean }
|
||||
}
|
||||
|
||||
export type SgsRouteTransferType = 'ELEVATOR' | 'STAIRS' | 'ESCALATOR'
|
||||
export type SgsRouteSegmentType = 'WALK' | 'TRANSFER'
|
||||
|
||||
export type SgsErrorCode =
|
||||
| 'ERR_TIMEOUT'
|
||||
| 'ERR_NO_PATH'
|
||||
@@ -50,6 +73,9 @@ export type SgsErrorCode =
|
||||
| 'ERR_UNAUTHORIZED'
|
||||
| 'ERR_UNSUPPORTED'
|
||||
| 'ERR_FAILED'
|
||||
| 'ERR_DESTROYED'
|
||||
| 'ERR_IFRAME_LOAD'
|
||||
| 'ERR_READY_TIMEOUT'
|
||||
|
||||
export interface SgsMarkerConfig {
|
||||
id: string
|
||||
@@ -64,21 +90,316 @@ export interface SgsMapSDKInstance {
|
||||
off<K extends keyof SgsMapEvents>(event: K, listener: (payload: SgsMapEvents[K]) => void): void
|
||||
getIsReady(): boolean
|
||||
getCurrentFloor(): string | number
|
||||
getMapId(): string | number
|
||||
getVersion(): string
|
||||
whenReady(): Promise<unknown>
|
||||
ready(): Promise<unknown>
|
||||
focusTo(node: SgsMapNode | string): void
|
||||
changeFloor(floorId: string | number, timeout?: number): Promise<{ success: boolean; floorId: string | number }>
|
||||
addMarker(config: SgsMarkerConfig): void
|
||||
removeMarker(markerId: string): void
|
||||
clearMarkers(): void
|
||||
highlightPolygon(nodeName: string): void
|
||||
highlightPolygon(payload: string | object): void
|
||||
planRoute(from: SgsMapNode | string, to: SgsMapNode | string, options?: unknown, timeout?: number): Promise<SgsRouteResult>
|
||||
planRouteV2(from: SgsMapNode, to: SgsMapNode, options?: unknown, timeout?: number): Promise<SgsRouteResult>
|
||||
clearRoute(): void
|
||||
getState(): Promise<unknown>
|
||||
resetView(): void
|
||||
setViewMode(mode: '2d' | '3d'): void
|
||||
resetView(timeout?: number): Promise<{ success: boolean }>
|
||||
setViewMode(mode: '2d' | '3d', timeout?: number): Promise<{ success: boolean; mode: string }>
|
||||
toggleLayer(types: string[], visible: boolean, timeout?: number): Promise<{ success: boolean; visibleTypes: string[] }>
|
||||
setVisibleLayers(types: string[], timeout?: number): Promise<{ success: boolean; visibleTypes: string[] }>
|
||||
setRouteViewActive(active: boolean, timeout?: number): Promise<{ success: boolean; active: boolean }>
|
||||
getManifest(timeout?: number): Promise<SgsSdkManifest>
|
||||
loadFloorBundle(floorId: string | number, timeout?: number): Promise<SgsFloorBundle>
|
||||
getFloorPois(floorId: string | number, timeout?: number): Promise<SgsPoi[]>
|
||||
getNavigablePlaces(floorId: string | number, timeout?: number): Promise<SgsNavigablePlace[]>
|
||||
getPois(floorCode: string, timeout?: number): Promise<SgsPoi[]>
|
||||
getSpaces(floorId: string | number, timeout?: number): Promise<SgsSpaceArea[]>
|
||||
getGuideStops(floorId: string | number, timeout?: number): Promise<SgsGuideStop[]>
|
||||
getGuideStopsByHall(hallId: string | number, timeout?: number): Promise<SgsGuideStop[]>
|
||||
preloadFloor(floorId: string | number, timeout?: number): Promise<{ cached: boolean }>
|
||||
getPerformanceStats(timeout?: number): Promise<SgsPerformanceStats>
|
||||
getDiagnostics(timeout?: number): Promise<SgsMapDiagnostics>
|
||||
getFloorDiagnostics(floorId: string | number, timeout?: number): Promise<SgsFloorDiagnostics>
|
||||
clearModelCache(): void
|
||||
getBusinessPois(floorId: string | number, options?: { types?: string[]; keyword?: string; limit?: number }, timeout?: number): Promise<SgsPoi[]>
|
||||
queryPois(params: SgsPoiQueryParams, timeout?: number): Promise<SgsPoi[]>
|
||||
getFeaturedRoutes(mapId?: string | number, options?: { limit?: number }, timeout?: number): Promise<SgsFeaturedRouteSummary[]>
|
||||
getFeaturedRoute(routeId: string | number, timeout?: number): Promise<SgsFeaturedRouteDetail>
|
||||
showFlowline(routeId: string | number, options?: SgsFlowlineOptions, timeout?: number): Promise<{ success: boolean; routeId: string | number }>
|
||||
clearFlowline(): void
|
||||
destroy(): void
|
||||
}
|
||||
|
||||
export type SgsPoiGroup = 'SERVICE' | 'BUSINESS' | 'OTHER'
|
||||
export type SgsBusinessPoiType =
|
||||
| 'shop'
|
||||
| 'restaurant'
|
||||
| 'cafe'
|
||||
| 'vending'
|
||||
| 'bookstore'
|
||||
| 'cultural_shop'
|
||||
| 'photo_spot'
|
||||
| string
|
||||
|
||||
export interface SgsPoiQueryParams {
|
||||
mapId?: string | number
|
||||
floorId?: string | number
|
||||
group?: SgsPoiGroup
|
||||
types?: string[]
|
||||
keyword?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface SgsPoi {
|
||||
id: string | number
|
||||
name: string
|
||||
type: string
|
||||
typeName: string
|
||||
floorCode: string
|
||||
floorId?: string | number
|
||||
position: { x: number; y: number; z: number }
|
||||
status: 'ACTIVE' | 'INACTIVE'
|
||||
anchorNodeName?: string | null
|
||||
description?: string
|
||||
iconUrl?: string
|
||||
poiGroup?: SgsPoiGroup
|
||||
businessType?: SgsBusinessPoiType
|
||||
coverImageUrl?: string | null
|
||||
phone?: string | null
|
||||
businessHours?: string | null
|
||||
sortOrder?: number | null
|
||||
spatialAreaId?: string | number | null
|
||||
spatialAreaName?: string | null
|
||||
}
|
||||
|
||||
export interface SgsSdkManifest {
|
||||
mapId: string | number
|
||||
mapName: string
|
||||
sdkVersion: string
|
||||
protocolVersion: number
|
||||
dataVersion: string
|
||||
updatedAt: string
|
||||
coordinateSystem: string
|
||||
floors: SgsSdkFloorSummary[]
|
||||
capabilities: Record<string, boolean | undefined>
|
||||
}
|
||||
|
||||
export interface SgsSdkFloorSummary {
|
||||
floorId: string | number
|
||||
floorCode: string
|
||||
floorName: string
|
||||
sortOrder: number
|
||||
modelSizeBytes: number
|
||||
poiCount: number
|
||||
spaceCount: number
|
||||
}
|
||||
|
||||
export interface SgsFloorBundle {
|
||||
floor: SgsSdkFloorSummary
|
||||
model: {
|
||||
modelUrl: string
|
||||
fallbackModelUrl: string
|
||||
compressionType: 'draco' | 'none'
|
||||
modelVersion: string
|
||||
nodeCount: number
|
||||
sizeBytes: number
|
||||
originSizeBytes: number
|
||||
}
|
||||
pois: SgsPoi[]
|
||||
spaces: SgsSpaceArea[]
|
||||
guideStops: SgsGuideStop[]
|
||||
routeSummary: {
|
||||
hasRouteNetwork: boolean
|
||||
nodeCount: number
|
||||
edgeCount: number
|
||||
}
|
||||
hiddenSceneNodeNames: string[]
|
||||
dataVersion: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export interface SgsSpaceArea {
|
||||
id: string | number
|
||||
name: string
|
||||
type: string
|
||||
floorId: string | number
|
||||
boundaryWkt: string
|
||||
center: { x: number; y: number; z: number }
|
||||
sourceNodeName?: string
|
||||
status: 'ACTIVE' | 'INACTIVE'
|
||||
colorHex?: string
|
||||
}
|
||||
|
||||
export interface SgsGuideStop {
|
||||
id: string | number
|
||||
name: string
|
||||
type: string
|
||||
typeName?: string
|
||||
floorId: string | number
|
||||
position: { x: number; y: number; z: number }
|
||||
targetType: string
|
||||
targetId?: string | number
|
||||
audioUrl?: string
|
||||
coverImageUrl?: string
|
||||
description?: string
|
||||
status: 'ACTIVE' | 'INACTIVE'
|
||||
located?: boolean
|
||||
hasAudio?: boolean
|
||||
poiId?: string | number
|
||||
outlineId?: string | number
|
||||
outlineName?: string
|
||||
hallId?: string | number
|
||||
hallName?: string
|
||||
sort?: number
|
||||
routeId?: string | number
|
||||
routeName?: string
|
||||
seqOrder?: number
|
||||
stayMinutes?: number
|
||||
}
|
||||
|
||||
export interface SgsNavigablePlace {
|
||||
id: string | number
|
||||
name: string
|
||||
category: 'door' | 'poi' | 'space' | 'guide_stop'
|
||||
floorId: string | number
|
||||
floorCode: string
|
||||
floorName?: string
|
||||
x: number
|
||||
z: number
|
||||
nodeId?: string | number
|
||||
ownerName?: string
|
||||
typeCode?: string
|
||||
typeName?: string
|
||||
}
|
||||
|
||||
export interface SgsRouteSegment {
|
||||
segmentIndex: number
|
||||
floorId?: string | number | null
|
||||
floorCode: string
|
||||
floorName: string
|
||||
segmentType?: SgsRouteSegmentType
|
||||
type: 'WALK' | SgsRouteTransferType
|
||||
transferType?: 'WALK' | SgsRouteTransferType
|
||||
distance: number
|
||||
duration: number
|
||||
pathPoints: Array<{ x: number; y: number; z: number }>
|
||||
points?: Array<{ x: number; y: number; z: number }>
|
||||
fromNodeName?: string | null
|
||||
toNodeName?: string | null
|
||||
startNodeName?: string | null
|
||||
endNodeName?: string | null
|
||||
connectorName?: string | null
|
||||
}
|
||||
|
||||
export interface SgsPerformanceStats {
|
||||
sdkCreatedAt?: number
|
||||
iframeDomReadyMs?: number
|
||||
engineReadyMs?: number
|
||||
manifestLoadMs?: number
|
||||
bundleLoadMs?: number
|
||||
modelDownloadMs?: number
|
||||
modelDownloadAndParseMs?: number
|
||||
modelParseMs?: number
|
||||
firstRenderMs?: number
|
||||
routePlanMs?: number
|
||||
dracoUsed?: boolean
|
||||
fallbackUsed?: boolean
|
||||
currentFloorId?: string | number
|
||||
}
|
||||
|
||||
export interface SgsMapDiagnostics {
|
||||
mapId: string | number
|
||||
mapName: string
|
||||
sdkVersion: string
|
||||
status: 'OK' | 'WARN' | 'ERROR'
|
||||
floors: SgsFloorDiagnosticsSummary[]
|
||||
summary: {
|
||||
floorCount: number
|
||||
modelReadyFloorCount: number
|
||||
poiCount: number
|
||||
spaceCount: number
|
||||
guideStopCount: number
|
||||
navigablePlaceCount: number
|
||||
routeNodeCount: number
|
||||
routeEdgeCount: number
|
||||
}
|
||||
warnings: string[]
|
||||
}
|
||||
|
||||
export interface SgsFloorDiagnosticsSummary {
|
||||
floorId: string | number
|
||||
floorCode: string
|
||||
floorName: string
|
||||
status: 'OK' | 'WARN' | 'ERROR'
|
||||
modelReady: boolean
|
||||
routePlanningReady: boolean
|
||||
navigablePlaceCount: number
|
||||
}
|
||||
|
||||
export interface SgsFloorDiagnostics extends SgsFloorDiagnosticsSummary {
|
||||
poiCount: number
|
||||
spaceCount: number
|
||||
guideStopCount: number
|
||||
routeNodeCount: number
|
||||
routeEdgeCount: number
|
||||
warnings: string[]
|
||||
}
|
||||
|
||||
export interface SgsFeaturedRouteSummary {
|
||||
id: string | number
|
||||
mapId: string | number
|
||||
routeName: string
|
||||
routeNameEn?: string | null
|
||||
description?: string | null
|
||||
descriptionEn?: string | null
|
||||
coverImageUrl?: string | null
|
||||
routeColor?: string | null
|
||||
estimatedMinutes?: number | null
|
||||
displayOrder?: number | null
|
||||
waypointCount: number
|
||||
startEntranceId?: string | number | null
|
||||
endEntranceId?: string | number | null
|
||||
updatedAt?: string | null
|
||||
}
|
||||
|
||||
export interface SgsRouteEndpoint {
|
||||
id: string | number
|
||||
name: string
|
||||
floorId: string | number
|
||||
floorCode?: string | null
|
||||
position?: { x: number; y: number; z: number } | null
|
||||
}
|
||||
|
||||
export interface SgsFeaturedRouteWaypoint {
|
||||
order: number
|
||||
spaceId: string | number
|
||||
spaceName?: string | null
|
||||
floorId?: string | number | null
|
||||
floorCode?: string | null
|
||||
position: { x: number; y: number; z: number }
|
||||
title?: string | null
|
||||
subtitle?: string | null
|
||||
description?: string | null
|
||||
imageUrl?: string | null
|
||||
audioUrl?: string | null
|
||||
staySeconds?: number | null
|
||||
tags?: string[]
|
||||
highlight?: boolean
|
||||
}
|
||||
|
||||
export interface SgsFeaturedRouteDetail extends SgsFeaturedRouteSummary {
|
||||
startEntrance?: SgsRouteEndpoint | null
|
||||
endEntrance?: SgsRouteEndpoint | null
|
||||
waypoints: SgsFeaturedRouteWaypoint[]
|
||||
}
|
||||
|
||||
export interface SgsFlowlineOptions {
|
||||
autoFit?: boolean
|
||||
showLabels?: boolean
|
||||
animate?: boolean
|
||||
}
|
||||
|
||||
export type SgsMapSDKConstructor = new (options: SgsMapSDKOptions) => SgsMapSDKInstance
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# SGS Map SDK Changelog
|
||||
|
||||
## [2.4.0] - 2026-06-27
|
||||
|
||||
### 🚀 新特性 (New Features)
|
||||
- **业务 POI 接口与扩展机制**:新增 `getBusinessPois` 获取商户级业务 POI,新增 `queryPois` 支持按地图、楼层、分组、类型、关键词进行组合查询,实现与底层空间基础设施数据解耦。
|
||||
- **特色动线查询与展示**:新增 `getFeaturedRoutes` / `getFeaturedRoute` 接口获取馆方精选路线,新增 `showFlowline` / `clearFlowline` 接口提供跨层全局鸟瞰特色动线展示功能。
|
||||
- **独立 H5 渲染引擎包 (SDK Engine)**:新增 `sdk-engine/` 独立打包构建目录,支持静态编译输出至静态 `engine/` 目录。底座不依赖 Next.js 前端路由及 hydration 状态限制,由宿主系统通过 iframe 挂载 `../engine/index.html` 独立运行。
|
||||
- **配置与数据解耦**:底座数据服务入口由 `server` 查询参数动态指定,静态部署后可通过 `?server=http://localhost:3001` 指向任意数据服务地址,彻底解耦。
|
||||
|
||||
### 🐞 修复与强化 (Fixes & Improvements)
|
||||
- **解耦 Next.js 依赖**:底座引擎完全脱离 Next.js / Zustand 等大体积依赖,精简为极速加载的原生单页应用(Vite + React)。
|
||||
- **优化发包构建管线**:重新梳理 `package.json` scripts,将 SDK Bridge 与 SDK Engine 打包构建命令在命令行端进行解耦和串联(`npm run build:sdk`),优化了 `scripts/copy-sdk.js` 拷贝管线,避免嵌套与死循环构建。
|
||||
- **演示 Demo 改造**:修改 SDK 官方 Demo 的 `app.js` 使其默认消费静态 `../engine/index.html` 渲染底座,并开启 `server` 参数透传及 `targetOrigin: '*'` 确权广播,实现宿主与静态底座零配置无缝通信。
|
||||
|
||||
---
|
||||
|
||||
## [2.3.0] - 2026-06-23
|
||||
|
||||
### 🚀 新特性 (New Features)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SGS Map SDK 交付包
|
||||
|
||||
> **版本**:V2.3.0
|
||||
> **版本**:V2.4.0
|
||||
> **定位**:深圳自然博物馆统一三维高精地图导航服务平台 H5 SDK
|
||||
|
||||
欢迎接入 SGS Map SDK!本 SDK 将复杂的 WebGL 三维渲染、GLB 模型管线与 NavMesh 物理寻路引擎封装在服务端基座中,业务端(H5 / 大屏 / 小程序)只需通过几行代码即可极速唤起 3D 地图。
|
||||
@@ -16,7 +16,13 @@ sgs-map-sdk-release/
|
||||
│ ├── index.mjs.map # ESM source map
|
||||
│ ├── index.d.ts # TypeScript 类型声明文件
|
||||
│ └── index.d.mts # TypeScript 模块声明文件
|
||||
├── demo/ # SDK 能力展示 Demo(可直接运行)
|
||||
│ ├── index.html # Demo 入口页面
|
||||
│ ├── app.js # Demo 应用逻辑
|
||||
│ └── styles.css # Demo 样式表
|
||||
├── package.json # NPM 元信息
|
||||
├── CHANGELOG.md # 版本变更日志
|
||||
├── RELEASE_NOTES_2.4.0.md # V2.4.0 正式发布说明
|
||||
├── sdk-quickstart.md # 【必读】10 分钟快速接入指南(含完整示例代码)
|
||||
├── sdk-api-reference.md # 【必读】第三方开发 API 参考手册
|
||||
├── sdk-protocol.md # 【选读】底层通信协议与安全沙箱规范说明
|
||||
@@ -52,6 +58,14 @@ sgs-map-sdk-release/
|
||||
|
||||
## 📚 如何开始?
|
||||
|
||||
- **快速体验 Demo**:
|
||||
发布包内附带 `demo/` 目录,是一个完整的 SDK 能力展示页面,支持空间查询、POI 查询、讲解点、导航规划、诊断等全部功能。运行方式:
|
||||
```bash
|
||||
npx -y serve . -l 5555
|
||||
# 浏览器打开(?server= 指向运行中的地图服务)
|
||||
# http://localhost:5555/demo/?server=http://localhost:3001
|
||||
```
|
||||
|
||||
- **如果您是普通前端业务开发 / 微信小程序开发**:
|
||||
直接打开 `sdk-quickstart.md`,复制里面的示例代码,10分钟即可完成接入。
|
||||
*(注:微信小程序团队完全无需引入 `dist` 下的代码,请仔细阅读文档中小程序 `<web-view>` 的原生接入方式)*
|
||||
@@ -59,12 +73,28 @@ sgs-map-sdk-release/
|
||||
- **如果您需要逐个查询 API 参数、返回值和错误码**:
|
||||
打开 `sdk-api-reference.md`,按方法名查阅第三方调用说明。
|
||||
|
||||
- **如果您需要了解 V2.4.0 新版本变化与发布边界**:
|
||||
打开 `RELEASE_NOTES_2.4.0.md`,查看业务 POI、精品路线、动线展示、兼容性和已验证范围。
|
||||
|
||||
- **如果您是对架构感兴趣的高级开发**:
|
||||
可以阅读 `sdk-protocol.md`,了解我们如何通过双域确权协议解决 `postMessage` 多实例安全问题,以及 WebGL 的安全释放机制。
|
||||
|
||||
---
|
||||
|
||||
## 🆕 V2.3.0 当前能力概览
|
||||
## 🆕 V2.4.0 当前能力概览
|
||||
|
||||
### V2.4.0 新增方法
|
||||
|
||||
| 方法 | 签名 | 说明 |
|
||||
|------|------|------|
|
||||
| `getBusinessPois` | `getBusinessPois(floorId: string \| number, options?: any)` | 获取指定楼层的业务 POI(例如商铺、餐饮等),与基础设施 POI 分离 |
|
||||
| `queryPois` | `queryPois(params: SgsPoiQueryParams)` | 灵活的多字段 POI 检索接口,支持按地图、楼层、分组、类型、关键词组合查询 |
|
||||
| `getFeaturedRoutes` | `getFeaturedRoutes(mapId: string \| number, options?: any)` | 获取当前地图关联的特色精选路线列表摘要 |
|
||||
| `getFeaturedRoute` | `getFeaturedRoute(routeId: string \| number)` | 根据路线 ID 获取特色精选路线的详细路点序列与说明 |
|
||||
| `showFlowline` | `showFlowline(routeId: string \| number)` | 在地图上高亮渲染展示一条特色动线(自动切换至全局俯瞰视角) |
|
||||
| `clearFlowline` | `clearFlowline()` | 清除当前展示的特色动线并恢复默认视图 |
|
||||
|
||||
## V2.3.0 基础数据能力
|
||||
|
||||
### V2.3.0 新增方法
|
||||
|
||||
|
||||
141
static/sgs-map-sdk/index.d.ts
vendored
141
static/sgs-map-sdk/index.d.ts
vendored
@@ -240,6 +240,16 @@ interface SgsLayerTreeNode {
|
||||
/** 包含的 3D 节点数量 */
|
||||
nodeCount?: number;
|
||||
}
|
||||
type SgsPoiGroup = "SERVICE" | "BUSINESS" | "OTHER";
|
||||
type SgsBusinessPoiType = "shop" | "restaurant" | "cafe" | "vending" | "bookstore" | "cultural_shop" | "photo_spot";
|
||||
interface SgsPoiQueryParams {
|
||||
mapId?: string | number;
|
||||
floorId?: string | number;
|
||||
group?: SgsPoiGroup;
|
||||
types?: string[];
|
||||
keyword?: string;
|
||||
limit?: number;
|
||||
}
|
||||
/** SDK 消费的 POI — 对应 GET /app-api/gis/sdk/floors/{floorId}/pois */
|
||||
interface SgsPoi {
|
||||
/** POI ID(雪花 ID,字符串或数字均可) */
|
||||
@@ -266,6 +276,15 @@ interface SgsPoi {
|
||||
description?: string;
|
||||
/** 图标 URL */
|
||||
iconUrl?: string;
|
||||
floorId?: string | number;
|
||||
poiGroup?: SgsPoiGroup;
|
||||
businessType?: SgsBusinessPoiType | string;
|
||||
coverImageUrl?: string | null;
|
||||
phone?: string | null;
|
||||
businessHours?: string | null;
|
||||
sortOrder?: number | null;
|
||||
spatialAreaId?: string | number | null;
|
||||
spatialAreaName?: string | null;
|
||||
}
|
||||
/** 路径规划结果 — 对应 POST /app-api/gis/sdk/routes/plan */
|
||||
interface SgsRoutePlanV2 {
|
||||
@@ -369,6 +388,10 @@ interface SgsSdkManifest {
|
||||
highlight?: boolean;
|
||||
/** 是否支持诊断接口 */
|
||||
diagnostics?: boolean;
|
||||
businessPoi?: boolean;
|
||||
poiSearch?: boolean;
|
||||
featuredRoutes?: boolean;
|
||||
flowlinePreview?: boolean;
|
||||
};
|
||||
}
|
||||
/** v2.2.0 楼层摘要(manifest 内嵌) */
|
||||
@@ -651,6 +674,80 @@ interface SgsFloorDiagnostics {
|
||||
/** 警告信息列表 */
|
||||
warnings: string[];
|
||||
}
|
||||
interface SgsFeaturedRouteSummary {
|
||||
id: string | number;
|
||||
mapId: string | number;
|
||||
routeName: string;
|
||||
routeNameEn?: string | null;
|
||||
description?: string | null;
|
||||
descriptionEn?: string | null;
|
||||
coverImageUrl?: string | null;
|
||||
routeColor?: string | null;
|
||||
estimatedMinutes?: number | null;
|
||||
displayOrder?: number | null;
|
||||
waypointCount: number;
|
||||
startEntranceId?: string | number | null;
|
||||
endEntranceId?: string | number | null;
|
||||
updatedAt?: string | null;
|
||||
}
|
||||
interface SgsRouteEndpoint {
|
||||
id: string | number;
|
||||
name: string;
|
||||
floorId: string | number;
|
||||
floorCode?: string | null;
|
||||
position?: {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
} | null;
|
||||
}
|
||||
interface SgsFeaturedRouteWaypoint {
|
||||
order: number;
|
||||
spaceId: string | number;
|
||||
spaceName?: string | null;
|
||||
floorId?: string | number | null;
|
||||
floorCode?: string | null;
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
};
|
||||
title?: string | null;
|
||||
subtitle?: string | null;
|
||||
description?: string | null;
|
||||
imageUrl?: string | null;
|
||||
audioUrl?: string | null;
|
||||
staySeconds?: number | null;
|
||||
tags?: string[];
|
||||
highlight?: boolean;
|
||||
}
|
||||
interface SgsFeaturedRouteDetail extends SgsFeaturedRouteSummary {
|
||||
startEntrance?: SgsRouteEndpoint | null;
|
||||
endEntrance?: SgsRouteEndpoint | null;
|
||||
waypoints: SgsFeaturedRouteWaypoint[];
|
||||
}
|
||||
interface SgsFlowlineOptions {
|
||||
autoFit?: boolean;
|
||||
showLabels?: boolean;
|
||||
animate?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤 EXTERIOR 楼层,检查楼层是否是室内可导航楼层
|
||||
*/
|
||||
declare function isIndoorNavigableFloor(floorCode: string): boolean;
|
||||
/**
|
||||
* 物理楼层顺序由低到高排序
|
||||
*/
|
||||
declare function sortIndoorFloors<T extends {
|
||||
floorCode: string;
|
||||
}>(floors: T[]): T[];
|
||||
|
||||
declare const utils_isIndoorNavigableFloor: typeof isIndoorNavigableFloor;
|
||||
declare const utils_sortIndoorFloors: typeof sortIndoorFloors;
|
||||
declare namespace utils {
|
||||
export { utils_isIndoorNavigableFloor as isIndoorNavigableFloor, utils_sortIndoorFloors as sortIndoorFloors };
|
||||
}
|
||||
|
||||
/**
|
||||
* SGS 3D 地图 H5 SDK 入口类
|
||||
@@ -659,9 +756,10 @@ interface SgsFloorDiagnostics {
|
||||
* <p>所有需要后端数据的操作均通过 postMessage 指令由底座代理,
|
||||
* Demo / 宿主不允许直连后端 API。
|
||||
*
|
||||
* @version 2.3.0
|
||||
* @version 2.4.0
|
||||
*/
|
||||
declare class SGSMapSDK extends EventEmitter<SGSMapEvents> {
|
||||
static utils: typeof utils;
|
||||
private container;
|
||||
private sdkUrl;
|
||||
private floorId;
|
||||
@@ -685,6 +783,8 @@ declare class SGSMapSDK extends EventEmitter<SGSMapEvents> {
|
||||
private _messageListener;
|
||||
/** ready 超时计时器 */
|
||||
private _readyTimer;
|
||||
/** 🔧 P0: HELLO 重试定时器 — 解决 iframe onload 与 React useEffect 时序竞争 */
|
||||
private _helloInterval;
|
||||
/** ENGINE_READY 返回的 payload(供外部读取) */
|
||||
readyPayload: any;
|
||||
/** ready Promise 的 resolve/reject,保证 whenReady() 返回同一个 Promise */
|
||||
@@ -769,7 +869,7 @@ declare class SGSMapSDK extends EventEmitter<SGSMapEvents> {
|
||||
/** 清空所有业务图钉 */
|
||||
clearMarkers(): void;
|
||||
/** 高亮多边形轮廓 */
|
||||
highlightPolygon(nodeName: string): void;
|
||||
highlightPolygon(payload: string | object): void;
|
||||
/** 寻路规划(v1 兼容) */
|
||||
planRoute(from: SgsMapNode | string, to: SgsMapNode | string, options?: any, timeout?: number): Promise<RouteResult>;
|
||||
/** 寻路规划 V2(结构化参数) */
|
||||
@@ -779,9 +879,14 @@ declare class SGSMapSDK extends EventEmitter<SGSMapEvents> {
|
||||
/** 获取引擎状态 */
|
||||
getState(): Promise<any>;
|
||||
/** 重置视角 */
|
||||
resetView(): void;
|
||||
resetView(timeout?: number): Promise<{
|
||||
success: boolean;
|
||||
}>;
|
||||
/** 设置 2D/3D 视图模式 */
|
||||
setViewMode(mode: '2d' | '3d'): void;
|
||||
setViewMode(mode: '2d' | '3d', timeout?: number): Promise<{
|
||||
success: boolean;
|
||||
mode: string;
|
||||
}>;
|
||||
/** 切换图层可见性 */
|
||||
toggleLayer(types: string[], visible: boolean, timeout?: number): Promise<{
|
||||
success: boolean;
|
||||
@@ -792,6 +897,11 @@ declare class SGSMapSDK extends EventEmitter<SGSMapEvents> {
|
||||
success: boolean;
|
||||
visibleTypes: string[];
|
||||
}>;
|
||||
/** 设置路线展示视图是否活跃 */
|
||||
setRouteViewActive(active: boolean, timeout?: number): Promise<{
|
||||
success: boolean;
|
||||
active: boolean;
|
||||
}>;
|
||||
/** 获取地图 Manifest 清单 */
|
||||
getManifest(timeout?: number): Promise<SgsSdkManifest>;
|
||||
/** 加载指定楼层的完整 Bundle 数据(含 POI/空间面/讲解点/路网) */
|
||||
@@ -820,6 +930,27 @@ declare class SGSMapSDK extends EventEmitter<SGSMapEvents> {
|
||||
getFloorDiagnostics(floorId: string | number, timeout?: number): Promise<SgsFloorDiagnostics>;
|
||||
/** 清空客户端模型缓存 */
|
||||
clearModelCache(): void;
|
||||
/** 获取指定楼层的业务 POI 列表 */
|
||||
getBusinessPois(floorId: string | number, options?: {
|
||||
types?: string[];
|
||||
keyword?: string;
|
||||
limit?: number;
|
||||
}, timeout?: number): Promise<SgsPoi[]>;
|
||||
/** 查询 POI 列表 */
|
||||
queryPois(params: SgsPoiQueryParams, timeout?: number): Promise<SgsPoi[]>;
|
||||
/** 获取特色路线列表 */
|
||||
getFeaturedRoutes(mapId?: string | number, options?: {
|
||||
limit?: number;
|
||||
}, timeout?: number): Promise<SgsFeaturedRouteSummary[]>;
|
||||
/** 获取特色路线详情 */
|
||||
getFeaturedRoute(routeId: string | number, timeout?: number): Promise<SgsFeaturedRouteDetail>;
|
||||
/** 显示动线 */
|
||||
showFlowline(routeId: string | number, options?: SgsFlowlineOptions, timeout?: number): Promise<{
|
||||
success: boolean;
|
||||
routeId: string | number;
|
||||
}>;
|
||||
/** 清除动线 */
|
||||
clearFlowline(): void;
|
||||
/** @deprecated 使用 getManifest() 替代 */
|
||||
getReleaseManifest(timeout?: number): Promise<any>;
|
||||
/** @deprecated 已废弃,无替代方法 */
|
||||
@@ -837,4 +968,4 @@ declare class SGSMapSDK extends EventEmitter<SGSMapEvents> {
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
export { type MarkerConfig, type RouteOptions, type RouteResult, type SGSErrorCode, type SGSMapEvents, type SGSMapSDKOptions, type SgsFloorBundle, type SgsFloorDiagnostics, type SgsFloorDiagnosticsSummary, type SgsFloorResource, type SgsGuideStop, type SgsLayerTreeNode, type SgsMapDiagnostics, type SgsMapManifest, type SgsMapNode, type SgsModelResource, type SgsNavigablePlace, type SgsPerformanceStats, type SgsPoi, type SgsRoutePlanV2, type SgsRouteSegment, type SgsRouteSegmentType, type SgsRouteTransferType, type SgsSdkError, type SgsSdkFloorSummary, type SgsSdkManifest, type SgsSpaceArea, type SnapDetail, SGSMapSDK as default };
|
||||
export { type MarkerConfig, type RouteOptions, type RouteResult, type SGSErrorCode, type SGSMapEvents, type SGSMapSDKOptions, type SgsBusinessPoiType, type SgsFeaturedRouteDetail, type SgsFeaturedRouteSummary, type SgsFeaturedRouteWaypoint, type SgsFloorBundle, type SgsFloorDiagnostics, type SgsFloorDiagnosticsSummary, type SgsFloorResource, type SgsFlowlineOptions, type SgsGuideStop, type SgsLayerTreeNode, type SgsMapDiagnostics, type SgsMapManifest, type SgsMapNode, type SgsModelResource, type SgsNavigablePlace, type SgsPerformanceStats, type SgsPoi, type SgsPoiGroup, type SgsPoiQueryParams, type SgsRouteEndpoint, type SgsRoutePlanV2, type SgsRouteSegment, type SgsRouteSegmentType, type SgsRouteTransferType, type SgsSdkError, type SgsSdkFloorSummary, type SgsSdkManifest, type SgsSpaceArea, type SnapDetail, SGSMapSDK as default };
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@sgs/map-sdk",
|
||||
"version": "2.3.0",
|
||||
"description": "SGS Map SDK",
|
||||
"version": "2.4.0",
|
||||
"description": "SGS Map SDK API contract copy for frontend-miniapp; iframe runtime is not enabled by this project",
|
||||
"main": "./index.global.js",
|
||||
"types": "./index.d.ts",
|
||||
"exports": {
|
||||
@@ -10,12 +10,13 @@
|
||||
"default": "./index.global.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": true,
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"index.global.js",
|
||||
"index.global.js.map",
|
||||
"index.d.ts",
|
||||
"README.md",
|
||||
"CHANGELOG.md",
|
||||
"sdk-quickstart.md",
|
||||
"sdk-api-reference.md",
|
||||
"sdk-protocol.md"
|
||||
|
||||
@@ -62,7 +62,7 @@ interface SGSMapSDKOptions {
|
||||
| `floorId` | 否 | `1` | 初始楼层 ID,支持字符串或数字 |
|
||||
| `mapId` | 否 | `1` | 地图 ID,当前由 SDK 实例保存 |
|
||||
| `timeout` | 否 | `5000` | 普通命令超时时间,单位 ms |
|
||||
| `readyTimeout` | 否 | `15000` | 等待 `ENGINE_READY` 的最大时间,单位 ms |
|
||||
| `readyTimeout` | 否 | `30000` | 等待 `ENGINE_READY` 的最大时间,单位 ms |
|
||||
|
||||
生产环境必须保证 `sdkUrl` 可访问,并且 `targetOrigin` 与 `sdkUrl` 的 Origin 一致。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user