统一首页点位详情目标解析

This commit is contained in:
cxk
2026-07-20 08:09:58 +08:00
parent 153be754a9
commit 298e7d7606
5 changed files with 388 additions and 133 deletions

View File

@@ -20,6 +20,12 @@ const testState = vi.hoisted(() => ({
searchResetCount: 0,
onShowHandler: null as null | (() => Promise<void> | void),
halls: [] as Array<{ id: string; poiId?: string; location?: { poiId?: string }; name: string }>,
hallResolutionPromises: [] as Array<Promise<Array<{
id: string
poiId?: string
location?: { poiId?: string }
name: string
}>>>,
explainResults: [] as Array<{
type: 'hall' | 'exhibit'
hallId?: string
@@ -76,7 +82,9 @@ vi.mock('@/usecases/explainUseCase', () => ({
explainUseCase: {
loadExplainHalls: async () => [],
loadExplainHallSummaries: async () => ({}),
listHalls: async () => testState.halls,
listHalls: async () => (
testState.hallResolutionPromises.shift() || Promise.resolve(testState.halls)
),
searchExplain: async () => testState.explainResults
}
}))
@@ -211,6 +219,7 @@ beforeEach(() => {
testState.searchResetCount = 0
testState.onShowHandler = null
testState.halls = []
testState.hallResolutionPromises = []
testState.explainResults = []
window.history.replaceState({}, '', '/#/pages/index/index?tab=guide')
vi.stubGlobal('uni', {
@@ -403,15 +412,10 @@ describe('首页搜索与地图闭环', () => {
const navigateTo = vi.mocked(uni.navigateTo)
const detailUrl = navigateTo.mock.calls[0]?.[0]?.url as string
const query = new URLSearchParams(detailUrl.split('?')[1])
expect(query.get('source')).toBe('search')
expect(query.get('searchOrigin')).toBe('home')
expect(query.get('searchKeyword')).toBe('卫生间')
expect(query.get('searchCategoryId')).toBe('restroom')
expect(query.get('searchFloorId')).toBe('L2')
expect(query.get('resultCount')).toBe('2')
expect(query.get('floorResultCount')).toBe('2')
expect(query.get('visiblePoiIds')).toBe(categoryContext.visiblePoiIds.join(','))
expect(query.get('listScrollTop')).toBe('126')
expect(query.get('source')).toBe('guide-poi')
expect(query.get('id')).toBe(poi.id)
expect(query.get('floorId')).toBe('L2')
expect(query.has('searchKeyword')).toBe(false)
expect(testState.searchMountCount).toBe(1)
expect(testState.searchUnmountCount).toBe(0)
@@ -422,7 +426,7 @@ describe('首页搜索与地图闭环', () => {
expect(testState.searchResetCount).toBe(0)
expect(testState.searchRestoreCount).toBeGreaterThan(0)
expect(map.props('activeFloor')).toBe('L2')
expect(map.props('visiblePoiIds')).toBeNull()
expect(map.props('visiblePoiIds')).toEqual(categoryContext.visiblePoiIds)
expect(map.props('targetFocusRequest')).toBeNull()
const resetCount = testState.searchResetCount
@@ -560,7 +564,74 @@ describe('首页搜索与地图闭环', () => {
expect(wrapper.find('.guide-poi-card').exists()).toBe(false)
})
it('展厅类型空间没有讲解展厅关联时不显示展厅与讲解按钮', async () => {
it('同一个展厅从地图和搜索进入时使用相同详情路由和 hallId', async () => {
const hallPoi = {
...poi,
kind: 'hall' as const,
hallId: 'hall-l2',
primaryCategory: { id: 'exhibition_hall', label: '展厅' }
}
testState.halls = [{ id: 'hall-l2', poiId: poi.id, name: '二层展厅' }]
const wrapper = await mountIndex()
const map = wrapper.getComponent(GuideMapShellStub)
const search = wrapper.getComponent(PoiSearchPanelStub)
map.vm.$emit('poi-click', {
...hallPoi,
primaryCategory: 'exhibition_hall',
primaryCategoryZh: '展厅'
})
await flushPromises()
await wrapper.find('.poi-action.primary').trigger('tap')
await flushPromises()
const mapUrl = vi.mocked(uni.navigateTo).mock.calls.at(-1)?.[0]?.url as string
vi.mocked(uni.navigateTo).mock.calls.at(-1)?.[0]?.fail?.({ errMsg: 'navigateTo:fail test cleanup' })
search.vm.$emit('result-tap', hallPoi, categoryContext)
await flushPromises()
const searchUrl = vi.mocked(uni.navigateTo).mock.calls.at(-1)?.[0]?.url as string
const mapRoute = mapUrl.split('?')[0]
const searchRoute = searchUrl.split('?')[0]
const mapQuery = new URLSearchParams(mapUrl.split('?')[1])
const searchQuery = new URLSearchParams(searchUrl.split('?')[1])
expect(mapRoute).toBe('/pages/explain/guide-stop-list')
expect(searchRoute).toBe(mapRoute)
expect(mapQuery.get('hallId')).toBe('hall-l2')
expect(searchQuery.get('hallId')).toBe(mapQuery.get('hallId'))
expect(searchUrl).toBe(mapUrl)
})
it('同一个普通设施从地图和搜索进入时都解析为设施详情', async () => {
const wrapper = await mountIndex()
const map = wrapper.getComponent(GuideMapShellStub)
const search = wrapper.getComponent(PoiSearchPanelStub)
map.vm.$emit('poi-click', {
...poi,
primaryCategory: 'restroom',
primaryCategoryZh: '卫生间'
})
await flushPromises()
await wrapper.find('.poi-card-collapsed').trigger('tap')
await wrapper.vm.$nextTick()
await wrapper.find('.poi-action.primary').trigger('tap')
await flushPromises()
const mapUrl = vi.mocked(uni.navigateTo).mock.calls.at(-1)?.[0]?.url as string
vi.mocked(uni.navigateTo).mock.calls.at(-1)?.[0]?.fail?.({ errMsg: 'navigateTo:fail test cleanup' })
search.vm.$emit('result-tap', poi, categoryContext)
await flushPromises()
const searchUrl = vi.mocked(uni.navigateTo).mock.calls.at(-1)?.[0]?.url as string
expect(mapUrl.split('?')[0]).toBe('/pages/facility/detail')
expect(searchUrl.split('?')[0]).toBe('/pages/facility/detail')
expect(new URLSearchParams(mapUrl.split('?')[1]).get('id')).toBe(poi.id)
expect(new URLSearchParams(searchUrl.split('?')[1]).get('id')).toBe(poi.id)
expect(searchUrl).toBe(mapUrl)
})
it('展厅类型空间没有讲解展厅关联时只进入普通点位详情,不显示虚假讲解入口', async () => {
testState.halls = [{ id: 'hall-biology', poiId: 'another-poi', name: '生物厅' }]
const wrapper = await mountIndex()
const map = wrapper.getComponent(GuideMapShellStub)
@@ -577,9 +648,53 @@ describe('首页搜索与地图闭环', () => {
await flushPromises()
expect(wrapper.find('.guide-poi-card').exists()).toBe(true)
expect(wrapper.find('.poi-card-actions').exists()).toBe(false)
expect(wrapper.find('.poi-card-actions').exists()).toBe(true)
expect(wrapper.text()).not.toContain('查看展厅')
expect(wrapper.text()).not.toContain('相关讲解')
expect(wrapper.text()).toContain('查看详情')
await wrapper.find('.poi-action.primary').trigger('tap')
await flushPromises()
expect(vi.mocked(uni.navigateTo).mock.calls[0]?.[0]?.url).toContain('/pages/facility/detail?')
})
it('快速切换点位时忽略上一个点位较晚返回的展厅关联结果', async () => {
let resolveFirst!: (halls: typeof testState.halls) => void
let resolveSecond!: (halls: typeof testState.halls) => void
testState.hallResolutionPromises = [
new Promise((resolve) => { resolveFirst = resolve }),
new Promise((resolve) => { resolveSecond = resolve })
]
const wrapper = await mountIndex()
const map = wrapper.getComponent(GuideMapShellStub)
const firstPoi = {
...poi,
id: 'poi-hall-first',
kind: 'hall' as const,
hallId: 'hall-first',
primaryCategory: 'exhibition_hall',
primaryCategoryZh: '展厅'
}
const secondPoi = {
...poi,
id: 'poi-hall-second',
kind: 'hall' as const,
hallId: 'hall-second',
primaryCategory: 'exhibition_hall',
primaryCategoryZh: '展厅'
}
map.vm.$emit('poi-click', firstPoi)
map.vm.$emit('poi-click', secondPoi)
resolveSecond([{ id: 'hall-second', poiId: secondPoi.id, name: '第二展厅' }])
await flushPromises()
resolveFirst([{ id: 'hall-first', poiId: firstPoi.id, name: '第一展厅' }])
await flushPromises()
expect(wrapper.text()).toContain(secondPoi.name)
await wrapper.find('.poi-action.primary').trigger('tap')
await flushPromises()
const url = vi.mocked(uni.navigateTo).mock.calls[0]?.[0]?.url as string
expect(new URLSearchParams(url.split('?')[1]).get('hallId')).toBe('hall-second')
})
it('展厅编号名称规范化后仍能关联真实讲解展厅', async () => {
@@ -746,7 +861,7 @@ describe('首页搜索与地图闭环', () => {
expect(testState.resetToViewBaselineCalls).toHaveLength(0)
})
it('单结果分类写入 resultCount=1,主动取消恢复默认标记并清除目标', async () => {
it('单结果分类使用统一详情目标,主动取消恢复默认标记并清除目标', async () => {
const wrapper = await mountIndex()
const search = wrapper.getComponent(PoiSearchPanelStub)
const map = wrapper.getComponent(GuideMapShellStub)
@@ -762,7 +877,7 @@ describe('首页搜索与地图闭环', () => {
await flushPromises()
const detailUrl = vi.mocked(uni.navigateTo).mock.calls[0]?.[0]?.url as string
expect(new URLSearchParams(detailUrl.split('?')[1]).get('resultCount')).toBe('1')
expect(new URLSearchParams(detailUrl.split('?')[1]).get('source')).toBe('guide-poi')
expect(map.props('targetFocusRequest')).toBeNull()
search.vm.$emit('cancel')