@@ -234,6 +234,8 @@ const detailEntryRequest = ref<{
|
|||||||
floorId?: string
|
floorId?: string
|
||||||
floorLabel?: string
|
floorLabel?: string
|
||||||
poiId?: string
|
poiId?: string
|
||||||
|
returnToGuideStopList?: boolean
|
||||||
|
returnToHallList?: boolean
|
||||||
} | null>(null)
|
} | null>(null)
|
||||||
const detailTextByLanguage = ref<Record<AudioLanguage, string>>({
|
const detailTextByLanguage = ref<Record<AudioLanguage, string>>({
|
||||||
'zh-CN': defaultDetail.body,
|
'zh-CN': defaultDetail.body,
|
||||||
@@ -569,7 +571,13 @@ onLoad(async (options: any = {}) => {
|
|||||||
hallId: Array.isArray(options.hallId) ? options.hallId[0] : options.hallId,
|
hallId: Array.isArray(options.hallId) ? options.hallId[0] : options.hallId,
|
||||||
hallName: Array.isArray(options.hallName) ? options.hallName[0] : options.hallName,
|
hallName: Array.isArray(options.hallName) ? options.hallName[0] : options.hallName,
|
||||||
floorId: Array.isArray(options.floorId) ? options.floorId[0] : options.floorId,
|
floorId: Array.isArray(options.floorId) ? options.floorId[0] : options.floorId,
|
||||||
poiId: Array.isArray(options.poiId) ? options.poiId[0] : options.poiId
|
poiId: Array.isArray(options.poiId) ? options.poiId[0] : options.poiId,
|
||||||
|
returnToGuideStopList: (Array.isArray(options.returnToGuideStopList)
|
||||||
|
? options.returnToGuideStopList[0]
|
||||||
|
: options.returnToGuideStopList) === '1',
|
||||||
|
returnToHallList: (Array.isArray(options.returnToHallList)
|
||||||
|
? options.returnToHallList[0]
|
||||||
|
: options.returnToHallList) === '1'
|
||||||
}
|
}
|
||||||
await loadExplainDetail(detailEntryRequest.value, lang)
|
await loadExplainDetail(detailEntryRequest.value, lang)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -772,6 +780,12 @@ function buildDetailRoute(lang: AudioLanguage = selectedAudioLanguage.value) {
|
|||||||
if (lang) {
|
if (lang) {
|
||||||
params.set('lang', lang)
|
params.set('lang', lang)
|
||||||
}
|
}
|
||||||
|
if (request?.hallId) params.set('hallId', request.hallId)
|
||||||
|
if (request?.hallName) params.set('hallName', request.hallName)
|
||||||
|
if (request?.floorId) params.set('floorId', request.floorId)
|
||||||
|
if (request?.poiId) params.set('poiId', request.poiId)
|
||||||
|
if (request?.returnToGuideStopList) params.set('returnToGuideStopList', '1')
|
||||||
|
if (request?.returnToHallList) params.set('returnToHallList', '1')
|
||||||
return `/pages/exhibit/detail?${params.toString()}`
|
return `/pages/exhibit/detail?${params.toString()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -936,7 +950,9 @@ const fallbackToExplainObjectList = () => {
|
|||||||
const hallId = detailEntryRequest.value?.hallId || exhibit.value.hallId
|
const hallId = detailEntryRequest.value?.hallId || exhibit.value.hallId
|
||||||
const hallName = decodeRouteParam(detailEntryRequest.value?.hallName || exhibit.value.hallName || '讲解')
|
const hallName = decodeRouteParam(detailEntryRequest.value?.hallName || exhibit.value.hallName || '讲解')
|
||||||
const url = hallId
|
const url = hallId
|
||||||
? explainGuideStopListUrl(hallId, hallName)
|
? explainGuideStopListUrl(hallId, hallName, {
|
||||||
|
returnToHallList: detailEntryRequest.value?.returnToHallList
|
||||||
|
})
|
||||||
: '/pages/explain/list'
|
: '/pages/explain/list'
|
||||||
|
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
@@ -963,6 +979,11 @@ const returnToExplainObjectList = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (detailEntryRequest.value?.returnToGuideStopList) {
|
||||||
|
fallbackToExplainObjectList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (isEmbeddedInWechatMiniProgram()) {
|
if (isEmbeddedInWechatMiniProgram()) {
|
||||||
if (returningToMiniProgram) return
|
if (returningToMiniProgram) return
|
||||||
returningToMiniProgram = true
|
returningToMiniProgram = true
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ const explainError = ref('')
|
|||||||
const loadMoreError = ref('')
|
const loadMoreError = ref('')
|
||||||
const hasMore = ref(false)
|
const hasMore = ref(false)
|
||||||
const nextPageNo = ref(1)
|
const nextPageNo = ref(1)
|
||||||
|
const shouldReturnToHallList = ref(false)
|
||||||
let requestVersion = 0
|
let requestVersion = 0
|
||||||
let disposed = false
|
let disposed = false
|
||||||
let returningToMiniProgram = false
|
let returningToMiniProgram = false
|
||||||
@@ -119,6 +120,7 @@ onLoad((options: Record<string, string | string[] | undefined> = {}) => {
|
|||||||
const first = (value: string | string[] | undefined) => Array.isArray(value) ? value[0] : value
|
const first = (value: string | string[] | undefined) => Array.isArray(value) ? value[0] : value
|
||||||
selectedExplainHallId.value = first(options.hallId) || ''
|
selectedExplainHallId.value = first(options.hallId) || ''
|
||||||
selectedExplainHallName.value = first(options.hallName) || '讲解对象'
|
selectedExplainHallName.value = first(options.hallName) || '讲解对象'
|
||||||
|
shouldReturnToHallList.value = first(options.returnToHallList) === '1'
|
||||||
syncPageTitle('讲解对象')
|
syncPageTitle('讲解对象')
|
||||||
if (!selectedExplainHallId.value) {
|
if (!selectedExplainHallId.value) {
|
||||||
explainError.value = '缺少展厅参数,请返回展厅列表后重试'
|
explainError.value = '缺少展厅参数,请返回展厅列表后重试'
|
||||||
@@ -144,6 +146,8 @@ const handleExplainGuideStopClick = (stop: ExplainGuideStopCatalogItem) => {
|
|||||||
if (hallName) params.set('hallName', hallName)
|
if (hallName) params.set('hallName', hallName)
|
||||||
if (stop.floorId) params.set('floorId', stop.floorId)
|
if (stop.floorId) params.set('floorId', stop.floorId)
|
||||||
if (stop.poiId) params.set('poiId', stop.poiId)
|
if (stop.poiId) params.set('poiId', stop.poiId)
|
||||||
|
params.set('returnToGuideStopList', '1')
|
||||||
|
if (shouldReturnToHallList.value) params.set('returnToHallList', '1')
|
||||||
uni.navigateTo({ url: `/pages/exhibit/detail?${params.toString()}` })
|
uni.navigateTo({ url: `/pages/exhibit/detail?${params.toString()}` })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +177,12 @@ const returnToHallList = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// H5 web-view 有时不会暴露完整页面栈,保留入口上下文即可回到展厅列表。
|
||||||
|
if (shouldReturnToHallList.value) {
|
||||||
|
fallbackToHallList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (isEmbeddedInWechatMiniProgram()) {
|
if (isEmbeddedInWechatMiniProgram()) {
|
||||||
if (returningToMiniProgram) return
|
if (returningToMiniProgram) return
|
||||||
returningToMiniProgram = true
|
returningToMiniProgram = true
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ const handleTopTabChange = (tab: GuideTopTab) => {
|
|||||||
const handleExplainHallClick = (hallId: string) => {
|
const handleExplainHallClick = (hallId: string) => {
|
||||||
const hall = explainHallItems.value.find((item) => item.id === hallId)
|
const hall = explainHallItems.value.find((item) => item.id === hallId)
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: explainGuideStopListUrl(hallId, hall?.name || '讲解')
|
url: explainGuideStopListUrl(hallId, hall?.name || '讲解', { returnToHallList: true })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
export const explainGuideStopListUrl = (hallId: string, hallName = '讲解') => {
|
type ExplainGuideStopListNavigationOptions = {
|
||||||
|
returnToHallList?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const explainGuideStopListUrl = (
|
||||||
|
hallId: string,
|
||||||
|
hallName = '讲解',
|
||||||
|
options: ExplainGuideStopListNavigationOptions = {}
|
||||||
|
) => {
|
||||||
const params = new URLSearchParams({ hallId, hallName })
|
const params = new URLSearchParams({ hallId, hallName })
|
||||||
|
if (options.returnToHallList) params.set('returnToHallList', '1')
|
||||||
return `/pages/explain/guide-stop-list?${params.toString()}`
|
return `/pages/explain/guide-stop-list?${params.toString()}`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,6 +411,34 @@ describe('讲解详情音频优先布局', () => {
|
|||||||
expect(uni.redirectTo).not.toHaveBeenCalled()
|
expect(uni.redirectTo).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('从讲解对象列表进入时,即使 H5 页面栈缺失也回到对象列表', async () => {
|
||||||
|
mocks.embeddedInWechatMiniProgram = true
|
||||||
|
mocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'returned' })
|
||||||
|
const wrapper = mount(ExhibitDetail, {
|
||||||
|
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
|
||||||
|
})
|
||||||
|
|
||||||
|
await mocks.onLoadHandler?.({
|
||||||
|
id: exhibit.id,
|
||||||
|
targetType: 'STOP',
|
||||||
|
targetId: 'stop-1',
|
||||||
|
hallId: 'hall-1',
|
||||||
|
hallName: '恐龙厅',
|
||||||
|
returnToGuideStopList: '1',
|
||||||
|
returnToHallList: '1'
|
||||||
|
})
|
||||||
|
wrapper.getComponent(GuidePageFrameStub).vm.$emit('back')
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const url = vi.mocked(uni.redirectTo).mock.calls[0]?.[0]?.url || ''
|
||||||
|
const params = new URLSearchParams(url.split('?')[1])
|
||||||
|
expect(url.split('?')[0]).toBe('/pages/explain/guide-stop-list')
|
||||||
|
expect(params.get('hallId')).toBe('hall-1')
|
||||||
|
expect(params.get('returnToHallList')).toBe('1')
|
||||||
|
expect(mocks.returnToWechatMiniProgram).not.toHaveBeenCalled()
|
||||||
|
expect(uni.navigateBack).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
it('离开详情页时立即关闭当前讲解播放器', async () => {
|
it('离开详情页时立即关闭当前讲解播放器', async () => {
|
||||||
audioState.currentAudio.value = { id: 'audio-1', audioUrl: exhibit.audioUrl }
|
audioState.currentAudio.value = { id: 'audio-1', audioUrl: exhibit.audioUrl }
|
||||||
audioState.currentSource.value = { targetType: 'STOP', targetId: 'stop-1', lang: 'en-US' }
|
audioState.currentSource.value = { targetType: 'STOP', targetId: 'stop-1', lang: 'en-US' }
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ describe('讲解对象列表返回', () => {
|
|||||||
expect(params.get('hallName')).toBe('恐龙厅')
|
expect(params.get('hallName')).toBe('恐龙厅')
|
||||||
expect(params.get('targetType')).toBe('STOP')
|
expect(params.get('targetType')).toBe('STOP')
|
||||||
expect(params.get('targetId')).toBe('target-1')
|
expect(params.get('targetId')).toBe('target-1')
|
||||||
|
expect(params.get('returnToGuideStopList')).toBe('1')
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -192,6 +193,25 @@ describe('讲解对象列表返回', () => {
|
|||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('从展厅列表进入时,即使 H5 页面栈缺失也保留内部返回路径', async () => {
|
||||||
|
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
|
||||||
|
miniProgramReturnMocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'returned' })
|
||||||
|
const wrapper = mountGuideStopList()
|
||||||
|
testState.onLoadHandler?.({ hallId: 'hall-1', hallName: '恐龙厅', returnToHallList: '1' })
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
await wrapper.get('[data-testid="detail-click"]').trigger('click')
|
||||||
|
const detailUrl = vi.mocked(uni.navigateTo).mock.calls[0]?.[0]?.url || ''
|
||||||
|
expect(new URLSearchParams(detailUrl.split('?')[1]).get('returnToHallList')).toBe('1')
|
||||||
|
|
||||||
|
await wrapper.get('[data-testid="list-back"]').trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(uni.reLaunch).toHaveBeenCalledWith({ url: '/pages/explain/list' })
|
||||||
|
expect(miniProgramReturnMocks.returnToWechatMiniProgram).not.toHaveBeenCalled()
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
it('页面栈返回失败时回退至独立展厅列表', async () => {
|
it('页面栈返回失败时回退至独立展厅列表', async () => {
|
||||||
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
||||||
{ route: 'pages/explain/list', options: {} },
|
{ route: 'pages/explain/list', options: {} },
|
||||||
|
|||||||
Reference in New Issue
Block a user