修复:首页点位讲解入口展示逻辑
This commit is contained in:
@@ -99,15 +99,12 @@
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="selectedGuidePoiIsHall"
|
||||
v-if="selectedGuidePoiExplainHall"
|
||||
class="poi-card-actions"
|
||||
>
|
||||
<view class="poi-action primary" @tap="handleViewSelectedHall">
|
||||
<text class="poi-action-text">查看展厅</text>
|
||||
</view>
|
||||
<view class="poi-action" @tap="handleSelectedPoiRelated">
|
||||
<text class="poi-action-text">相关讲解</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
@@ -290,7 +287,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
|
||||
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
|
||||
@@ -400,6 +397,8 @@ const loadingFloorId = ref('')
|
||||
const renderedFloorId = ref('')
|
||||
const failedFloorId = ref('')
|
||||
const selectedGuidePoi = ref<GuideRenderPoi | null>(null)
|
||||
const selectedGuidePoiExplainHall = ref<MuseumHall | null>(null)
|
||||
let selectedGuidePoiExplainHallRequestId = 0
|
||||
|
||||
// 状态
|
||||
const currentTab = ref<GuideTopTab>(initialTopTab())
|
||||
@@ -714,9 +713,7 @@ const selectedGuidePoiSubtitle = computed(() => {
|
||||
return `${floorLabel} · ${poi.primaryCategoryZh || '位置预览'}`
|
||||
})
|
||||
|
||||
const selectedGuidePoiIsHall = computed(() => {
|
||||
const poi = selectedGuidePoi.value
|
||||
return Boolean(
|
||||
const isGuidePoiHallLike = (poi: GuideRenderPoi | null) => Boolean(
|
||||
poi
|
||||
&& (
|
||||
poi.kind === 'hall'
|
||||
@@ -725,10 +722,11 @@ const selectedGuidePoiIsHall = computed(() => {
|
||||
|| poi.primaryCategory === 'exhibition_hall_entrance'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
const selectedGuidePoiIsHall = computed(() => isGuidePoiHallLike(selectedGuidePoi.value))
|
||||
|
||||
const selectedGuidePoiCollapsedSubtitle = computed(() => (
|
||||
selectedGuidePoiIsHall.value ? '点按展开查看展厅' : selectedGuidePoiSubtitle.value
|
||||
selectedGuidePoiExplainHall.value ? '点按展开查看展厅' : selectedGuidePoiSubtitle.value
|
||||
))
|
||||
|
||||
const routeSimulationStepText = computed(() => {
|
||||
@@ -1132,12 +1130,10 @@ const togglePoiCardCollapsed = () => {
|
||||
const normalizeHallMatchText = (value?: string) => (value || '')
|
||||
.trim()
|
||||
.replace(/[\s()()【】[\]_-]/g, '')
|
||||
.replace(/^展厅\d+/, '')
|
||||
.toLowerCase()
|
||||
|
||||
const resolveSelectedPoiHall = async (): Promise<MuseumHall | null> => {
|
||||
const poi = selectedGuidePoi.value
|
||||
if (!poi) return null
|
||||
|
||||
const resolvePoiExplainHall = async (poi: GuideRenderPoi): Promise<MuseumHall | null> => {
|
||||
const halls = await explainUseCase.listHalls()
|
||||
const matchedByPoiId = halls.find((hall) => (
|
||||
hall.poiId === poi.id
|
||||
@@ -1162,10 +1158,30 @@ const resolveSelectedPoiHall = async (): Promise<MuseumHall | null> => {
|
||||
const poiHallName = normalizeHallMatchText(poi.hallName || poi.name)
|
||||
return halls.find((hall) => {
|
||||
const hallName = normalizeHallMatchText(hall.name)
|
||||
return hallName && poiHallName && (hallName.includes(poiHallName) || poiHallName.includes(hallName))
|
||||
return hallName && poiHallName && hallName === poiHallName
|
||||
}) || null
|
||||
}
|
||||
|
||||
watch(selectedGuidePoi, (poi) => {
|
||||
const requestId = ++selectedGuidePoiExplainHallRequestId
|
||||
selectedGuidePoiExplainHall.value = null
|
||||
if (!poi || !isGuidePoiHallLike(poi)) return
|
||||
|
||||
void resolvePoiExplainHall(poi)
|
||||
.then((hall) => {
|
||||
if (
|
||||
requestId !== selectedGuidePoiExplainHallRequestId
|
||||
|| selectedGuidePoi.value?.id !== poi.id
|
||||
) return
|
||||
|
||||
selectedGuidePoiExplainHall.value = hall
|
||||
})
|
||||
.catch((error) => {
|
||||
if (requestId !== selectedGuidePoiExplainHallRequestId) return
|
||||
console.warn('点位讲解展厅关联解析失败:', error)
|
||||
})
|
||||
}, { flush: 'sync' })
|
||||
|
||||
const navigateToPoiDetail = ({
|
||||
url,
|
||||
floorId,
|
||||
@@ -1209,43 +1225,12 @@ const navigateToHallExplainObjects = (hallId: string, hallName = '讲解') => {
|
||||
)
|
||||
}
|
||||
|
||||
const handleViewSelectedHall = async () => {
|
||||
const hall = await resolveSelectedPoiHall()
|
||||
if (!hall) {
|
||||
uni.showToast({
|
||||
title: '该展厅详情暂未接入',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const handleViewSelectedHall = () => {
|
||||
const hall = selectedGuidePoiExplainHall.value
|
||||
if (!hall) return
|
||||
navigateToHallExplainObjects(hall.id, hall.name)
|
||||
}
|
||||
|
||||
const handleSelectedPoiRelated = async () => {
|
||||
if (!selectedGuidePoi.value) return
|
||||
|
||||
const hall = await resolveSelectedPoiHall()
|
||||
if (hall) {
|
||||
navigateToHallExplainObjects(hall.id, hall.name)
|
||||
return
|
||||
}
|
||||
|
||||
const keyword = selectedGuidePoi.value.hallName || selectedGuidePoi.value.name
|
||||
const results = await explainUseCase.searchExplain(keyword)
|
||||
const firstHall = results.find((item) => item.type === 'hall' && item.hallId)
|
||||
|
||||
if (firstHall?.hallId) {
|
||||
navigateToHallExplainObjects(firstHall.hallId, selectedGuidePoi.value.hallName || '讲解')
|
||||
return
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '该展厅暂无对应讲解',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
const loadRouteTargets = async (keyword = '') => {
|
||||
routeTargetsLoading.value = true
|
||||
routeTargetsError.value = ''
|
||||
|
||||
@@ -528,7 +528,7 @@ describe('首页搜索与地图闭环', () => {
|
||||
expect(testState.resetToViewBaselineCalls).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('模型点选展厅的相关讲解进入该展厅的讲解对象列表,并在返回时复位原楼层', async () => {
|
||||
it('模型点选展厅只显示一个讲解入口,并在返回时复位原楼层', async () => {
|
||||
testState.halls = [{ id: 'hall-l2', poiId: poi.id, name: '二层展厅' }]
|
||||
const wrapper = await mountIndex()
|
||||
const map = wrapper.getComponent(GuideMapShellStub)
|
||||
@@ -541,9 +541,10 @@ describe('首页搜索与地图闭环', () => {
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
const relatedActions = wrapper.findAll('.poi-action')
|
||||
expect(relatedActions).toHaveLength(2)
|
||||
await relatedActions[1]!.trigger('tap')
|
||||
const actions = wrapper.findAll('.poi-action')
|
||||
expect(actions).toHaveLength(1)
|
||||
expect(wrapper.text()).not.toContain('相关讲解')
|
||||
await wrapper.find('.poi-action.primary').trigger('tap')
|
||||
await flushPromises()
|
||||
|
||||
expect(vi.mocked(uni.navigateTo).mock.calls[0]?.[0]?.url).toContain('/pages/explain/guide-stop-list?hallId=hall-l2')
|
||||
@@ -559,7 +560,54 @@ describe('首页搜索与地图闭环', () => {
|
||||
expect(wrapper.find('.guide-poi-card').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('模型点选展厅的相关讲解优先进入讲解对象列表并保留一次性返回上下文', async () => {
|
||||
it('展厅类型空间没有讲解展厅关联时不显示展厅与讲解按钮', async () => {
|
||||
testState.halls = [{ id: 'hall-biology', poiId: 'another-poi', name: '生物厅' }]
|
||||
const wrapper = await mountIndex()
|
||||
const map = wrapper.getComponent(GuideMapShellStub)
|
||||
|
||||
map.vm.$emit('poi-click', {
|
||||
...poi,
|
||||
id: 'space-l2-temporary',
|
||||
name: '生物厅临展空间',
|
||||
kind: 'space',
|
||||
hallId: 'space-l2-temporary',
|
||||
primaryCategory: 'exhibition_hall',
|
||||
primaryCategoryZh: '展厅'
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('.guide-poi-card').exists()).toBe(true)
|
||||
expect(wrapper.find('.poi-card-actions').exists()).toBe(false)
|
||||
expect(wrapper.text()).not.toContain('查看展厅')
|
||||
expect(wrapper.text()).not.toContain('相关讲解')
|
||||
})
|
||||
|
||||
it('展厅编号名称规范化后仍能关联真实讲解展厅', async () => {
|
||||
testState.halls = [{ id: 'hall-biology', name: '生物厅' }]
|
||||
const wrapper = await mountIndex()
|
||||
const map = wrapper.getComponent(GuideMapShellStub)
|
||||
|
||||
map.vm.$emit('poi-click', {
|
||||
...poi,
|
||||
id: 'hall-space-biology',
|
||||
name: '展厅_6生物厅',
|
||||
kind: 'space',
|
||||
hallId: 'space-biology',
|
||||
primaryCategory: 'exhibition_hall',
|
||||
primaryCategoryZh: '展厅'
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
const actions = wrapper.findAll('.poi-action')
|
||||
expect(actions).toHaveLength(1)
|
||||
await actions[0]!.trigger('tap')
|
||||
await flushPromises()
|
||||
expect(vi.mocked(uni.navigateTo).mock.calls[0]?.[0]?.url).toContain(
|
||||
'/pages/explain/guide-stop-list?hallId=hall-biology'
|
||||
)
|
||||
})
|
||||
|
||||
it('模型点选展厅的唯一讲解入口进入讲解对象列表并保留一次性返回上下文', async () => {
|
||||
testState.halls = [{ id: 'hall-l2', poiId: poi.id, name: '二层展厅' }]
|
||||
const wrapper = await mountIndex()
|
||||
const map = wrapper.getComponent(GuideMapShellStub)
|
||||
@@ -571,7 +619,7 @@ describe('首页搜索与地图闭环', () => {
|
||||
primaryCategoryZh: '展厅'
|
||||
})
|
||||
await flushPromises()
|
||||
await wrapper.findAll('.poi-action')[1]!.trigger('tap')
|
||||
await wrapper.find('.poi-action.primary').trigger('tap')
|
||||
await flushPromises()
|
||||
|
||||
expect(vi.mocked(uni.navigateTo).mock.calls[0]?.[0]?.url).toContain('/pages/explain/guide-stop-list?hallId=hall-l2')
|
||||
|
||||
Reference in New Issue
Block a user