整改点位搜索数据加载与分类逻辑
This commit is contained in:
@@ -9,6 +9,9 @@ import type {
|
||||
import {
|
||||
isIndoorNavigableFloor
|
||||
} from '@/domain/guideFloor'
|
||||
import {
|
||||
normalizePoiSemanticValue
|
||||
} from '@/domain/poiCategories'
|
||||
|
||||
const floorIdPattern = /^L(-?\d+(?:\.\d+)?)$/
|
||||
|
||||
@@ -43,33 +46,176 @@ export const isStaticIndoorNavigableFloorId = (floorId: string) => (
|
||||
})
|
||||
)
|
||||
|
||||
const toCategory = (category: StaticNavPoiCategoryPayload): MuseumCategory => ({
|
||||
id: category.topCategory,
|
||||
label: category.topCategoryZh,
|
||||
iconType: category.iconType
|
||||
})
|
||||
const normalizedText = (value?: string | null) => (value || '').trim().toLowerCase()
|
||||
|
||||
const staticDestinationCategoryBySemanticType: Readonly<Record<string, string>> = {
|
||||
exhibition_hall: 'exhibition_hall',
|
||||
theater: 'space_theater',
|
||||
restaurant: 'space_restaurant',
|
||||
cafe: 'space_restaurant',
|
||||
shop: 'space_shop',
|
||||
cultural_shop: 'space_shop',
|
||||
bookstore: 'space_shop',
|
||||
vending: 'space_shop'
|
||||
}
|
||||
|
||||
const staticFallbackDestinationTypes = new Set(
|
||||
Object.keys(staticDestinationCategoryBySemanticType)
|
||||
)
|
||||
|
||||
const staticFacilityCategoryBySemanticType: Readonly<Record<string, string>> = {
|
||||
ticket_office: 'basic_service_facility',
|
||||
service_desk: 'basic_service_facility',
|
||||
locker: 'basic_service_facility',
|
||||
rental_service: 'basic_service_facility',
|
||||
toilet: 'basic_service_facility',
|
||||
accessible_toilet: 'accessibility_special_service',
|
||||
mother_baby_room: 'basic_service_facility',
|
||||
elevator: 'transport_circulation',
|
||||
escalator: 'transport_circulation',
|
||||
stairs: 'transport_circulation'
|
||||
}
|
||||
|
||||
const staticCategoryLabelBySemanticType: Readonly<Record<string, string>> = {
|
||||
exhibition_hall: '展厅',
|
||||
theater: '影院',
|
||||
restaurant: '餐饮',
|
||||
cafe: '餐饮',
|
||||
shop: '购物',
|
||||
cultural_shop: '购物',
|
||||
bookstore: '购物',
|
||||
vending: '购物',
|
||||
ticket_office: '售票处',
|
||||
service_desk: '服务',
|
||||
locker: '服务',
|
||||
rental_service: '服务',
|
||||
toilet: '洗手间',
|
||||
accessible_toilet: '洗手间',
|
||||
mother_baby_room: '母婴',
|
||||
elevator: '电梯',
|
||||
escalator: '扶梯',
|
||||
stairs: '楼梯'
|
||||
}
|
||||
|
||||
const staticNameSemanticType = (name: string) => {
|
||||
if (/(?:售票|票务|ticket)/.test(name)) return 'ticket_office'
|
||||
if (/(?:服务台|咨询台|接待|服务中心|service[_ ]?(?:desk|center)|information)/.test(name)) return 'service_desk'
|
||||
if (/(?:存包|寄存|储物|locker)/.test(name)) return 'locker'
|
||||
if (/(?:租赁|租借|rental)/.test(name)) return 'rental_service'
|
||||
if (/(?:茶水间|饮水间|water)/.test(name)) return 'service_space'
|
||||
if (/(?:影院|影厅|剧场|cinema|theater)/.test(name)) return 'theater'
|
||||
if (/(?:餐饮|餐厅|餐馆|咖啡|restaurant|dining|food|cafe)/.test(name)) return 'restaurant'
|
||||
if (/(?:购物|商店|商铺|文创|零售|shop|store|retail)/.test(name)) return 'shop'
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* The static navigation package has legacy facility labels where stairways,
|
||||
* escalators, and nursing rooms inherit a generic elevator/restroom icon.
|
||||
* Keep the provider source-faithful and repair that visitor-facing semantic at
|
||||
* the adapter boundary.
|
||||
*/
|
||||
export const normalizeStaticPoiIconType = (
|
||||
poi: Pick<StaticNavPoiPayload, 'name'>,
|
||||
rawIconType?: string | null
|
||||
) => {
|
||||
const name = normalizedText(poi.name)
|
||||
const iconType = normalizedText(rawIconType)
|
||||
|
||||
if (name.includes('扶梯')) return 'escalator'
|
||||
if (name.includes('楼梯')) return 'stairs'
|
||||
if (name.includes('母婴')) return 'mother_baby_room'
|
||||
if (/(?:无障碍|残疾人|残障).*(?:卫生间|洗手间|厕所)/.test(name)) {
|
||||
return 'accessible_toilet'
|
||||
}
|
||||
if (/(?:卫生间|洗手间|厕所)/.test(name)) return 'toilet'
|
||||
|
||||
return iconType
|
||||
}
|
||||
|
||||
const getStaticPoiSemanticType = (
|
||||
poi: StaticNavPoiPayload,
|
||||
rawIconType?: string | null
|
||||
) => (
|
||||
staticNameSemanticType(normalizedText(poi.name))
|
||||
|| normalizePoiSemanticValue(normalizeStaticPoiIconType(poi, rawIconType))
|
||||
)
|
||||
|
||||
const getStaticPoiCategoryId = (
|
||||
rawCategoryId: string,
|
||||
semanticType: string
|
||||
) => {
|
||||
const normalizedCategoryId = normalizePoiSemanticValue(rawCategoryId)
|
||||
const isTouringFallback = normalizedCategoryId === 'touring_poi'
|
||||
|| staticFallbackDestinationTypes.has(normalizedCategoryId)
|
||||
|
||||
if (isTouringFallback) {
|
||||
return staticDestinationCategoryBySemanticType[semanticType]
|
||||
|| staticFacilityCategoryBySemanticType[semanticType]
|
||||
|| rawCategoryId
|
||||
}
|
||||
|
||||
return rawCategoryId
|
||||
}
|
||||
|
||||
const getStaticPoiCategoryLabel = (
|
||||
rawCategoryId: string,
|
||||
rawCategoryLabel: string,
|
||||
semanticType: string
|
||||
) => {
|
||||
const normalizedCategoryId = normalizePoiSemanticValue(rawCategoryId)
|
||||
const isGenericTouringCategory = normalizedCategoryId === 'touring_poi'
|
||||
return isGenericTouringCategory
|
||||
? staticCategoryLabelBySemanticType[semanticType] || rawCategoryLabel
|
||||
: rawCategoryLabel
|
||||
}
|
||||
|
||||
const getStaticPoiKind = (categoryId: string): MuseumPoi['kind'] => {
|
||||
if (categoryId === 'exhibition_hall') return 'hall'
|
||||
if (categoryId.startsWith('space_')) return 'space'
|
||||
return 'facility'
|
||||
}
|
||||
|
||||
const toCategory = (
|
||||
poi: StaticNavPoiPayload,
|
||||
category: StaticNavPoiCategoryPayload
|
||||
): MuseumCategory => {
|
||||
const semanticType = getStaticPoiSemanticType(poi, category.iconType)
|
||||
return {
|
||||
id: getStaticPoiCategoryId(category.topCategory, semanticType),
|
||||
label: getStaticPoiCategoryLabel(category.topCategory, category.topCategoryZh, semanticType),
|
||||
iconType: semanticType
|
||||
}
|
||||
}
|
||||
|
||||
const isPoiAccessible = (poi: StaticNavPoiPayload) => (
|
||||
poi.primaryCategory === 'accessibility_special_service'
|
||||
|| poi.categories?.some((category) => category.topCategory === 'accessibility_special_service') === true
|
||||
)
|
||||
|
||||
export const toMuseumPoi = (poi: StaticNavPoiPayload): MuseumPoi => ({
|
||||
id: poi.id,
|
||||
name: poi.name,
|
||||
floorId: poi.floorId,
|
||||
floorLabel: formatNavFloorLabel(poi.floorId),
|
||||
primaryCategory: {
|
||||
id: poi.primaryCategory,
|
||||
label: poi.primaryCategoryZh,
|
||||
iconType: poi.iconType
|
||||
},
|
||||
categories: (poi.categories || []).map(toCategory),
|
||||
positionGltf: poi.positionGltf,
|
||||
sourceObjectName: poi.sourceObjectName,
|
||||
sourceConfidence: poi.sourceConfidence,
|
||||
navigationReadiness: poi.navigationReadiness,
|
||||
accessible: isPoiAccessible(poi),
|
||||
kind: poi.primaryCategory === 'touring_poi' ? 'hall' : 'facility',
|
||||
hallName: poi.primaryCategory === 'touring_poi' ? poi.name : undefined
|
||||
})
|
||||
export const toMuseumPoi = (poi: StaticNavPoiPayload): MuseumPoi => {
|
||||
const categoryFallbackIconType = poi.categories?.[0]?.iconType
|
||||
const iconType = getStaticPoiSemanticType(poi, poi.iconType || categoryFallbackIconType)
|
||||
const primaryCategoryId = getStaticPoiCategoryId(poi.primaryCategory, iconType)
|
||||
const kind = getStaticPoiKind(primaryCategoryId)
|
||||
|
||||
return {
|
||||
id: poi.id,
|
||||
name: poi.name,
|
||||
floorId: poi.floorId,
|
||||
floorLabel: formatNavFloorLabel(poi.floorId),
|
||||
primaryCategory: {
|
||||
id: primaryCategoryId,
|
||||
label: getStaticPoiCategoryLabel(poi.primaryCategory, poi.primaryCategoryZh, iconType),
|
||||
iconType
|
||||
},
|
||||
categories: (poi.categories || []).map((category) => toCategory(poi, category)),
|
||||
positionGltf: poi.positionGltf,
|
||||
sourceObjectName: poi.sourceObjectName,
|
||||
sourceConfidence: poi.sourceConfidence,
|
||||
navigationReadiness: poi.navigationReadiness,
|
||||
accessible: isPoiAccessible(poi),
|
||||
kind,
|
||||
hallName: kind === 'hall' ? poi.name : undefined
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ import {
|
||||
isIndoorNavigableFloor
|
||||
} from '@/domain/guideFloor'
|
||||
import {
|
||||
isPoiSearchCategorySupported
|
||||
isPoiSearchCategorySupported,
|
||||
normalizePoiSemanticValue
|
||||
} from '@/domain/poiCategories'
|
||||
import type {
|
||||
SgsFloorDiagnosticsPayload,
|
||||
@@ -91,9 +92,39 @@ const spaceCategoryBySgsType: Record<string, MuseumCategory> = {
|
||||
iconType: 'service_space'
|
||||
},
|
||||
commercial: {
|
||||
id: 'space_commercial',
|
||||
label: '商业空间',
|
||||
iconType: 'commercial'
|
||||
id: 'space_shop',
|
||||
label: '购物空间',
|
||||
iconType: 'shop'
|
||||
},
|
||||
restaurant: {
|
||||
id: 'space_restaurant',
|
||||
label: '餐饮空间',
|
||||
iconType: 'restaurant'
|
||||
},
|
||||
cafe: {
|
||||
id: 'space_restaurant',
|
||||
label: '餐饮空间',
|
||||
iconType: 'cafe'
|
||||
},
|
||||
shop: {
|
||||
id: 'space_shop',
|
||||
label: '购物空间',
|
||||
iconType: 'shop'
|
||||
},
|
||||
cultural_shop: {
|
||||
id: 'space_shop',
|
||||
label: '购物空间',
|
||||
iconType: 'cultural_shop'
|
||||
},
|
||||
bookstore: {
|
||||
id: 'space_shop',
|
||||
label: '购物空间',
|
||||
iconType: 'bookstore'
|
||||
},
|
||||
vending: {
|
||||
id: 'space_shop',
|
||||
label: '购物空间',
|
||||
iconType: 'vending'
|
||||
},
|
||||
parking: {
|
||||
id: 'space_parking',
|
||||
@@ -113,6 +144,15 @@ const spaceCategoryBySgsType: Record<string, MuseumCategory> = {
|
||||
}
|
||||
|
||||
const categoryBySgsType: Record<string, MuseumCategory & { accessible?: boolean }> = {
|
||||
exhibition_hall: hallCategory,
|
||||
theater: spaceCategoryBySgsType.theater,
|
||||
commercial: spaceCategoryBySgsType.commercial,
|
||||
restaurant: spaceCategoryBySgsType.restaurant,
|
||||
cafe: spaceCategoryBySgsType.cafe,
|
||||
shop: spaceCategoryBySgsType.shop,
|
||||
cultural_shop: spaceCategoryBySgsType.cultural_shop,
|
||||
bookstore: spaceCategoryBySgsType.bookstore,
|
||||
vending: spaceCategoryBySgsType.vending,
|
||||
poi: {
|
||||
id: 'poi',
|
||||
label: '点位',
|
||||
@@ -126,7 +166,7 @@ const categoryBySgsType: Record<string, MuseumCategory & { accessible?: boolean
|
||||
operation_experience: {
|
||||
id: 'operation_experience',
|
||||
label: '导览点位',
|
||||
iconType: 'poi'
|
||||
iconType: 'guide'
|
||||
},
|
||||
toilet: {
|
||||
id: 'basic_service_facility',
|
||||
@@ -155,11 +195,27 @@ const categoryBySgsType: Record<string, MuseumCategory & { accessible?: boolean
|
||||
label: '扶梯',
|
||||
iconType: 'escalator'
|
||||
},
|
||||
entrance_exit: {
|
||||
id: 'transport_circulation',
|
||||
label: '出入口',
|
||||
iconType: 'entrance_exit'
|
||||
},
|
||||
entrance_exit: {
|
||||
id: 'navigation_anchor',
|
||||
label: '出入口',
|
||||
iconType: 'entrance_exit'
|
||||
},
|
||||
hall_entrance: hallEntranceCategory,
|
||||
entrance_anchor: {
|
||||
id: 'navigation_anchor',
|
||||
label: '入口锚点',
|
||||
iconType: 'entrance_anchor'
|
||||
},
|
||||
route_node: {
|
||||
id: 'navigation_anchor',
|
||||
label: '路线节点',
|
||||
iconType: 'route_node'
|
||||
},
|
||||
navigable_place: {
|
||||
id: 'navigation_anchor',
|
||||
label: '可导航点',
|
||||
iconType: 'navigable_place'
|
||||
},
|
||||
service_desk: {
|
||||
id: 'basic_service_facility',
|
||||
label: '服务台',
|
||||
@@ -203,7 +259,9 @@ const optionalNumber = (value: number | null | undefined) => (
|
||||
: undefined
|
||||
)
|
||||
|
||||
const normalizedText = (value?: string | null) => (value || '').trim()
|
||||
const normalizedText = (value?: string | null) => (value || '').trim()
|
||||
|
||||
export const normalizeSgsPoiSemanticType = (value?: string | null) => normalizePoiSemanticValue(value)
|
||||
|
||||
const normalizePositionSource = (source: SgsPositionPayload): [number, number, number] | undefined => {
|
||||
const x = optionalNumber(source.x)
|
||||
@@ -302,6 +360,8 @@ const nonHallNavigablePlaceTypes = new Set([
|
||||
'toilet',
|
||||
'accessible_toilet',
|
||||
'restroom',
|
||||
'route_node',
|
||||
'navigable_place',
|
||||
'卫生间',
|
||||
'洗手间',
|
||||
'无障碍卫生间',
|
||||
@@ -322,15 +382,38 @@ export interface SgsHallPoiDiagnostics {
|
||||
}
|
||||
|
||||
const businessTypeLabels: Record<string, string> = {
|
||||
shop: '商店',
|
||||
shop: '购物',
|
||||
commercial: '购物',
|
||||
restaurant: '餐饮',
|
||||
cafe: '咖啡',
|
||||
vending: '售卖机',
|
||||
bookstore: '书店',
|
||||
cultural_shop: '文创商店',
|
||||
cafe: '餐饮',
|
||||
vending: '购物',
|
||||
bookstore: '购物',
|
||||
cultural_shop: '购物',
|
||||
photo_spot: '打卡点'
|
||||
}
|
||||
|
||||
const businessTypeIconTypes: Record<string, string> = {
|
||||
shop: 'shop',
|
||||
commercial: 'shop',
|
||||
restaurant: 'restaurant',
|
||||
cafe: 'cafe',
|
||||
vending: 'vending',
|
||||
bookstore: 'bookstore',
|
||||
cultural_shop: 'cultural_shop',
|
||||
photo_spot: 'photo_spot'
|
||||
}
|
||||
|
||||
const categoryForBusinessType = (businessType?: string | null): MuseumCategory => {
|
||||
const normalizedBusinessType = normalizeSgsPoiSemanticType(businessType)
|
||||
if (!normalizedBusinessType) return businessCategory
|
||||
|
||||
return {
|
||||
...businessCategory,
|
||||
label: businessTypeLabels[normalizedBusinessType] || businessCategory.label,
|
||||
iconType: businessTypeIconTypes[normalizedBusinessType] || normalizedBusinessType
|
||||
}
|
||||
}
|
||||
|
||||
interface SgsHallPoiBuildOptions {
|
||||
fallbackY?: number
|
||||
}
|
||||
@@ -339,10 +422,28 @@ const sgsSpaceCenterConfidence = 'backend-sgs-sdk-space-center'
|
||||
const sgsSpaceBoundaryCenterConfidence = 'backend-sgs-sdk-space-boundary-center'
|
||||
const sgsHallEntranceConfidence = 'backend-sgs-sdk-hall-entrance'
|
||||
|
||||
const normalizeTypeId = (value?: string | null) => normalizedText(value)
|
||||
.toLowerCase()
|
||||
const normalizeTypeId = (value?: string | null) => normalizeSgsPoiSemanticType(value)
|
||||
.replace(/[^a-z0-9_-]+/g, '_')
|
||||
.replace(/^_+|_+$/g, '')
|
||||
|
||||
const hiddenSgsPoiTypes = new Set([
|
||||
'entrance_exit',
|
||||
'hall_entrance',
|
||||
'entrance_anchor',
|
||||
'route_node',
|
||||
'navigable_place',
|
||||
'operation_experience'
|
||||
])
|
||||
|
||||
/** Raw navigable-place records may enrich a hall, but are never visitor results themselves. */
|
||||
export const isSgsNavigablePlaceVisitorResult = (_place: SgsNavigablePlacePayload) => false
|
||||
|
||||
export const isSgsPoiHiddenFromVisitorSearch = (poi: Pick<
|
||||
SgsPoiPayload,
|
||||
'type' | 'typeName'
|
||||
>) => [poi.type, poi.typeName]
|
||||
.map(normalizeSgsPoiSemanticType)
|
||||
.some((type) => hiddenSgsPoiTypes.has(type))
|
||||
|
||||
const hasExhibitionKeyword = (value?: string | null) => (
|
||||
exhibitionHallKeywords.some((keyword) => normalizedText(value).includes(keyword))
|
||||
@@ -412,7 +513,7 @@ const normalizeSpacePosition = (
|
||||
}
|
||||
|
||||
export const isExhibitionHallSpace = (space: SgsSpacePayload) => {
|
||||
const type = normalizedText(space.type).toLowerCase()
|
||||
const type = normalizeSgsPoiSemanticType(space.type)
|
||||
const name = normalizedText(space.name)
|
||||
const searchableText = searchableSpaceText(space)
|
||||
|
||||
@@ -430,7 +531,7 @@ export const isExhibitionHallNavigablePlace = (place: SgsNavigablePlacePayload)
|
||||
place.typeCode,
|
||||
place.typeName
|
||||
]
|
||||
.map((value) => normalizedText(value).toLowerCase())
|
||||
.map((value) => normalizeSgsPoiSemanticType(value))
|
||||
.filter(Boolean)
|
||||
|
||||
if (placeTypes.some((type) => nonHallNavigablePlaceTypes.has(type))) return false
|
||||
@@ -480,23 +581,26 @@ const normalizePlacePosition = (
|
||||
)
|
||||
|
||||
const categoryFor = (poi: SgsPoiPayload): MuseumCategory & { accessible?: boolean } => {
|
||||
const normalizedType = poi.type?.trim().toLowerCase()
|
||||
const normalizedBusinessType = poi.businessType?.trim().toLowerCase()
|
||||
const normalizedType = normalizeSgsPoiSemanticType(poi.type)
|
||||
const normalizedTypeName = normalizeSgsPoiSemanticType(poi.typeName)
|
||||
const resolvedType = categoryBySgsType[normalizedType]
|
||||
? normalizedType
|
||||
: normalizedTypeName || normalizedType
|
||||
const normalizedBusinessType = normalizeSgsPoiSemanticType(poi.businessType)
|
||||
|
||||
if (String(poi.poiGroup || '').toUpperCase() === 'BUSINESS') {
|
||||
return {
|
||||
...businessCategory,
|
||||
label: normalizedBusinessType ? businessTypeLabels[normalizedBusinessType] || poi.typeName || businessCategory.label : poi.typeName || businessCategory.label,
|
||||
iconType: normalizedBusinessType || businessCategory.iconType
|
||||
}
|
||||
const category = categoryForBusinessType(normalizedBusinessType || resolvedType)
|
||||
return category.iconType === businessCategory.iconType && poi.typeName
|
||||
? { ...category, label: poi.typeName }
|
||||
: category
|
||||
}
|
||||
|
||||
if (String(poi.poiGroup || '').toUpperCase() === 'OTHER') {
|
||||
return categoryBySgsType[normalizedType || ''] || defaultCategory
|
||||
return categoryBySgsType[resolvedType] || defaultCategory
|
||||
}
|
||||
|
||||
if (normalizedType && categoryBySgsType[normalizedType]) {
|
||||
return categoryBySgsType[normalizedType]
|
||||
if (resolvedType && categoryBySgsType[resolvedType]) {
|
||||
return categoryBySgsType[resolvedType]
|
||||
}
|
||||
|
||||
if (poi.typeName) {
|
||||
@@ -511,9 +615,13 @@ const categoryFor = (poi: SgsPoiPayload): MuseumCategory & { accessible?: boolea
|
||||
}
|
||||
|
||||
const kindForSgsPoi = (poi: SgsPoiPayload, category: MuseumCategory) => {
|
||||
if (category.id === 'business_poi') return 'facility'
|
||||
if (category.id === 'operation_experience') return 'guide'
|
||||
if (isSgsPoiHiddenFromVisitorSearch(poi)) return 'guide'
|
||||
if (category.id === 'operation_experience' || category.id === 'navigation_anchor') return 'guide'
|
||||
if (category.id === hallCategory.id) return 'hall'
|
||||
|
||||
// Raw POI endpoints can use a space-like semantic type (restaurant, shop,
|
||||
// theater) without being a source space. Space records are adapted through
|
||||
// toMuseumSpacePointFromSgs; raw records remain facility POIs.
|
||||
return 'facility'
|
||||
}
|
||||
|
||||
@@ -527,10 +635,14 @@ export const toMuseumPoiFromSgs = (
|
||||
|| sourceFloorId
|
||||
|| stringifyId(poi.floorCode)
|
||||
const category = categoryFor(poi)
|
||||
|
||||
return {
|
||||
id: stringifyId(poi.id),
|
||||
name: poi.name?.trim() || `未命名点位 ${stringifyId(poi.id)}`,
|
||||
const kind = kindForSgsPoi(poi, category)
|
||||
const spatialAreaId = stringifyId(poi.spatialAreaId)
|
||||
const spatialAreaName = normalizedText(poi.spatialAreaName)
|
||||
const name = poi.name?.trim() || `未命名点位 ${stringifyId(poi.id)}`
|
||||
|
||||
return {
|
||||
id: stringifyId(poi.id),
|
||||
name,
|
||||
floorId,
|
||||
floorLabel: formatSgsFloorLabel(matchedFloor?.floorCode || poi.floorCode, matchedFloor?.floorName),
|
||||
primaryCategory: {
|
||||
@@ -550,7 +662,11 @@ export const toMuseumPoiFromSgs = (
|
||||
sourceConfidence: 'backend-sgs-sdk',
|
||||
navigationReadiness: '位置预览',
|
||||
accessible: category.accessible === true,
|
||||
kind: kindForSgsPoi(poi, category)
|
||||
kind,
|
||||
hallId: kind === 'hall' ? spatialAreaId || stringifyId(poi.id) : undefined,
|
||||
hallName: spatialAreaName || (kind === 'hall' ? name : undefined),
|
||||
spaceId: spatialAreaId || undefined,
|
||||
sourceSpaceId: spatialAreaId || undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user