diff --git a/src/components/map/ThreeMap.vue b/src/components/map/ThreeMap.vue index 6e72969..da8ecd8 100644 --- a/src/components/map/ThreeMap.vue +++ b/src/components/map/ThreeMap.vue @@ -526,6 +526,7 @@ const poiCategoryPriority: Record = { poi: 86, accessibility_special_service: 88, basic_service_facility: 82, + business_poi: 80, transport_circulation: 76, operation_experience: 46 } @@ -539,6 +540,7 @@ const isHallPoi = (poi: RenderPoi) => ( const isServiceFacilityPoi = (poi: RenderPoi) => ( poi.primaryCategory === 'basic_service_facility' || poi.primaryCategory === 'accessibility_special_service' + || poi.primaryCategory === 'business_poi' ) const isTransportPoi = (poi: RenderPoi) => poi.primaryCategory === 'transport_circulation' @@ -554,6 +556,12 @@ const poiGlyphMap: Record = { stair: '梯', experience: '展', theater: '演', + restaurant: '餐', + cafe: '咖', + shop: '购', + bookstore: '书', + cultural_shop: '文', + business: '商', exhibition_hall: '展', hall_entrance: '门', entrance_exit: '门', @@ -4102,6 +4110,7 @@ const getPoiColor = (category: string) => { exhibition_hall: '#2f6fed', exhibition_hall_entrance: '#4659d8', basic_service_facility: '#1f8f5f', + business_poi: '#0f9aa5', transport_circulation: '#d77b20', accessibility_special_service: '#8a5cf6', operation_experience: '#cf3f59' diff --git a/src/domain/guideModel.ts b/src/domain/guideModel.ts index 5ce2753..ee31840 100644 --- a/src/domain/guideModel.ts +++ b/src/domain/guideModel.ts @@ -15,6 +15,9 @@ export interface GuideRenderPoi { kind?: MuseumPoiKind hallId?: string hallName?: string + spaceId?: string + sourcePlaceId?: string + sourceSpaceId?: string entrances?: MuseumPoiEntrance[] } diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index 2602b9e..82b58fa 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -972,7 +972,7 @@ const handleIndoorToolClick = (tool: string) => { if (!is3DMode.value) return if (tool === '复位') { - showIndoorHint('已复位视角,单指旋转、双指可平移', 2800) + showIndoorHint('已复位视角,单指平移、双指可缩放', 2800) } else if (tool === '俯视') { showIndoorHint('已切换俯视视角,可点选标记查看位置', 2800) } else if (tool === '斜视') { diff --git a/src/repositories/GuideModelRepository.ts b/src/repositories/GuideModelRepository.ts index 2e5e216..811c0a7 100644 --- a/src/repositories/GuideModelRepository.ts +++ b/src/repositories/GuideModelRepository.ts @@ -4,6 +4,9 @@ import type { GuideModelSource, GuideRenderPoi } from '@/domain/guideModel' +import type { + MuseumPoi +} from '@/domain/museum' import { dataSourceConfig } from '@/config/dataSource' @@ -35,6 +38,12 @@ import { import { mapWithConcurrency } from '@/utils/concurrency' +import type { + GuideRepository +} from '@/repositories/GuideRepository' +import { + guideRepository +} from '@/repositories/createGuideRepository' const SDK_FLOOR_BUNDLE_CONCURRENCY = 2 @@ -57,9 +66,7 @@ const toRenderPoi = (poi: StaticNavPoiPayload): GuideRenderPoi => ({ hallName: poi.primaryCategory === 'touring_poi' ? poi.name : undefined }) -const toSgsRenderPoi = ( - poi: ReturnType -): GuideRenderPoi => ({ +const toGuideRenderPoi = (poi: MuseumPoi): GuideRenderPoi => ({ id: poi.id, name: poi.name, floorId: poi.floorId, @@ -71,14 +78,28 @@ const toSgsRenderPoi = ( kind: poi.kind, hallId: poi.hallId, hallName: poi.hallName, + spaceId: poi.spaceId, + sourcePlaceId: poi.sourcePlaceId, + sourceSpaceId: poi.sourceSpaceId, entrances: poi.entrances }) +const toSgsRenderPoi = (poi: ReturnType) => 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 seen = new Set() return pois.filter((poi) => { - if (!poi.id || seen.has(poi.id)) return false - seen.add(poi.id) + const keys = getRenderPoiDedupeKeys(poi) + if (!keys.length || keys.some((key) => seen.has(key))) return false + keys.forEach((key) => seen.add(key)) return true }) } @@ -283,7 +304,10 @@ export class StaticGuideModelRepository implements GuideModelRepository { export class SgsSdkGuideModelRepository implements GuideModelRepository { 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 { const startedAt = getNow() @@ -419,7 +443,7 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository { const resolvedFloorId = String(matchedFloor.floorId) const loadFloorData = async ( - endpoint: 'pois' | 'spaces' | 'navigablePlaces', + endpoint: 'pois' | 'spaces' | 'navigablePlaces' | 'guidePois' | 'guideSpacePoints', loader: () => Promise ) => { 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('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 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 museumHallPois = toMuseumHallPoisFromSgs(spaces, navigablePlaces, manifest.floors, resolvedFloorId, { fallbackY: floorPoiMedianY @@ -456,7 +488,9 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository { const hallPois = museumHallPois.map(toSgsRenderPoi) const adaptedPois = dedupeRenderPoisById([ ...hallPois, - ...ordinaryPois + ...ordinaryPois, + ...repositorySpacePois, + ...repositoryBusinessPois ]) const floorMatchedPois = adaptedPois.filter((poi) => poi.floorId === resolvedFloorId) const renderPois = floorMatchedPois @@ -467,6 +501,8 @@ export class SgsSdkGuideModelRepository implements GuideModelRepository { floorId: resolvedFloorId, floorCode: matchedFloor.floorCode, rawPoiCount: pois.length, + rawRepositoryBusinessPoiCount: repositoryBusinessPois.length, + rawRepositorySpacePoiCount: repositorySpacePois.length, rawPoiTypeCounts: countByValue(pois, (poi) => poi.type), rawPoiGroupCounts: countByValue(pois, (poi) => poi.poiGroup), adaptedPoiCount: adaptedPois.length, diff --git a/src/repositories/GuideRepository.ts b/src/repositories/GuideRepository.ts index 201ce14..2743dec 100644 --- a/src/repositories/GuideRepository.ts +++ b/src/repositories/GuideRepository.ts @@ -49,6 +49,7 @@ const searchableCategories = new Set([ 'basic_service_facility', 'transport_circulation', 'accessibility_special_service', + 'business_poi', 'operation_experience' ]) @@ -301,15 +302,19 @@ export class SgsSdkGuideRepository implements GuideRepository { const floorDataGroups = await Promise.all( indoorFloors.map(async (floor) => { 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.getFloorBusinessPois(floorId).catch(() => []), this.provider.getFloorSpaces(floorId).catch(() => []), this.provider.getNavigablePlaces(floorId).catch(() => []) ]) return { floorId, - pois, + pois: [ + ...pois, + ...businessPois + ], hallPois: toMuseumHallPoisFromSgs(spaces, navigablePlaces, manifest.floors, floorId) } })