@@ -218,7 +218,7 @@ const detailTextLoadedByLanguage = ref<Record<AudioLanguage, boolean>>({
|
|||||||
const isLocationActionVisible = false
|
const isLocationActionVisible = false
|
||||||
const shouldUseHostNavigation = computed(() => isEmbeddedInWechatMiniProgram())
|
const shouldUseHostNavigation = computed(() => isEmbeddedInWechatMiniProgram())
|
||||||
|
|
||||||
const contentLanguageOptions: Array<{
|
const languageOptionDefinitions: Array<{
|
||||||
value: AudioLanguage
|
value: AudioLanguage
|
||||||
label: string
|
label: string
|
||||||
}> = [
|
}> = [
|
||||||
@@ -240,6 +240,24 @@ const isAudioLanguage = (value: unknown): value is AudioLanguage => (
|
|||||||
value === 'zh-CN' || value === 'yue-HK' || value === 'en-US'
|
value === 'zh-CN' || value === 'yue-HK' || value === 'en-US'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const supportedDetailLanguages = computed(() => (
|
||||||
|
(exhibit.value.audio.supportedLanguages || []).filter(isAudioLanguage)
|
||||||
|
))
|
||||||
|
|
||||||
|
const contentLanguageOptions = computed(() => {
|
||||||
|
const supportedLanguages = supportedDetailLanguages.value
|
||||||
|
return languageOptionDefinitions.filter((option) => supportedLanguages.includes(option.value))
|
||||||
|
})
|
||||||
|
|
||||||
|
const resolveSupportedDetailLanguage = (requestedLanguage: AudioLanguage) => {
|
||||||
|
const supportedLanguages = supportedDetailLanguages.value
|
||||||
|
if (!supportedLanguages.length || supportedLanguages.includes(requestedLanguage)) {
|
||||||
|
return requestedLanguage
|
||||||
|
}
|
||||||
|
|
||||||
|
return supportedLanguages.includes('zh-CN') ? 'zh-CN' : supportedLanguages[0]
|
||||||
|
}
|
||||||
|
|
||||||
const audioLanguageLabel = (lang: AudioLanguage) => {
|
const audioLanguageLabel = (lang: AudioLanguage) => {
|
||||||
if (lang === 'en-US') return 'English'
|
if (lang === 'en-US') return 'English'
|
||||||
if (lang === 'yue-HK') return '粤语'
|
if (lang === 'yue-HK') return '粤语'
|
||||||
@@ -446,13 +464,20 @@ const loadExplainDetail = async (
|
|||||||
})
|
})
|
||||||
|
|
||||||
exhibit.value = toExplainDetailPageViewModel(exhibitData)
|
exhibit.value = toExplainDetailPageViewModel(exhibitData)
|
||||||
selectedAudioLanguage.value = lang
|
const resolvedLanguage = resolveSupportedDetailLanguage(lang)
|
||||||
|
selectedAudioLanguage.value = resolvedLanguage
|
||||||
|
|
||||||
if (exhibitData.hallId) {
|
if (exhibitData.hallId) {
|
||||||
resolvedHallId.value = exhibitData.hallId
|
resolvedHallId.value = exhibitData.hallId
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadFullDetailTextForLanguage(request, lang, exhibit.value)
|
if (resolvedLanguage !== lang) {
|
||||||
|
replaceDetailRouteLanguage(resolvedLanguage)
|
||||||
|
await loadExplainDetail(request, resolvedLanguage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadFullDetailTextForLanguage(request, resolvedLanguage, exhibit.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad(async (options: any = {}) => {
|
onLoad(async (options: any = {}) => {
|
||||||
@@ -581,7 +606,11 @@ const replaceDetailRouteLanguage = (lang: AudioLanguage) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleLanguageChange = async (lang: AudioLanguage, options: { syncAudio?: boolean } = {}) => {
|
const handleLanguageChange = async (lang: AudioLanguage, options: { syncAudio?: boolean } = {}) => {
|
||||||
if (lang === selectedAudioLanguage.value || languageSwitchLoading.value) return
|
if (
|
||||||
|
lang === selectedAudioLanguage.value
|
||||||
|
|| languageSwitchLoading.value
|
||||||
|
|| (supportedDetailLanguages.value.length > 0 && !supportedDetailLanguages.value.includes(lang))
|
||||||
|
) return
|
||||||
|
|
||||||
const shouldSyncAudio = options.syncAudio !== false && isCurrentDetailAudioTarget.value
|
const shouldSyncAudio = options.syncAudio !== false && isCurrentDetailAudioTarget.value
|
||||||
const request = detailEntryRequest.value
|
const request = detailEntryRequest.value
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ const exhibit = {
|
|||||||
audioLanguage: 'en-US',
|
audioLanguage: 'en-US',
|
||||||
audioHasText: false,
|
audioHasText: false,
|
||||||
playTargetType: 'STOP',
|
playTargetType: 'STOP',
|
||||||
playTargetId: 'stop-1'
|
playTargetId: 'stop-1',
|
||||||
|
supportedLanguages: ['zh-CN', 'yue-HK', 'en-US']
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('讲解详情音频优先布局', () => {
|
describe('讲解详情音频优先布局', () => {
|
||||||
@@ -148,6 +149,59 @@ describe('讲解详情音频优先布局', () => {
|
|||||||
expect(wrapper.get('.section-text').text()).toContain('detailed English narration')
|
expect(wrapper.get('.section-text').text()).toContain('detailed English narration')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('仅展示 stop-info 声明支持的语言按钮', async () => {
|
||||||
|
mocks.enterExplainDetail.mockResolvedValue({
|
||||||
|
...exhibit,
|
||||||
|
supportedLanguages: ['zh-CN', 'en-US']
|
||||||
|
})
|
||||||
|
const wrapper = mount(ExhibitDetail, {
|
||||||
|
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
|
||||||
|
})
|
||||||
|
|
||||||
|
await mocks.onLoadHandler?.({ id: exhibit.id, lang: 'zh-CN', targetType: 'STOP', targetId: 'stop-1' })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const labels = wrapper.findAll('.language-option-text').map((node) => node.text())
|
||||||
|
expect(labels).toEqual(['中文', 'English'])
|
||||||
|
expect(labels).not.toContain('粤语')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('无支持语言时不显示语言栏', async () => {
|
||||||
|
mocks.enterExplainDetail.mockResolvedValue({
|
||||||
|
...exhibit,
|
||||||
|
supportedLanguages: []
|
||||||
|
})
|
||||||
|
const wrapper = mount(ExhibitDetail, {
|
||||||
|
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
|
||||||
|
})
|
||||||
|
|
||||||
|
await mocks.onLoadHandler?.({ id: exhibit.id, lang: 'zh-CN', targetType: 'STOP', targetId: 'stop-1' })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.find('.detail-language-bar').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('深链语言不受支持时回退至中文并规范化地址', async () => {
|
||||||
|
mocks.enterExplainDetail.mockImplementation(async (request: { lang: string }) => ({
|
||||||
|
...exhibit,
|
||||||
|
audioLanguage: request.lang,
|
||||||
|
supportedLanguages: ['zh-CN']
|
||||||
|
}))
|
||||||
|
const replaceState = vi.spyOn(window.history, 'replaceState')
|
||||||
|
const wrapper = mount(ExhibitDetail, {
|
||||||
|
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
|
||||||
|
})
|
||||||
|
|
||||||
|
await mocks.onLoadHandler?.({ id: exhibit.id, lang: 'en-US', targetType: 'STOP', targetId: 'stop-1' })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(mocks.enterExplainDetail).toHaveBeenNthCalledWith(1, expect.objectContaining({ lang: 'en-US' }))
|
||||||
|
expect(mocks.enterExplainDetail).toHaveBeenNthCalledWith(2, expect.objectContaining({ lang: 'zh-CN' }))
|
||||||
|
expect(wrapper.get('.language-option').classes()).toContain('active')
|
||||||
|
expect(wrapper.get('.language-option-text').text()).toBe('中文')
|
||||||
|
expect(replaceState).toHaveBeenCalledWith(null, '', expect.stringContaining('lang=zh-CN'))
|
||||||
|
})
|
||||||
|
|
||||||
it('通过同一全局音频播放器开始播放,不创建页面播放器', async () => {
|
it('通过同一全局音频播放器开始播放,不创建页面播放器', async () => {
|
||||||
const wrapper = mount(ExhibitDetail, {
|
const wrapper = mount(ExhibitDetail, {
|
||||||
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
|
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
|
||||||
|
|||||||
Reference in New Issue
Block a user