适配H5讲解统一详情接口
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-08-05 14:52:36 +08:00
parent c287ef3a2a
commit 2edb6bd9f2
25 changed files with 946 additions and 1148 deletions

View File

@@ -1,137 +1,67 @@
import { describe, expect, it } from 'vitest'
import { toGuideStopInfo } from '@/data/adapters/guideStopInfoAdapter'
import { toGuideStopDetail } from '@/data/adapters/guideStopInfoAdapter'
describe('guide stop-info adapter', () => {
it('normalizes aggregated language variants and exposes only displayable languages', () => {
const result = toGuideStopInfo({
available: true,
targetType: 'STOP',
targetId: '9001',
lang: 'zh-CN',
const languages = ['zh-CN', 'en-US', 'yue-HK'] as const
describe('unified guide stop detail adapter', () => {
it('preserves snowflake IDs, synthesizes stable track codes, and ignores images marked missing', () => {
const textVariants = languages.map((languageCode) => ({
version: 'standard',
languageCode,
text: `standard-${languageCode}`
}))
const audioTracks = languages.flatMap((languageCode) => (
languageCode === 'yue-HK'
? [{ version: 'standard', languageCode, gender: 'female', playUrl: `/standard-${languageCode}-female.mp3` }]
: ['female', 'male'].map((gender) => ({ version: 'standard', languageCode, gender, playUrl: `/standard-${languageCode}-${gender}.mp3` }))
))
const detail = toGuideStopDetail({
id: '865546647764037632',
version: 'standard',
outlineId: '7467940240901013505',
linkedExhibits: [{ id: '865546647764037633', name: '关联展品' }],
name: '青铜神树',
coverImageUrl: '/should-not-be-used.webp',
galleryUrls: '["/should-not-be-used-gallery.webp"]',
imageStatus: 'MISSING',
recommendedTrackCode: 'standard.zh-CN.female',
textVariants,
audioTracks,
textVariantCount: 3,
audioTrackCount: 5
})
expect(detail.id).toBe('865546647764037632')
expect(detail.version).toBe('standard')
expect(detail.outlineId).toBe('7467940240901013505')
expect(detail.linkedExhibits[0]?.id).toBe('865546647764037633')
expect(detail.coverImageUrl).toBeUndefined()
expect(detail.galleryUrls).toEqual([])
expect(detail.textVariants).toHaveLength(3)
expect(detail.audioTracks).toHaveLength(5)
expect(detail.recommendedTrackCode).toBe('standard.zh-CN.female')
expect(detail.audioTracks.find((track) => track.channelCode === 'standard.zh-CN.female')?.playUrl)
.toBe('/standard-zh-CN-female.mp3')
})
it('drops unusable tracks while retaining a Chinese text variant for Cantonese fallback', () => {
const detail = toGuideStopDetail({
id: 'stop-1',
version: 'extended',
name: '测试',
imageStatus: 'READY',
coverImageUrl: '/museum-assets/cover.webp',
languageVariants: [
{
lang: 'zh',
enabled: true,
playable: true,
audioStatus: 'READY',
playUrl: '/museum-assets/audio/zh.mp3',
duration: '50',
audioId: 12,
hasText: true,
textAvailable: true,
text: '普通话讲解词',
textLength: '6',
textHash: 'zh-hash'
},
{
lang: 'yue-HK',
enabled: true,
playable: false,
audioStatus: 'MISSING',
textAvailable: true,
text: '粤语使用普通话文案',
reason: 'NO_PUBLISHED_AUDIO'
},
{
lang: 'en-US',
enabled: false,
playable: true,
playUrl: '/museum-assets/audio/en.mp3'
}
textVariants: [{ version: 'extended', languageCode: 'zh-CN', text: '普通话正文' }],
audioTracks: [
{ version: 'extended', languageCode: 'yue-HK', gender: 'female', playUrl: '/cantonese.mp3' },
{ version: 'extended', languageCode: 'zh-CN', gender: 'female' }
]
}, {
targetType: 'STOP',
targetId: '9001',
lang: 'zh-CN'
})
expect(result.supportedLanguages).toEqual(['zh-CN', 'yue-HK'])
expect(result.languageVariants['zh-CN']).toMatchObject({
playable: true,
playUrl: '/museum-assets/audio/zh.mp3',
duration: 50,
audioId: '12',
text: '普通话讲解词',
textLength: 6
})
expect(result.languageVariants['yue-HK']).toMatchObject({
playable: false,
textAvailable: true,
reason: 'NO_PUBLISHED_AUDIO'
})
})
it('keeps supportedLanguages as the compatibility fallback when variants are absent', () => {
const result = toGuideStopInfo({
supportedLanguages: ['zh-CN', 'en-US']
}, {
targetType: 'STOP',
targetId: '9001',
lang: 'zh-CN'
})
expect(result.supportedLanguages).toEqual(['zh-CN', 'en-US'])
expect(result.languageVariants).toEqual({})
})
it('uses playable audio options as the primary language and voice contract', () => {
const result = toGuideStopInfo({
supportedLanguages: ['zh-CN', 'yue-HK'],
audioOptions: [
{
channelCode: 'standard.zh-CN.male',
displayName: '普通话男声',
languageCode: 'zh-CN',
gender: 'male',
playUrl: '/museum-assets/audio/zh-male.mp3',
duration: '51',
isDefault: false,
sortOrder: 11
},
{
channelCode: 'standard.en-US.female',
displayName: '英文女声',
languageCode: 'en-US',
gender: 'female',
playUrl: '/museum-assets/audio/en-female.mp3',
duration: 49,
isDefault: true,
sortOrder: 20
},
{
channelCode: 'standard.zh-CN.female',
displayName: '普通话女声',
languageCode: 'zh-CN',
gender: 'female',
playUrl: '/museum-assets/audio/zh-female.mp3',
isDefault: true,
sortOrder: 10
},
{
channelCode: 'invalid',
languageCode: 'zh-CN',
gender: 'female'
}
]
}, {
targetType: 'STOP',
targetId: '9001',
lang: 'zh-CN'
})
expect(result.supportedLanguages).toEqual(['zh-CN', 'en-US'])
expect(result.audioOptions.map((option) => option.channelCode)).toEqual([
'standard.zh-CN.female',
'standard.zh-CN.male',
'standard.en-US.female'
])
expect(result.audioOptions[0]).toMatchObject({
displayName: '普通话女声',
gender: 'female',
playUrl: '/museum-assets/audio/zh-female.mp3',
isDefault: true
})
expect(detail.version).toBe('extended')
expect(detail.textVariants[0]?.text).toBe('普通话正文')
expect(detail.audioTracks).toEqual([expect.objectContaining({
channelCode: 'extended.yue-HK.female',
gender: 'female'
})])
})
})