import type { MuseumExhibit, MuseumHall, SearchIndexItem } from '@/domain/museum' export type ExplainContentType = 'hall' | 'zone' | 'exhibit' | 'theme' export type ExplainAudioStatus = 'playable' | 'unavailable' | 'none' export interface ExplainCardViewModel { id: string title: string subtitle?: string summary?: string coverImage?: string contentType: ExplainContentType hallName?: string floorLabel?: string durationLabel?: string languageLabel?: string audioStatus: ExplainAudioStatus audioStatusText: string badges: string[] progress?: number poiId?: string locationActionText?: string } export interface ExplainDetailPageViewModel { id: string title: string subtitle?: string contentType: ExplainContentType coverImages: string[] hallName?: string floorLabel?: string summary: string body: string audio: { status: ExplainAudioStatus url?: string durationLabel?: string language?: string unavailableReason?: string } chapters: Array<{ id: string title: string startTime?: number }> transcript?: string location?: { poiId: string actionText: string previewOnly: boolean } relatedItems: ExplainCardViewModel[] } export type ExplainExhibitViewModel = ExplainCardViewModel export type ExplainDetailViewModel = ExplainDetailPageViewModel export interface HallDetailViewModel { id: string name: string floorLabel: string description: string image: string exhibitCount: number area?: string poiId?: string } const contentTypeFor = (exhibit: MuseumExhibit): ExplainContentType => { if (exhibit.tags?.some((tag) => /主题/.test(tag))) return 'theme' if (exhibit.hallName && exhibit.tags?.some((tag) => /展厅/.test(tag))) return 'hall' return 'exhibit' } const buildSubtitle = (exhibit: MuseumExhibit) => [ exhibit.hallName, exhibit.floorLabel ].filter(Boolean).join(' · ') const buildBadges = (exhibit: MuseumExhibit) => { const badges = [ exhibit.hallName ? '展厅讲解' : '讲解点', exhibit.floorLabel || '', ...(exhibit.tags || []) ].filter(Boolean) return Array.from(new Set(badges)).slice(0, 3) } export const toExplainCardViewModel = (exhibit: MuseumExhibit): ExplainCardViewModel => ({ id: exhibit.id, title: exhibit.name, subtitle: buildSubtitle(exhibit), summary: exhibit.description || '讲解内容待正式内容库补充。', coverImage: exhibit.image, contentType: contentTypeFor(exhibit), hallName: exhibit.hallName, floorLabel: exhibit.floorLabel, durationLabel: undefined, languageLabel: undefined, audioStatus: 'unavailable', audioStatusText: '图文讲解', badges: buildBadges(exhibit), progress: undefined, poiId: exhibit.poiId, locationActionText: '查看位置' }) export const toExplainExhibitViewModel = (exhibit: MuseumExhibit): ExplainExhibitViewModel => toExplainCardViewModel(exhibit) export const toExplainDetailPageViewModel = (exhibit: MuseumExhibit): ExplainDetailPageViewModel => ({ id: exhibit.id, title: exhibit.name, subtitle: buildSubtitle(exhibit), contentType: contentTypeFor(exhibit), coverImages: [exhibit.image || '/static/exhibit-placeholder.jpg'].filter(Boolean), hallName: exhibit.hallName, floorLabel: exhibit.floorLabel, summary: exhibit.description || '该讲解内容待正式内容库补充。', body: exhibit.description || '该讲解内容待正式内容库补充。', audio: { status: 'unavailable', unavailableReason: '正式讲解音频尚未接入媒体仓储' }, chapters: [], transcript: undefined, location: exhibit.poiId ? { poiId: exhibit.poiId, actionText: '查看三维位置', previewOnly: true } : undefined, relatedItems: [] }) export const toExplainDetailViewModel = (exhibit: MuseumExhibit): ExplainDetailViewModel => toExplainDetailPageViewModel(exhibit) export const toHallDetailViewModel = (hall: MuseumHall): HallDetailViewModel => ({ id: hall.id, name: hall.name, floorLabel: hall.floorLabel || '楼层待补充', description: hall.description || '该展厅介绍待正式内容库补充。', image: hall.image || '/static/hall-placeholder.jpg', exhibitCount: hall.exhibitCount || 0, area: hall.area, poiId: hall.poiId }) export const toExplainSearchResultViewModel = (item: SearchIndexItem) => ({ id: item.id, name: item.name, desc: item.desc, type: item.type })