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)) }