适配讲解详情聚合接口

This commit is contained in:
lyf
2026-07-22 19:40:17 +08:00
parent dd29ead041
commit 4d8cc55a5c
10 changed files with 440 additions and 152 deletions

View File

@@ -42,11 +42,31 @@ export interface BackendGuideStopInfo {
hasText?: boolean
supportedLanguages?: string[] | null
audioStatus?: string | null
languageVariants?: BackendGuideStopLanguageVariant[] | null
reason?: string | null
linkedExhibitCount?: number | string | null
isSharedStop?: boolean | null
}
export interface BackendGuideStopLanguageVariant {
lang?: string | null
enabled?: boolean | null
playable?: boolean | null
audioStatus?: string | null
playUrl?: string | null
duration?: number | string | null
format?: string | null
audioId?: string | number | null
narrationTier?: 'STANDARD' | 'EXTENDED' | string | null
hasText?: boolean | null
textAvailable?: boolean | null
text?: string | null
textLength?: number | string | null
textHash?: string | null
fallback?: boolean | null
reason?: string | null
}
export interface BackendAudioPlayInfo {
playable?: boolean
targetType?: string | null
@@ -90,6 +110,25 @@ export interface GuideStopLinkedExhibit {
sortOrder?: number
}
export interface GuideStopLanguageVariant {
lang: GuideAudioLanguage
enabled: boolean
playable: boolean
audioStatus: 'READY' | 'MISSING' | string
playUrl?: string
duration?: number
format?: string
audioId?: string
narrationTier?: 'STANDARD' | 'EXTENDED'
hasText: boolean
textAvailable: boolean
text?: string
textLength?: number
textHash?: string
fallback: boolean
reason?: string
}
export interface GuideStopInfo {
available: boolean
targetType: AudioPlayTargetType
@@ -112,6 +151,7 @@ export interface GuideStopInfo {
hasAudio: boolean
hasText: boolean
supportedLanguages: GuideAudioLanguage[]
languageVariants: Record<GuideAudioLanguage, GuideStopLanguageVariant>
audioStatus: 'READY' | 'MISSING' | string
reason?: string
linkedExhibitCount?: number
@@ -177,16 +217,57 @@ export const normalizeGuideAudioLanguage = (
return 'zh-CN'
}
const isSupportedGuideAudioLanguage = (value: string | null | undefined) => (
['zh', 'zh-cn', 'en', 'en-us', 'yue', 'yue-cn', 'yue-hk'].includes(value?.trim().toLowerCase() || '')
)
const normalizeSupportedLanguages = (languages: string[] | null | undefined): GuideAudioLanguage[] => (
Array.from(new Set((languages || [])
.map((language) => {
const normalized = language?.trim().toLowerCase()
if (!['zh', 'zh-cn', 'en', 'en-us', 'yue', 'yue-cn', 'yue-hk'].includes(normalized)) {
return null
}
return normalizeGuideAudioLanguage(language)
})
.filter(Boolean))) as GuideAudioLanguage[]
.filter(isSupportedGuideAudioLanguage)
.map(normalizeGuideAudioLanguage))) as GuideAudioLanguage[]
)
const normalizeLanguageVariants = (
variants: BackendGuideStopLanguageVariant[] | null | undefined
): Record<GuideAudioLanguage, GuideStopLanguageVariant> => {
const normalizedVariants = {} as Record<GuideAudioLanguage, GuideStopLanguageVariant>
;(variants || []).forEach((variant) => {
if (!isSupportedGuideAudioLanguage(variant.lang)) return
const lang = normalizeGuideAudioLanguage(variant.lang)
const playUrl = normalizeSameOriginPublicUrl(variant.playUrl) || undefined
const playable = variant.playable === true && Boolean(playUrl)
const text = variant.text?.trim() || undefined
const textAvailable = variant.textAvailable === true || Boolean(text)
normalizedVariants[lang] = {
lang,
enabled: variant.enabled === true,
playable,
audioStatus: variant.audioStatus || (playable ? 'READY' : 'MISSING'),
playUrl,
duration: normalizeNumber(variant.duration),
format: variant.format?.trim() || undefined,
audioId: stringifyId(variant.audioId) || undefined,
narrationTier: normalizeNarrationTier(variant.narrationTier),
hasText: variant.hasText === true || textAvailable,
textAvailable,
text,
textLength: normalizeNumber(variant.textLength),
textHash: variant.textHash?.trim() || undefined,
fallback: variant.fallback === true,
reason: variant.reason?.trim() || undefined
}
})
return normalizedVariants
}
const supportedLanguagesFromVariants = (variants: Record<GuideAudioLanguage, GuideStopLanguageVariant>) => (
(Object.values(variants) as GuideStopLanguageVariant[])
.filter((variant) => variant.enabled && (variant.playable || variant.textAvailable))
.map((variant) => variant.lang)
)
const parseGalleryUrls = (value: BackendGuideStopInfo['galleryUrls'] | BackendGuideStopLinkedExhibit['galleryUrls']) => {
@@ -255,6 +336,8 @@ export const toGuideStopInfo = (
const coverImageUrl = canUseStopImages
? normalizeSameOriginPublicUrl(source.coverImageUrl) || undefined
: undefined
const languageVariants = normalizeLanguageVariants(source.languageVariants)
const supportedLanguages = supportedLanguagesFromVariants(languageVariants)
return {
available: source.available === true,
@@ -277,7 +360,10 @@ export const toGuideStopInfo = (
playTargetId,
hasAudio: source.hasAudio === true,
hasText: source.hasText === true,
supportedLanguages: normalizeSupportedLanguages(source.supportedLanguages),
supportedLanguages: supportedLanguages.length
? supportedLanguages
: normalizeSupportedLanguages(source.supportedLanguages),
languageVariants,
audioStatus: source.audioStatus || 'MISSING',
reason: source.reason || undefined,
linkedExhibitCount: normalizeNumber(source.linkedExhibitCount),