feat: wire guide data source and POI focus UI

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
lyf
2026-06-12 09:25:22 +08:00
parent a6bfda30e1
commit 2055b13b90
58 changed files with 5768 additions and 1898 deletions

View File

@@ -2,10 +2,6 @@
这些 JSON 是早期演示数据,当前导览模块不再以这里作为数据源。
当前室内导览、设施搜索、位置预览统一从:
当前室内导览、设施搜索、位置预览统一通过 Provider / Adapter / Repository / UseCase 数据边界读取 `static/nav-assets/app_nav_assets_v2_clean_20260611_093623`,页面和展示组件不要直接依赖静态包 JSON 文件。
`/static/nav-assets/app_nav_assets_v2_clean_20260609_075339/app_nav_manifest.json`
以及同目录下的 `data/poi_all.json``data/poi_by_floor/*.json` 读取。
如需继续改造历史页面,请优先接入 `src/services/navAssets.ts`,不要新增对本目录 JSON 的业务依赖。
如需继续改造历史页面,请优先接入 `GuideRepository``MuseumContentRepository``ExplainRepository` 或对应 use case不要新增对本目录 JSON 的业务依赖。

View File

@@ -206,15 +206,11 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import type {
ExplainExhibitViewModel
} from '@/view-models/explainViewModels'
export interface Exhibit {
id: string
name: string
artist?: string
hall?: string
floor?: string
image?: string
hasAudio?: boolean
export interface Exhibit extends ExplainExhibitViewModel {
audioUrl?: string
}
@@ -225,6 +221,16 @@ interface SearchResult {
type: 'exhibit' | 'hall' | 'facility'
}
const props = withDefaults(defineProps<{
exhibits?: Exhibit[]
hotSearches?: string[]
initialSearchHistory?: string[]
}>(), {
exhibits: () => [],
hotSearches: () => ['恐龙化石', '银杏', '海洋生物', '霸王龙', '古植物', '矿石标本', '恐龙', '化石'],
initialSearchHistory: () => ['霸王龙', '化石', '恐龙']
})
const emit = defineEmits<{
exhibitClick: [exhibit: Exhibit]
audioClick: [exhibit: Exhibit]
@@ -259,46 +265,31 @@ let touchStartY = 0
let touchCurrentY = 0
// 热门搜索
const hotSearches = ['恐龙化石', '银杏', '海洋生物', '霸王龙', '古植物', '矿石标本', '恐龙', '化石']
const hotSearches = computed(() => props.hotSearches)
// 搜索历史
const searchHistory = ref<string[]>(['霸王龙', '化石', '恐龙'])
const searchHistory = ref<string[]>([...props.initialSearchHistory])
// 搜索数据
const allData: SearchResult[] = [
{ id: '1', name: '霸王龙化石骨架', desc: '恐龙厅 · 2F', type: 'exhibit' },
{ id: '2', name: '银杏化石', desc: '演化厅 · B1', type: 'exhibit' },
{ id: '3', name: '三叶虫化石', desc: '演化厅 · B1', type: 'exhibit' },
{ id: '4', name: '腕龙骨骼', desc: '恐龙厅 · 2F', type: 'exhibit' },
{ id: '5', name: '猛犸象象牙', desc: '人类厅 · 3F', type: 'exhibit' },
{ id: 'h1', name: '恐龙厅', desc: '2F · 25件展品', type: 'hall' },
{ id: 'h2', name: '演化厅', desc: 'B1 · 30件展品', type: 'hall' },
{ id: 'h3', name: '生物厅', desc: '3F · 18件展品', type: 'hall' },
{ id: 'f1', name: '洗手间', desc: '1F', type: 'facility' },
{ id: 'f2', name: '咖啡厅', desc: '1F', type: 'facility' },
]
const allData = computed<SearchResult[]>(() => props.exhibits.map((exhibit) => ({
id: exhibit.id,
name: exhibit.name,
desc: exhibit.hall || exhibit.floor || '展项内容',
type: 'exhibit'
})))
// 搜索结果计算
const searchResults = computed(() => {
if (!searchInputValue.value.trim()) return []
const kw = searchInputValue.value.toLowerCase()
return allData.filter(item =>
return allData.value.filter(item =>
item.name.toLowerCase().includes(kw) ||
item.desc.toLowerCase().includes(kw)
)
})
// 展品列表
const exhibits = ref<Exhibit[]>([
{ id: '1', name: '银杏化石', hall: '演化厅 B1', hasAudio: true, audioUrl: '' },
{ id: '2', name: '三叶虫化石', hall: '演化厅 B1', hasAudio: true, audioUrl: '' },
{ id: '3', name: '腕龙骨骼', hall: '恐龙厅 2F', hasAudio: true, audioUrl: '' },
{ id: '4', name: '始祖鸟标本', hall: '演化厅 B1', hasAudio: false, audioUrl: '' },
{ id: '5', name: '猛犸象象牙', hall: '人类厅 3F', hasAudio: true, audioUrl: '' },
{ id: '6', name: '珊瑚礁标本', hall: '生物厅 3F', hasAudio: false, audioUrl: '' },
{ id: '7', name: '剑龙化石', hall: '恐龙厅 2F', hasAudio: true, audioUrl: '' },
{ id: '8', name: '鹦鹉螺化石', hall: '演化厅 B1', hasAudio: true, audioUrl: '' }
])
const exhibits = computed(() => props.exhibits)
// 过滤展品
const filteredExhibits = computed(() => {

View File

@@ -30,16 +30,9 @@ const emit = defineEmits<{
change: [floorId: string]
}>()
const currentFloor = ref(props.current || '1F')
const currentFloor = ref(props.current || props.floors?.[0]?.id || '')
const defaultFloors: Floor[] = [
{ id: '3F', label: '3F' },
{ id: '2F', label: '2F' },
{ id: '1F', label: '1F' },
{ id: 'B1', label: 'B1' }
]
const floors = props.floors || defaultFloors
const floors = props.floors || []
const handleFloorClick = (floor: Floor) => {
if (floor.disabled) return

View File

@@ -58,7 +58,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { computed, ref, onMounted } from 'vue'
const isH5 = typeof window !== 'undefined'
@@ -94,6 +94,19 @@ interface Polygon {
zIndex: number
}
interface MapFloor {
id: string
label: string
}
const props = withDefaults(defineProps<{
activeFloor?: string
floors?: MapFloor[]
}>(), {
activeFloor: '1F',
floors: () => [] as MapFloor[]
})
const emit = defineEmits<{
markerClick: [markerId: number]
floorChange: [floor: string]
@@ -111,15 +124,10 @@ const mapCenter = ref<MapCenter>({
const mapScale = ref(17)
// 当前楼层
const currentFloor = ref('1F')
const currentFloor = ref(props.activeFloor)
// 楼层列表
const floors = [
{ id: '3F', label: '3F' },
{ id: '2F', label: '2F' },
{ id: '1F', label: '1F' },
{ id: 'B1', label: 'B1' }
]
const floors = computed(() => props.floors)
// 博物馆建筑围栏(多边形)
// 深圳自然博物馆实际建筑轮廓坐标

View File

@@ -50,56 +50,23 @@ import * as THREE from 'three'
import { GLTFLoader, type GLTF } from 'three/addons/loaders/GLTFLoader.js'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import FloorSwitcher from './FloorSwitcher.vue'
import { NAV_ASSET_BASE_URL } from '@/services/navAssets'
import type {
GuideModelFloorAsset,
GuideModelRenderPackage,
GuideModelSource,
GuideRenderPoi
} from '@/domain/guideModel'
type ViewMode = 'overview' | 'floor'
interface ManifestFloorModel {
floorId: string
order: number
asset: string
}
interface CleanNavManifest {
status: string
assets: {
overviewModel: {
asset: string
}
floorModels: ManifestFloorModel[]
}
data: {
floorIndex: string
}
}
interface FloorIndexItem {
floorId: string
order: number
modelAsset: string
poiDataAsset: string
poiCount: number
}
interface FloorIndexData {
status: string
floors: FloorIndexItem[]
}
type FloorIndexItem = GuideModelFloorAsset
interface FloorOption {
id: string
label: string
}
interface CleanPoi {
id: string
name: string
floorId: string
primaryCategory: string
primaryCategoryZh: string
iconType: string
positionGltf?: [number, number, number]
}
type RenderPoi = GuideRenderPoi
interface TargetPoiFocusRequest {
requestId: number | string
@@ -119,23 +86,18 @@ interface TargetPoiFocusResult {
message?: string
}
interface FloorPoiData {
status: string
floorId: string
pois: CleanPoi[]
}
type ContainerRef = HTMLElement | { $el?: HTMLElement } | null
const props = withDefaults(defineProps<{
assetBaseUrl?: string
modelSource: GuideModelSource
initialFloorId?: string
initialView?: ViewMode
showControls?: boolean
showPoi?: boolean
targetFocus?: TargetPoiFocusRequest | null
}>(), {
assetBaseUrl: NAV_ASSET_BASE_URL,
assetBaseUrl: '',
initialFloorId: 'L1',
initialView: 'overview',
showControls: true,
@@ -145,7 +107,7 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
floorChange: [floorId: string]
poiClick: [poi: CleanPoi]
poiClick: [poi: RenderPoi]
targetFocus: [result: TargetPoiFocusResult]
}>()
@@ -156,9 +118,10 @@ const loadingProgress = ref(0)
const loadingMessage = ref('正在读取室内导览资源...')
const activeView = ref<ViewMode>(props.initialView)
const currentFloor = ref(props.initialFloorId)
const selectedPOI = ref<CleanPoi | null>(null)
const selectedPOI = ref<RenderPoi | null>(null)
const activeFocusPoiId = ref('')
const floorIndex = ref<FloorIndexItem[]>([])
const renderPackage = ref<GuideModelRenderPackage | null>(null)
const floors = computed<FloorOption[]>(() => (
[...floorIndex.value]
@@ -170,7 +133,6 @@ const floors = computed<FloorOption[]>(() => (
))
const shouldRenderPoiMarkers = computed(() => props.showPoi || props.showControls || Boolean(props.targetFocus))
let manifest: CleanNavManifest | null = null
let scene: THREE.Scene | null = null
let camera: THREE.PerspectiveCamera | null = null
let renderer: THREE.WebGLRenderer | null = null
@@ -178,16 +140,13 @@ let controls: OrbitControls | null = null
let loader: GLTFLoader | null = null
let activeModel: THREE.Object3D | null = null
let poiGroup: THREE.Group | null = null
let activeFocusLabelSprite: THREE.Sprite | null = null
let animationId = 0
let resizeObserver: ResizeObserver | null = null
let isDisposed = false
let pendingTargetFocus: TargetPoiFocusRequest | null = null
let targetFocusQueue: Promise<unknown> = Promise.resolve()
const normalizeBaseUrl = (baseUrl: string) => baseUrl.replace(/\/+$/, '')
const assetUrl = (relativePath: string) => `${normalizeBaseUrl(props.assetBaseUrl)}/${relativePath.replace(/^\/+/, '')}`
const getContainerElement = () => {
const container = containerRef.value
if (!container) return null
@@ -202,27 +161,15 @@ const getContainerElement = () => {
return element instanceof HTMLElement ? element : null
}
const formatFloorLabel = (floorId: string) => {
if (floorId === 'L-2') return 'B2'
if (floorId === 'L-1') return 'B1'
if (floorId === 'L1.5') return '1.5F'
if (floorId.startsWith('L')) return `${floorId.slice(1)}F`
return floorId
}
const formatFloorLabel = (floorId: string) => (
floorIndex.value.find((floor) => floor.floorId === floorId)?.label || floorId
)
const setProgress = (progress: number, message: string) => {
loadingProgress.value = Math.min(100, Math.max(0, progress))
loadingMessage.value = message
}
const fetchJson = async <T,>(url: string): Promise<T> => {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`资源读取失败: ${response.status} ${url}`)
}
return response.json() as Promise<T>
}
const waitForContainer = async () => {
await nextTick()
@@ -274,7 +221,7 @@ const initThree = async () => {
loader = new GLTFLoader()
poiGroup = new THREE.Group()
poiGroup.name = 'CleanPackagePOI'
poiGroup.name = 'GuideModelPOI'
scene.add(poiGroup)
const ambientLight = new THREE.AmbientLight(0xffffff, 1.6)
@@ -340,6 +287,7 @@ const clearSceneData = () => {
}
activeModel = null
disposeFocusLabel()
selectedPOI.value = null
if (poiGroup) {
@@ -405,15 +353,16 @@ const fitCameraToObject = (object: THREE.Object3D) => {
}
const loadOverview = async () => {
if (!manifest || !scene) return
const packageData = renderPackage.value
if (!packageData || !scene) return
activeView.value = 'overview'
clearSceneData()
setProgress(18, '正在加载全馆三维模型...')
const gltf = await loadModel(assetUrl(manifest.assets.overviewModel.asset), '正在加载全馆三维模型')
const gltf = await loadModel(packageData.overviewModelUrl, '正在加载全馆三维模型')
activeModel = gltf.scene
activeModel.name = 'CleanOverviewModel'
activeModel.name = 'GuideOverviewModel'
prepareModel(activeModel)
scene.add(activeModel)
fitCameraToObject(activeModel)
@@ -428,9 +377,9 @@ const loadFloor = async (floorId: string) => {
clearSceneData()
setProgress(18, `正在加载 ${formatFloorLabel(floor.floorId)} 模型...`)
const gltf = await loadModel(assetUrl(floor.modelAsset), `正在加载 ${formatFloorLabel(floor.floorId)} 模型`)
const gltf = await loadModel(floor.modelUrl, `正在加载 ${formatFloorLabel(floor.floorId)} 模型`)
activeModel = gltf.scene
activeModel.name = `CleanFloorModel_${floor.floorId}`
activeModel.name = `GuideFloorModel_${floor.floorId}`
prepareModel(activeModel)
scene.add(activeModel)
fitCameraToObject(activeModel)
@@ -440,7 +389,7 @@ const loadFloor = async (floorId: string) => {
}
}
const createPoiMaterial = (poi: CleanPoi) => {
const createPoiMaterial = (poi: RenderPoi) => {
const canvas = document.createElement('canvas')
canvas.width = 96
canvas.height = 96
@@ -476,6 +425,69 @@ const createPoiMaterial = (poi: CleanPoi) => {
})
}
const createPoiLabelSprite = (poi: RenderPoi, markerSize: number) => {
const canvas = document.createElement('canvas')
canvas.width = 512
canvas.height = 144
const context = canvas.getContext('2d')
const label = poi.name.length > 14 ? `${poi.name.slice(0, 14)}` : poi.name
if (context) {
context.clearRect(0, 0, canvas.width, canvas.height)
context.fillStyle = 'rgba(0, 0, 0, 0.82)'
context.beginPath()
context.roundRect(36, 18, 440, 82, 30)
context.fill()
context.beginPath()
context.moveTo(238, 100)
context.lineTo(274, 100)
context.lineTo(256, 124)
context.closePath()
context.fill()
context.font = '600 38px sans-serif'
context.textAlign = 'center'
context.textBaseline = 'middle'
context.fillStyle = '#ffffff'
context.fillText(label, 256, 59, 390)
}
const texture = new THREE.CanvasTexture(canvas)
texture.colorSpace = THREE.SRGBColorSpace
const sprite = new THREE.Sprite(new THREE.SpriteMaterial({
map: texture,
transparent: true,
depthTest: false,
depthWrite: false
}))
sprite.userData.isPoiLabel = true
sprite.renderOrder = 30
sprite.scale.set(markerSize * 4.8, markerSize * 1.35, 1)
return sprite
}
const disposeFocusLabel = () => {
if (!activeFocusLabelSprite) return
activeFocusLabelSprite.parent?.remove(activeFocusLabelSprite)
disposeObject(activeFocusLabelSprite)
activeFocusLabelSprite = null
}
const showFocusPoiLabel = (poi: RenderPoi) => {
if (!poiGroup || !poi.positionGltf) return
disposeFocusLabel()
const markerSize = getPoiMarkerSize()
const [x, y, z] = poi.positionGltf
activeFocusLabelSprite = createPoiLabelSprite(poi, markerSize)
activeFocusLabelSprite.position.set(x, y + markerSize * 2.35, z)
poiGroup.add(activeFocusLabelSprite)
}
const getPoiColor = (category: string) => {
const colorMap: Record<string, string> = {
touring_poi: '#2f6fed',
@@ -509,8 +521,8 @@ const updatePoiMarkerFocus = () => {
if (!poiGroup) return
poiGroup.children.forEach((child) => {
if (child instanceof THREE.Sprite) {
const poi = child.userData.poi as CleanPoi | undefined
if (child instanceof THREE.Sprite && !child.userData.isPoiLabel) {
const poi = child.userData.poi as RenderPoi | undefined
setPoiSpriteFocusStyle(child, Boolean(poi && poi.id === activeFocusPoiId.value))
}
})
@@ -518,15 +530,15 @@ const updatePoiMarkerFocus = () => {
const findPoiSprite = (poiId: string) => (
poiGroup?.children.find((child): child is THREE.Sprite => (
child instanceof THREE.Sprite && (child.userData.poi as CleanPoi | undefined)?.id === poiId
child instanceof THREE.Sprite && (child.userData.poi as RenderPoi | undefined)?.id === poiId
))
)
const findLoadedPoi = (poiId: string) => (
findPoiSprite(poiId)?.userData.poi as CleanPoi | undefined
findPoiSprite(poiId)?.userData.poi as RenderPoi | undefined
)
const createPoiFromFocusRequest = (request: TargetPoiFocusRequest): CleanPoi | null => {
const createPoiFromFocusRequest = (request: TargetPoiFocusRequest): RenderPoi | null => {
if (!request.positionGltf) return null
return {
@@ -561,8 +573,7 @@ const addFocusMarkerFromRequest = (request: TargetPoiFocusRequest) => {
const loadFloorPOIs = async (floor: FloorIndexItem) => {
if (!poiGroup) return
const data = await fetchJson<FloorPoiData>(assetUrl(floor.poiDataAsset))
const validPois = data.pois.filter((poi) => Array.isArray(poi.positionGltf) && poi.positionGltf.length === 3)
const validPois = await props.modelSource.loadFloorPois(floor.floorId)
const markerSize = getPoiMarkerSize()
validPois.forEach((poi) => {
@@ -588,8 +599,10 @@ const handlePointerDown = (event: PointerEvent) => {
raycaster.setFromCamera(pointer, camera)
const hits = raycaster.intersectObjects(poiGroup.children, false)
if (hits[0]?.object.userData.poi) {
selectedPOI.value = hits[0].object.userData.poi as CleanPoi
const hit = hits.find((item) => !item.object.userData.isPoiLabel && item.object.userData.poi)
if (hit?.object.userData.poi) {
selectedPOI.value = hit.object.userData.poi as RenderPoi
activeFocusPoiId.value = selectedPOI.value.id
updatePoiMarkerFocus()
emit('poiClick', selectedPOI.value)
@@ -614,6 +627,7 @@ const clearTargetFocus = () => {
pendingTargetFocus = null
activeFocusPoiId.value = ''
selectedPOI.value = null
disposeFocusLabel()
updatePoiMarkerFocus()
}
@@ -623,7 +637,7 @@ const isSceneReadyForTargetFocus = () => (
&& !loadError.value
)
const focusCameraOnPoi = (poi: CleanPoi) => {
const focusCameraOnPoi = (poi: RenderPoi) => {
if (!camera || !controls || !poi.positionGltf) return
const [x, y, z] = poi.positionGltf
@@ -675,6 +689,7 @@ const focusTargetPoi = async (request: TargetPoiFocusRequest) => {
if (!poi?.positionGltf) {
selectedPOI.value = null
disposeFocusLabel()
updatePoiMarkerFocus()
emitTargetFocus(request, 'missing', '目标暂无三维坐标')
return false
@@ -682,6 +697,7 @@ const focusTargetPoi = async (request: TargetPoiFocusRequest) => {
selectedPOI.value = poi
updatePoiMarkerFocus()
showFocusPoiLabel(poi)
focusCameraOnPoi(poi)
emitTargetFocus(request, 'focused')
return true
@@ -718,17 +734,13 @@ const queueTargetFocus = (request: TargetPoiFocusRequest | null) => {
})
}
const loadCleanPackage = async () => {
const loadModelPackage = async () => {
setProgress(8, '正在读取室内导览资源...')
manifest = await fetchJson<CleanNavManifest>(assetUrl('app_nav_manifest.json'))
if (manifest.status !== 'pass') {
throw new Error('室内导览资源包状态不是 pass')
}
const packageData = await props.modelSource.loadPackage()
renderPackage.value = packageData
setProgress(14, '正在读取楼层索引...')
const floorData = await fetchJson<FloorIndexData>(assetUrl(manifest.data.floorIndex))
floorIndex.value = [...floorData.floors].sort((a, b) => a.order - b.order)
floorIndex.value = [...packageData.floors].sort((a, b) => a.order - b.order)
if (!floorIndex.value.some((floor) => floor.floorId === currentFloor.value)) {
currentFloor.value = floorIndex.value.find((floor) => floor.floorId === 'L1')?.floorId || floorIndex.value[0]?.floorId || 'L1'
@@ -752,13 +764,13 @@ const init3DScene = async () => {
setProgress(0, '正在初始化三维场景...')
await initThree()
await loadCleanPackage()
await loadModelPackage()
setProgress(100, '室内三维模型加载完成')
isLoading.value = false
queueTargetFocus(pendingTargetFocus || props.targetFocus || null)
} catch (error) {
console.error('室内 3D clean package 加载失败:', error)
console.error('室内 3D 模型资源加载失败:', error)
loadError.value = true
isLoading.value = false
setProgress(0, error instanceof Error ? error.message : '请检查模型资源或网络状态后重试')
@@ -840,11 +852,12 @@ defineExpose({
clearNavigation: () => {
activeFocusPoiId.value = ''
selectedPOI.value = null
disposeFocusLabel()
updatePoiMarkerFocus()
}
})
watch(() => props.assetBaseUrl, () => {
watch(() => props.modelSource, () => {
init3DScene()
})

View File

@@ -4,9 +4,11 @@
<template v-if="mapType === 'indoor'">
<!-- #ifdef H5 -->
<ThreeMap
v-if="indoorModelSource"
ref="threeMapRef"
class="indoor-three-map"
:asset-base-url="indoorAssetBaseUrl"
:model-source="indoorModelSource"
:initial-floor-id="activeFloorId"
:initial-view="indoorInitialView"
:show-controls="false"
@@ -23,7 +25,11 @@
<!-- #endif -->
</template>
<view v-else class="outdoor-map-bg">
<TencentMap class="outdoor-map" />
<TencentMap
class="outdoor-map"
:active-floor="activeFloor"
:floors="props.floors"
/>
</view>
<view v-if="dimmed" class="dim-layer"></view>
</view>
@@ -105,7 +111,7 @@
<view v-if="showFloor" class="floor-switcher" :style="floorSwitcherStyle">
<view
v-for="floor in floors"
v-for="floor in floorLabels"
:key="floor"
class="floor-item"
:class="{ active: activeFloor === floor }"
@@ -136,11 +142,14 @@ import TencentMap from '@/components/map/TencentMap.vue'
// #ifdef H5
import ThreeMap from '@/components/map/ThreeMap.vue'
// #endif
import {
NAV_ASSET_BASE_URL,
NAV_FLOOR_OPTIONS,
navFloorIdFromLabel
} from '@/services/navAssets'
import type {
GuideModelSource
} from '@/domain/guideModel'
interface GuideFloorOption {
id: string
label: string
}
interface TargetPoiFocusRequest {
requestId: number | string
@@ -183,6 +192,9 @@ const props = withDefaults(defineProps<{
mapType?: 'indoor' | 'outdoor'
outdoorVariant?: 'home' | 'entrance'
indoorAssetBaseUrl?: string
indoorModelSource?: GuideModelSource
floors?: GuideFloorOption[]
normalizeFloorId?: (labelOrId: string) => string
dimmed?: boolean
targetFocusRequest?: TargetPoiFocusRequest | null
}>(), {
@@ -205,7 +217,10 @@ const props = withDefaults(defineProps<{
modeStatusTone: 'solid',
mapType: 'indoor',
outdoorVariant: 'home',
indoorAssetBaseUrl: NAV_ASSET_BASE_URL,
indoorAssetBaseUrl: '',
indoorModelSource: undefined,
floors: () => [] as GuideFloorOption[],
normalizeFloorId: (labelOrId: string) => labelOrId,
dimmed: false,
targetFocusRequest: null
})
@@ -223,9 +238,11 @@ const threeMapRef = ref<{
switchFloor?: (floorId: string) => Promise<void> | void
showOverview?: () => Promise<void> | void
} | null>(null)
const floors = NAV_FLOOR_OPTIONS.map((floor) => floor.label)
const activeFloorId = computed(() => navFloorIdFromLabel(props.activeFloor))
const floorLabels = computed(() => props.floors.map((floor) => floor.label))
const indoorModelSource = computed(() => props.indoorModelSource)
const activeFloorId = computed(() => props.normalizeFloorId(props.activeFloor))
const searchFieldStyle = computed(() => ({
top: props.searchTop
@@ -258,7 +275,7 @@ const handleModeChange = (mode: '2d' | '3d') => {
}
const handleFloorChange = (floor: string) => {
const floorId = navFloorIdFromLabel(floor)
const floorId = props.normalizeFloorId(floor)
void threeMapRef.value?.switchFloor?.(floorId)
emit('indoorViewChange', 'floor')
emit('floorChange', floor)
@@ -507,10 +524,11 @@ const handleTargetFocus = (result: TargetPoiFocusResult) => {
position: absolute;
right: 16px;
width: 46px;
height: 218px;
height: auto;
max-height: calc(100vh - 260px);
padding: 1px;
box-sizing: border-box;
overflow: hidden;
overflow: visible;
background: rgba(255, 255, 255, 0.84);
border: 1px solid #dde5df;
border-radius: 10px;

View File

@@ -25,7 +25,7 @@
<text class="action-text">查看室外地图</text>
</view>
<view class="action-btn primary" @tap="handleShowTargetLocation">
<text class="action-text">查看目标位置</text>
<text class="action-text">重新定位目标</text>
</view>
</view>
</view>

View File

@@ -107,14 +107,9 @@
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick, onMounted } from 'vue'
import {
formatNavFloorLabel,
searchCleanNavPois,
type CleanNavPoi
} from '@/services/navAssets'
import { ref, computed, watch, nextTick } from 'vue'
interface SearchResult {
export interface SearchResult {
id: string
name: string
desc: string
@@ -126,9 +121,11 @@ const props = withDefaults(defineProps<{
placeholder?: string
/** 嵌入模式:隐藏背景遮罩和取消按钮,直接嵌入父容器 */
embedded?: boolean
results?: SearchResult[]
}>(), {
placeholder: '搜索展品、展厅、设施...',
embedded: false
embedded: false,
results: () => []
})
const emit = defineEmits<{
@@ -144,14 +141,7 @@ const hotSearches = ref(['卫生间', '电梯', '服务台', '无障碍', '入
const searchHistory = ref<string[]>([])
const allData = ref<SearchResult[]>([])
const toSearchResult = (poi: CleanNavPoi): SearchResult => ({
id: poi.id,
name: poi.name,
desc: `${formatNavFloorLabel(poi.floorId)} · ${poi.primaryCategoryZh}`,
type: poi.primaryCategory === 'touring_poi' ? 'hall' : 'facility'
})
const allData = computed(() => props.results)
// 搜索结果计算
const allResults = computed(() => {
@@ -218,20 +208,6 @@ const getResultIcon = (type: string): string => {
return icons[type] || '📍'
}
const loadCleanResults = async () => {
try {
const pois = await searchCleanNavPois()
allData.value = pois.slice(0, 120).map(toSearchResult)
} catch (error) {
console.error('加载 clean POI 搜索数据失败:', error)
allData.value = []
}
}
onMounted(() => {
loadCleanResults()
})
// 打开时聚焦输入框
watch(() => props.isOpen, async (newVal) => {
if (newVal) {

View File

@@ -0,0 +1,60 @@
import type {
MuseumCategory,
MuseumPoi
} from '@/domain/museum'
import type {
StaticNavPoiCategoryPayload,
StaticNavPoiPayload
} from '@/data/providers/staticNavAssetsProvider'
const floorIdPattern = /^L(-?\d+(?:\.\d+)?)$/
export const formatNavFloorLabel = (floorId: string) => {
const match = floorId.match(floorIdPattern)
if (!match) return floorId
const value = Number(match[1])
if (Number.isNaN(value)) return floorId
return value < 0 ? `B${Math.abs(value)}` : `${value}F`
}
export const navFloorIdFromLabel = (labelOrId: string) => {
if (floorIdPattern.test(labelOrId)) return labelOrId
const basementMatch = labelOrId.match(/^B(\d+(?:\.\d+)?)$/i)
if (basementMatch) return `L-${basementMatch[1]}`
const floorMatch = labelOrId.match(/^(\d+(?:\.\d+)?)F$/i)
if (floorMatch) return `L${floorMatch[1]}`
return labelOrId
}
const toCategory = (category: StaticNavPoiCategoryPayload): MuseumCategory => ({
id: category.topCategory,
label: category.topCategoryZh,
iconType: category.iconType
})
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,
sourceConfidence: poi.sourceConfidence,
navigationReadiness: poi.navigationReadiness,
accessible: isPoiAccessible(poi)
})

View File

@@ -0,0 +1,123 @@
import type {
MuseumExhibit,
MuseumHall
} from '@/domain/museum'
export interface MuseumContentProvider {
listExhibits(): Promise<MuseumExhibit[]>
listHalls(): Promise<MuseumHall[]>
}
const transitionalHalls: MuseumHall[] = [
{
id: 'hall-evolution',
name: '演化厅',
floorId: 'L-1',
floorLabel: 'B1',
description: '自然演化主题内容。当前为内容仓储过渡数据,待 CMS/API 接入后替换。',
image: '/static/hall-placeholder.jpg',
exhibitCount: 3,
area: '待补充'
},
{
id: 'hall-dinosaur',
name: '恐龙厅',
floorId: 'L2',
floorLabel: '2F',
description: '恐龙与古生物主题内容。当前为内容仓储过渡数据,待 CMS/API 接入后替换。',
image: '/static/hall-placeholder.jpg',
exhibitCount: 2,
area: '待补充'
},
{
id: 'hall-biology',
name: '生物厅',
floorId: 'L3',
floorLabel: '3F',
description: '生物多样性主题内容。当前为内容仓储过渡数据,待 CMS/API 接入后替换。',
image: '/static/hall-placeholder.jpg',
exhibitCount: 2,
area: '待补充'
}
]
const transitionalExhibits: MuseumExhibit[] = [
{
id: 'exhibit-ginkgo-fossil',
name: '银杏化石',
hallId: 'hall-evolution',
hallName: '演化厅',
floorId: 'L-1',
floorLabel: 'B1',
image: '/static/exhibit-placeholder.jpg',
description: '银杏化石内容待由正式内容库补充。当前仅用于讲解业务架构迁移。',
tags: ['化石', '古植物']
},
{
id: 'exhibit-trilobite-fossil',
name: '三叶虫化石',
hallId: 'hall-evolution',
hallName: '演化厅',
floorId: 'L-1',
floorLabel: 'B1',
image: '/static/exhibit-placeholder.jpg',
description: '三叶虫化石内容待由正式内容库补充。当前仅用于讲解业务架构迁移。',
tags: ['化石', '古生物']
},
{
id: 'exhibit-brachiosaurus',
name: '腕龙骨骼',
hallId: 'hall-dinosaur',
hallName: '恐龙厅',
floorId: 'L2',
floorLabel: '2F',
image: '/static/exhibit-placeholder.jpg',
description: '腕龙骨骼内容待由正式内容库补充。当前仅用于讲解业务架构迁移。',
tags: ['恐龙', '骨骼']
},
{
id: 'exhibit-archaeopteryx',
name: '始祖鸟标本',
hallId: 'hall-evolution',
hallName: '演化厅',
floorId: 'L-1',
floorLabel: 'B1',
image: '/static/exhibit-placeholder.jpg',
description: '始祖鸟标本内容待由正式内容库补充。当前仅用于讲解业务架构迁移。',
tags: ['演化', '标本']
},
{
id: 'exhibit-mammoth-tusk',
name: '猛犸象象牙',
hallId: 'hall-biology',
hallName: '生物厅',
floorId: 'L3',
floorLabel: '3F',
image: '/static/exhibit-placeholder.jpg',
description: '猛犸象象牙内容待由正式内容库补充。当前仅用于讲解业务架构迁移。',
tags: ['古生物', '标本']
},
{
id: 'exhibit-coral-reef',
name: '珊瑚礁标本',
hallId: 'hall-biology',
hallName: '生物厅',
floorId: 'L3',
floorLabel: '3F',
image: '/static/exhibit-placeholder.jpg',
description: '珊瑚礁标本内容待由正式内容库补充。当前仅用于讲解业务架构迁移。',
tags: ['海洋生物', '标本']
}
]
export class StaticMuseumContentProvider implements MuseumContentProvider {
async listExhibits() {
return transitionalExhibits
}
async listHalls() {
return transitionalHalls
}
}
export const staticMuseumContentProvider = new StaticMuseumContentProvider()

View File

@@ -0,0 +1,214 @@
import {
NAV_ASSET_BASE_URL
} from '@/domain/guideReadiness'
export interface StaticNavPoiCategoryPayload {
topCategory: string
topCategoryZh: string
subcategory: string
iconType: string
reason?: string
}
export interface StaticNavPoiPayload {
id: string
name: string
floorId: string
primaryCategory: string
primaryCategoryZh: string
categories?: StaticNavPoiCategoryPayload[]
iconType?: string
positionGltf?: [number, number, number]
navigationReadiness?: string
sourceConfidence?: string
}
export interface StaticNavManifestFloorModelPayload {
floorId: string
order: number
asset: string
}
export interface StaticNavManifestPayload {
status: string
assets: {
overviewModel: {
asset: string
}
floorModels: StaticNavManifestFloorModelPayload[]
}
data: {
floorIndex: string
}
}
export interface StaticNavFloorIndexItemPayload {
floorId: string
order: number
modelAsset: string
poiDataAsset: string
poiCount: number
}
export interface StaticNavFloorIndexPayload {
status: string
floors: StaticNavFloorIndexItemPayload[]
}
interface StaticFloorPoiPayload {
status: string
floorId: string
pois: StaticNavPoiPayload[]
}
interface StaticPoiIndexPayload {
status: string
pois: StaticNavPoiPayload[]
}
const normalizeBaseUrl = (baseUrl: string) => baseUrl.replace(/\/+$/, '')
const parseJsonPayload = <T>(payload: unknown): T => {
if (typeof payload === 'string') {
return JSON.parse(payload) as T
}
return payload as T
}
const requestJson = <T>(url: string): Promise<T> => new Promise((resolve, reject) => {
uni.request({
url,
method: 'GET',
success: (response) => {
const statusCode = Number(response.statusCode || 0)
if (statusCode < 200 || statusCode >= 300) {
reject(new Error(`导览资源读取失败: ${statusCode} ${url}`))
return
}
try {
resolve(parseJsonPayload<T>(response.data))
} catch (error) {
reject(error)
}
},
fail: reject
})
})
export interface StaticNavAssetsProvider {
readonly baseUrl: string
assetUrl(relativePath: string): string
loadManifest(): Promise<StaticNavManifestPayload>
loadFloorIndex(): Promise<StaticNavFloorIndexPayload>
loadPoiIndex(): Promise<StaticNavPoiPayload[]>
loadFloorPois(relativePath: string): Promise<StaticNavPoiPayload[]>
}
export const createStaticNavAssetsProvider = (
baseUrl = NAV_ASSET_BASE_URL
): StaticNavAssetsProvider => {
const normalizedBaseUrl = normalizeBaseUrl(baseUrl)
let poiCache: StaticNavPoiPayload[] | null = null
let poiRequest: Promise<StaticNavPoiPayload[]> | null = null
let manifestCache: StaticNavManifestPayload | null = null
let manifestRequest: Promise<StaticNavManifestPayload> | null = null
let floorIndexCache: StaticNavFloorIndexPayload | null = null
let floorIndexRequest: Promise<StaticNavFloorIndexPayload> | null = null
const floorPoiCache = new Map<string, StaticNavPoiPayload[]>()
const floorPoiRequests = new Map<string, Promise<StaticNavPoiPayload[]>>()
const provider: StaticNavAssetsProvider = {
baseUrl: normalizedBaseUrl,
assetUrl(relativePath: string) {
return `${normalizedBaseUrl}/${relativePath.replace(/^\/+/, '')}`
},
async loadManifest() {
if (manifestCache) return manifestCache
if (manifestRequest) return manifestRequest
manifestRequest = requestJson<StaticNavManifestPayload>(provider.assetUrl('app_nav_manifest.json'))
.then((data) => {
if (data.status !== 'pass') {
throw new Error('室内导览资源包状态不是 pass')
}
manifestCache = data
return manifestCache
})
.finally(() => {
manifestRequest = null
})
return manifestRequest
},
async loadFloorIndex() {
if (floorIndexCache) return floorIndexCache
if (floorIndexRequest) return floorIndexRequest
floorIndexRequest = provider.loadManifest()
.then((manifest) => requestJson<StaticNavFloorIndexPayload>(provider.assetUrl(manifest.data.floorIndex)))
.then((data) => {
if (data.status !== 'pass') {
throw new Error('导览楼层索引状态不是 pass')
}
floorIndexCache = data
return floorIndexCache
})
.finally(() => {
floorIndexRequest = null
})
return floorIndexRequest
},
async loadPoiIndex() {
if (poiCache) return poiCache
if (poiRequest) return poiRequest
poiRequest = requestJson<StaticPoiIndexPayload>(provider.assetUrl('data/poi_all.json'))
.then((data) => {
if (data.status !== 'pass') {
throw new Error('导览 POI 数据状态不是 pass')
}
poiCache = data.pois
return poiCache
})
.finally(() => {
poiRequest = null
})
return poiRequest
},
async loadFloorPois(relativePath: string) {
const cacheKey = relativePath.replace(/^\/+/, '')
const cached = floorPoiCache.get(cacheKey)
if (cached) return cached
const pending = floorPoiRequests.get(cacheKey)
if (pending) return pending
const request = requestJson<StaticFloorPoiPayload>(provider.assetUrl(cacheKey))
.then((data) => {
if (data.status !== 'pass') {
throw new Error('导览楼层 POI 数据状态不是 pass')
}
floorPoiCache.set(cacheKey, data.pois)
return data.pois
})
.finally(() => {
floorPoiRequests.delete(cacheKey)
})
floorPoiRequests.set(cacheKey, request)
return request
}
}
return provider
}
export const defaultStaticNavAssetsProvider = createStaticNavAssetsProvider()

26
src/domain/guideModel.ts Normal file
View File

@@ -0,0 +1,26 @@
export interface GuideRenderPoi {
id: string
name: string
floorId: string
primaryCategory: string
primaryCategoryZh: string
iconType: string
positionGltf?: [number, number, number]
}
export interface GuideModelFloorAsset {
floorId: string
label: string
order: number
modelUrl: string
}
export interface GuideModelRenderPackage {
overviewModelUrl: string
floors: GuideModelFloorAsset[]
}
export interface GuideModelSource {
loadPackage(): Promise<GuideModelRenderPackage>
loadFloorPois(floorId: string): Promise<GuideRenderPoi[]>
}

View File

@@ -0,0 +1,11 @@
export const NAV_ROUTE_GRAPH_READY = false
export const NAV_ROUTE_UNAVAILABLE_MESSAGE = '正式路线数据尚未接入,可先查看馆内三维位置'
export const NAV_ROUTE_READINESS = {
ready: NAV_ROUTE_GRAPH_READY,
message: NAV_ROUTE_UNAVAILABLE_MESSAGE,
requiredData: ['route_graph', 'nav_data']
} as const
export const NAV_ASSET_BASE_URL = '/static/nav-assets/app_nav_assets_v2_clean_20260611_093623'

123
src/domain/museum.ts Normal file
View File

@@ -0,0 +1,123 @@
export interface MuseumFloor {
id: string
label: string
order: number
}
export interface MuseumCategory {
id: string
label: string
iconType?: string
}
export interface MuseumPoi {
id: string
name: string
floorId: string
floorLabel: string
primaryCategory: MuseumCategory
categories: MuseumCategory[]
positionGltf?: [number, number, number]
sourceConfidence?: string
navigationReadiness?: string
accessible: boolean
}
export interface MuseumHall {
id: string
name: string
floorId?: string
floorLabel?: string
description?: string
image?: string
exhibitCount?: number
area?: string
poiId?: string
}
export interface MuseumExhibit {
id: string
name: string
hallId?: string
hallName?: string
floorId?: string
floorLabel?: string
image?: string
description?: string
poiId?: string
artist?: string
year?: string
material?: string
size?: string
tags?: string[]
}
export interface GuideLocationPreview {
poiId: string
name: string
floorId: string
floorLabel: string
primaryCategoryZh?: string
positionGltf?: [number, number, number]
}
export interface GuideStartLocation {
label: string
floor?: string
source?: string
}
export interface GuidePreviewStep {
id: string
text: string
}
export interface GuideLocationPreviewPlan {
id: string
facilityId: string
target: string
summary: string
steps: GuidePreviewStep[]
targetLocation: GuideLocationPreview | null
startLocation: GuideStartLocation | null
}
export interface GuideRouteReadiness {
ready: boolean
message: string
requiredData: string[]
}
export interface MediaAsset {
id: string
type: 'audio' | 'image' | 'transcript'
url?: string
duration?: number
language?: string
available: boolean
unavailableReason?: string
}
export interface ExplainTrack {
id: string
exhibitId?: string
hallId?: string
title: string
summary?: string
mediaId?: string
coverImage?: string
poiId?: string
floorId?: string
available: boolean
}
export interface SearchIndexItem {
id: string
name: string
desc: string
type: 'exhibit' | 'hall' | 'facility'
poiId?: string
floorId?: string
exhibitId?: string
hallId?: string
}

View File

@@ -50,7 +50,7 @@
<view class="action-btn-group">
<view class="action-btn" @tap="handleNavigate">
<text class="btn-icon">🗺</text>
<text class="btn-text">导航</text>
<text class="btn-text">查看位置</text>
</view>
<view class="action-btn" @tap="handleCollect">
<text class="btn-icon">{{ isCollected ? '❤️' : '🤍' }}</text>
@@ -70,32 +70,39 @@
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import {
explainUseCase
} from '@/usecases/explainUseCase'
import {
toExplainDetailViewModel,
type ExplainDetailViewModel
} from '@/view-models/explainViewModels'
import {
isGuideTopTab,
navigateToGuideTopTab,
type GuideTopTab
} from '@/utils/guideTopTabs'
const exhibit = ref({
id: '1',
name: '蒙娜丽莎',
artist: '列奥纳多·达·芬奇',
year: '1503-1519',
material: '木板油画',
size: '77cm × 53cm',
hall: '1号展厅 1F',
const exhibit = ref<ExplainDetailViewModel>({
id: '',
name: '展项内容',
hall: '展厅位置待补充',
image: '/static/exhibit-placeholder.jpg',
description: '《蒙娜丽莎》是意大利文艺复兴时期画家列奥纳多·达·芬奇创作的油画,现收藏于法国卢浮宫博物馆。该画作主要表现了女性的典雅和恬静的典型形象,塑造了资本主义上升时期一位城市有产阶级的妇女形象。'
description: '该展项介绍待正式内容库补充。',
hasAudio: false,
audioUnavailableReason: '正式讲解音频尚未接入媒体仓储'
})
const isPlaying = ref(false)
const isCollected = ref(false)
const activeTopTab = ref<GuideTopTab>('guide')
onLoad((options: any) => {
onLoad(async (options: any) => {
if (options.id) {
// 根据 ID 加载展品数据
console.log('加载展品:', options.id)
const exhibitData = await explainUseCase.getExhibitById(options.id)
if (exhibitData) {
exhibit.value = toExplainDetailViewModel(exhibitData)
}
}
const tab = Array.isArray(options.tab) ? options.tab[0] : options.tab
@@ -104,14 +111,29 @@ onLoad((options: any) => {
}
})
const handlePlayAudio = () => {
isPlaying.value = !isPlaying.value
console.log('播放/暂停音频')
const handlePlayAudio = async () => {
const selection = exhibit.value.id
? await explainUseCase.selectAudioForExhibit(exhibit.value.id)
: null
uni.showToast({
title: selection?.unavailableMessage || exhibit.value.audioUnavailableReason || '该展项暂无讲解音频',
icon: 'none'
})
}
const handleNavigate = () => {
console.log('导航到展品位置')
uni.navigateBack()
if (!exhibit.value.poiId) {
uni.showToast({
title: '该展项暂无三维位置数据',
icon: 'none'
})
return
}
uni.navigateTo({
url: `/pages/route/detail?facilityId=${encodeURIComponent(exhibit.value.poiId)}&target=${encodeURIComponent(exhibit.value.name)}&state=preview`
})
}
const handleCollect = () => {

View File

@@ -15,6 +15,9 @@
floor-top="208px"
tools-top="450px"
:tools="['回正', '2D']"
:indoor-model-source="indoorModelSource"
:floors="guideFloors"
:normalize-floor-id="normalizeGuideFloorId"
@search-tap="handleSearchTap"
@mode-change="handleModeChange"
@floor-change="handleFloorChange"
@@ -115,16 +118,19 @@ import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
import {
NAV_FLOOR_OPTIONS,
NAV_ROUTE_UNAVAILABLE_MESSAGE,
formatNavFloorLabel,
isPoiAccessible,
loadCleanNavPoiById
} from '@/services/navAssets'
guideUseCase
} from '@/usecases/guideUseCase'
import {
toFacilityDetailViewModel,
type FacilityDetailViewModel
} from '@/view-models/guideViewModels'
import {
navigateToGuideTopTab,
type GuideTopTab
} from '@/utils/guideTopTabs'
import type {
MuseumFloor
} from '@/domain/museum'
interface ConfirmedStart {
label: string
@@ -132,19 +138,23 @@ interface ConfirmedStart {
source: 'facility-detail'
}
const facility = ref({
const indoorModelSource = guideUseCase.getModelSource()
const guideFloors = ref<MuseumFloor[]>([])
const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloorId(labelOrId)
const facility = ref<FacilityDetailViewModel>({
id: '',
name: '目标位置',
status: '可预览',
location: 'clean 导览数据点位',
traffic: NAV_ROUTE_UNAVAILABLE_MESSAGE,
traffic: guideUseCase.getRouteReadiness().message,
tags: ['三维位置', 'clean 数据']
})
const isStartPanelOpen = ref(false)
const selectedStartFloor = ref('1F')
const selectedStartArea = ref('服务台附近')
const confirmedStart = ref<ConfirmedStart | null>(null)
const startFloors = NAV_FLOOR_OPTIONS.map((floor) => floor.label)
const startFloors = computed(() => guideFloors.value.map((floor) => floor.label))
const startAreas = ['主入口', '服务台附近', '停车场入口']
const pendingStartLabel = computed(() => `${selectedStartFloor.value} ${selectedStartArea.value}`)
@@ -165,7 +175,23 @@ const syncDraftStartSelection = () => {
selectedStartArea.value = resolveConfirmedStartArea()
}
const loadGuideFloors = async () => {
try {
const floors = await guideUseCase.getFloors()
guideFloors.value = floors
selectedStartFloor.value = floors.find((floor) => floor.label === selectedStartFloor.value)?.label
|| floors.find((floor) => floor.id === 'L1')?.label
|| floors[0]?.label
|| selectedStartFloor.value
} catch (error) {
console.error('加载导览楼层失败:', error)
guideFloors.value = []
}
}
onLoad(async (options: any) => {
void loadGuideFloors()
if (options.id) {
facility.value.id = options.id
}
@@ -177,22 +203,13 @@ onLoad(async (options: any) => {
if (!facility.value.id) return
try {
const poi = await loadCleanNavPoiById(facility.value.id)
const poi = await guideUseCase.getPoiById(facility.value.id)
if (!poi) return
const floor = formatNavFloorLabel(poi.floorId)
facility.value = {
id: poi.id,
name: poi.name,
status: '可预览',
location: `${floor} · ${poi.primaryCategoryZh}`,
traffic: NAV_ROUTE_UNAVAILABLE_MESSAGE,
tags: [
floor,
poi.primaryCategoryZh,
isPoiAccessible(poi) ? '无障碍相关' : '展示点位'
]
}
facility.value = toFacilityDetailViewModel(
poi,
guideUseCase.getRouteReadiness().message
)
} catch (error) {
console.error('加载 clean 设施详情失败:', error)
}

View File

@@ -10,7 +10,7 @@
<view class="hall-hero">
<image class="hero-image" :src="hall.image" mode="aspectFill" />
<view class="hall-badge">
<text class="badge-text">{{ hall.floor }}</text>
<text class="badge-text">{{ hall.floorLabel }}</text>
</view>
</view>
@@ -48,7 +48,7 @@
<!-- 底部操作栏 -->
<view class="action-bar">
<view class="action-btn primary" @tap="handleNavigate">
<text class="btn-text">导航到展厅</text>
<text class="btn-text">查看展厅位置</text>
</view>
</view>
</view>
@@ -60,6 +60,15 @@ import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import ExhibitCard from '@/components/content/ExhibitCard.vue'
import {
explainUseCase
} from '@/usecases/explainUseCase'
import {
toExplainExhibitViewModel,
toHallDetailViewModel,
type ExplainExhibitViewModel,
type HallDetailViewModel
} from '@/view-models/explainViewModels'
import {
isGuideTopTab,
navigateToGuideTopTab,
@@ -68,24 +77,26 @@ import {
const activeTopTab = ref<GuideTopTab>('guide')
const hall = ref({
id: '1',
name: '1号展厅',
floor: '1F',
description: '文艺复兴时期艺术作品展厅,展示了欧洲文艺复兴时期最具代表性的绘画和雕塑作品。',
const hall = ref<HallDetailViewModel>({
id: '',
name: '展厅内容',
floorLabel: '楼层待补充',
description: '该展厅介绍待正式内容库补充。',
image: '/static/hall-placeholder.jpg',
exhibitCount: 25,
area: '500㎡'
exhibitCount: 0,
area: '待补充'
})
const exhibits = ref([
{ id: '1', name: '蒙娜丽莎', artist: '达芬奇', hasAudio: true },
{ id: '2', name: '最后的晚餐', artist: '达芬奇', hasAudio: true }
])
const exhibits = ref<ExplainExhibitViewModel[]>([])
onLoad((options: any) => {
onLoad(async (options: any) => {
if (options.id) {
console.log('加载展厅:', options.id)
const hallData = await explainUseCase.getHallById(options.id)
if (hallData) {
hall.value = toHallDetailViewModel(hallData)
const hallExhibits = await explainUseCase.listExhibitsByHallId(hallData.id)
exhibits.value = hallExhibits.map(toExplainExhibitViewModel)
}
}
const tab = Array.isArray(options.tab) ? options.tab[0] : options.tab
@@ -101,8 +112,17 @@ const handleExhibitClick = (exhibit: any) => {
}
const handleNavigate = () => {
console.log('导航到展厅')
uni.navigateBack()
if (!hall.value.poiId) {
uni.showToast({
title: '该展厅暂无三维位置数据',
icon: 'none'
})
return
}
uni.navigateTo({
url: `/pages/route/detail?facilityId=${encodeURIComponent(hall.value.poiId)}&target=${encodeURIComponent(hall.value.name)}&state=preview`
})
}
const handleTopTabChange = (tab: GuideTopTab) => {

View File

@@ -16,6 +16,9 @@
:map-type="guideMapType"
:outdoor-variant="guideOutdoorVariant"
:indoor-asset-base-url="indoorNavAssetBaseUrl"
:indoor-model-source="indoorModelSource"
:floors="guideFloors"
:normalize-floor-id="normalizeGuideFloorId"
indoor-initial-view="overview"
:indoor-view="indoorView"
:active-floor="activeGuideFloor"
@@ -80,6 +83,7 @@
<view v-else-if="currentTab === 'explain'" class="explain-page">
<ExplainList
:exhibits="explainExhibits"
@exhibit-click="handleExplainExhibitClick"
@featured-click="handleExplainFeaturedClick"
@audio-click="handleAudioClick"
@@ -109,7 +113,7 @@ import { computed, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
import ExplainList from '@/components/explain/ExplainList.vue'
import ExplainList, { type Exhibit } from '@/components/explain/ExplainList.vue'
import FloatingAudioButton from '@/components/audio/FloatingAudioButton.vue'
import AudioPlayer, { type AudioItem } from '@/components/audio/AudioPlayer.vue'
import {
@@ -117,9 +121,20 @@ import {
type GuideTopTab
} from '@/utils/guideTopTabs'
import {
NAV_ASSET_BASE_URL,
NAV_ROUTE_UNAVAILABLE_MESSAGE
} from '@/services/navAssets'
} from '@/domain/guideReadiness'
import {
guideUseCase
} from '@/usecases/guideUseCase'
import {
explainUseCase
} from '@/usecases/explainUseCase'
import {
toExplainExhibitViewModel
} from '@/view-models/explainViewModels'
import type {
MuseumFloor
} from '@/domain/museum'
// 3D 模式状态
const is3DMode = ref(false)
@@ -135,7 +150,10 @@ const showMarkerDetail = ref(false)
const showAreaSelector = ref(false)
const selectedAreaId = ref('service')
const indoorNavAssetBaseUrl = NAV_ASSET_BASE_URL
const indoorNavAssetBaseUrl = guideUseCase.getAssetBaseUrl()
const indoorModelSource = guideUseCase.getModelSource()
const guideFloors = ref<MuseumFloor[]>([])
const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloorId(labelOrId)
const shortcutItems = [
{ id: 'toilet', name: '卫生间', abbr: '卫' },
@@ -149,6 +167,7 @@ const shortcutItems = [
const showAudioPlayer = ref(false)
const isAudioPlaying = ref(false)
const currentAudio = ref<AudioItem | null>(null)
const explainExhibits = ref<Exhibit[]>([])
// 选中的标记详情
interface MarkerDetail {
@@ -188,8 +207,35 @@ onLoad((options: any = {}) => {
if (isGuideTopTab(tab)) {
currentTab.value = tab
}
void loadGuideFloors()
void loadExplainExhibits()
})
const loadGuideFloors = async () => {
try {
const floors = await guideUseCase.getFloors()
guideFloors.value = floors
activeGuideFloor.value = floors.find((floor) => floor.label === activeGuideFloor.value)?.label
|| floors.find((floor) => floor.id === 'L1')?.label
|| floors[0]?.label
|| activeGuideFloor.value
} catch (error) {
console.error('加载导览楼层失败:', error)
guideFloors.value = []
}
}
const loadExplainExhibits = async () => {
try {
const exhibits = await explainUseCase.listExhibits()
explainExhibits.value = exhibits.map(toExplainExhibitViewModel)
} catch (error) {
console.error('加载讲解内容失败:', error)
explainExhibits.value = []
}
}
// 搜索处理
const handleSearchFocus = () => {
searchBarFocused.value = true
@@ -391,13 +437,23 @@ const guideSearchText = computed(() => {
})
// 音频相关处理
const handleAudioClick = (exhibit: any) => {
console.log('点击音频播放:', exhibit)
const handleAudioClick = async (exhibit: Exhibit) => {
const selection = await explainUseCase.selectAudioForExhibit(exhibit.id)
if (!selection?.playable || !selection.media?.url) {
uni.showToast({
title: selection?.unavailableMessage || exhibit.audioUnavailableReason || '该展项暂无讲解音频',
icon: 'none'
})
return
}
currentAudio.value = {
id: exhibit.id,
name: exhibit.name,
audioUrl: exhibit.audioUrl || 'https://example.com/audio.mp3',
image: exhibit.image
id: selection.media.id,
name: selection.track?.title || selection.exhibit.name,
audioUrl: selection.media.url,
image: selection.exhibit.image,
duration: selection.media.duration
}
showAudioPlayer.value = true
}
@@ -431,30 +487,14 @@ const handleAudioEnded = (audio: AudioItem) => {
}
// 讲解页面处理
const handleExplainExhibitClick = (exhibit: any) => {
console.log('点击讲解展品:', exhibit)
const handleExplainExhibitClick = (exhibit: Exhibit) => {
uni.navigateTo({
url: `/pages/exhibit/detail?id=${exhibit.id}&tab=explain`
})
}
const handleExplainFeaturedClick = (exhibit: any) => {
console.log('点击推荐讲解:', exhibit)
// 播放音频讲解
if (exhibit.hasAudio) {
currentAudio.value = {
id: exhibit.id,
name: exhibit.name,
audioUrl: exhibit.audioUrl || 'https://example.com/audio.mp3',
image: exhibit.image
}
showAudioPlayer.value = true
} else {
uni.showToast({
title: '该展品暂无讲解音频',
icon: 'none'
})
}
const handleExplainFeaturedClick = async (exhibit: Exhibit) => {
await handleAudioClick(exhibit)
}
</script>

View File

@@ -10,6 +10,9 @@
>
<GuideMapShell
v-bind="shellConfig"
:indoor-model-source="indoorModelSource"
:floors="guideFloors"
:normalize-floor-id="normalizeGuideFloorId"
:target-focus-request="targetFocusRequest"
@search-tap="handleSearchTap"
@mode-change="handleModeChange"
@@ -125,12 +128,18 @@ import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
import LocationPreview from '@/components/navigation/LocationPreview.vue'
import {
NAV_FLOOR_OPTIONS,
NAV_ROUTE_UNAVAILABLE_MESSAGE,
formatNavFloorLabel,
loadCleanNavPoiById,
type CleanNavPoi
} from '@/services/navAssets'
guideUseCase
} from '@/usecases/guideUseCase'
import {
initialLocationPreviewPlan,
toTargetFocusRequestViewModel
} from '@/view-models/guideViewModels'
import type {
GuideLocationPreview,
GuideLocationPreviewPlan,
GuideStartLocation,
MuseumFloor
} from '@/domain/museum'
import {
navigateToGuideTopTab,
type GuideTopTab
@@ -138,28 +147,11 @@ import {
type RouteViewState = 'preview' | 'location-error' | 'outdoor-preview'
type GuideMode = '2d' | '3d'
interface RouteStep {
id: string
text: string
}
interface RouteTargetLocation {
poiId: string
name: string
floorId: string
floorLabel?: string
primaryCategoryZh?: string
positionGltf?: [number, number, number]
}
interface RouteStartLocation {
label: string
floor?: string
source?: string
}
type RouteTargetLocation = GuideLocationPreview
type RouteStartLocation = GuideStartLocation
interface TargetPoiFocusRequest extends RouteTargetLocation {
requestId: number
requestId: number | string
}
interface TargetPoiFocusResult {
@@ -170,104 +162,44 @@ interface TargetPoiFocusResult {
message?: string
}
interface RoutePlan {
id: string
facilityId: string
target: string
summary: string
steps: RouteStep[]
targetLocation: RouteTargetLocation | null
startLocation: RouteStartLocation | null
}
type RoutePlan = GuideLocationPreviewPlan
const routeDeepLinkStates: RouteViewState[] = ['preview', 'outdoor-preview']
const indoorModelSource = guideUseCase.getModelSource()
const guideFloors = ref<MuseumFloor[]>([])
const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloorId(labelOrId)
const startSourceLabels: Record<string, string> = {
'facility-detail': '设施详情选择',
manual: '手动选择'
}
const formatStartSourceLabel = (source?: string) => (
source ? startSourceLabels[source] || source : ''
)
const formatStartStepText = (startLocation: RouteStartLocation) => {
const sourceLabel = formatStartSourceLabel(startLocation.source)
const floorSuffix = startLocation.floor && !startLocation.label.includes(startLocation.floor)
? ` · ${startLocation.floor}`
: ''
const sourceSuffix = sourceLabel ? `${sourceLabel}` : ''
return `起点:${startLocation.label}${floorSuffix}${sourceSuffix}`
}
const createPreviewSteps = (
poi: CleanNavPoi | null,
startLocation: RouteStartLocation | null
): RouteStep[] => {
if (startLocation) {
return [
{
id: 'start',
text: formatStartStepText(startLocation)
},
{
id: 'target',
text: poi
? `目标:${formatNavFloorLabel(poi.floorId)} · ${poi.primaryCategoryZh} · 位置预览`
: '目标来自 clean 导览数据,暂仅支持位置预览'
}
]
}
return [
{
id: 'floor',
text: poi ? `目标位于 ${formatNavFloorLabel(poi.floorId)} · ${poi.primaryCategoryZh}` : '目标来自 clean 导览数据'
},
{
id: 'status',
text: NAV_ROUTE_UNAVAILABLE_MESSAGE
}
]
}
const createRoutePlan = (
facilityId: string,
target: string,
poi: CleanNavPoi | null = null,
startLocation: RouteStartLocation | null = null
): RoutePlan => ({
id: `route-${facilityId || 'custom'}`,
facilityId,
target,
summary: poi
? `${formatNavFloorLabel(poi.floorId)} · ${poi.primaryCategoryZh} · 位置预览`
: '位置预览 · 尚未接入正式路线图',
steps: createPreviewSteps(poi, startLocation),
targetLocation: poi ? {
poiId: poi.id,
name: poi.name,
floorId: poi.floorId,
floorLabel: formatNavFloorLabel(poi.floorId),
primaryCategoryZh: poi.primaryCategoryZh,
positionGltf: poi.positionGltf
} : null,
startLocation
})
const route = ref<RoutePlan>(createRoutePlan('', '目标地点'))
const route = ref<RoutePlan>(initialLocationPreviewPlan())
const hasRouteTarget = ref(false)
const routeViewState = ref<RouteViewState>('preview')
const activeFloor = ref('1F')
const targetFocusRequest = ref<TargetPoiFocusRequest | null>(null)
const targetFocusRequestId = ref(0)
const manualFloors = NAV_FLOOR_OPTIONS.map((floor) => floor.label)
const manualFloors = computed(() => guideFloors.value.map((floor) => floor.label))
const guideFloorLabel = (floorId: string) => (
guideFloors.value.find((floor) => floor.id === floorId)?.label || floorId
)
const defaultGuideFloorLabel = () => (
guideFloors.value.find((floor) => floor.id === 'L1')?.label
|| guideFloors.value[0]?.label
|| '1F'
)
const loadGuideFloors = async () => {
if (guideFloors.value.length) return guideFloors.value
try {
guideFloors.value = await guideUseCase.getFloors()
} catch (error) {
console.error('加载导览楼层失败:', error)
guideFloors.value = []
}
return guideFloors.value
}
const manualAreas = ['主入口', '服务台附近', '停车场入口']
const isManualLocationPanelOpen = ref(false)
const selectedManualFloor = ref('1F')
const selectedManualArea = ref('服务台附近')
const normalizeRouteOption = (value: unknown) => {
if (Array.isArray(value)) {
return value[0]
@@ -380,7 +312,36 @@ const createStartLocationFromOptions = (options: Record<string, unknown>) => {
}
}
const requestTargetFocus = (target: Partial<RouteTargetLocation> | null, fallbackName = route.value.target) => {
if (!target?.poiId || !target.floorId) {
targetFocusRequest.value = null
return false
}
const floorLabel = target.floorLabel || guideFloorLabel(target.floorId)
const focusTarget: RouteTargetLocation = {
poiId: target.poiId,
name: target.name || fallbackName,
floorId: target.floorId,
floorLabel,
primaryCategoryZh: target.primaryCategoryZh,
positionGltf: target.positionGltf
}
activeFloor.value = floorLabel
routeViewState.value = 'preview'
targetFocusRequestId.value += 1
targetFocusRequest.value = toTargetFocusRequestViewModel(
focusTarget,
targetFocusRequestId.value
)
return true
}
const applyRouteOptions = async (options: Record<string, unknown> = {}) => {
await loadGuideFloors()
const facilityId = normalizeStringOption(options.facilityId)
const target = normalizeStringOption(options.target)
const state = normalizeRouteOption(options.state)
@@ -388,39 +349,42 @@ const applyRouteOptions = async (options: Record<string, unknown> = {}) => {
if (!facilityId && !target) {
hasRouteTarget.value = false
route.value = createRoutePlan('', '目标地点')
route.value = initialLocationPreviewPlan()
routeViewState.value = 'preview'
activeFloor.value = '1F'
activeFloor.value = defaultGuideFloorLabel()
targetFocusRequest.value = null
isManualLocationPanelOpen.value = false
return false
}
const matchedPoi = facilityId ? await loadCleanNavPoiById(facilityId) : null
const matchedPoi = facilityId ? await guideUseCase.getPoiById(facilityId) : null
if (!matchedPoi) {
hasRouteTarget.value = false
route.value = createRoutePlan('', target || '目标地点')
route.value = await guideUseCase.createLocationPreviewPlan('', target || '目标地点', startLocation)
routeViewState.value = 'preview'
activeFloor.value = startLocation?.floor || '1F'
activeFloor.value = startLocation?.floor || defaultGuideFloorLabel()
targetFocusRequest.value = null
isManualLocationPanelOpen.value = false
return false
}
route.value = createRoutePlan(
route.value = await guideUseCase.createLocationPreviewPlan(
facilityId,
target || matchedPoi.name,
matchedPoi,
startLocation
)
hasRouteTarget.value = true
routeViewState.value = isRouteViewState(state) ? state : 'preview'
activeFloor.value = matchedPoi ? formatNavFloorLabel(matchedPoi.floorId) : startLocation?.floor || '1F'
targetFocusRequest.value = null
isManualLocationPanelOpen.value = false
if (routeViewState.value === 'preview') {
requestTargetFocus(route.value.targetLocation, matchedPoi.name)
} else {
activeFloor.value = matchedPoi.floorLabel || guideFloorLabel(matchedPoi.floorId)
}
return true
}
@@ -479,23 +443,14 @@ const handleViewOutdoorMap = () => {
routeViewState.value = 'outdoor-preview'
}
const handleShowTargetLocation = (target: RouteTargetLocation | null) => {
const targetLocation = target || route.value.targetLocation
const handleShowTargetLocation = (target: Partial<RouteTargetLocation> | null) => {
const focused = requestTargetFocus(target || route.value.targetLocation)
if (!targetLocation?.poiId || !targetLocation.floorId) {
if (!focused) {
uni.showToast({
title: '目标暂无三维位置数据',
icon: 'none'
})
return
}
routeViewState.value = 'preview'
activeFloor.value = targetLocation.floorLabel || formatNavFloorLabel(targetLocation.floorId)
targetFocusRequestId.value += 1
targetFocusRequest.value = {
...targetLocation,
requestId: targetFocusRequestId.value
}
}
@@ -511,6 +466,7 @@ const handleTargetFocus = (result: TargetPoiFocusResult) => {
const handleReturnToPreview = () => {
isManualLocationPanelOpen.value = false
routeViewState.value = 'preview'
requestTargetFocus(route.value.targetLocation)
}
const handleRelocate = () => {
@@ -540,39 +496,24 @@ const createManualStartLocation = (): RouteStartLocation => ({
source: 'manual'
})
const createCurrentTargetStep = (): RouteStep => {
const targetLocation = route.value.targetLocation
return {
id: 'target',
text: targetLocation
? `目标:${targetLocation.floorLabel || formatNavFloorLabel(targetLocation.floorId)} · ${targetLocation.primaryCategoryZh || route.value.target} · 位置预览`
: '目标来自 clean 导览数据,暂仅支持位置预览'
}
}
const handleConfirmLocation = () => {
const handleConfirmLocation = async () => {
const startLocation = createManualStartLocation()
route.value = {
...route.value,
startLocation,
steps: [
{
id: 'start',
text: formatStartStepText(startLocation)
},
createCurrentTargetStep()
]
}
route.value = await guideUseCase.createLocationPreviewPlan(
route.value.facilityId,
route.value.target,
startLocation
)
activeFloor.value = startLocation.floor || activeFloor.value
isManualLocationPanelOpen.value = false
routeViewState.value = 'preview'
requestTargetFocus(route.value.targetLocation)
}
const handleModeChange = (mode: GuideMode) => {
if (routeViewState.value === 'outdoor-preview' && mode === '3d') {
routeViewState.value = 'preview'
requestTargetFocus(route.value.targetLocation)
return
}
@@ -596,7 +537,7 @@ const handleToolClick = (tool: string) => {
}
uni.showToast({
title: tool === '回正' ? '已回到三维总览' : NAV_ROUTE_UNAVAILABLE_MESSAGE,
title: tool === '回正' ? '已回到三维总览' : guideUseCase.getRouteReadiness().message,
icon: 'none'
})
}

View File

@@ -13,6 +13,9 @@
search-top="60px"
mode-top="104px"
floor-top="208px"
:indoor-model-source="indoorModelSource"
:floors="guideFloors"
:normalize-floor-id="normalizeGuideFloorId"
@search-tap="handleSearchTap"
@mode-change="handleModeChange"
@floor-change="handleFloorChange"
@@ -100,31 +103,31 @@ import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
import {
formatNavFloorLabel,
isPoiAccessible,
searchCleanNavPois,
type CleanNavPoi
} from '@/services/navAssets'
guideUseCase
} from '@/usecases/guideUseCase'
import {
toFacilityResultViewModel,
type FacilityResultViewModel
} from '@/view-models/guideViewModels'
import {
navigateToGuideTopTab,
type GuideTopTab
} from '@/utils/guideTopTabs'
import type {
MuseumFloor
} from '@/domain/museum'
interface FilterItem {
id: 'all' | 'accessible' | 'floor'
label: string
}
interface FacilityResult {
id: string
name: string
floor: string
meta: string
accessible: boolean
action: '查看'
}
interface FacilityResult extends FacilityResultViewModel {}
const searchKeyword = ref('卫生间')
const indoorModelSource = guideUseCase.getModelSource()
const guideFloors = ref<MuseumFloor[]>([])
const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloorId(labelOrId)
const searchDraftKeyword = ref('')
const currentFilter = ref<FilterItem['id']>('all')
const isLoading = ref(false)
@@ -140,18 +143,6 @@ const filters: FilterItem[] = [
const facilities = ref<FacilityResult[]>([])
const toFacilityResult = (poi: CleanNavPoi): FacilityResult => {
const floor = formatNavFloorLabel(poi.floorId)
return {
id: poi.id,
name: poi.name,
floor,
meta: `${floor}${poi.primaryCategoryZh}${poi.navigationReadiness || '展示点位'}`,
accessible: isPoiAccessible(poi),
action: '查看'
}
}
const visibleFacilities = computed(() => {
if (currentFilter.value === 'accessible') {
return facilities.value.filter((item) => item.accessible)
@@ -170,10 +161,10 @@ const resultTitle = computed(() => {
const loadFacilityResults = async () => {
isLoading.value = true
try {
const pois = await searchCleanNavPois(searchKeyword.value)
const pois = await guideUseCase.searchPois(searchKeyword.value)
facilities.value = pois
.filter((poi) => poi.primaryCategory !== 'touring_poi')
.map(toFacilityResult)
.filter((poi) => poi.primaryCategory.id !== 'touring_poi')
.map(toFacilityResultViewModel)
} catch (error) {
console.error('加载 clean 导览搜索结果失败:', error)
facilities.value = []
@@ -186,11 +177,21 @@ const loadFacilityResults = async () => {
}
}
const loadGuideFloors = async () => {
try {
guideFloors.value = await guideUseCase.getFloors()
} catch (error) {
console.error('加载导览楼层失败:', error)
guideFloors.value = []
}
}
onLoad((options: any) => {
if (options.keyword) {
searchKeyword.value = decodeURIComponent(options.keyword)
}
searchDraftKeyword.value = searchKeyword.value
void loadGuideFloors()
void loadFacilityResults()
})

View File

@@ -0,0 +1,120 @@
import type {
ExplainTrack,
MuseumExhibit,
MuseumHall,
SearchIndexItem
} from '@/domain/museum'
import {
mediaRepository,
type MediaRepository
} from '@/repositories/MediaRepository'
import {
museumContentRepository,
type MuseumContentRepository
} from '@/repositories/MuseumContentRepository'
export interface ExplainRepository {
listExhibits(): Promise<MuseumExhibit[]>
getExhibitById(id: string): Promise<MuseumExhibit | null>
listHalls(): Promise<MuseumHall[]>
getHallById(id: string): Promise<MuseumHall | null>
listTracks(): Promise<ExplainTrack[]>
getTrackByExhibitId(exhibitId: string): Promise<ExplainTrack | null>
searchExplain(keyword?: string): Promise<SearchIndexItem[]>
}
const trackTitleFor = (exhibit: MuseumExhibit) => `${exhibit.name}讲解`
export class DefaultExplainRepository implements ExplainRepository {
constructor(
private readonly content: MuseumContentRepository = museumContentRepository,
private readonly media: MediaRepository = mediaRepository
) {}
listExhibits() {
return this.content.listExhibits()
}
getExhibitById(id: string) {
return this.content.getExhibitById(id)
}
listHalls() {
return this.content.listHalls()
}
getHallById(id: string) {
return this.content.getHallById(id)
}
async listTracks() {
const exhibits = await this.content.listExhibits()
return Promise.all(exhibits.map(async (exhibit): Promise<ExplainTrack> => {
const media = await this.media.getMediaForExplainTrack(exhibit.id)
return {
id: `track-${exhibit.id}`,
exhibitId: exhibit.id,
hallId: exhibit.hallId,
title: trackTitleFor(exhibit),
summary: exhibit.description,
mediaId: media?.id,
coverImage: exhibit.image,
poiId: exhibit.poiId,
floorId: exhibit.floorId,
available: media?.available === true
}
}))
}
async getTrackByExhibitId(exhibitId: string) {
const tracks = await this.listTracks()
return tracks.find((track) => track.exhibitId === exhibitId) || null
}
async searchExplain(keyword = '') {
const normalizedKeyword = keyword.trim().toLowerCase()
const [exhibits, halls] = await Promise.all([
this.content.listExhibits(),
this.content.listHalls()
])
const exhibitItems = exhibits
.filter((exhibit) => !normalizedKeyword || [
exhibit.name,
exhibit.hallName,
exhibit.floorLabel,
...(exhibit.tags || [])
].filter(Boolean).join(' ').toLowerCase().includes(normalizedKeyword))
.map<SearchIndexItem>((exhibit) => ({
id: exhibit.id,
name: exhibit.name,
desc: `${exhibit.hallName || '展项'} · ${exhibit.floorLabel || ''}`.trim(),
type: 'exhibit',
exhibitId: exhibit.id,
hallId: exhibit.hallId,
poiId: exhibit.poiId,
floorId: exhibit.floorId
}))
const hallItems = halls
.filter((hall) => !normalizedKeyword || [
hall.name,
hall.floorLabel,
hall.description
].filter(Boolean).join(' ').toLowerCase().includes(normalizedKeyword))
.map<SearchIndexItem>((hall) => ({
id: hall.id,
name: hall.name,
desc: `${hall.floorLabel || ''} · ${hall.exhibitCount || 0}件展项`.trim(),
type: 'hall',
hallId: hall.id,
poiId: hall.poiId,
floorId: hall.floorId
}))
return [...exhibitItems, ...hallItems]
}
}
export const explainRepository = new DefaultExplainRepository()

View File

@@ -0,0 +1,64 @@
import type {
GuideModelFloorAsset,
GuideModelRenderPackage,
GuideModelSource,
GuideRenderPoi
} from '@/domain/guideModel'
import {
formatNavFloorLabel
} from '@/data/adapters/navAssetsAdapter'
import {
defaultStaticNavAssetsProvider,
type StaticNavAssetsProvider,
type StaticNavPoiPayload
} from '@/data/providers/staticNavAssetsProvider'
const toRenderPoi = (poi: StaticNavPoiPayload): GuideRenderPoi => ({
id: poi.id,
name: poi.name,
floorId: poi.floorId,
primaryCategory: poi.primaryCategory,
primaryCategoryZh: poi.primaryCategoryZh,
iconType: poi.iconType || poi.primaryCategory,
positionGltf: poi.positionGltf
})
export interface GuideModelRepository extends GuideModelSource {}
export class StaticGuideModelRepository implements GuideModelRepository {
constructor(private readonly provider: StaticNavAssetsProvider = defaultStaticNavAssetsProvider) {}
async loadPackage(): Promise<GuideModelRenderPackage> {
const [manifest, floorIndex] = await Promise.all([
this.provider.loadManifest(),
this.provider.loadFloorIndex()
])
const floors: GuideModelFloorAsset[] = [...floorIndex.floors]
.sort((a, b) => a.order - b.order)
.map((floor) => ({
floorId: floor.floorId,
label: formatNavFloorLabel(floor.floorId),
order: floor.order,
modelUrl: this.provider.assetUrl(floor.modelAsset)
}))
return {
overviewModelUrl: this.provider.assetUrl(manifest.assets.overviewModel.asset),
floors
}
}
async loadFloorPois(floorId: string) {
const floorIndex = await this.provider.loadFloorIndex()
const floor = floorIndex.floors.find((item) => item.floorId === floorId)
if (!floor) return []
const pois = await this.provider.loadFloorPois(floor.poiDataAsset)
return pois
.map(toRenderPoi)
.filter((poi) => Array.isArray(poi.positionGltf) && poi.positionGltf.length === 3)
}
}
export const guideModelRepository = new StaticGuideModelRepository()

View File

@@ -0,0 +1,122 @@
import type {
GuideLocationPreview,
MuseumFloor,
MuseumPoi
} from '@/domain/museum'
import {
NAV_ROUTE_READINESS
} from '@/domain/guideReadiness'
import {
formatNavFloorLabel,
navFloorIdFromLabel,
toMuseumPoi
} from '@/data/adapters/navAssetsAdapter'
import {
defaultStaticNavAssetsProvider,
type StaticNavAssetsProvider
} from '@/data/providers/staticNavAssetsProvider'
const searchableCategories = new Set([
'touring_poi',
'basic_service_facility',
'transport_circulation',
'accessibility_special_service',
'operation_experience'
])
const toSearchText = (poi: MuseumPoi) => [
poi.name,
poi.floorId,
poi.floorLabel,
poi.primaryCategory.label,
poi.primaryCategory.iconType,
...poi.categories.flatMap((category) => [
category.label,
category.id,
category.iconType
])
]
.filter(Boolean)
.join(' ')
.toLowerCase()
const toLocationPreview = (poi: MuseumPoi): GuideLocationPreview => ({
poiId: poi.id,
name: poi.name,
floorId: poi.floorId,
floorLabel: poi.floorLabel,
primaryCategoryZh: poi.primaryCategory.label,
positionGltf: poi.positionGltf
})
export interface GuideRepository {
getAssetBaseUrl(): string
getFloors(): Promise<MuseumFloor[]>
normalizeFloorId(labelOrId: string): string
listPois(): Promise<MuseumPoi[]>
getPoiById(id: string): Promise<MuseumPoi | null>
searchPois(keyword?: string): Promise<MuseumPoi[]>
getLocationPreview(poiId: string): Promise<GuideLocationPreview | null>
getRouteReadiness(): typeof NAV_ROUTE_READINESS
}
export class StaticGuideRepository implements GuideRepository {
private poiCache: MuseumPoi[] | null = null
constructor(private readonly provider: StaticNavAssetsProvider = defaultStaticNavAssetsProvider) {}
getAssetBaseUrl() {
return this.provider.baseUrl
}
async getFloors() {
const floorIndex = await this.provider.loadFloorIndex()
return [...floorIndex.floors]
.sort((a, b) => b.order - a.order)
.map((floor) => ({
id: floor.floorId,
label: formatNavFloorLabel(floor.floorId),
order: floor.order
}))
}
normalizeFloorId(labelOrId: string) {
return navFloorIdFromLabel(labelOrId)
}
async listPois() {
if (this.poiCache) return this.poiCache
const pois = await this.provider.loadPoiIndex()
this.poiCache = pois
.filter((poi) => searchableCategories.has(poi.primaryCategory))
.map(toMuseumPoi)
return this.poiCache
}
async getPoiById(id: string) {
const pois = await this.listPois()
return pois.find((poi) => poi.id === id) || null
}
async searchPois(keyword = '') {
const pois = await this.listPois()
const normalizedKeyword = keyword.trim().toLowerCase()
if (!normalizedKeyword) return pois
return pois.filter((poi) => toSearchText(poi).includes(normalizedKeyword))
}
async getLocationPreview(poiId: string) {
const poi = await this.getPoiById(poiId)
return poi ? toLocationPreview(poi) : null
}
getRouteReadiness() {
return NAV_ROUTE_READINESS
}
}
export const guideRepository = new StaticGuideRepository()

View File

@@ -0,0 +1,27 @@
import type {
MediaAsset
} from '@/domain/museum'
export interface MediaRepository {
getMediaById(id: string): Promise<MediaAsset | null>
getMediaForExplainTrack(trackId: string): Promise<MediaAsset | null>
}
const unavailableAudio = (id: string): MediaAsset => ({
id,
type: 'audio',
available: false,
unavailableReason: '正式讲解音频尚未接入媒体仓储'
})
export class DefaultMediaRepository implements MediaRepository {
async getMediaById(id: string) {
return unavailableAudio(id)
}
async getMediaForExplainTrack(trackId: string) {
return unavailableAudio(`media-${trackId}`)
}
}
export const mediaRepository = new DefaultMediaRepository()

View File

@@ -0,0 +1,124 @@
import type {
MuseumExhibit,
MuseumHall,
MuseumPoi,
SearchIndexItem
} from '@/domain/museum'
import {
guideRepository,
type GuideRepository
} from '@/repositories/GuideRepository'
import {
staticMuseumContentProvider,
type MuseumContentProvider
} from '@/data/providers/staticMuseumContentProvider'
export interface MuseumContentRepository {
listFacilities(): Promise<MuseumPoi[]>
getFacilityById(id: string): Promise<MuseumPoi | null>
searchFacilities(keyword?: string): Promise<MuseumPoi[]>
listExhibits(): Promise<MuseumExhibit[]>
getExhibitById(id: string): Promise<MuseumExhibit | null>
listHalls(): Promise<MuseumHall[]>
getHallById(id: string): Promise<MuseumHall | null>
searchContent(keyword?: string): Promise<SearchIndexItem[]>
}
const normalize = (value: string) => value.trim().toLowerCase()
const includesKeyword = (values: Array<string | undefined>, keyword: string) => (
values.filter(Boolean).join(' ').toLowerCase().includes(keyword)
)
export class DefaultMuseumContentRepository implements MuseumContentRepository {
constructor(
private readonly contentProvider: MuseumContentProvider = staticMuseumContentProvider,
private readonly guide: GuideRepository = guideRepository
) {}
listFacilities() {
return this.guide.listPois()
}
getFacilityById(id: string) {
return this.guide.getPoiById(id)
}
searchFacilities(keyword = '') {
return this.guide.searchPois(keyword)
}
listExhibits() {
return this.contentProvider.listExhibits()
}
async getExhibitById(id: string) {
const exhibits = await this.contentProvider.listExhibits()
return exhibits.find((exhibit) => exhibit.id === id) || null
}
listHalls() {
return this.contentProvider.listHalls()
}
async getHallById(id: string) {
const halls = await this.contentProvider.listHalls()
return halls.find((hall) => hall.id === id) || null
}
async searchContent(keyword = '') {
const normalizedKeyword = normalize(keyword)
const facilities = await this.searchFacilities(keyword)
const exhibits = await this.listExhibits()
const halls = await this.listHalls()
const exhibitItems = exhibits
.filter((exhibit) => !normalizedKeyword || includesKeyword([
exhibit.name,
exhibit.hallName,
exhibit.floorLabel,
...(exhibit.tags || [])
], normalizedKeyword))
.map<SearchIndexItem>((exhibit) => ({
id: exhibit.id,
name: exhibit.name,
desc: `${exhibit.hallName || '展项'} · ${exhibit.floorLabel || ''}`.trim(),
type: 'exhibit',
exhibitId: exhibit.id,
poiId: exhibit.poiId,
floorId: exhibit.floorId
}))
const hallItems = halls
.filter((hall) => !normalizedKeyword || includesKeyword([
hall.name,
hall.floorLabel,
hall.description
], normalizedKeyword))
.map<SearchIndexItem>((hall) => ({
id: hall.id,
name: hall.name,
desc: `${hall.floorLabel || ''} · ${hall.exhibitCount || 0}件展项`.trim(),
type: 'hall',
hallId: hall.id,
poiId: hall.poiId,
floorId: hall.floorId
}))
const facilityItems = facilities.map<SearchIndexItem>((poi) => ({
id: poi.id,
name: poi.name,
desc: `${poi.floorLabel} · ${poi.primaryCategory.label}`,
type: 'facility',
poiId: poi.id,
floorId: poi.floorId
}))
return [
...exhibitItems,
...hallItems,
...facilityItems
]
}
}
export const museumContentRepository = new DefaultMuseumContentRepository()

View File

@@ -1,164 +0,0 @@
export const NAV_ASSET_BASE_URL = '/static/nav-assets/app_nav_assets_v2_clean_20260609_075339'
export const NAV_ROUTE_UNAVAILABLE_MESSAGE = '正式路线数据尚未接入,可先查看馆内三维位置'
export interface NavFloorOption {
id: string
label: string
order: number
}
export interface CleanNavPoiCategory {
topCategory: string
topCategoryZh: string
subcategory: string
iconType: string
reason?: string
}
export interface CleanNavPoi {
id: string
name: string
floorId: string
primaryCategory: string
primaryCategoryZh: string
categories?: CleanNavPoiCategory[]
iconType?: string
positionGltf?: [number, number, number]
navigationReadiness?: string
sourceConfidence?: string
}
interface CleanPoiIndex {
status: string
pois: CleanNavPoi[]
}
export const NAV_FLOOR_OPTIONS: NavFloorOption[] = [
{ id: 'L5', label: '5F', order: 5 },
{ id: 'L4', label: '4F', order: 4 },
{ id: 'L3', label: '3F', order: 3 },
{ id: 'L2', label: '2F', order: 2 },
{ id: 'L1.5', label: '1.5F', order: 1.5 },
{ id: 'L1', label: '1F', order: 1 },
{ id: 'L-1', label: 'B1', order: -1 },
{ id: 'L-2', label: 'B2', order: -2 }
]
const searchableCategories = new Set([
'touring_poi',
'basic_service_facility',
'transport_circulation',
'accessibility_special_service',
'operation_experience'
])
const normalizeBaseUrl = (baseUrl: string) => baseUrl.replace(/\/+$/, '')
const poiCache = new Map<string, CleanNavPoi[]>()
const poiRequestCache = new Map<string, Promise<CleanNavPoi[]>>()
export const navAssetUrl = (relativePath: string, baseUrl = NAV_ASSET_BASE_URL) => (
`${normalizeBaseUrl(baseUrl)}/${relativePath.replace(/^\/+/, '')}`
)
export const formatNavFloorLabel = (floorId: string) => (
NAV_FLOOR_OPTIONS.find((floor) => floor.id === floorId)?.label || floorId
)
export const navFloorIdFromLabel = (labelOrId: string) => (
NAV_FLOOR_OPTIONS.find((floor) => floor.label === labelOrId || floor.id === labelOrId)?.id || labelOrId
)
export const isPoiAccessible = (poi: CleanNavPoi) => (
poi.primaryCategory === 'accessibility_special_service'
|| poi.categories?.some((category) => category.topCategory === 'accessibility_special_service') === true
)
const parseJsonPayload = <T>(payload: unknown): T => {
if (typeof payload === 'string') {
return JSON.parse(payload) as T
}
return payload as T
}
const requestJson = <T>(url: string): Promise<T> => new Promise((resolve, reject) => {
uni.request({
url,
method: 'GET',
success: (response) => {
const statusCode = Number(response.statusCode || 0)
if (statusCode < 200 || statusCode >= 300) {
reject(new Error(`导览资源读取失败: ${statusCode} ${url}`))
return
}
try {
resolve(parseJsonPayload<T>(response.data))
} catch (error) {
reject(error)
}
},
fail: reject
})
})
export const loadCleanNavPois = async (baseUrl = NAV_ASSET_BASE_URL) => {
const cacheKey = normalizeBaseUrl(baseUrl)
const cachedPois = poiCache.get(cacheKey)
if (cachedPois) return cachedPois
const pendingPois = poiRequestCache.get(cacheKey)
if (pendingPois) return pendingPois
const request = requestJson<CleanPoiIndex>(navAssetUrl('data/poi_all.json', cacheKey))
.then((data) => {
if (data.status !== 'pass') {
throw new Error('导览 POI 数据状态不是 pass')
}
const pois = data.pois.filter((poi) => searchableCategories.has(poi.primaryCategory))
poiCache.set(cacheKey, pois)
return pois
})
.finally(() => {
poiRequestCache.delete(cacheKey)
})
poiRequestCache.set(cacheKey, request)
return request
}
export const loadCleanNavPoiById = async (id: string, baseUrl = NAV_ASSET_BASE_URL) => {
const pois = await loadCleanNavPois(baseUrl)
return pois.find((poi) => poi.id === id) || null
}
export const searchCleanNavPois = async (keyword = '', baseUrl = NAV_ASSET_BASE_URL) => {
const pois = await loadCleanNavPois(baseUrl)
const normalizedKeyword = keyword.trim().toLowerCase()
const matchedPois = normalizedKeyword
? pois.filter((poi) => {
const searchableText = [
poi.name,
poi.floorId,
formatNavFloorLabel(poi.floorId),
poi.primaryCategoryZh,
poi.iconType,
...(poi.categories || []).flatMap((category) => [
category.topCategoryZh,
category.subcategory,
category.iconType
])
]
.filter(Boolean)
.join(' ')
.toLowerCase()
return searchableText.includes(normalizedKeyword)
})
: pois
return matchedPois
}

View File

@@ -0,0 +1,75 @@
import type {
ExplainTrack,
MediaAsset,
MuseumExhibit,
MuseumHall,
SearchIndexItem
} from '@/domain/museum'
import {
explainRepository,
type ExplainRepository
} from '@/repositories/ExplainRepository'
import {
mediaRepository,
type MediaRepository
} from '@/repositories/MediaRepository'
export interface ExplainAudioSelection {
exhibit: MuseumExhibit
track: ExplainTrack | null
media: MediaAsset | null
playable: boolean
unavailableMessage?: string
}
export class ExplainUseCase {
constructor(
private readonly explain: ExplainRepository = explainRepository,
private readonly media: MediaRepository = mediaRepository
) {}
listExhibits() {
return this.explain.listExhibits()
}
getExhibitById(id: string) {
return this.explain.getExhibitById(id)
}
listHalls(): Promise<MuseumHall[]> {
return this.explain.listHalls()
}
getHallById(id: string) {
return this.explain.getHallById(id)
}
async listExhibitsByHallId(hallId: string) {
const exhibits = await this.explain.listExhibits()
return exhibits.filter((exhibit) => exhibit.hallId === hallId)
}
searchExplain(keyword?: string): Promise<SearchIndexItem[]> {
return this.explain.searchExplain(keyword)
}
async selectAudioForExhibit(exhibitId: string): Promise<ExplainAudioSelection | null> {
const exhibit = await this.explain.getExhibitById(exhibitId)
if (!exhibit) return null
const track = await this.explain.getTrackByExhibitId(exhibitId)
const media = track?.mediaId
? await this.media.getMediaById(track.mediaId)
: null
return {
exhibit,
track,
media,
playable: media?.available === true && Boolean(media.url),
unavailableMessage: media?.unavailableReason || '该展项暂无讲解音频'
}
}
}
export const explainUseCase = new ExplainUseCase()

View File

@@ -0,0 +1,124 @@
import type {
GuideLocationPreviewPlan,
GuidePreviewStep,
GuideStartLocation,
MuseumPoi
} from '@/domain/museum'
import {
guideRepository,
type GuideRepository
} from '@/repositories/GuideRepository'
import {
guideModelRepository,
type GuideModelRepository
} from '@/repositories/GuideModelRepository'
const startSourceLabels: Record<string, string> = {
'facility-detail': '设施详情选择',
manual: '手动选择'
}
const formatStartSourceLabel = (source?: string) => (
source ? startSourceLabels[source] || source : ''
)
const formatStartStepText = (startLocation: GuideStartLocation) => {
const sourceLabel = formatStartSourceLabel(startLocation.source)
const floorSuffix = startLocation.floor && !startLocation.label.includes(startLocation.floor)
? ` · ${startLocation.floor}`
: ''
const sourceSuffix = sourceLabel ? `${sourceLabel}` : ''
return `起点:${startLocation.label}${floorSuffix}${sourceSuffix}`
}
const createPreviewSteps = (
poi: MuseumPoi | null,
startLocation: GuideStartLocation | null,
routeUnavailableMessage: string
): GuidePreviewStep[] => {
if (startLocation) {
return [
{
id: 'start',
text: formatStartStepText(startLocation)
},
{
id: 'target',
text: poi
? `目标:${poi.floorLabel} · ${poi.primaryCategory.label} · 位置预览`
: '目标来自 clean 导览数据,暂仅支持位置预览'
}
]
}
return [
{
id: 'floor',
text: poi ? `目标位于 ${poi.floorLabel} · ${poi.primaryCategory.label}` : '目标来自 clean 导览数据'
},
{
id: 'status',
text: routeUnavailableMessage
}
]
}
export class GuideUseCase {
constructor(
private readonly guide: GuideRepository = guideRepository,
private readonly guideModel: GuideModelRepository = guideModelRepository
) {}
getRouteReadiness() {
return this.guide.getRouteReadiness()
}
getFloors() {
return this.guide.getFloors()
}
getAssetBaseUrl() {
return this.guide.getAssetBaseUrl()
}
getModelSource() {
return this.guideModel
}
normalizeFloorId(labelOrId: string) {
return this.guide.normalizeFloorId(labelOrId)
}
searchPois(keyword?: string) {
return this.guide.searchPois(keyword)
}
getPoiById(id: string) {
return this.guide.getPoiById(id)
}
async createLocationPreviewPlan(
facilityId: string,
target: string,
startLocation: GuideStartLocation | null = null
): Promise<GuideLocationPreviewPlan> {
const poi = facilityId ? await this.guide.getPoiById(facilityId) : null
const routeReadiness = this.guide.getRouteReadiness()
const targetLocation = poi ? await this.guide.getLocationPreview(poi.id) : null
return {
id: `route-${facilityId || 'custom'}`,
facilityId,
target: target || poi?.name || '目标地点',
summary: poi
? `${poi.floorLabel} · ${poi.primaryCategory.label} · 位置预览`
: '位置预览 · 尚未接入正式路线图',
steps: createPreviewSteps(poi, startLocation, routeReadiness.message),
targetLocation,
startLocation
}
}
}
export const guideUseCase = new GuideUseCase()

View File

@@ -1,98 +0,0 @@
/**
* Legacy demo data loader.
*
* 当前导览模块不要再从 src/assets/data 取数;室内导览、搜索、位置预览
* 统一使用 src/services/navAssets.ts 读取 clean nav assets。
* 这里保留给尚未重构的历史演示页面,避免删除造成不可控回归。
*/
// 加载楼层数据
export const loadFloors = async () => {
try {
const data = await import('@/assets/data/floors.json')
return data.default || data
} catch (error) {
console.error('加载楼层数据失败:', error)
return []
}
}
// 加载展厅数据
export const loadHalls = async () => {
try {
const data = await import('@/assets/data/halls.json')
return data.default || data
} catch (error) {
console.error('加载展厅数据失败:', error)
return []
}
}
// 加载展品数据
export const loadExhibits = async () => {
try {
const data = await import('@/assets/data/exhibits.json')
return data.default || data
} catch (error) {
console.error('加载展品数据失败:', error)
return []
}
}
// 加载设施数据
export const loadFacilities = async () => {
try {
const data = await import('@/assets/data/facilities.json')
return data.default || data
} catch (error) {
console.error('加载设施数据失败:', error)
return []
}
}
// 加载路线数据
export const loadRoutes = async () => {
try {
const data = await import('@/assets/data/routes.json')
return data.default || data
} catch (error) {
console.error('加载路线数据失败:', error)
return []
}
}
// 根据 ID 查找展品
export const findExhibitById = async (id: string) => {
const exhibits = await loadExhibits()
return exhibits.find((item: any) => item.id === id)
}
// 根据 ID 查找展厅
export const findHallById = async (id: string) => {
const halls = await loadHalls()
return halls.find((item: any) => item.id === id)
}
// 根据 ID 查找设施
export const findFacilityById = async (id: string) => {
const facilities = await loadFacilities()
return facilities.find((item: any) => item.id === id)
}
// 根据 ID 查找路线
export const findRouteById = async (id: string) => {
const routes = await loadRoutes()
return routes.find((item: any) => item.id === id)
}
// 根据楼层筛选展厅
export const filterHallsByFloor = async (floorId: string) => {
const halls = await loadHalls()
return halls.filter((item: any) => item.floor === floorId)
}
// 根据展厅筛选展品
export const filterExhibitsByHall = async (hallId: string) => {
const exhibits = await loadExhibits()
return exhibits.filter((item: any) => item.hallId === hallId)
}

View File

@@ -0,0 +1,90 @@
import type {
MuseumExhibit,
MuseumHall,
SearchIndexItem
} from '@/domain/museum'
export interface ExplainExhibitViewModel {
id: string
name: string
hall?: string
floor?: string
image?: string
hasAudio: boolean
audioUnavailableReason?: string
poiId?: string
}
export interface ExplainDetailViewModel {
id: string
name: string
artist?: string
year?: string
material?: string
size?: string
hall?: string
image: string
description: string
hasAudio: boolean
audioUnavailableReason?: string
poiId?: string
}
export interface HallDetailViewModel {
id: string
name: string
floorLabel: string
description: string
image: string
exhibitCount: number
area?: string
poiId?: string
}
export const toExplainExhibitViewModel = (exhibit: MuseumExhibit): ExplainExhibitViewModel => ({
id: exhibit.id,
name: exhibit.name,
hall: exhibit.hallName && exhibit.floorLabel
? `${exhibit.hallName} ${exhibit.floorLabel}`
: exhibit.hallName || exhibit.floorLabel,
floor: exhibit.floorLabel,
image: exhibit.image,
hasAudio: false,
audioUnavailableReason: '正式讲解音频尚未接入媒体仓储',
poiId: exhibit.poiId
})
export const toExplainDetailViewModel = (exhibit: MuseumExhibit): ExplainDetailViewModel => ({
id: exhibit.id,
name: exhibit.name,
artist: exhibit.artist,
year: exhibit.year,
material: exhibit.material,
size: exhibit.size,
hall: exhibit.hallName && exhibit.floorLabel
? `${exhibit.hallName} ${exhibit.floorLabel}`
: exhibit.hallName || exhibit.floorLabel,
image: exhibit.image || '/static/exhibit-placeholder.jpg',
description: exhibit.description || '该展项介绍待正式内容库补充。',
hasAudio: false,
audioUnavailableReason: '正式讲解音频尚未接入媒体仓储',
poiId: exhibit.poiId
})
export const toHallDetailViewModel = (hall: MuseumHall): HallDetailViewModel => ({
id: hall.id,
name: hall.name,
floorLabel: hall.floorLabel || '楼层待补充',
description: hall.description || '该展厅介绍待正式内容库补充。',
image: hall.image || '/static/hall-placeholder.jpg',
exhibitCount: hall.exhibitCount || 0,
area: hall.area,
poiId: hall.poiId
})
export const toExplainSearchResultViewModel = (item: SearchIndexItem) => ({
id: item.id,
name: item.name,
desc: item.desc,
type: item.type
})

View File

@@ -0,0 +1,70 @@
import type {
GuideLocationPreview,
GuideLocationPreviewPlan,
MuseumPoi
} from '@/domain/museum'
export interface FacilityResultViewModel {
id: string
name: string
floor: string
meta: string
accessible: boolean
action: '查看'
}
export interface FacilityDetailViewModel {
id: string
name: string
status: string
location: string
traffic: string
tags: string[]
}
export interface TargetPoiFocusRequestViewModel extends GuideLocationPreview {
requestId: number | string
}
export const toFacilityResultViewModel = (poi: MuseumPoi): FacilityResultViewModel => ({
id: poi.id,
name: poi.name,
floor: poi.floorLabel,
meta: `${poi.floorLabel}${poi.primaryCategory.label}${poi.navigationReadiness || '展示点位'}`,
accessible: poi.accessible,
action: '查看'
})
export const toFacilityDetailViewModel = (
poi: MuseumPoi,
routeUnavailableMessage: string
): FacilityDetailViewModel => ({
id: poi.id,
name: poi.name,
status: '可预览',
location: `${poi.floorLabel} · ${poi.primaryCategory.label}`,
traffic: routeUnavailableMessage,
tags: [
poi.floorLabel,
poi.primaryCategory.label,
poi.accessible ? '无障碍相关' : '展示点位'
]
})
export const toTargetFocusRequestViewModel = (
targetLocation: GuideLocationPreview,
requestId: number | string
): TargetPoiFocusRequestViewModel => ({
...targetLocation,
requestId
})
export const initialLocationPreviewPlan = (): GuideLocationPreviewPlan => ({
id: 'route-custom',
facilityId: '',
target: '目标地点',
summary: '位置预览 · 尚未接入正式路线图',
steps: [],
targetLocation: null,
startLocation: null
})

View File

@@ -5,7 +5,7 @@
## 入口
- app_nav_manifest.json
- building_overview.glb
- building_overview.glb(无 L 楼层前缀的外墙/建筑外围/装饰对象)
- data/poi_all.json
- data/poi_by_floor/<floorId>.json
- data/floor_index.json
@@ -13,4 +13,5 @@
## 说明
旧版 17 点 POI 与旧 poi_by_floor 目录没有复制到本包,避免小程序误读。
models_by_floor/<floorId>.glb 只包含对象名以对应 L 楼层前缀开头的模型;无 L 前缀对象只进入 building_overview.glb。
POI 坐标前端推荐使用 positionGltf。

View File

@@ -1,13 +1,13 @@
{
"schemaVersion": "miniapp-nav-assets-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.467Z",
"generatedAt": "2026-06-11T09:36:23.719Z",
"projectRoot": "E:/MyWork/深圳国际艺术馆/lender-museum",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"sourcePackage": "E:\\MyWork\\深圳国际艺术馆\\lender-museum\\evidence\\runs\\codex_nav_20260607_reloaded_223947\\app_nav_assets_20260609_072638",
"outputRoot": "E:\\MyWork\\深圳国际艺术馆\\lender-museum\\evidence\\runs\\codex_nav_20260607_reloaded_223947\\app_nav_assets_v2_clean_20260609_075339",
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"sourcePackage": "E:\\MyWork\\深圳国际艺术馆\\lender-museum\\evidence\\runs\\codex_nav_20260607_reloaded_223947\\app_nav_assets_20260611_093410",
"outputRoot": "E:\\MyWork\\深圳国际艺术馆\\lender-museum\\evidence\\runs\\codex_nav_20260607_reloaded_223947\\app_nav_assets_v2_clean_20260611_093623",
"safety": {
"opensSwitchesReloadsOrSavesBlend": false,
"writesRouteGraph": false,
@@ -16,6 +16,11 @@
"writesWebModelCurrentSessionGlb": false,
"blenderFree": true
},
"modelSeparationPolicy": {
"floorModelRule": "models_by_floor/<floorId>.glb contains only mesh objects whose Blender object names start with that exact L floor prefix",
"overviewModelRule": "building_overview.glb contains only no-floor-prefix exterior/envelope/decorative mesh objects",
"noZHeuristicForModelExport": true
},
"frontendLoadingStrategy": {
"initialView": [
"load app_nav_manifest.json",
@@ -38,82 +43,82 @@
"assets": {
"overviewModel": {
"asset": "building_overview.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/building_overview.glb",
"bytes": 9602412,
"sha256": "6df745c8760db68ca5bdd95f91bd523fd29b33998bb7b269ed8453c4762e6050"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/building_overview.glb",
"bytes": 3060532,
"sha256": "64c5d0f7c82bf7fbdd1094e9c2adf5646c57f6e38666669e8daea77f1fbd0692"
},
"floorModels": [
{
"floorId": "L-2",
"order": -2,
"objectCount": 55,
"objectCount": 65,
"asset": "models_by_floor/L-2.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L-2.glb",
"bytes": 2064656,
"sha256": "72ba73e98b56e27875f8b8168e09f171cc3eb10b9208c8cc7970644d33a78198"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L-2.glb",
"bytes": 4380824,
"sha256": "3e7179f0b0aa6e4be9bdd9941814843762d20c496c1f0e84a59181f5925cc43a"
},
{
"floorId": "L-1",
"order": -1,
"objectCount": 49,
"objectCount": 50,
"asset": "models_by_floor/L-1.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L-1.glb",
"bytes": 1601948,
"sha256": "617f958d17232938f26239f6fd3051894cae9d5a0e6fe9de526ecce03acf9db9"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L-1.glb",
"bytes": 1604640,
"sha256": "d0a9ee315722d44c6bd62e3275f7af582de23ffe5a8017eacf07b28b7a4f247a"
},
{
"floorId": "L1",
"order": 1,
"objectCount": 90,
"objectCount": 94,
"asset": "models_by_floor/L1.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L1.glb",
"bytes": 3992740,
"sha256": "d1bf105c00bf7fa724d82dc8ac7c067c29dadc991dd550d404d4f3a75bab72cb"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L1.glb",
"bytes": 8550188,
"sha256": "315c8d325cda7de5f0650114e64b5ccd8279ae1b3155fd176caf313ee7dd1e50"
},
{
"floorId": "L1.5",
"order": 1.5,
"objectCount": 26,
"asset": "models_by_floor/L1.5.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L1.5.glb",
"bytes": 1144212,
"sha256": "6f372715c1837ec670cbfdfe2cee70bb1d11b2b6479ab95df81f0f863a00ad29"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L1.5.glb",
"bytes": 1128032,
"sha256": "43e82bf2c77fd961850644daf47e1222c1c1e58f850b696376c7e526e4cea7d0"
},
{
"floorId": "L2",
"order": 2,
"objectCount": 50,
"objectCount": 58,
"asset": "models_by_floor/L2.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L2.glb",
"bytes": 1595720,
"sha256": "ca1581e89127275018d7402d1bbe0197b6aa28f0a77257bfe3bfffacf226b397"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L2.glb",
"bytes": 2165388,
"sha256": "481073fe17868f6fb3a563cd4f3d696da66a9e0c3db2c59485c96f1b41ba7e47"
},
{
"floorId": "L3",
"order": 3,
"objectCount": 22,
"objectCount": 18,
"asset": "models_by_floor/L3.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L3.glb",
"bytes": 3692804,
"sha256": "f5099d6572dd4daf4f170678939839bb7b4f8a31fb5fe74eaaabc587cc31b21f"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L3.glb",
"bytes": 821016,
"sha256": "f9985fb5c7a7442be658a0359874e96a8f5155c7970bdf1933fa6f5f035c5d21"
},
{
"floorId": "L4",
"order": 4,
"objectCount": 36,
"asset": "models_by_floor/L4.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L4.glb",
"bytes": 1073744,
"sha256": "2f6c181ed840b4384878c9d3e138a865d3d355f7c17d65e8b48092875276181e"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L4.glb",
"bytes": 1073656,
"sha256": "9e86746cec793f3ae5dbfa57a3471cf231e9e2a686b9efa797df28182e6ffae4"
},
{
"floorId": "L5",
"order": 5,
"objectCount": 15,
"objectCount": 14,
"asset": "models_by_floor/L5.glb",
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260609_075339/models_by_floor/L5.glb",
"bytes": 911340,
"sha256": "ca0aa271996842ae083f96aebeaffac46b4a0499ab901046d7aaeb60c282fcdb"
"relativePath": "evidence/runs/codex_nav_20260607_reloaded_223947/app_nav_assets_v2_clean_20260611_093623/models_by_floor/L5.glb",
"bytes": 751904,
"sha256": "6dbe090d31a13edee95f860e032db214cdccf20786efc326a90e5e437d46933f"
}
]
},
@@ -124,15 +129,15 @@
"poiByFloor": {
"L-2": {
"asset": "data/poi_by_floor/L-2.json",
"poiCount": 52
"poiCount": 62
},
"L-1": {
"asset": "data/poi_by_floor/L-1.json",
"poiCount": 46
"poiCount": 47
},
"L1": {
"asset": "data/poi_by_floor/L1.json",
"poiCount": 78
"poiCount": 81
},
"L1.5": {
"asset": "data/poi_by_floor/L1.5.json",
@@ -140,11 +145,11 @@
},
"L2": {
"asset": "data/poi_by_floor/L2.json",
"poiCount": 47
"poiCount": 55
},
"L3": {
"asset": "data/poi_by_floor/L3.json",
"poiCount": 16
"poiCount": 15
},
"L4": {
"asset": "data/poi_by_floor/L4.json",
@@ -170,27 +175,27 @@
"L4",
"L5"
],
"overviewObjectCount": 45,
"poiCount": 298,
"sourceEnhancedPoiCount": 294,
"supplementalPoiCount": 4,
"overviewObjectCount": 5,
"poiCount": 319,
"sourceEnhancedPoiCount": 316,
"supplementalPoiCount": 3,
"poiCountByFloor": {
"L-2": 52,
"L-1": 46,
"L1": 78,
"L-2": 62,
"L-1": 47,
"L1": 81,
"L1.5": 21,
"L2": 47,
"L3": 16,
"L2": 55,
"L3": 15,
"L4": 27,
"L5": 11
},
"poiCountByCategory": {
"touring_poi": 17,
"basic_service_facility": 47,
"transport_circulation": 229,
"touring_poi": 34,
"basic_service_facility": 57,
"transport_circulation": 232,
"accessibility_special_service": 10,
"safety_management": 0,
"operation_experience": 8
"operation_experience": 7
},
"connectorEndpointCount": 10
},
@@ -209,14 +214,6 @@
"primaryCategory": "operation_experience",
"navigationReadiness": "display_candidate_requires_access_or_nav_anchor_confirmation"
},
{
"id": "supplemental_919d93c114",
"name": "楼顶绿化",
"sourceObjectName": "楼顶绿化",
"floorId": "L3",
"primaryCategory": "operation_experience",
"navigationReadiness": "display_candidate_requires_access_or_nav_anchor_confirmation"
},
{
"id": "supplemental_306932bd08",
"name": "L1 室外水景",
@@ -238,6 +235,7 @@
"该 clean 包只保留前端应该读取的 canonical POI 数据,不再包含旧版 poi_all.json / poi_by_floor。",
"data/poi_all.json 已是增强版 POI不是旧 17 点版本。",
"data/poi_by_floor/<floorId>.json 覆盖每个模型楼层,包括 L-1。",
"补充的景观/公共空间点位来自模型 bbox center适合展示和搜索精确路线需要后续 NAV anchor。"
"补充的景观/公共空间点位来自模型 bbox center适合展示和搜索精确路线需要后续 NAV anchor。",
"本 strict_floor_prefix 包不会把无 L 前缀的外墙、建筑外围或装饰对象归入任何楼层 GLB。"
]
}

View File

@@ -3,11 +3,11 @@
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"sourceInvocation": "clean_app_nav_assets_v2_audit",
"outputRoot": "E:\\MyWork\\深圳国际艺术馆\\lender-museum\\evidence\\runs\\codex_nav_20260607_reloaded_223947\\app_nav_assets_v2_clean_20260609_075339",
"outputRoot": "E:\\MyWork\\深圳国际艺术馆\\lender-museum\\evidence\\runs\\codex_nav_20260607_reloaded_223947\\app_nav_assets_v2_clean_20260611_093623",
"checks": {
"noLegacyPoiByFloorDir": true,
"noLegacyEnhancedAlias": true,
"canonicalPoiAllCount": 298,
"canonicalPoiAllCount": 319,
"allFloorPoiFilesExist": true,
"floorIndexUsesCanonicalPoiByFloor": true,
"nullPositionCount": 0,
@@ -25,27 +25,27 @@
"L4",
"L5"
],
"overviewObjectCount": 45,
"poiCount": 298,
"sourceEnhancedPoiCount": 294,
"supplementalPoiCount": 4,
"overviewObjectCount": 5,
"poiCount": 319,
"sourceEnhancedPoiCount": 316,
"supplementalPoiCount": 3,
"poiCountByFloor": {
"L-2": 52,
"L-1": 46,
"L1": 78,
"L-2": 62,
"L-1": 47,
"L1": 81,
"L1.5": 21,
"L2": 47,
"L3": 16,
"L2": 55,
"L3": 15,
"L4": 27,
"L5": 11
},
"poiCountByCategory": {
"touring_poi": 17,
"basic_service_facility": 47,
"transport_circulation": 229,
"touring_poi": 34,
"basic_service_facility": 57,
"transport_circulation": 232,
"accessibility_special_service": 10,
"safety_management": 0,
"operation_experience": 8
"operation_experience": 7
},
"connectorEndpointCount": 10
}

View File

@@ -1,6 +1,6 @@
{
"schemaVersion": "miniapp-connector-endpoints-clean-2.0",
"generatedAt": "2026-06-09T07:26:41.747324+00:00",
"generatedAt": "2026-06-11T09:34:13.839693+00:00",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",

View File

@@ -1,6 +1,6 @@
{
"schemaVersion": "miniapp-floor-index-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.466Z",
"generatedAt": "2026-06-11T09:36:23.719Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
@@ -9,25 +9,25 @@
"floorId": "L-2",
"order": -2,
"modelAsset": "models_by_floor/L-2.glb",
"objectCount": 55,
"objectCount": 65,
"poiDataAsset": "data/poi_by_floor/L-2.json",
"poiCount": 52
"poiCount": 62
},
{
"floorId": "L-1",
"order": -1,
"modelAsset": "models_by_floor/L-1.glb",
"objectCount": 49,
"objectCount": 50,
"poiDataAsset": "data/poi_by_floor/L-1.json",
"poiCount": 46
"poiCount": 47
},
{
"floorId": "L1",
"order": 1,
"modelAsset": "models_by_floor/L1.glb",
"objectCount": 90,
"objectCount": 94,
"poiDataAsset": "data/poi_by_floor/L1.json",
"poiCount": 78
"poiCount": 81
},
{
"floorId": "L1.5",
@@ -41,17 +41,17 @@
"floorId": "L2",
"order": 2,
"modelAsset": "models_by_floor/L2.glb",
"objectCount": 50,
"objectCount": 58,
"poiDataAsset": "data/poi_by_floor/L2.json",
"poiCount": 47
"poiCount": 55
},
{
"floorId": "L3",
"order": 3,
"modelAsset": "models_by_floor/L3.glb",
"objectCount": 22,
"objectCount": 18,
"poiDataAsset": "data/poi_by_floor/L3.json",
"poiCount": 16
"poiCount": 15
},
{
"floorId": "L4",
@@ -65,7 +65,7 @@
"floorId": "L5",
"order": 5,
"modelAsset": "models_by_floor/L5.glb",
"objectCount": 15,
"objectCount": 14,
"poiDataAsset": "data/poi_by_floor/L5.json",
"poiCount": 11
}

View File

@@ -1,17 +1,25 @@
id,name,floorId,primaryCategory,primaryCategoryZh,iconType,sourceObjectName,positionGltfX,positionGltfY,positionGltfZ,coordinateSource,navigationReadiness
modelpoi_L-2_492e987660,L-2 母婴室,L-2,accessibility_special_service,无障碍与特殊人群服务,nursery,L-2_母婴室,-51.175003,-14.191206,39.344395,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_433ee81108,L-2 男卫生间01,L-2,basic_service_facility,基础服务设施,restroom,L-2_男卫生间01,-82.988602,-14.491209,43.190712,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_673c254e4d,L-2 男卫生间02,L-2,basic_service_facility,基础服务设施,restroom,L-2_男卫生间02,-18.808712,-14.491209,19.713522,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_1468d92dfd,L-2 男卫生间04,L-2,basic_service_facility,基础服务设施,restroom,L-2_男卫生间04,57.642273,-14.491209,24.258451,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a38a8c488e,L-2 女卫生间01,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间01,-91.456207,-14.491209,38.036762,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_b94325224a,L-2 女卫生间02,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间02,-30.663593,-14.491209,14.251428,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_e2cac3d857,L-2 女卫生间03,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间03,16.534239,-14.491209,25.273596,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_d36fe2dc9d,L-2 女卫生间03.001,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间03.001,32.573727,-14.491209,24.407684,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_c0855378b9,L-2 女卫生间04,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间04,68.159348,-14.491209,27.444523,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_492e987660,L-2 母婴室,L-2,accessibility_special_service,无障碍与特殊人群服务,nursery,L-2_母婴室,-51.175003,-13.147993,39.344395,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_433ee81108,L-2 男卫生间01,L-2,basic_service_facility,基础服务设施,restroom,L-2_男卫生间01,-82.988602,-13.447996,43.190712,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_673c254e4d,L-2 男卫生间02,L-2,basic_service_facility,基础服务设施,restroom,L-2_男卫生间02,-18.808712,-13.447996,19.713522,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_1468d92dfd,L-2 男卫生间04,L-2,basic_service_facility,基础服务设施,restroom,L-2_男卫生间04,57.642273,-13.447996,24.258451,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a38a8c488e,L-2 女卫生间01,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间01,-91.456207,-13.447996,38.036762,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_b94325224a,L-2 女卫生间02,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间02,-30.663593,-13.447996,14.251428,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_e2cac3d857,L-2 女卫生间03,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间03,16.534239,-13.447996,25.273596,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_d36fe2dc9d,L-2 女卫生间03.001,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间03.001,32.573727,-13.447996,24.407684,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_c0855378b9,L-2 女卫生间04,L-2,basic_service_facility,基础服务设施,restroom,L-2_女卫生间04,68.159348,-13.447996,27.444523,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0009,L-2 展厅1宇宙厅,L-2,touring_poi,游览 POI,exhibition,L-2_展厅1宇宙厅,-90.488953,-14.388401,44.977547,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L-2_1fa3680520,L-2 展厅1宇宙厅 展柜,L-2,touring_poi,游览 POI,exhibition,L-2_展厅1宇宙厅_展柜,-87.730865,-13.891212,54.098366,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_0328e49a57,L-2 展厅1宇宙厅 装饰,L-2,touring_poi,游览 POI,exhibition,L-2_展厅1宇宙厅_装饰,-90.488953,-11.498024,44.977547,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0010,L-2 展厅2地球厅,L-2,touring_poi,游览 POI,exhibition,L-2_展厅2地球厅,-17.07975,-14.388401,-8.416769,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L-2_e2ec8ce8ba,L-2 展厅2地球厅 展柜,L-2,touring_poi,游览 POI,exhibition,L-2_展厅2地球厅_展柜,-17.069817,-13.827784,-8.752005,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_f23816be84,L-2 展厅2地球厅 装饰,L-2,touring_poi,游览 POI,exhibition,L-2_展厅2地球厅_装饰,-17.07975,-11.498024,-8.416769,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0008,L-2 展厅3演化厅,L-2,touring_poi,游览 POI,exhibition,L-2_展厅3演化厅,25.952524,-14.388403,51.155842,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L-2_34bbb3d9d4,L-2 展厅3演化厅 展柜,L-2,touring_poi,游览 POI,exhibition,L-2_展厅3演化厅_展柜,25.310183,-13.89121,51.903332,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a2d90df88c,L-2 展厅3演化厅 装饰,L-2,touring_poi,游览 POI,exhibition,L-2_展厅3演化厅_装饰,25.952511,-11.48424,51.155872,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0007,L-2 展厅4恐龙厅,L-2,touring_poi,游览 POI,exhibition,L-2_展厅4恐龙厅,69.308327,-14.388403,-0.631475,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L-2_f877db497b,L-2 展厅4恐龙厅 展柜,L-2,touring_poi,游览 POI,exhibition,L-2_展厅4恐龙厅_展柜,69.237717,-13.987548,-0.634724,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_81c1403384,L-2 展厅4恐龙厅 装饰,L-2,touring_poi,游览 POI,exhibition,L-2_展厅4恐龙厅_装饰,70.205048,-7.689972,2.088411,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_ae5be493c0,L-2 电梯0001,L-2,transport_circulation,交通与通行动线,elevator,L-2_电梯0001,34.112198,-13.127687,77.432434,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_e628190832,L-2 电梯0002,L-2,transport_circulation,交通与通行动线,elevator,L-2_电梯0002,48.350098,-12.874514,67.133812,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a1322a6c4d,L-2 电梯0003,L-2,transport_circulation,交通与通行动线,elevator,L-2_电梯0003,90.601959,-12.863037,49.503075,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -32,25 +40,27 @@ modelpoi_L-2_a7f866a09a,L-2 电梯0017,L-2,transport_circulation,交通与通行
modelpoi_L-2_0d88e71c27,L-2 电梯0018,L-2,transport_circulation,交通与通行动线,elevator,L-2_电梯0018,-99.716293,-12.873795,12.790838,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_ca23f27f00,L-2 电梯0019,L-2,transport_circulation,交通与通行动线,elevator,L-2_电梯0019,-100.377762,-12.873795,9.507727,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_73874acb68,L-2 扶梯,L-2,transport_circulation,交通与通行动线,escalator,L-2_扶梯,67.947716,-12.484815,42.180843,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_77bdede69c,L-2 楼梯0001,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0001,-113.980553,-14.191214,15.791812,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_d6275be404,L-2 楼梯0002,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0002,-125.09758,-14.191216,44.947601,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_d9df5eab1e,L-2 楼梯0003,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0003,-105.471481,-14.19121,-80.607361,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_3dd779ffc4,L-2 楼梯0004,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0004,-119.36657,-14.19121,-77.92852,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_bcfbe38b8c,L-2 楼梯0005,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0005,-118.673454,-14.191213,-19.434433,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_f5a71cd735,L-2 楼梯0006,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0006,-96.47963,-14.191214,1.494661,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_acacdf7cd3,L-2 楼梯0007,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0007,-34.926815,-14.191212,-27.636536,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_706e6e65ea,L-2 楼梯0008,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0008,-54.706528,-14.191216,59.089958,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_586f1dcb89,L-2 楼梯0009,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0009,-62.075691,-14.191199,69.846909,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_5e6d33b390,L-2 楼梯0010,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0010,-78.359177,-14.191216,79.284683,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a158651e42,L-2 楼梯0011,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0011,-51.635437,-14.191216,48.365948,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_4d987dbec1,L-2 楼梯0012,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0012,-2.737168,-14.191216,53.378433,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_ff21400c01,L-2 楼梯0013,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0013,91.222206,-14.191216,58.967903,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_990fd35b22,L-2 楼梯0014,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0014,93.295212,-14.191216,42.003674,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_49592f09b2,L-2 楼梯0015,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0015,94.548233,-14.191213,-5.112744,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a9c1ecac07,L-2 楼梯0016,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0016,46.435764,-14.191214,-3.948162,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_7a4fb7e3e7,L-2 楼梯0017,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0017,45.298622,-14.191214,4.789413,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_5250437db8,L-2 楼梯0018,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0018,53.007278,-14.191216,58.379272,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_84885548c6,L-2 停车位,L-2,transport_circulation,交通与通行动线,parking,L-2_停车位,-13.833179,-14.191204,10.672264,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_77bdede69c,L-2 楼梯0001,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0001,-113.980553,-13.148001,15.791812,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_d6275be404,L-2 楼梯0002,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0002,-125.09758,-13.148003,44.947601,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_d9df5eab1e,L-2 楼梯0003,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0003,-105.471481,-13.147997,-80.607361,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_3dd779ffc4,L-2 楼梯0004,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0004,-119.36657,-13.147997,-77.92852,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_bcfbe38b8c,L-2 楼梯0005,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0005,-118.673454,-13.148,-19.434433,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_f5a71cd735,L-2 楼梯0006,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0006,-96.47963,-13.148001,1.494661,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_acacdf7cd3,L-2 楼梯0007,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0007,-34.926815,-13.147999,-27.636536,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_706e6e65ea,L-2 楼梯0008,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0008,-54.706528,-13.148003,59.089958,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_586f1dcb89,L-2 楼梯0009,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0009,-62.075691,-13.147986,69.846909,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_5e6d33b390,L-2 楼梯0010,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0010,-78.359177,-13.148004,79.284683,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a158651e42,L-2 楼梯0011,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0011,-51.635437,-13.148003,48.365948,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_4d987dbec1,L-2 楼梯0012,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0012,-2.737168,-13.148003,53.378433,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_ff21400c01,L-2 楼梯0013,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0013,91.222206,-13.148003,58.967903,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_990fd35b22,L-2 楼梯0014,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0014,93.295212,-13.148003,42.003674,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_49592f09b2,L-2 楼梯0015,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0015,94.548233,-13.148,-5.112744,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_a9c1ecac07,L-2 楼梯0016,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0016,46.435764,-13.148001,-3.948162,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_7a4fb7e3e7,L-2 楼梯0017,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0017,45.298622,-13.148001,4.789413,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_5250437db8,L-2 楼梯0018,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0018,53.007278,-13.148003,58.379272,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_482544cba6,L-2 楼梯0019,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0019,-91.555466,-11.787357,46.893166,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_5753e93667,L-2 楼梯0020,L-2,transport_circulation,交通与通行动线,stair,L-2_楼梯0020,-77.065353,-11.787357,46.893166,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-2_84885548c6,L-2 停车位,L-2,transport_circulation,交通与通行动线,parking,L-2_停车位,-13.833179,-14.391253,10.672264,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-1_14ec89b181,L-1 球幕影院,L-1,touring_poi,游览 POI,theater,L-1_球幕影院,0.941269,-10.898361,-4.725914,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-1_e98e1e7579,L-1 电梯0001,L-1,transport_circulation,交通与通行动线,elevator,L-1_电梯0001,-99.961014,-9.296165,9.723492,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-1_31bfe24f01,L-1 电梯0002,L-1,transport_circulation,交通与通行动线,elevator,L-1_电梯0002,87.788162,-9.28541,49.793114,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -96,6 +106,7 @@ modelpoi_L-1_5b96f2b36e,L-1 楼梯0021,L-1,transport_circulation,交通与通行
modelpoi_L-1_c2152945b5,L-1 楼梯0022,L-1,transport_circulation,交通与通行动线,stair,L-1_楼梯0022,-118.173111,-10.669845,-18.677877,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-1_d10fc5993f,L-1 楼梯0023,L-1,transport_circulation,交通与通行动线,stair,L-1_楼梯0023,-105.15239,-10.669839,-79.589508,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-1_7639982b98,L-1 楼梯0024,L-1,transport_circulation,交通与通行动线,stair,L-1_楼梯0024,-119.786385,-10.669839,-77.311356,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-1_04e400880b,L-1 楼梯0025,L-1,transport_circulation,交通与通行动线,stair,L-1_楼梯0025,-13.88942,-10.669846,-5.084072,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L-1_e3aff063cb,L-1 停车场地面,L-1,transport_circulation,交通与通行动线,parking,L-1_停车场地面,85.808472,-10.834019,67.684715,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_19555b8890,L1 轮椅及儿童车租赁,L1,accessibility_special_service,无障碍与特殊人群服务,rental,L1_轮椅及儿童车租赁,-65.994453,0.058651,15.326918,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_55e995bb4d,L1 母婴间,L1,accessibility_special_service,无障碍与特殊人群服务,nursery,L1_母婴间,-95.211792,0.058651,26.434822,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -111,10 +122,11 @@ modelpoi_L1_a89f999ce8,L1 男卫生间02,L1,basic_service_facility,基础服务
modelpoi_L1_8045e85848,L1 女卫生间,L1,basic_service_facility,基础服务设施,restroom,L1_女卫生间,-70.903793,0.258651,24.592087,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_170ebd7038,L1 女卫生间01,L1,basic_service_facility,基础服务设施,restroom,L1_女卫生间01,131.002686,0.25865,38.265602,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_90b628a1d5,L1 女卫生间02,L1,basic_service_facility,基础服务设施,restroom,L1_女卫生间02,49.345047,0.258652,11.62169,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_11ae2666ee,L1 售票机,L1,basic_service_facility,基础服务设施,ticket,L1_售票机,17.294315,1,24.678955,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_f41223bb9c,L1 贵宾接待区,L1,operation_experience,运营体验类点位,vip,L1_贵宾接待区,-77.729813,0.058651,19.560249,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
supplemental_b23c543281,L1 室外绿化,L1,operation_experience,运营体验类点位,landscape,L1_室外绿化,3.996948,0.172545,-0.012264,model_object_bbox_center_candidate,display_candidate_requires_access_or_nav_anchor_confirmation
supplemental_306932bd08,L1 室外水景,L1,operation_experience,运营体验类点位,photo,L1_室外水景,22.258747,-0.488044,-0.367207,model_object_bbox_center_candidate,display_candidate_requires_access_or_nav_anchor_confirmation
supplemental_cc67428117,L1 室外下沉广场,L1,operation_experience,运营体验类点位,plaza,L1_室外下沉广场,31.983009,-2.810548,-12.300758,model_object_bbox_center_candidate,display_candidate_requires_access_or_nav_anchor_confirmation
supplemental_b23c543281,L1 室外绿化,L1,operation_experience,运营体验类点位,landscape,L1_室外绿化,4.52948,0.172545,-0.231293,model_object_bbox_center_candidate,display_candidate_requires_access_or_nav_anchor_confirmation
supplemental_306932bd08,L1 室外水景,L1,operation_experience,运营体验类点位,photo,L1_室外水景,23.06905,0.274697,-0.831573,model_object_bbox_center_candidate,display_candidate_requires_access_or_nav_anchor_confirmation
supplemental_cc67428117,L1 室外下沉广场,L1,operation_experience,运营体验类点位,plaza,L1_室外下沉广场,32.247353,-2.810548,-12.300758,model_object_bbox_center_candidate,display_candidate_requires_access_or_nav_anchor_confirmation
modelpoi_L1_350cd0e084,L1 动感多维影院,L1,touring_poi,游览 POI,theater,L1_动感多维影院,37.22998,0.058651,45.027328,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_9ba9a658bb,L1 巨幕影院,L1,touring_poi,游览 POI,theater,L1_巨幕影院,16.42691,0.058651,45.047546,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0003,L1 临展厅01,L1,touring_poi,游览 POI,exhibition,L1_临展厅01,-78.678642,0,-30.900698,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
@@ -122,6 +134,8 @@ poi_navpoi_0014,L1 临展厅02,L1,touring_poi,游览 POI,exhibition,L1_临展厅
modelpoi_L1_d2b5d8b621,L1 球幕影院,L1,touring_poi,游览 POI,theater,L1_球幕影院,1.775749,3.377288,-5.777876,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0002,L1 展厅5人类厅,L1,touring_poi,游览 POI,exhibition,L1_展厅5人类厅,112.822556,-0.000004,51.974705,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L1_4e1111c7b1,L1 自然剧场,L1,touring_poi,游览 POI,theater,L1_自然剧场,24.2363,0.05865,65.833115,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_bce5578bda,L1 L1 展厅5人类厅 装饰01,L1,touring_poi,游览 POI,exhibition,L1_L1_展厅5人类厅_装饰01,112.835953,2.864931,51.190968,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_d6bfac9efe,L1 L1 展厅5人类厅 装饰02,L1,touring_poi,游览 POI,exhibition,L1_L1_展厅5人类厅_装饰02,112.655197,3.820072,51.249493,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_45de13b368,L1 电梯0001,L1,transport_circulation,交通与通行动线,elevator,L1_电梯0001,-100.345444,1.526052,9.748894,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_aae15a9bf4,L1 电梯0002,L1,transport_circulation,交通与通行动线,elevator,L1_电梯0002,86.457626,1.526052,9.073389,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_874fe33d28,L1 电梯0003,L1,transport_circulation,交通与通行动线,elevator,L1_电梯0003,79.746368,1.526052,17.265091,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -145,7 +159,6 @@ modelpoi_L1_d22f4e53ae,L1 电梯0020,L1,transport_circulation,交通与通行动
modelpoi_L1_5338a76c2c,L1 电梯0021,L1,transport_circulation,交通与通行动线,elevator,L1_电梯0021,-99.683975,1.526052,13.032006,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_b3347e28c9,L1 扶梯,L1,transport_circulation,交通与通行动线,escalator,L1_扶梯,81.070969,-0.552914,36.499767,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_84fb77260b,L1 楼梯0001,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0001,-113.303513,0.217286,15.44129,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_a4a00c978d,L1 楼梯0002,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0002,-118.638206,0.217286,-19.517469,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_360cce5a19,L1 楼梯0003,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0003,-34.709263,0.300862,-27.007214,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_12b7990225,L1 楼梯0004,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0004,-51.784405,0.300859,43.113773,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_87efe86522,L1 楼梯0005,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0005,90.36853,0.296874,-5.492186,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -169,9 +182,10 @@ modelpoi_L1_4247dcb42a,L1 楼梯0022,L1,transport_circulation,交通与通行动
modelpoi_L1_2ce36ed339,L1 楼梯0023,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0023,-123.082703,0.217286,29.087791,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_9461bfead0,L1 楼梯0024,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0024,-125.829529,0.217285,45.41563,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_8a9434da15,L1 楼梯0025,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0025,-73.533424,0.25,63.954227,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_9a31638f63,L1 楼梯0026,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0026,-127.951675,0.217286,-2.199766,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_fa423c9ad0,L1 楼梯0027,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0027,-104.784119,0.217286,-81.176064,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_7d0051d2a6,L1 楼梯0028,L1,transport_circulation,交通与通行动线,stair,L1_楼梯0028,-119.274986,0,-78.993362,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_5655c264c1,L1 室外楼梯0001,L1,transport_circulation,交通与通行动线,stair,L1_室外楼梯0001,-104.784119,0.217286,-81.176064,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_6fa8f94e0d,L1 室外楼梯0002,L1,transport_circulation,交通与通行动线,stair,L1_室外楼梯0002,-119.274986,0,-78.993362,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_9d38633ca9,L1 室外楼梯0003,L1,transport_circulation,交通与通行动线,stair,L1_室外楼梯0003,-118.638206,0.217286,-19.517469,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_3936c7e2b1,L1 室外楼梯0004,L1,transport_circulation,交通与通行动线,stair,L1_室外楼梯0004,-127.951675,0.217286,-2.199766,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_a6652685b8,L1 停车场,L1,transport_circulation,交通与通行动线,parking,L1_停车场,-126.124298,0,-16.088915,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_9611467f0f,L1 停车场入口,L1,transport_circulation,交通与通行动线,parking,L1_停车场入口,-117.349075,-2.64097,-76.993629,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_ce023b99e4,L1 停车场入口02,L1,transport_circulation,交通与通行动线,parking,L1_停车场入口02,72.57579,-4.072168,72.416092,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -202,10 +216,18 @@ modelpoi_L2_a5009070bb,L2 男卫生间001,L2,basic_service_facility,基础服务
modelpoi_L2_2d14073a06,L2 男卫生间002,L2,basic_service_facility,基础服务设施,restroom,L2_男卫生间002,8.952654,10.273865,-1.457422,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_4470473302,L2 女卫生间001,L2,basic_service_facility,基础服务设施,restroom,L2_女卫生间001,-92.132439,10.558371,37.83683,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_e9fc021625,L2 女卫生间002,L2,basic_service_facility,基础服务设施,restroom,L2_女卫生间002,4.273729,10.273865,4.899143,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_9267c2d1d4,L2 卫生间,L2,basic_service_facility,基础服务设施,restroom,L2_卫生间,52.255562,10.273865,9.283119,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_f362d56eba,L2 文创店旗舰店,L2,basic_service_facility,基础服务设施,shop,L2_文创店旗舰店,-70.947243,10.178164,38.432304,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0006,L2 展厅 6生物厅,L2,touring_poi,游览 POI,exhibition,L2_展厅_6生物厅,69.074303,10.178165,1.496778,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L2_ecd476d1be,L2 展厅 6生物厅 展柜01,L2,touring_poi,游览 POI,exhibition,L2_展厅_6生物厅_展柜01,69.279694,10.281687,5.825405,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_d93b7e7a22,L2 展厅 6生物厅 展柜02,L2,touring_poi,游览 POI,exhibition,L2_展厅_6生物厅_展柜02,69.861053,10.594574,5.292932,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_bf6262807a,L2 展厅 6生物厅 装饰,L2,touring_poi,游览 POI,exhibition,L2_展厅_6生物厅_装饰,69.074303,13.479435,1.496778,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0005,L2 展厅 7生态厅,L2,touring_poi,游览 POI,exhibition,L2_展厅_7生态厅,24.894789,10.178165,53.795837,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L2_2fea6b6cff,L2 展厅 7生态厅 展柜,L2,touring_poi,游览 POI,exhibition,L2_展厅_7生态厅_展柜,25.018467,10.511989,53.729153,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_91de093d1e,L2 展厅 7生态厅 装饰,L2,touring_poi,游览 POI,exhibition,L2_展厅_7生态厅_装饰,24.894787,13.408146,53.795837,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
poi_navpoi_0004,L2 展厅 8家园厅,L2,touring_poi,游览 POI,exhibition,L2_展厅_8家园厅,-13.14613,10.178164,-10.430546,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L2_8b43a8a2a8,L2 展厅 8家园厅 展柜,L2,touring_poi,游览 POI,exhibition,L2_展厅_8家园厅_展柜,-12.998978,10.478165,-10.578304,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_83406e72e2,L2 展厅 8家园厅 装饰,L2,touring_poi,游览 POI,exhibition,L2_展厅_8家园厅_装饰,-13.14613,13.373477,-10.430546,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_4e0d3ab858,L2 电梯0001,L2,transport_circulation,交通与通行动线,elevator,L2_电梯0001,-100.345444,11.510569,9.748894,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_768d09579a,L2 电梯0002,L2,transport_circulation,交通与通行动线,elevator,L2_电梯0002,86.457626,11.510569,9.073389,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_9d3633cb8c,L2 电梯0003,L2,transport_circulation,交通与通行动线,elevator,L2_电梯0003,79.746368,11.510569,17.265091,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -222,17 +244,17 @@ modelpoi_L2_69b6036c36,L2 电梯0013,L2,transport_circulation,交通与通行动
modelpoi_L2_50d761d668,L2 电梯0014,L2,transport_circulation,交通与通行动线,elevator,L2_电梯0014,-89.315796,11.510569,36.826317,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_8144b8df38,L2 电梯0015,L2,transport_circulation,交通与通行动线,elevator,L2_电梯0015,-88.703072,11.510569,33.007458,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_580aca14fe,L2 电梯0016,L2,transport_circulation,交通与通行动线,elevator,L2_电梯0016,-99.683975,11.510569,13.032006,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_9040c9507a,L2 电梯017,L2,transport_circulation,交通与通行动线,elevator,L2_电梯017,60.687622,11.510571,19.346493,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_041990743f,L2 扶梯001,L2,transport_circulation,交通与通行动线,escalator,L2_扶梯001,94.99762,8.514649,36.362118,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_5b3ad4268d,L2 楼梯0001,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0001,49.78883,10.178167,-2.614235,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_579220538a,L2 楼梯0002,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0002,47.912979,10.178167,-3.191393,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_579220538a,L2 楼梯0002,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0002,48.342949,10.178167,-2.291168,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_e8eb126078,L2 楼梯0003,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0003,95.642593,10.178164,58.023407,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_aacd33c979,L2 楼梯0004,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0004,89.312012,10.178167,1.252304,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_75beeb2694,L2 楼梯0005,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0005,87.619148,10.178167,-5.131519,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_dfc31aec44,L2 楼梯0006,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0006,47.859646,10.178166,3.881408,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_aacd33c979,L2 楼梯0004,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0004,89.507751,10.178167,1.233227,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_75beeb2694,L2 楼梯0005,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0005,87.892075,10.178167,-4.699806,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_dfc31aec44,L2 楼梯0006,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0006,47.717403,10.178167,3.410032,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_67c8408dca,L2 楼梯0007,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0007,41.546097,10.178164,69.148041,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_fbfebb3318,L2 楼梯0008,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0008,49.141712,10.178164,57.450394,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_600395b893,L2 楼梯0009,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0009,0.464776,10.178164,52.972031,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_220658455e,L2 楼梯0010,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0010,-4.680887,10.178166,10.44739,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_220658455e,L2 楼梯0010,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0010,-3.329174,10.178166,9.639655,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_2493f07479,L2 楼梯0011,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0011,-124.356628,10.178165,45.499649,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_f55d36b16e,L2 楼梯0012,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0012,-120.651779,10.178165,30.800243,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_8f3d7a0d43,L2 楼梯0013,L2,transport_circulation,交通与通行动线,stair,L2_楼梯0013,-111.083786,10.178166,18.195475,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
@@ -246,7 +268,6 @@ modelpoi_L2_50f2c5fe7f,L2 楼梯0020,L2,transport_circulation,交通与通行动
poi_navpoi_0016,L3 无障碍卫生间,L3,accessibility_special_service,无障碍与特殊人群服务,accessibility,L3_无障碍卫生间,-88.936966,16.489281,42.595558,nav_data.navAnchors.policy_approved_machine_verified_nav_layer,nav_anchor_available
modelpoi_L3_73737c95dc,L3 男卫生间,L3,basic_service_facility,基础服务设施,restroom,L3_男卫生间,-83.324158,16.540436,43.138031,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L3_7ead513df1,L3 女卫生间,L3,basic_service_facility,基础服务设施,restroom,L3_女卫生间,-91.718369,16.540436,37.972088,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
supplemental_919d93c114,楼顶绿化,L3,operation_experience,运营体验类点位,landscape,楼顶绿化,6.860313,16.841034,-5.471432,model_object_bbox_center_candidate,display_candidate_requires_access_or_nav_anchor_confirmation
modelpoi_L3_293d59fa33,L3 电梯0001,L3,transport_circulation,交通与通行动线,elevator,L3_电梯0001,-100.076187,17.991472,12.459318,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L3_e311f0daf4,L3 电梯0002,L3,transport_circulation,交通与通行动线,elevator,L3_电梯0002,-100.57962,17.991472,9.362567,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
modelpoi_L3_4f70d09801,L3 电梯0003,L3,transport_circulation,交通与通行动线,elevator,L3_电梯0003,-81.503433,17.991472,30.988474,model_object_bbox_center_candidate,display_candidate_requires_nav_anchor_for_routing
1 id name floorId primaryCategory primaryCategoryZh iconType sourceObjectName positionGltfX positionGltfY positionGltfZ coordinateSource navigationReadiness
2 modelpoi_L-2_492e987660 L-2 母婴室 L-2 accessibility_special_service 无障碍与特殊人群服务 nursery L-2_母婴室 -51.175003 -14.191206 -13.147993 39.344395 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
3 modelpoi_L-2_433ee81108 L-2 男卫生间01 L-2 basic_service_facility 基础服务设施 restroom L-2_男卫生间01 -82.988602 -14.491209 -13.447996 43.190712 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
4 modelpoi_L-2_673c254e4d L-2 男卫生间02 L-2 basic_service_facility 基础服务设施 restroom L-2_男卫生间02 -18.808712 -14.491209 -13.447996 19.713522 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
5 modelpoi_L-2_1468d92dfd L-2 男卫生间04 L-2 basic_service_facility 基础服务设施 restroom L-2_男卫生间04 57.642273 -14.491209 -13.447996 24.258451 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
6 modelpoi_L-2_a38a8c488e L-2 女卫生间01 L-2 basic_service_facility 基础服务设施 restroom L-2_女卫生间01 -91.456207 -14.491209 -13.447996 38.036762 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
7 modelpoi_L-2_b94325224a L-2 女卫生间02 L-2 basic_service_facility 基础服务设施 restroom L-2_女卫生间02 -30.663593 -14.491209 -13.447996 14.251428 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
8 modelpoi_L-2_e2cac3d857 L-2 女卫生间03 L-2 basic_service_facility 基础服务设施 restroom L-2_女卫生间03 16.534239 -14.491209 -13.447996 25.273596 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
9 modelpoi_L-2_d36fe2dc9d L-2 女卫生间03.001 L-2 basic_service_facility 基础服务设施 restroom L-2_女卫生间03.001 32.573727 -14.491209 -13.447996 24.407684 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
10 modelpoi_L-2_c0855378b9 L-2 女卫生间04 L-2 basic_service_facility 基础服务设施 restroom L-2_女卫生间04 68.159348 -14.491209 -13.447996 27.444523 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
11 poi_navpoi_0009 L-2 展厅1宇宙厅 L-2 touring_poi 游览 POI exhibition L-2_展厅1宇宙厅 -90.488953 -14.388401 44.977547 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
12 modelpoi_L-2_1fa3680520 L-2 展厅1宇宙厅 展柜 L-2 touring_poi 游览 POI exhibition L-2_展厅1宇宙厅_展柜 -87.730865 -13.891212 54.098366 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
13 modelpoi_L-2_0328e49a57 L-2 展厅1宇宙厅 装饰 L-2 touring_poi 游览 POI exhibition L-2_展厅1宇宙厅_装饰 -90.488953 -11.498024 44.977547 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
14 poi_navpoi_0010 L-2 展厅2地球厅 L-2 touring_poi 游览 POI exhibition L-2_展厅2地球厅 -17.07975 -14.388401 -8.416769 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
15 modelpoi_L-2_e2ec8ce8ba L-2 展厅2地球厅 展柜 L-2 touring_poi 游览 POI exhibition L-2_展厅2地球厅_展柜 -17.069817 -13.827784 -8.752005 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
16 modelpoi_L-2_f23816be84 L-2 展厅2地球厅 装饰 L-2 touring_poi 游览 POI exhibition L-2_展厅2地球厅_装饰 -17.07975 -11.498024 -8.416769 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
17 poi_navpoi_0008 L-2 展厅3演化厅 L-2 touring_poi 游览 POI exhibition L-2_展厅3演化厅 25.952524 -14.388403 51.155842 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
18 modelpoi_L-2_34bbb3d9d4 L-2 展厅3演化厅 展柜 L-2 touring_poi 游览 POI exhibition L-2_展厅3演化厅_展柜 25.310183 -13.89121 51.903332 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
19 modelpoi_L-2_a2d90df88c L-2 展厅3演化厅 装饰 L-2 touring_poi 游览 POI exhibition L-2_展厅3演化厅_装饰 25.952511 -11.48424 51.155872 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
20 poi_navpoi_0007 L-2 展厅4恐龙厅 L-2 touring_poi 游览 POI exhibition L-2_展厅4恐龙厅 69.308327 -14.388403 -0.631475 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
21 modelpoi_L-2_f877db497b L-2 展厅4恐龙厅 展柜 L-2 touring_poi 游览 POI exhibition L-2_展厅4恐龙厅_展柜 69.237717 -13.987548 -0.634724 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
22 modelpoi_L-2_81c1403384 L-2 展厅4恐龙厅 装饰 L-2 touring_poi 游览 POI exhibition L-2_展厅4恐龙厅_装饰 70.205048 -7.689972 2.088411 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
23 modelpoi_L-2_ae5be493c0 L-2 电梯0001 L-2 transport_circulation 交通与通行动线 elevator L-2_电梯0001 34.112198 -13.127687 77.432434 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
24 modelpoi_L-2_e628190832 L-2 电梯0002 L-2 transport_circulation 交通与通行动线 elevator L-2_电梯0002 48.350098 -12.874514 67.133812 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
25 modelpoi_L-2_a1322a6c4d L-2 电梯0003 L-2 transport_circulation 交通与通行动线 elevator L-2_电梯0003 90.601959 -12.863037 49.503075 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
40 modelpoi_L-2_0d88e71c27 L-2 电梯0018 L-2 transport_circulation 交通与通行动线 elevator L-2_电梯0018 -99.716293 -12.873795 12.790838 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
41 modelpoi_L-2_ca23f27f00 L-2 电梯0019 L-2 transport_circulation 交通与通行动线 elevator L-2_电梯0019 -100.377762 -12.873795 9.507727 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
42 modelpoi_L-2_73874acb68 L-2 扶梯 L-2 transport_circulation 交通与通行动线 escalator L-2_扶梯 67.947716 -12.484815 42.180843 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
43 modelpoi_L-2_77bdede69c L-2 楼梯0001 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0001 -113.980553 -14.191214 -13.148001 15.791812 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
44 modelpoi_L-2_d6275be404 L-2 楼梯0002 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0002 -125.09758 -14.191216 -13.148003 44.947601 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
45 modelpoi_L-2_d9df5eab1e L-2 楼梯0003 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0003 -105.471481 -14.19121 -13.147997 -80.607361 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
46 modelpoi_L-2_3dd779ffc4 L-2 楼梯0004 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0004 -119.36657 -14.19121 -13.147997 -77.92852 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
47 modelpoi_L-2_bcfbe38b8c L-2 楼梯0005 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0005 -118.673454 -14.191213 -13.148 -19.434433 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
48 modelpoi_L-2_f5a71cd735 L-2 楼梯0006 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0006 -96.47963 -14.191214 -13.148001 1.494661 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
49 modelpoi_L-2_acacdf7cd3 L-2 楼梯0007 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0007 -34.926815 -14.191212 -13.147999 -27.636536 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
50 modelpoi_L-2_706e6e65ea L-2 楼梯0008 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0008 -54.706528 -14.191216 -13.148003 59.089958 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
51 modelpoi_L-2_586f1dcb89 L-2 楼梯0009 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0009 -62.075691 -14.191199 -13.147986 69.846909 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
52 modelpoi_L-2_5e6d33b390 L-2 楼梯0010 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0010 -78.359177 -14.191216 -13.148004 79.284683 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
53 modelpoi_L-2_a158651e42 L-2 楼梯0011 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0011 -51.635437 -14.191216 -13.148003 48.365948 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
54 modelpoi_L-2_4d987dbec1 L-2 楼梯0012 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0012 -2.737168 -14.191216 -13.148003 53.378433 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
55 modelpoi_L-2_ff21400c01 L-2 楼梯0013 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0013 91.222206 -14.191216 -13.148003 58.967903 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
56 modelpoi_L-2_990fd35b22 L-2 楼梯0014 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0014 93.295212 -14.191216 -13.148003 42.003674 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
57 modelpoi_L-2_49592f09b2 L-2 楼梯0015 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0015 94.548233 -14.191213 -13.148 -5.112744 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
58 modelpoi_L-2_a9c1ecac07 L-2 楼梯0016 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0016 46.435764 -14.191214 -13.148001 -3.948162 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
59 modelpoi_L-2_7a4fb7e3e7 L-2 楼梯0017 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0017 45.298622 -14.191214 -13.148001 4.789413 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
60 modelpoi_L-2_5250437db8 L-2 楼梯0018 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0018 53.007278 -14.191216 -13.148003 58.379272 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
61 modelpoi_L-2_84885548c6 modelpoi_L-2_482544cba6 L-2 停车位 L-2 楼梯0019 L-2 transport_circulation 交通与通行动线 parking stair L-2_停车位 L-2_楼梯0019 -13.833179 -91.555466 -14.191204 -11.787357 10.672264 46.893166 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
62 modelpoi_L-2_5753e93667 L-2 楼梯0020 L-2 transport_circulation 交通与通行动线 stair L-2_楼梯0020 -77.065353 -11.787357 46.893166 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
63 modelpoi_L-2_84885548c6 L-2 停车位 L-2 transport_circulation 交通与通行动线 parking L-2_停车位 -13.833179 -14.391253 10.672264 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
64 modelpoi_L-1_14ec89b181 L-1 球幕影院 L-1 touring_poi 游览 POI theater L-1_球幕影院 0.941269 -10.898361 -4.725914 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
65 modelpoi_L-1_e98e1e7579 L-1 电梯0001 L-1 transport_circulation 交通与通行动线 elevator L-1_电梯0001 -99.961014 -9.296165 9.723492 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
66 modelpoi_L-1_31bfe24f01 L-1 电梯0002 L-1 transport_circulation 交通与通行动线 elevator L-1_电梯0002 87.788162 -9.28541 49.793114 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
106 modelpoi_L-1_c2152945b5 L-1 楼梯0022 L-1 transport_circulation 交通与通行动线 stair L-1_楼梯0022 -118.173111 -10.669845 -18.677877 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
107 modelpoi_L-1_d10fc5993f L-1 楼梯0023 L-1 transport_circulation 交通与通行动线 stair L-1_楼梯0023 -105.15239 -10.669839 -79.589508 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
108 modelpoi_L-1_7639982b98 L-1 楼梯0024 L-1 transport_circulation 交通与通行动线 stair L-1_楼梯0024 -119.786385 -10.669839 -77.311356 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
109 modelpoi_L-1_04e400880b L-1 楼梯0025 L-1 transport_circulation 交通与通行动线 stair L-1_楼梯0025 -13.88942 -10.669846 -5.084072 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
110 modelpoi_L-1_e3aff063cb L-1 停车场地面 L-1 transport_circulation 交通与通行动线 parking L-1_停车场地面 85.808472 -10.834019 67.684715 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
111 modelpoi_L1_19555b8890 L1 轮椅及儿童车租赁 L1 accessibility_special_service 无障碍与特殊人群服务 rental L1_轮椅及儿童车租赁 -65.994453 0.058651 15.326918 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
112 modelpoi_L1_55e995bb4d L1 母婴间 L1 accessibility_special_service 无障碍与特殊人群服务 nursery L1_母婴间 -95.211792 0.058651 26.434822 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
122 modelpoi_L1_8045e85848 L1 女卫生间 L1 basic_service_facility 基础服务设施 restroom L1_女卫生间 -70.903793 0.258651 24.592087 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
123 modelpoi_L1_170ebd7038 L1 女卫生间01 L1 basic_service_facility 基础服务设施 restroom L1_女卫生间01 131.002686 0.25865 38.265602 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
124 modelpoi_L1_90b628a1d5 L1 女卫生间02 L1 basic_service_facility 基础服务设施 restroom L1_女卫生间02 49.345047 0.258652 11.62169 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
125 modelpoi_L1_11ae2666ee L1 售票机 L1 basic_service_facility 基础服务设施 ticket L1_售票机 17.294315 1 24.678955 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
126 modelpoi_L1_f41223bb9c L1 贵宾接待区 L1 operation_experience 运营体验类点位 vip L1_贵宾接待区 -77.729813 0.058651 19.560249 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
127 supplemental_b23c543281 L1 室外绿化 L1 operation_experience 运营体验类点位 landscape L1_室外绿化 3.996948 4.52948 0.172545 -0.012264 -0.231293 model_object_bbox_center_candidate display_candidate_requires_access_or_nav_anchor_confirmation
128 supplemental_306932bd08 L1 室外水景 L1 operation_experience 运营体验类点位 photo L1_室外水景 22.258747 23.06905 -0.488044 0.274697 -0.367207 -0.831573 model_object_bbox_center_candidate display_candidate_requires_access_or_nav_anchor_confirmation
129 supplemental_cc67428117 L1 室外下沉广场 L1 operation_experience 运营体验类点位 plaza L1_室外下沉广场 31.983009 32.247353 -2.810548 -12.300758 model_object_bbox_center_candidate display_candidate_requires_access_or_nav_anchor_confirmation
130 modelpoi_L1_350cd0e084 L1 动感多维影院 L1 touring_poi 游览 POI theater L1_动感多维影院 37.22998 0.058651 45.027328 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
131 modelpoi_L1_9ba9a658bb L1 巨幕影院 L1 touring_poi 游览 POI theater L1_巨幕影院 16.42691 0.058651 45.047546 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
132 poi_navpoi_0003 L1 临展厅01 L1 touring_poi 游览 POI exhibition L1_临展厅01 -78.678642 0 -30.900698 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
134 modelpoi_L1_d2b5d8b621 L1 球幕影院 L1 touring_poi 游览 POI theater L1_球幕影院 1.775749 3.377288 -5.777876 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
135 poi_navpoi_0002 L1 展厅5人类厅 L1 touring_poi 游览 POI exhibition L1_展厅5人类厅 112.822556 -0.000004 51.974705 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
136 modelpoi_L1_4e1111c7b1 L1 自然剧场 L1 touring_poi 游览 POI theater L1_自然剧场 24.2363 0.05865 65.833115 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
137 modelpoi_L1_bce5578bda L1 L1 展厅5人类厅 装饰01 L1 touring_poi 游览 POI exhibition L1_L1_展厅5人类厅_装饰01 112.835953 2.864931 51.190968 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
138 modelpoi_L1_d6bfac9efe L1 L1 展厅5人类厅 装饰02 L1 touring_poi 游览 POI exhibition L1_L1_展厅5人类厅_装饰02 112.655197 3.820072 51.249493 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
139 modelpoi_L1_45de13b368 L1 电梯0001 L1 transport_circulation 交通与通行动线 elevator L1_电梯0001 -100.345444 1.526052 9.748894 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
140 modelpoi_L1_aae15a9bf4 L1 电梯0002 L1 transport_circulation 交通与通行动线 elevator L1_电梯0002 86.457626 1.526052 9.073389 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
141 modelpoi_L1_874fe33d28 L1 电梯0003 L1 transport_circulation 交通与通行动线 elevator L1_电梯0003 79.746368 1.526052 17.265091 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
159 modelpoi_L1_5338a76c2c L1 电梯0021 L1 transport_circulation 交通与通行动线 elevator L1_电梯0021 -99.683975 1.526052 13.032006 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
160 modelpoi_L1_b3347e28c9 L1 扶梯 L1 transport_circulation 交通与通行动线 escalator L1_扶梯 81.070969 -0.552914 36.499767 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
161 modelpoi_L1_84fb77260b L1 楼梯0001 L1 transport_circulation 交通与通行动线 stair L1_楼梯0001 -113.303513 0.217286 15.44129 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
modelpoi_L1_a4a00c978d L1 楼梯0002 L1 transport_circulation 交通与通行动线 stair L1_楼梯0002 -118.638206 0.217286 -19.517469 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
162 modelpoi_L1_360cce5a19 L1 楼梯0003 L1 transport_circulation 交通与通行动线 stair L1_楼梯0003 -34.709263 0.300862 -27.007214 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
163 modelpoi_L1_12b7990225 L1 楼梯0004 L1 transport_circulation 交通与通行动线 stair L1_楼梯0004 -51.784405 0.300859 43.113773 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
164 modelpoi_L1_87efe86522 L1 楼梯0005 L1 transport_circulation 交通与通行动线 stair L1_楼梯0005 90.36853 0.296874 -5.492186 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
182 modelpoi_L1_2ce36ed339 L1 楼梯0023 L1 transport_circulation 交通与通行动线 stair L1_楼梯0023 -123.082703 0.217286 29.087791 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
183 modelpoi_L1_9461bfead0 L1 楼梯0024 L1 transport_circulation 交通与通行动线 stair L1_楼梯0024 -125.829529 0.217285 45.41563 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
184 modelpoi_L1_8a9434da15 L1 楼梯0025 L1 transport_circulation 交通与通行动线 stair L1_楼梯0025 -73.533424 0.25 63.954227 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
185 modelpoi_L1_9a31638f63 modelpoi_L1_5655c264c1 L1 楼梯0026 L1 室外楼梯0001 L1 transport_circulation 交通与通行动线 stair L1_楼梯0026 L1_室外楼梯0001 -127.951675 -104.784119 0.217286 -2.199766 -81.176064 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
186 modelpoi_L1_fa423c9ad0 modelpoi_L1_6fa8f94e0d L1 楼梯0027 L1 室外楼梯0002 L1 transport_circulation 交通与通行动线 stair L1_楼梯0027 L1_室外楼梯0002 -104.784119 -119.274986 0.217286 0 -81.176064 -78.993362 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
187 modelpoi_L1_7d0051d2a6 modelpoi_L1_9d38633ca9 L1 楼梯0028 L1 室外楼梯0003 L1 transport_circulation 交通与通行动线 stair L1_楼梯0028 L1_室外楼梯0003 -119.274986 -118.638206 0 0.217286 -78.993362 -19.517469 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
188 modelpoi_L1_3936c7e2b1 L1 室外楼梯0004 L1 transport_circulation 交通与通行动线 stair L1_室外楼梯0004 -127.951675 0.217286 -2.199766 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
189 modelpoi_L1_a6652685b8 L1 停车场 L1 transport_circulation 交通与通行动线 parking L1_停车场 -126.124298 0 -16.088915 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
190 modelpoi_L1_9611467f0f L1 停车场入口 L1 transport_circulation 交通与通行动线 parking L1_停车场入口 -117.349075 -2.64097 -76.993629 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
191 modelpoi_L1_ce023b99e4 L1 停车场入口02 L1 transport_circulation 交通与通行动线 parking L1_停车场入口02 72.57579 -4.072168 72.416092 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
216 modelpoi_L2_2d14073a06 L2 男卫生间002 L2 basic_service_facility 基础服务设施 restroom L2_男卫生间002 8.952654 10.273865 -1.457422 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
217 modelpoi_L2_4470473302 L2 女卫生间001 L2 basic_service_facility 基础服务设施 restroom L2_女卫生间001 -92.132439 10.558371 37.83683 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
218 modelpoi_L2_e9fc021625 L2 女卫生间002 L2 basic_service_facility 基础服务设施 restroom L2_女卫生间002 4.273729 10.273865 4.899143 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
219 modelpoi_L2_9267c2d1d4 L2 卫生间 L2 basic_service_facility 基础服务设施 restroom L2_卫生间 52.255562 10.273865 9.283119 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
220 modelpoi_L2_f362d56eba L2 文创店旗舰店 L2 basic_service_facility 基础服务设施 shop L2_文创店旗舰店 -70.947243 10.178164 38.432304 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
221 poi_navpoi_0006 L2 展厅 6生物厅 L2 touring_poi 游览 POI exhibition L2_展厅_6生物厅 69.074303 10.178165 1.496778 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
222 modelpoi_L2_ecd476d1be L2 展厅 6生物厅 展柜01 L2 touring_poi 游览 POI exhibition L2_展厅_6生物厅_展柜01 69.279694 10.281687 5.825405 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
223 modelpoi_L2_d93b7e7a22 L2 展厅 6生物厅 展柜02 L2 touring_poi 游览 POI exhibition L2_展厅_6生物厅_展柜02 69.861053 10.594574 5.292932 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
224 modelpoi_L2_bf6262807a L2 展厅 6生物厅 装饰 L2 touring_poi 游览 POI exhibition L2_展厅_6生物厅_装饰 69.074303 13.479435 1.496778 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
225 poi_navpoi_0005 L2 展厅 7生态厅 L2 touring_poi 游览 POI exhibition L2_展厅_7生态厅 24.894789 10.178165 53.795837 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
226 modelpoi_L2_2fea6b6cff L2 展厅 7生态厅 展柜 L2 touring_poi 游览 POI exhibition L2_展厅_7生态厅_展柜 25.018467 10.511989 53.729153 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
227 modelpoi_L2_91de093d1e L2 展厅 7生态厅 装饰 L2 touring_poi 游览 POI exhibition L2_展厅_7生态厅_装饰 24.894787 13.408146 53.795837 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
228 poi_navpoi_0004 L2 展厅 8家园厅 L2 touring_poi 游览 POI exhibition L2_展厅_8家园厅 -13.14613 10.178164 -10.430546 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
229 modelpoi_L2_8b43a8a2a8 L2 展厅 8家园厅 展柜 L2 touring_poi 游览 POI exhibition L2_展厅_8家园厅_展柜 -12.998978 10.478165 -10.578304 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
230 modelpoi_L2_83406e72e2 L2 展厅 8家园厅 装饰 L2 touring_poi 游览 POI exhibition L2_展厅_8家园厅_装饰 -13.14613 13.373477 -10.430546 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
231 modelpoi_L2_4e0d3ab858 L2 电梯0001 L2 transport_circulation 交通与通行动线 elevator L2_电梯0001 -100.345444 11.510569 9.748894 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
232 modelpoi_L2_768d09579a L2 电梯0002 L2 transport_circulation 交通与通行动线 elevator L2_电梯0002 86.457626 11.510569 9.073389 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
233 modelpoi_L2_9d3633cb8c L2 电梯0003 L2 transport_circulation 交通与通行动线 elevator L2_电梯0003 79.746368 11.510569 17.265091 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
244 modelpoi_L2_50d761d668 L2 电梯0014 L2 transport_circulation 交通与通行动线 elevator L2_电梯0014 -89.315796 11.510569 36.826317 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
245 modelpoi_L2_8144b8df38 L2 电梯0015 L2 transport_circulation 交通与通行动线 elevator L2_电梯0015 -88.703072 11.510569 33.007458 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
246 modelpoi_L2_580aca14fe L2 电梯0016 L2 transport_circulation 交通与通行动线 elevator L2_电梯0016 -99.683975 11.510569 13.032006 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
247 modelpoi_L2_9040c9507a L2 电梯017 L2 transport_circulation 交通与通行动线 elevator L2_电梯017 60.687622 11.510571 19.346493 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
248 modelpoi_L2_041990743f L2 扶梯001 L2 transport_circulation 交通与通行动线 escalator L2_扶梯001 94.99762 8.514649 36.362118 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
249 modelpoi_L2_5b3ad4268d modelpoi_L2_579220538a L2 楼梯0001 L2 楼梯0002 L2 transport_circulation 交通与通行动线 stair L2_楼梯0001 L2_楼梯0002 49.78883 48.342949 10.178167 -2.614235 -2.291168 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
modelpoi_L2_579220538a L2 楼梯0002 L2 transport_circulation 交通与通行动线 stair L2_楼梯0002 47.912979 10.178167 -3.191393 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
250 modelpoi_L2_e8eb126078 L2 楼梯0003 L2 transport_circulation 交通与通行动线 stair L2_楼梯0003 95.642593 10.178164 58.023407 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
251 modelpoi_L2_aacd33c979 L2 楼梯0004 L2 transport_circulation 交通与通行动线 stair L2_楼梯0004 89.312012 89.507751 10.178167 1.252304 1.233227 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
252 modelpoi_L2_75beeb2694 L2 楼梯0005 L2 transport_circulation 交通与通行动线 stair L2_楼梯0005 87.619148 87.892075 10.178167 -5.131519 -4.699806 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
253 modelpoi_L2_dfc31aec44 L2 楼梯0006 L2 transport_circulation 交通与通行动线 stair L2_楼梯0006 47.859646 47.717403 10.178166 10.178167 3.881408 3.410032 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
254 modelpoi_L2_67c8408dca L2 楼梯0007 L2 transport_circulation 交通与通行动线 stair L2_楼梯0007 41.546097 10.178164 69.148041 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
255 modelpoi_L2_fbfebb3318 L2 楼梯0008 L2 transport_circulation 交通与通行动线 stair L2_楼梯0008 49.141712 10.178164 57.450394 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
256 modelpoi_L2_600395b893 L2 楼梯0009 L2 transport_circulation 交通与通行动线 stair L2_楼梯0009 0.464776 10.178164 52.972031 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
257 modelpoi_L2_220658455e L2 楼梯0010 L2 transport_circulation 交通与通行动线 stair L2_楼梯0010 -4.680887 -3.329174 10.178166 10.44739 9.639655 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
258 modelpoi_L2_2493f07479 L2 楼梯0011 L2 transport_circulation 交通与通行动线 stair L2_楼梯0011 -124.356628 10.178165 45.499649 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
259 modelpoi_L2_f55d36b16e L2 楼梯0012 L2 transport_circulation 交通与通行动线 stair L2_楼梯0012 -120.651779 10.178165 30.800243 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
260 modelpoi_L2_8f3d7a0d43 L2 楼梯0013 L2 transport_circulation 交通与通行动线 stair L2_楼梯0013 -111.083786 10.178166 18.195475 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
268 poi_navpoi_0016 L3 无障碍卫生间 L3 accessibility_special_service 无障碍与特殊人群服务 accessibility L3_无障碍卫生间 -88.936966 16.489281 42.595558 nav_data.navAnchors.policy_approved_machine_verified_nav_layer nav_anchor_available
269 modelpoi_L3_73737c95dc L3 男卫生间 L3 basic_service_facility 基础服务设施 restroom L3_男卫生间 -83.324158 16.540436 43.138031 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
270 modelpoi_L3_7ead513df1 L3 女卫生间 L3 basic_service_facility 基础服务设施 restroom L3_女卫生间 -91.718369 16.540436 37.972088 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
supplemental_919d93c114 楼顶绿化 L3 operation_experience 运营体验类点位 landscape 楼顶绿化 6.860313 16.841034 -5.471432 model_object_bbox_center_candidate display_candidate_requires_access_or_nav_anchor_confirmation
271 modelpoi_L3_293d59fa33 L3 电梯0001 L3 transport_circulation 交通与通行动线 elevator L3_电梯0001 -100.076187 17.991472 12.459318 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
272 modelpoi_L3_e311f0daf4 L3 电梯0002 L3 transport_circulation 交通与通行动线 elevator L3_电梯0002 -100.57962 17.991472 9.362567 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing
273 modelpoi_L3_4f70d09801 L3 电梯0003 L3 transport_circulation 交通与通行动线 elevator L3_电梯0003 -81.503433 17.991472 30.988474 model_object_bbox_center_candidate display_candidate_requires_nav_anchor_for_routing

View File

@@ -1,12 +1,12 @@
{
"schemaVersion": "miniapp-floor-poi-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.446Z",
"generatedAt": "2026-06-11T09:36:23.694Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"floorId": "L-1",
"poiCount": 46,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"poiCount": 47,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"pois": [
{
"id": "modelpoi_L-1_14ec89b181",
@@ -2753,6 +2753,67 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L-1_04e400880b",
"name": "L-1 楼梯0025",
"sourceObjectName": "L-1_楼梯0025",
"floorId": "L-1",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
"categories": [
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"subcategory": "stair",
"iconType": "stair",
"reason": "matched_stair_keywords"
}
],
"iconType": "stair",
"positionBlender": [
-13.88942,
5.084072,
-10.669846
],
"positionGltf": [
-13.88942,
-10.669846,
-5.084072
],
"bboxBlender": {
"min": [
-15.016052,
0.703743,
-10.670072
],
"max": [
-12.762787,
9.464401,
-10.66962
],
"center": [
-13.88942,
5.084072,
-10.669846
],
"size": [
2.253265,
8.760658,
0.000452
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L-1_e3aff063cb",
"name": "L-1 停车场地面",

View File

@@ -1,12 +1,12 @@
{
"schemaVersion": "miniapp-floor-poi-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.449Z",
"generatedAt": "2026-06-11T09:36:23.698Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"floorId": "L1.5",
"poiCount": 21,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"pois": [
{
"id": "poi_navpoi_0012",

View File

@@ -1,12 +1,12 @@
{
"schemaVersion": "miniapp-floor-poi-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.447Z",
"generatedAt": "2026-06-11T09:36:23.696Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"floorId": "L1",
"poiCount": 78,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"poiCount": 81,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"pois": [
{
"id": "modelpoi_L1_19555b8890",
@@ -854,6 +854,67 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_11ae2666ee",
"name": "L1 售票机",
"sourceObjectName": "L1_售票机",
"floorId": "L1",
"primaryCategory": "basic_service_facility",
"primaryCategoryZh": "基础服务设施",
"categories": [
{
"topCategory": "basic_service_facility",
"topCategoryZh": "基础服务设施",
"subcategory": "ticket_check",
"iconType": "ticket",
"reason": "matched_ticket_keywords"
}
],
"iconType": "ticket",
"positionBlender": [
17.294315,
-24.678955,
1
],
"positionGltf": [
17.294315,
1,
24.678955
],
"bboxBlender": {
"min": [
16.932575,
-25.224066,
0
],
"max": [
17.656055,
-24.133844,
2
],
"center": [
17.294315,
-24.678955,
1
],
"size": [
0.72348,
1.090221,
2
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_f41223bb9c",
"name": "L1 贵宾接待区",
@@ -933,34 +994,34 @@
],
"iconType": "landscape",
"positionBlender": [
3.996948,
0.012264,
4.52948,
0.231293,
0.172545
],
"positionGltf": [
3.996948,
4.52948,
0.172545,
-0.012264
-0.231293
],
"bboxBlender": {
"min": [
-139.051422,
-105.240479,
-139.421356,
-104.762138,
-0.077455
],
"max": [
147.045319,
105.265007,
148.480316,
105.224724,
0.422545
],
"center": [
3.996948,
0.012264,
4.52948,
0.231293,
0.172545
],
"size": [
286.096741,
210.505493,
287.901672,
209.986862,
0.5
]
},
@@ -968,7 +1029,7 @@
"navigationReadiness": "display_candidate_requires_access_or_nav_anchor_confirmation",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object_supplemental_clean_package",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"floorInferenceMethod": "strict_object_name_floor_prefix",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
@@ -994,42 +1055,42 @@
],
"iconType": "photo",
"positionBlender": [
22.258747,
0.367207,
-0.488044
23.06905,
0.831573,
0.274697
],
"positionGltf": [
22.258747,
-0.488044,
-0.367207
23.06905,
0.274697,
-0.831573
],
"bboxBlender": {
"min": [
-93.667229,
-90.865891,
-1.82078
-92.856926,
-90.40152,
-0.329199
],
"max": [
138.184723,
91.600304,
0.844692
138.995026,
92.064667,
0.878593
],
"center": [
22.258747,
0.367207,
-0.488044
23.06905,
0.831573,
0.274697
],
"size": [
231.851959,
182.466187,
2.665472
1.207792
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_access_or_nav_anchor_confirmation",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object_supplemental_clean_package",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"floorInferenceMethod": "strict_object_name_floor_prefix",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
@@ -1062,12 +1123,12 @@
],
"iconType": "plaza",
"positionBlender": [
31.983009,
32.247353,
12.300758,
-2.810548
],
"positionGltf": [
31.983009,
32.247353,
-2.810548,
-12.300758
],
@@ -1078,17 +1139,17 @@
-6.257907
],
"max": [
49.637825,
50.166512,
37.382774,
0.63681
],
"center": [
31.983009,
32.247353,
12.300758,
-2.810548
],
"size": [
35.309631,
35.838318,
50.164032,
6.894717
]
@@ -1097,7 +1158,7 @@
"navigationReadiness": "display_candidate_requires_access_or_nav_anchor_confirmation",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object_supplemental_clean_package",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"floorInferenceMethod": "strict_object_name_floor_prefix",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
@@ -1457,6 +1518,128 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_bce5578bda",
"name": "L1 L1 展厅5人类厅 装饰01",
"sourceObjectName": "L1_L1_展厅5人类厅_装饰01",
"floorId": "L1",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
112.835953,
-51.190968,
2.864931
],
"positionGltf": [
112.835953,
2.864931,
51.190968
],
"bboxBlender": {
"min": [
84.834236,
-79.192871,
0.034751
],
"max": [
140.837662,
-23.189064,
5.695111
],
"center": [
112.835953,
-51.190968,
2.864931
],
"size": [
56.003426,
56.003807,
5.66036
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_d6bfac9efe",
"name": "L1 L1 展厅5人类厅 装饰02",
"sourceObjectName": "L1_L1_展厅5人类厅_装饰02",
"floorId": "L1",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
112.655197,
-51.249493,
3.820072
],
"positionGltf": [
112.655197,
3.820072,
51.249493
],
"bboxBlender": {
"min": [
108.68396,
-55.220016,
0.032804
],
"max": [
116.626434,
-47.278969,
7.607341
],
"center": [
112.655197,
-51.249493,
3.820072
],
"size": [
7.942474,
7.941048,
7.574537
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_45de13b368",
"name": "L1 电梯0001",
@@ -2860,67 +3043,6 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_a4a00c978d",
"name": "L1 楼梯0002",
"sourceObjectName": "L1_楼梯0002",
"floorId": "L1",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
"categories": [
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"subcategory": "stair",
"iconType": "stair",
"reason": "matched_stair_keywords"
}
],
"iconType": "stair",
"positionBlender": [
-118.638206,
19.517469,
0.217286
],
"positionGltf": [
-118.638206,
0.217286,
-19.517469
],
"bboxBlender": {
"min": [
-123.097366,
17.564606,
0.217286
],
"max": [
-114.179047,
21.470333,
0.217286
],
"center": [
-118.638206,
19.517469,
0.217286
],
"size": [
8.91832,
3.905727,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_360cce5a19",
"name": "L1 楼梯0003",
@@ -4325,70 +4447,9 @@
]
},
{
"id": "modelpoi_L1_9a31638f63",
"name": "L1 楼梯0026",
"sourceObjectName": "L1_楼梯0026",
"floorId": "L1",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
"categories": [
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"subcategory": "stair",
"iconType": "stair",
"reason": "matched_stair_keywords"
}
],
"iconType": "stair",
"positionBlender": [
-127.951675,
2.199766,
0.217286
],
"positionGltf": [
-127.951675,
0.217286,
-2.199766
],
"bboxBlender": {
"min": [
-129.983459,
-1.394757,
0.217286
],
"max": [
-125.919891,
5.794289,
0.217286
],
"center": [
-127.951675,
2.199766,
0.217286
],
"size": [
4.063568,
7.189046,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_fa423c9ad0",
"name": "L1 楼梯0027",
"sourceObjectName": "L1_楼梯0027",
"id": "modelpoi_L1_5655c264c1",
"name": "L1 室外楼梯0001",
"sourceObjectName": "L1_室外楼梯0001",
"floorId": "L1",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
@@ -4447,9 +4508,9 @@
]
},
{
"id": "modelpoi_L1_7d0051d2a6",
"name": "L1 楼梯0028",
"sourceObjectName": "L1_楼梯0028",
"id": "modelpoi_L1_6fa8f94e0d",
"name": "L1 室外楼梯0002",
"sourceObjectName": "L1_室外楼梯0002",
"floorId": "L1",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
@@ -4507,6 +4568,128 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_9d38633ca9",
"name": "L1 室外楼梯0003",
"sourceObjectName": "L1_室外楼梯0003",
"floorId": "L1",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
"categories": [
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"subcategory": "stair",
"iconType": "stair",
"reason": "matched_stair_keywords"
}
],
"iconType": "stair",
"positionBlender": [
-118.638206,
19.517469,
0.217286
],
"positionGltf": [
-118.638206,
0.217286,
-19.517469
],
"bboxBlender": {
"min": [
-123.097366,
17.564606,
0.217286
],
"max": [
-114.179047,
21.470333,
0.217286
],
"center": [
-118.638206,
19.517469,
0.217286
],
"size": [
8.91832,
3.905727,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_3936c7e2b1",
"name": "L1 室外楼梯0004",
"sourceObjectName": "L1_室外楼梯0004",
"floorId": "L1",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
"categories": [
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"subcategory": "stair",
"iconType": "stair",
"reason": "matched_stair_keywords"
}
],
"iconType": "stair",
"positionBlender": [
-127.951675,
2.199766,
0.217286
],
"positionGltf": [
-127.951675,
0.217286,
-2.199766
],
"bboxBlender": {
"min": [
-129.983459,
-1.394757,
0.217286
],
"max": [
-125.919891,
5.794289,
0.217286
],
"center": [
-127.951675,
2.199766,
0.217286
],
"size": [
4.063568,
7.189046,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L1_a6652685b8",
"name": "L1 停车场",

View File

@@ -1,12 +1,12 @@
{
"schemaVersion": "miniapp-floor-poi-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.450Z",
"generatedAt": "2026-06-11T09:36:23.699Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"floorId": "L2",
"poiCount": 47,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"poiCount": 55,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"pois": [
{
"id": "poi_navpoi_0015",
@@ -356,6 +356,67 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_9267c2d1d4",
"name": "L2 卫生间",
"sourceObjectName": "L2_卫生间",
"floorId": "L2",
"primaryCategory": "basic_service_facility",
"primaryCategoryZh": "基础服务设施",
"categories": [
{
"topCategory": "basic_service_facility",
"topCategoryZh": "基础服务设施",
"subcategory": "restroom",
"iconType": "restroom",
"reason": "matched_restroom_keywords"
}
],
"iconType": "restroom",
"positionBlender": [
52.255562,
-9.283119,
10.273865
],
"positionGltf": [
52.255562,
10.273865,
9.283119
],
"bboxBlender": {
"min": [
50.174667,
-11.629254,
10.273865
],
"max": [
54.336456,
-6.936984,
10.273865
],
"center": [
52.255562,
-9.283119,
10.273865
],
"size": [
4.161789,
4.69227,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_f362d56eba",
"name": "L2 文创店旗舰店",
@@ -453,6 +514,203 @@
"snappedWalkableId": "navwalk_0034",
"duplicateOfAuthorityPoiId": null
},
{
"id": "modelpoi_L2_ecd476d1be",
"name": "L2 展厅 6生物厅 展柜01",
"sourceObjectName": "L2_展厅_6生物厅_展柜01",
"floorId": "L2",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
},
{
"topCategory": "basic_service_facility",
"topCategoryZh": "基础服务设施",
"subcategory": "locker",
"iconType": "locker",
"reason": "matched_locker_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
69.279694,
-5.825405,
10.281687
],
"positionGltf": [
69.279694,
10.281687,
5.825405
],
"bboxBlender": {
"min": [
62.97464,
-12.536184,
10.031687
],
"max": [
75.584747,
0.885374,
10.531687
],
"center": [
69.279694,
-5.825405,
10.281687
],
"size": [
12.610107,
13.421558,
0.5
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_d93b7e7a22",
"name": "L2 展厅 6生物厅 展柜02",
"sourceObjectName": "L2_展厅_6生物厅_展柜02",
"floorId": "L2",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
},
{
"topCategory": "basic_service_facility",
"topCategoryZh": "基础服务设施",
"subcategory": "locker",
"iconType": "locker",
"reason": "matched_locker_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
69.861053,
-5.292932,
10.594574
],
"positionGltf": [
69.861053,
10.594574,
5.292932
],
"bboxBlender": {
"min": [
63.916744,
-9.808617,
10.031687
],
"max": [
75.805359,
-0.777246,
11.157462
],
"center": [
69.861053,
-5.292932,
10.594574
],
"size": [
11.888615,
9.03137,
1.125775
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_bf6262807a",
"name": "L2 展厅 6生物厅 装饰",
"sourceObjectName": "L2_展厅_6生物厅_装饰",
"floorId": "L2",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
69.074303,
-1.496778,
13.479435
],
"positionGltf": [
69.074303,
13.479435,
1.496778
],
"bboxBlender": {
"min": [
52.643074,
-17.928007,
13.479435
],
"max": [
85.505531,
14.934451,
13.479435
],
"center": [
69.074303,
-1.496778,
13.479435
],
"size": [
32.862457,
32.862457,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "poi_navpoi_0005",
"name": "L2 展厅 7生态厅",
@@ -489,6 +747,135 @@
"snappedWalkableId": "navwalk_0033",
"duplicateOfAuthorityPoiId": null
},
{
"id": "modelpoi_L2_2fea6b6cff",
"name": "L2 展厅 7生态厅 展柜",
"sourceObjectName": "L2_展厅_7生态厅_展柜",
"floorId": "L2",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
},
{
"topCategory": "basic_service_facility",
"topCategoryZh": "基础服务设施",
"subcategory": "locker",
"iconType": "locker",
"reason": "matched_locker_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
25.018467,
-53.729153,
10.511989
],
"positionGltf": [
25.018467,
10.511989,
53.729153
],
"bboxBlender": {
"min": [
6.264536,
-72.165092,
10.011989
],
"max": [
43.772396,
-35.293213,
11.011989
],
"center": [
25.018467,
-53.729153,
10.511989
],
"size": [
37.507858,
36.87188,
1
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_91de093d1e",
"name": "L2 展厅 7生态厅 装饰",
"sourceObjectName": "L2_展厅_7生态厅_装饰",
"floorId": "L2",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
24.894787,
-53.795837,
13.408146
],
"positionGltf": [
24.894787,
13.408146,
53.795837
],
"bboxBlender": {
"min": [
6.307831,
-72.382797,
13.408146
],
"max": [
43.481743,
-35.208881,
13.408146
],
"center": [
24.894787,
-53.795837,
13.408146
],
"size": [
37.173912,
37.173916,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "poi_navpoi_0004",
"name": "L2 展厅 8家园厅",
@@ -525,6 +912,135 @@
"snappedWalkableId": "navwalk_0032",
"duplicateOfAuthorityPoiId": null
},
{
"id": "modelpoi_L2_8b43a8a2a8",
"name": "L2 展厅 8家园厅 展柜",
"sourceObjectName": "L2_展厅_8家园厅_展柜",
"floorId": "L2",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
},
{
"topCategory": "basic_service_facility",
"topCategoryZh": "基础服务设施",
"subcategory": "locker",
"iconType": "locker",
"reason": "matched_locker_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
-12.998978,
10.578304,
10.478165
],
"positionGltf": [
-12.998978,
10.478165,
-10.578304
],
"bboxBlender": {
"min": [
-33.451897,
-9.404156,
9.978165
],
"max": [
7.453941,
30.560764,
10.978165
],
"center": [
-12.998978,
10.578304,
10.478165
],
"size": [
40.905838,
39.96492,
1
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_83406e72e2",
"name": "L2 展厅 8家园厅 装饰",
"sourceObjectName": "L2_展厅_8家园厅_装饰",
"floorId": "L2",
"primaryCategory": "touring_poi",
"primaryCategoryZh": "游览 POI",
"categories": [
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"subcategory": "exhibition_hall",
"iconType": "exhibition",
"reason": "matched_exhibition_keywords"
}
],
"iconType": "exhibition",
"positionBlender": [
-13.14613,
10.430546,
13.373477
],
"positionGltf": [
-13.14613,
13.373477,
-10.430546
],
"bboxBlender": {
"min": [
-33.201469,
-9.624794,
13.373477
],
"max": [
6.909211,
30.485886,
13.373477
],
"center": [
-13.14613,
10.430546,
13.373477
],
"size": [
40.11068,
40.11068,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_4e0d3ab858",
"name": "L2 电梯0001",
@@ -1501,6 +2017,67 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_9040c9507a",
"name": "L2 电梯017",
"sourceObjectName": "L2_电梯017",
"floorId": "L2",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
"categories": [
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"subcategory": "elevator",
"iconType": "elevator",
"reason": "matched_elevator_keywords"
}
],
"iconType": "elevator",
"positionBlender": [
60.687622,
-19.346493,
11.510571
],
"positionGltf": [
60.687622,
11.510571,
19.346493
],
"bboxBlender": {
"min": [
58.144585,
-21.878351,
10.008377
],
"max": [
63.230656,
-16.814634,
13.012766
],
"center": [
60.687622,
-19.346493,
11.510571
],
"size": [
5.086071,
5.063717,
3.004389
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_041990743f",
"name": "L2 扶梯001",
@@ -1562,67 +2139,6 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_5b3ad4268d",
"name": "L2 楼梯0001",
"sourceObjectName": "L2_楼梯0001",
"floorId": "L2",
"primaryCategory": "transport_circulation",
"primaryCategoryZh": "交通与通行动线",
"categories": [
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"subcategory": "stair",
"iconType": "stair",
"reason": "matched_stair_keywords"
}
],
"iconType": "stair",
"positionBlender": [
49.78883,
2.614235,
10.178167
],
"positionGltf": [
49.78883,
10.178167,
-2.614235
],
"bboxBlender": {
"min": [
48.060421,
0.55634,
10.178167
],
"max": [
51.517239,
4.67213,
10.178167
],
"center": [
49.78883,
2.614235,
10.178167
],
"size": [
3.456818,
4.115789,
0
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_nav_anchor_for_routing",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object",
"floorInferenceMethod": "name_or_collection_or_custom_property",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位从当前 Blender 模型对象名和 bbox center 提取,适合前端搜索、筛选和初步展示。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "modelpoi_L2_579220538a",
"name": "L2 楼梯0002",
@@ -1641,34 +2157,34 @@
],
"iconType": "stair",
"positionBlender": [
47.912979,
3.191393,
48.342949,
2.291168,
10.178167
],
"positionGltf": [
47.912979,
48.342949,
10.178167,
-3.191393
-2.291168
],
"bboxBlender": {
"min": [
46.033844,
1.109414,
44.615009,
-1.112592,
10.178167
],
"max": [
49.792118,
5.273373,
52.070892,
5.694929,
10.178167
],
"center": [
47.912979,
3.191393,
48.342949,
2.291168,
10.178167
],
"size": [
3.758274,
4.163959,
7.455883,
6.80752,
0
]
},
@@ -1763,34 +2279,34 @@
],
"iconType": "stair",
"positionBlender": [
89.312012,
-1.252304,
89.507751,
-1.233227,
10.178167
],
"positionGltf": [
89.312012,
89.507751,
10.178167,
1.252304
1.233227
],
"bboxBlender": {
"min": [
86.608589,
-4.589386,
86.639137,
-4.504424,
10.178167
],
"max": [
92.015442,
2.084779,
92.376358,
2.037969,
10.178167
],
"center": [
89.312012,
-1.252304,
89.507751,
-1.233227,
10.178167
],
"size": [
5.406853,
6.674165,
5.737221,
6.542393,
0
]
},
@@ -1824,34 +2340,34 @@
],
"iconType": "stair",
"positionBlender": [
87.619148,
5.131519,
87.892075,
4.699806,
10.178167
],
"positionGltf": [
87.619148,
87.892075,
10.178167,
-5.131519
-4.699806
],
"bboxBlender": {
"min": [
85.311478,
2.042627,
85.100731,
0.739156,
10.178167
],
"max": [
89.926819,
8.220411,
90.683418,
8.660455,
10.178167
],
"center": [
87.619148,
5.131519,
87.892075,
4.699806,
10.178167
],
"size": [
4.615341,
6.177784,
5.582687,
7.921299,
0
]
},
@@ -1885,34 +2401,34 @@
],
"iconType": "stair",
"positionBlender": [
47.859646,
-3.881408,
10.178166
47.717403,
-3.410032,
10.178167
],
"positionGltf": [
47.859646,
10.178166,
3.881408
47.717403,
10.178167,
3.410032
],
"bboxBlender": {
"min": [
45.350086,
-7.03454,
10.178166
44.856789,
-7.097251,
10.178167
],
"max": [
50.369205,
-0.728276,
10.178166
50.578018,
0.277186,
10.178167
],
"center": [
47.859646,
-3.881408,
10.178166
47.717403,
-3.410032,
10.178167
],
"size": [
5.019119,
6.306264,
5.72123,
7.374437,
0
]
},
@@ -2129,34 +2645,34 @@
],
"iconType": "stair",
"positionBlender": [
-4.680887,
-10.44739,
-3.329174,
-9.639655,
10.178166
],
"positionGltf": [
-4.680887,
-3.329174,
10.178166,
10.44739
9.639655
],
"bboxBlender": {
"min": [
-7.049561,
-12.861378,
-7.459712,
-13.094296,
10.178166
],
"max": [
-2.312214,
-8.033401,
0.801365,
-6.185015,
10.178166
],
"center": [
-4.680887,
-10.44739,
-3.329174,
-9.639655,
10.178166
],
"size": [
4.737347,
4.827976,
8.261077,
6.909281,
0
]
},

View File

@@ -1,12 +1,12 @@
{
"schemaVersion": "miniapp-floor-poi-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.451Z",
"generatedAt": "2026-06-11T09:36:23.700Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"floorId": "L3",
"poiCount": 16,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"poiCount": 15,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"pois": [
{
"id": "poi_navpoi_0016",
@@ -173,67 +173,6 @@
"如需用于精确路线规划,需要后续补充或确认 NAV anchor。"
]
},
{
"id": "supplemental_919d93c114",
"name": "楼顶绿化",
"sourceObjectName": "楼顶绿化",
"floorId": "L3",
"primaryCategory": "operation_experience",
"primaryCategoryZh": "运营体验类点位",
"categories": [
{
"topCategory": "operation_experience",
"topCategoryZh": "运营体验类点位",
"subcategory": "landscape_area",
"iconType": "landscape",
"reason": "clean_package_supplemental_rooftop_landscape_keyword"
}
],
"iconType": "landscape",
"positionBlender": [
6.860313,
5.471432,
16.841034
],
"positionGltf": [
6.860313,
16.841034,
-5.471432
],
"bboxBlender": {
"min": [
-126.819077,
-81.523155,
-0.851679
],
"max": [
140.539703,
92.466019,
34.533749
],
"center": [
6.860313,
5.471432,
16.841034
],
"size": [
267.358765,
173.989166,
35.385429
]
},
"coordinateSource": "model_object_bbox_center_candidate",
"navigationReadiness": "display_candidate_requires_access_or_nav_anchor_confirmation",
"sourceConfidence": "medium",
"sourceType": "current_blender_scene_model_object_supplemental_clean_package",
"floorInferenceMethod": "bbox_center_z_heuristic",
"currentSceneObjectFound": true,
"duplicateOfAuthorityPoiId": null,
"notesZh": [
"该点位是清洁资源包补充的景观/公共空间候选,适合前端展示、筛选和搜索。",
"如需用于精确路线规划,需要后续补充或确认 NAV anchor 与开放状态。"
]
},
{
"id": "modelpoi_L3_293d59fa33",
"name": "L3 电梯0001",

View File

@@ -1,12 +1,12 @@
{
"schemaVersion": "miniapp-floor-poi-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.452Z",
"generatedAt": "2026-06-11T09:36:23.701Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"floorId": "L4",
"poiCount": 27,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"pois": [
{
"id": "poi_navpoi_0017",

View File

@@ -1,12 +1,12 @@
{
"schemaVersion": "miniapp-floor-poi-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.453Z",
"generatedAt": "2026-06-11T09:36:23.703Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
"floorId": "L5",
"poiCount": 11,
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois",
"sourceInvocation": "clean_app_nav_assets_v2_from_enhanced_model_pois_strict_floor_prefix",
"pois": [
{
"id": "poi_navpoi_0013",

View File

@@ -1,6 +1,6 @@
{
"schemaVersion": "miniapp-poi-category-index-clean-2.0",
"generatedAt": "2026-06-09T07:53:40.463Z",
"generatedAt": "2026-06-11T09:36:23.714Z",
"runId": "codex_nav_20260607_reloaded_223947",
"workflowRunId": "codex_nav_20260607_reloaded_223947",
"status": "pass",
@@ -8,12 +8,20 @@
{
"topCategory": "touring_poi",
"topCategoryZh": "游览 POI",
"poiCount": 17,
"poiCount": 34,
"poiIds": [
"poi_navpoi_0009",
"modelpoi_L-2_1fa3680520",
"modelpoi_L-2_0328e49a57",
"poi_navpoi_0010",
"modelpoi_L-2_e2ec8ce8ba",
"modelpoi_L-2_f23816be84",
"poi_navpoi_0008",
"modelpoi_L-2_34bbb3d9d4",
"modelpoi_L-2_a2d90df88c",
"poi_navpoi_0007",
"modelpoi_L-2_f877db497b",
"modelpoi_L-2_81c1403384",
"modelpoi_L-1_14ec89b181",
"modelpoi_L1_350cd0e084",
"modelpoi_L1_9ba9a658bb",
@@ -22,9 +30,18 @@
"modelpoi_L1_d2b5d8b621",
"poi_navpoi_0002",
"modelpoi_L1_4e1111c7b1",
"modelpoi_L1_bce5578bda",
"modelpoi_L1_d6bfac9efe",
"poi_navpoi_0006",
"modelpoi_L2_ecd476d1be",
"modelpoi_L2_d93b7e7a22",
"modelpoi_L2_bf6262807a",
"poi_navpoi_0005",
"modelpoi_L2_2fea6b6cff",
"modelpoi_L2_91de093d1e",
"poi_navpoi_0004",
"modelpoi_L2_8b43a8a2a8",
"modelpoi_L2_83406e72e2",
"modelpoi_L4_4ba6b2c3cd",
"modelpoi_L4_a306ac4979"
]
@@ -32,7 +49,7 @@
{
"topCategory": "basic_service_facility",
"topCategoryZh": "基础服务设施",
"poiCount": 47,
"poiCount": 57,
"poiIds": [
"modelpoi_L-2_492e987660",
"modelpoi_L-2_433ee81108",
@@ -43,6 +60,10 @@
"modelpoi_L-2_e2cac3d857",
"modelpoi_L-2_d36fe2dc9d",
"modelpoi_L-2_c0855378b9",
"modelpoi_L-2_1fa3680520",
"modelpoi_L-2_e2ec8ce8ba",
"modelpoi_L-2_34bbb3d9d4",
"modelpoi_L-2_f877db497b",
"modelpoi_L1_55e995bb4d",
"poi_navpoi_0001",
"poi_navpoi_0011",
@@ -56,6 +77,7 @@
"modelpoi_L1_8045e85848",
"modelpoi_L1_170ebd7038",
"modelpoi_L1_90b628a1d5",
"modelpoi_L1_11ae2666ee",
"poi_navpoi_0012",
"modelpoi_L1.5_b21db95ba5",
"modelpoi_L1.5_a5b10d8b77",
@@ -65,7 +87,12 @@
"modelpoi_L2_2d14073a06",
"modelpoi_L2_4470473302",
"modelpoi_L2_e9fc021625",
"modelpoi_L2_9267c2d1d4",
"modelpoi_L2_f362d56eba",
"modelpoi_L2_ecd476d1be",
"modelpoi_L2_d93b7e7a22",
"modelpoi_L2_2fea6b6cff",
"modelpoi_L2_8b43a8a2a8",
"poi_navpoi_0016",
"modelpoi_L3_73737c95dc",
"modelpoi_L3_7ead513df1",
@@ -86,7 +113,7 @@
{
"topCategory": "transport_circulation",
"topCategoryZh": "交通与通行动线",
"poiCount": 229,
"poiCount": 232,
"poiIds": [
"modelpoi_L-2_ae5be493c0",
"modelpoi_L-2_e628190832",
@@ -126,6 +153,8 @@
"modelpoi_L-2_a9c1ecac07",
"modelpoi_L-2_7a4fb7e3e7",
"modelpoi_L-2_5250437db8",
"modelpoi_L-2_482544cba6",
"modelpoi_L-2_5753e93667",
"modelpoi_L-2_84885548c6",
"modelpoi_L-1_e98e1e7579",
"modelpoi_L-1_31bfe24f01",
@@ -171,6 +200,7 @@
"modelpoi_L-1_c2152945b5",
"modelpoi_L-1_d10fc5993f",
"modelpoi_L-1_7639982b98",
"modelpoi_L-1_04e400880b",
"modelpoi_L-1_e3aff063cb",
"supplemental_cc67428117",
"modelpoi_L1_45de13b368",
@@ -196,7 +226,6 @@
"modelpoi_L1_5338a76c2c",
"modelpoi_L1_b3347e28c9",
"modelpoi_L1_84fb77260b",
"modelpoi_L1_a4a00c978d",
"modelpoi_L1_360cce5a19",
"modelpoi_L1_12b7990225",
"modelpoi_L1_87efe86522",
@@ -220,9 +249,10 @@
"modelpoi_L1_2ce36ed339",
"modelpoi_L1_9461bfead0",
"modelpoi_L1_8a9434da15",
"modelpoi_L1_9a31638f63",
"modelpoi_L1_fa423c9ad0",
"modelpoi_L1_7d0051d2a6",
"modelpoi_L1_5655c264c1",
"modelpoi_L1_6fa8f94e0d",
"modelpoi_L1_9d38633ca9",
"modelpoi_L1_3936c7e2b1",
"modelpoi_L1_a6652685b8",
"modelpoi_L1_9611467f0f",
"modelpoi_L1_ce023b99e4",
@@ -260,8 +290,8 @@
"modelpoi_L2_50d761d668",
"modelpoi_L2_8144b8df38",
"modelpoi_L2_580aca14fe",
"modelpoi_L2_9040c9507a",
"modelpoi_L2_041990743f",
"modelpoi_L2_5b3ad4268d",
"modelpoi_L2_579220538a",
"modelpoi_L2_e8eb126078",
"modelpoi_L2_aacd33c979",
@@ -345,7 +375,7 @@
{
"topCategory": "operation_experience",
"topCategoryZh": "运营体验类点位",
"poiCount": 8,
"poiCount": 7,
"poiIds": [
"modelpoi_L1_19555b8890",
"modelpoi_L1_e1f290ee5a",
@@ -353,8 +383,7 @@
"modelpoi_L1_f41223bb9c",
"supplemental_b23c543281",
"supplemental_306932bd08",
"supplemental_cc67428117",
"supplemental_919d93c114"
"supplemental_cc67428117"
]
}
]