Files
gmTouringMiniApp/src/domain/poi/selectors.ts
T
zuozhou 09f8ec7ecf
AI Code Review / review (pull_request) Successful in 2m31s
feat: 统一推荐指数显示格式,移除地图底部免责声明
2026-07-31 15:01:44 +08:00

114 lines
3.5 KiB
TypeScript

import type {
Poi,
PoiCategory,
PoiDataset,
PoiFilter,
PoiImageAsset,
PoiOpeningHours,
PoiResolved,
PoiSummary,
PoiTag,
RecommendationSource,
} from './types'
export function formatOpeningHours(openingHours: PoiOpeningHours): string {
if (openingHours.status === 'unknown')
return '开放时间待确认'
return openingHours.displayText?.trim() || '开放时间待确认'
}
export function formatRecommendationLabel(_source: RecommendationSource, index: number): string {
return `推荐指数 ${index}/5`
}
export function filterPois(pois: readonly Poi[], filter: PoiFilter = {}): Poi[] {
const requiredTags = Array.from(new Set(filter.tagCodes ?? []))
return pois.filter((poi) => {
if (filter.categoryCode && poi.categoryCode !== filter.categoryCode)
return false
return requiredTags.every(tagCode => poi.tagCodes.includes(tagCode))
})
}
export function findPoiById(pois: readonly Poi[], poiId: string): Poi | null {
const normalizedId = poiId.trim()
if (!normalizedId)
return null
return pois.find(poi => poi.id === normalizedId) ?? null
}
export function sortCategories(categories: readonly PoiCategory[]): PoiCategory[] {
return categories
.filter(category => category.status === 'enabled')
.slice()
.sort((left, right) => left.sortOrder - right.sortOrder || left.name.localeCompare(right.name, 'zh-CN'))
}
export function sortTags(tags: readonly PoiTag[]): PoiTag[] {
return tags
.filter(tag => tag.status === 'enabled')
.slice()
.sort((left, right) => left.sortOrder - right.sortOrder || left.name.localeCompare(right.name, 'zh-CN'))
}
export function resolvePoi(
poi: Poi,
categories: readonly PoiCategory[],
tags: readonly PoiTag[],
images: readonly PoiImageAsset[],
): PoiResolved | null {
const category = categories.find(item => item.code === poi.categoryCode && item.status === 'enabled')
const coverImage = images.find(item => item.id === poi.coverImageId)
if (!category || !coverImage)
return null
const tagMap = new Map(tags.map(tag => [tag.code, tag]))
const imageMap = new Map(images.map(image => [image.id, image]))
const resolvedTags = poi.tagCodes
.map(tagCode => tagMap.get(tagCode))
.filter((tag): tag is PoiTag => Boolean(tag && tag.status === 'enabled'))
const resolvedImages = poi.imageIds
.map(imageId => imageMap.get(imageId))
.filter((image): image is PoiImageAsset => Boolean(image))
return {
...poi,
category,
tags: resolvedTags,
coverImage,
images: [coverImage, ...resolvedImages],
openingHoursText: formatOpeningHours(poi.openingHours),
}
}
export function toPoiSummary(poi: PoiResolved): PoiSummary {
return {
id: poi.id,
name: poi.name,
categoryCode: poi.categoryCode,
categoryName: poi.category.name,
tagCodes: [...poi.tagCodes],
tags: poi.tags.map(tag => ({ ...tag, synonyms: tag.synonyms ? [...tag.synonyms] : undefined })),
longitude: poi.longitude,
latitude: poi.latitude,
coordinateSystem: poi.coordinateSystem,
coverImage: { ...poi.coverImage },
summary: poi.summary,
description: poi.description,
address: poi.address,
recommendationIndex: poi.recommendationIndex,
recommendationSource: poi.recommendationSource,
openingHoursText: poi.openingHoursText,
}
}
export function resolveDatasetPois(dataset: PoiDataset, pois: readonly Poi[]): PoiResolved[] {
return pois
.map(poi => resolvePoi(poi, dataset.categories, dataset.tags, dataset.images))
.filter((poi): poi is PoiResolved => Boolean(poi))
}