feat: wire guide data source and POI focus UI
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
120
src/repositories/ExplainRepository.ts
Normal file
120
src/repositories/ExplainRepository.ts
Normal 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()
|
||||
Reference in New Issue
Block a user