合并展示馆内空间点位和业务点位
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-07 04:06:38 +08:00
parent 347efd3007
commit eaec80bdc3
5 changed files with 66 additions and 13 deletions

View File

@@ -526,6 +526,7 @@ const poiCategoryPriority: Record<string, number> = {
poi: 86, poi: 86,
accessibility_special_service: 88, accessibility_special_service: 88,
basic_service_facility: 82, basic_service_facility: 82,
business_poi: 80,
transport_circulation: 76, transport_circulation: 76,
operation_experience: 46 operation_experience: 46
} }
@@ -539,6 +540,7 @@ const isHallPoi = (poi: RenderPoi) => (
const isServiceFacilityPoi = (poi: RenderPoi) => ( const isServiceFacilityPoi = (poi: RenderPoi) => (
poi.primaryCategory === 'basic_service_facility' poi.primaryCategory === 'basic_service_facility'
|| poi.primaryCategory === 'accessibility_special_service' || poi.primaryCategory === 'accessibility_special_service'
|| poi.primaryCategory === 'business_poi'
) )
const isTransportPoi = (poi: RenderPoi) => poi.primaryCategory === 'transport_circulation' const isTransportPoi = (poi: RenderPoi) => poi.primaryCategory === 'transport_circulation'
@@ -554,6 +556,12 @@ const poiGlyphMap: Record<string, string> = {
stair: '梯', stair: '梯',
experience: '展', experience: '展',
theater: '演', theater: '演',
restaurant: '餐',
cafe: '咖',
shop: '购',
bookstore: '书',
cultural_shop: '文',
business: '商',
exhibition_hall: '展', exhibition_hall: '展',
hall_entrance: '门', hall_entrance: '门',
entrance_exit: '门', entrance_exit: '门',
@@ -4102,6 +4110,7 @@ const getPoiColor = (category: string) => {
exhibition_hall: '#2f6fed', exhibition_hall: '#2f6fed',
exhibition_hall_entrance: '#4659d8', exhibition_hall_entrance: '#4659d8',
basic_service_facility: '#1f8f5f', basic_service_facility: '#1f8f5f',
business_poi: '#0f9aa5',
transport_circulation: '#d77b20', transport_circulation: '#d77b20',
accessibility_special_service: '#8a5cf6', accessibility_special_service: '#8a5cf6',
operation_experience: '#cf3f59' operation_experience: '#cf3f59'

View File

@@ -15,6 +15,9 @@ export interface GuideRenderPoi {
kind?: MuseumPoiKind kind?: MuseumPoiKind
hallId?: string hallId?: string
hallName?: string hallName?: string
spaceId?: string
sourcePlaceId?: string
sourceSpaceId?: string
entrances?: MuseumPoiEntrance[] entrances?: MuseumPoiEntrance[]
} }

View File

@@ -972,7 +972,7 @@ const handleIndoorToolClick = (tool: string) => {
if (!is3DMode.value) return if (!is3DMode.value) return
if (tool === '复位') { if (tool === '复位') {
showIndoorHint('已复位视角,单指旋转、双指可平移', 2800) showIndoorHint('已复位视角,单指平移、双指可缩放', 2800)
} else if (tool === '俯视') { } else if (tool === '俯视') {
showIndoorHint('已切换俯视视角,可点选标记查看位置', 2800) showIndoorHint('已切换俯视视角,可点选标记查看位置', 2800)
} else if (tool === '斜视') { } else if (tool === '斜视') {

View File

@@ -4,6 +4,9 @@ import type {
GuideModelSource, GuideModelSource,
GuideRenderPoi GuideRenderPoi
} from '@/domain/guideModel' } from '@/domain/guideModel'
import type {
MuseumPoi
} from '@/domain/museum'
import { import {
dataSourceConfig dataSourceConfig
} from '@/config/dataSource' } from '@/config/dataSource'
@@ -35,6 +38,12 @@ import {
import { import {
mapWithConcurrency mapWithConcurrency
} from '@/utils/concurrency' } from '@/utils/concurrency'
import type {
GuideRepository
} from '@/repositories/GuideRepository'
import {
guideRepository
} from '@/repositories/createGuideRepository'
const SDK_FLOOR_BUNDLE_CONCURRENCY = 2 const SDK_FLOOR_BUNDLE_CONCURRENCY = 2
@@ -57,9 +66,7 @@ const toRenderPoi = (poi: StaticNavPoiPayload): GuideRenderPoi => ({
hallName: poi.primaryCategory === 'touring_poi' ? poi.name : undefined hallName: poi.primaryCategory === 'touring_poi' ? poi.name : undefined
}) })
const toSgsRenderPoi = ( const toGuideRenderPoi = (poi: MuseumPoi): GuideRenderPoi => ({
poi: ReturnType<typeof toMuseumPoiFromSgs>
): GuideRenderPoi => ({
id: poi.id, id: poi.id,
name: poi.name, name: poi.name,
floorId: poi.floorId, floorId: poi.floorId,
@@ -71,14 +78,28 @@ const toSgsRenderPoi = (
kind: poi.kind, kind: poi.kind,
hallId: poi.hallId, hallId: poi.hallId,
hallName: poi.hallName, hallName: poi.hallName,
spaceId: poi.spaceId,
sourcePlaceId: poi.sourcePlaceId,
sourceSpaceId: poi.sourceSpaceId,
entrances: poi.entrances entrances: poi.entrances
}) })
const toSgsRenderPoi = (poi: ReturnType<typeof toMuseumPoiFromSgs>) => toGuideRenderPoi(poi)
const getRenderPoiDedupeKeys = (poi: GuideRenderPoi) => [
poi.id ? `id:${poi.id}` : '',
poi.sourceSpaceId ? `space:${poi.floorId}:${poi.sourceSpaceId}` : '',
poi.spaceId ? `space:${poi.floorId}:${poi.spaceId}` : '',
poi.sourcePlaceId ? `place:${poi.floorId}:${poi.sourcePlaceId}` : '',
poi.sourceObjectName ? `object:${poi.floorId}:${poi.sourceObjectName}` : ''
].filter(Boolean)
const dedupeRenderPoisById = (pois: GuideRenderPoi[]) => { const dedupeRenderPoisById = (pois: GuideRenderPoi[]) => {
const seen = new Set<string>() const seen = new Set<string>()
return pois.filter((poi) => { return pois.filter((poi) => {
if (!poi.id || seen.has(poi.id)) return false const keys = getRenderPoiDedupeKeys(poi)
seen.add(poi.id) if (!keys.length || keys.some((key) => seen.has(key))) return false
keys.forEach((key) => seen.add(key))
return true return true
}) })
} }
@@ -283,7 +304,10 @@ export class StaticGuideModelRepository implements GuideModelRepository {
export class SgsSdkGuideModelRepository implements GuideModelRepository { export class SgsSdkGuideModelRepository implements GuideModelRepository {
private floorsCache: SgsSdkFloorSummaryPayload[] | null = null private floorsCache: SgsSdkFloorSummaryPayload[] | null = null
constructor(private readonly provider: SgsSdkApiProvider = defaultSgsSdkApiProvider) {} constructor(
private readonly provider: SgsSdkApiProvider = defaultSgsSdkApiProvider,
private readonly guide: GuideRepository = guideRepository
) {}
async loadPackage(): Promise<GuideModelRenderPackage> { async loadPackage(): Promise<GuideModelRenderPackage> {
const startedAt = getNow() const startedAt = getNow()
@@ -419,7 +443,7 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
const resolvedFloorId = String(matchedFloor.floorId) const resolvedFloorId = String(matchedFloor.floorId)
const loadFloorData = async <T>( const loadFloorData = async <T>(
endpoint: 'pois' | 'spaces' | 'navigablePlaces', endpoint: 'pois' | 'spaces' | 'navigablePlaces' | 'guidePois' | 'guideSpacePoints',
loader: () => Promise<T[]> loader: () => Promise<T[]>
) => { ) => {
try { try {
@@ -434,12 +458,20 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
} }
} }
const [pois, spaces, navigablePlaces] = await Promise.all([ const [pois, spaces, navigablePlaces, guidePois, guideSpacePoints] = await Promise.all([
loadFloorData('pois', () => this.provider.getFloorPois(resolvedFloorId)), loadFloorData('pois', () => this.provider.getFloorPois(resolvedFloorId)),
loadFloorData('spaces', () => this.provider.getFloorSpaces(resolvedFloorId)), loadFloorData('spaces', () => this.provider.getFloorSpaces(resolvedFloorId)),
loadFloorData('navigablePlaces', () => this.provider.getNavigablePlaces(resolvedFloorId)) loadFloorData('navigablePlaces', () => this.provider.getNavigablePlaces(resolvedFloorId)),
loadFloorData('guidePois', () => this.guide.listPois()),
loadFloorData('guideSpacePoints', () => this.guide.listSpacePoints())
]) ])
const ordinaryPois = pois.map((poi) => toSgsRenderPoi(toMuseumPoiFromSgs(poi, manifest.floors))) const ordinaryPois = pois.map((poi) => toSgsRenderPoi(toMuseumPoiFromSgs(poi, manifest.floors)))
const repositoryBusinessPois = guidePois
.filter((poi) => poi.floorId === resolvedFloorId && poi.primaryCategory.id === 'business_poi')
.map(toGuideRenderPoi)
const repositorySpacePois = guideSpacePoints
.filter((poi) => poi.floorId === resolvedFloorId)
.map(toGuideRenderPoi)
const floorPoiMedianY = getMedianPoiY(ordinaryPois) const floorPoiMedianY = getMedianPoiY(ordinaryPois)
const museumHallPois = toMuseumHallPoisFromSgs(spaces, navigablePlaces, manifest.floors, resolvedFloorId, { const museumHallPois = toMuseumHallPoisFromSgs(spaces, navigablePlaces, manifest.floors, resolvedFloorId, {
fallbackY: floorPoiMedianY fallbackY: floorPoiMedianY
@@ -456,7 +488,9 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
const hallPois = museumHallPois.map(toSgsRenderPoi) const hallPois = museumHallPois.map(toSgsRenderPoi)
const adaptedPois = dedupeRenderPoisById([ const adaptedPois = dedupeRenderPoisById([
...hallPois, ...hallPois,
...ordinaryPois ...ordinaryPois,
...repositorySpacePois,
...repositoryBusinessPois
]) ])
const floorMatchedPois = adaptedPois.filter((poi) => poi.floorId === resolvedFloorId) const floorMatchedPois = adaptedPois.filter((poi) => poi.floorId === resolvedFloorId)
const renderPois = floorMatchedPois const renderPois = floorMatchedPois
@@ -467,6 +501,8 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository {
floorId: resolvedFloorId, floorId: resolvedFloorId,
floorCode: matchedFloor.floorCode, floorCode: matchedFloor.floorCode,
rawPoiCount: pois.length, rawPoiCount: pois.length,
rawRepositoryBusinessPoiCount: repositoryBusinessPois.length,
rawRepositorySpacePoiCount: repositorySpacePois.length,
rawPoiTypeCounts: countByValue(pois, (poi) => poi.type), rawPoiTypeCounts: countByValue(pois, (poi) => poi.type),
rawPoiGroupCounts: countByValue(pois, (poi) => poi.poiGroup), rawPoiGroupCounts: countByValue(pois, (poi) => poi.poiGroup),
adaptedPoiCount: adaptedPois.length, adaptedPoiCount: adaptedPois.length,

View File

@@ -49,6 +49,7 @@ const searchableCategories = new Set([
'basic_service_facility', 'basic_service_facility',
'transport_circulation', 'transport_circulation',
'accessibility_special_service', 'accessibility_special_service',
'business_poi',
'operation_experience' 'operation_experience'
]) ])
@@ -301,15 +302,19 @@ export class SgsSdkGuideRepository implements GuideRepository {
const floorDataGroups = await Promise.all( const floorDataGroups = await Promise.all(
indoorFloors.map(async (floor) => { indoorFloors.map(async (floor) => {
const floorId = String(floor.floorId) const floorId = String(floor.floorId)
const [pois, spaces, navigablePlaces] = await Promise.all([ const [pois, businessPois, spaces, navigablePlaces] = await Promise.all([
this.provider.getFloorPois(floorId).catch(() => []), this.provider.getFloorPois(floorId).catch(() => []),
this.provider.getFloorBusinessPois(floorId).catch(() => []),
this.provider.getFloorSpaces(floorId).catch(() => []), this.provider.getFloorSpaces(floorId).catch(() => []),
this.provider.getNavigablePlaces(floorId).catch(() => []) this.provider.getNavigablePlaces(floorId).catch(() => [])
]) ])
return { return {
floorId, floorId,
pois, pois: [
...pois,
...businessPois
],
hallPois: toMuseumHallPoisFromSgs(spaces, navigablePlaces, manifest.floors, floorId) hallPois: toMuseumHallPoisFromSgs(spaces, navigablePlaces, manifest.floors, floorId)
} }
}) })