同步 sgs-frontend-mobile 源码
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-27 11:26:01 +08:00
parent 575dca430f
commit 9ea1bfab71
181 changed files with 24395 additions and 5212 deletions

View File

@@ -4,6 +4,10 @@ import { defineComponent } from 'vue'
import { mount } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
import {
clearGuidePerformanceRecords,
getGuidePerformanceRecords
} from '@/services/performance/guidePerformance'
const ThreeMapStub = defineComponent({
name: 'ThreeMap',
@@ -25,9 +29,20 @@ const ThreeMapStub = defineComponent({
default: null
}
},
emits: ['floor-change', 'target-focus'],
emits: ['floor-change', 'target-focus', 'auto-switch', 'render-mode-fallback'],
setup(_, { expose }) {
expose({ switchFloor: vi.fn() })
expose({
switchFloor: vi.fn(),
showMultiFloor: vi.fn(async () => true),
getGuideViewportState: vi.fn(() => ({
scene: 'floor',
floorId: 'L1',
centerX: 29.0598,
centerZ: 23.9424,
visibleWorldSpan: 270.39,
revision: 1
}))
})
return {}
},
template: '<div data-testid="three-map"></div>'
@@ -57,6 +72,73 @@ const mountShell = (visiblePoiIds: string[] | null) => mount(GuideMapShell, {
})
describe('GuideMapShell 点位过滤契约', () => {
it('馆内渲染模式使用单个开关,二维外观不显示楼层列表', async () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [{ id: 'L1', label: '1F' }, { id: 'L2', label: '2F' }],
activeFloor: 'L1',
indoorView: 'overview',
indoorInitialView: 'overview',
indoorRenderMode: 'two-d',
showIndoorRenderModeToggle: true,
showFloor: true,
showFloorHeader: true,
showLayerModeToggle: true
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
const toggle = wrapper.get('[data-testid="indoor-render-mode-toggle"]')
expect(toggle.text()).toBe('2D')
expect(wrapper.findAll('[data-testid="indoor-render-mode-toggle"]')).toHaveLength(1)
expect(wrapper.find('.floor-switcher').exists()).toBe(false)
expect(wrapper.find('.floor-header').exists()).toBe(false)
expect(wrapper.find('.layer-mode-toggle').exists()).toBe(false)
await toggle.trigger('tap')
expect(wrapper.emitted('indoorRenderModeChange')).toEqual([['three-d']])
expect(wrapper.emitted('sceneViewportChange')).toBeUndefined()
})
it('二维单层视图仍显示楼层栏,楼层栏只取决于业务场景', () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [{ id: 'L1', label: '1F' }, { id: 'L2', label: '2F' }],
activeFloor: 'L1',
indoorView: 'floor',
indoorRenderMode: 'two-d',
showFloor: true,
showFloorHeader: true
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
expect(wrapper.find('.floor-switcher').exists()).toBe(true)
expect(wrapper.find('.floor-header').exists()).toBe(false)
})
it('外观路线和起点选择状态也不会显示室内楼层栏', () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [{ id: 'L1', label: '1F' }, { id: 'L2', label: '2F' }],
activeFloor: 'L1',
indoorView: 'overview',
showFloor: true,
showRoute: true,
routeStartSelectionActive: true
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
expect(wrapper.find('.floor-switcher').exists()).toBe(false)
})
it.each([
['不过滤时透传 null', null],
['无结果时透传空列表', []],
@@ -84,6 +166,32 @@ describe('GuideMapShell 点位过滤契约', () => {
expect(wrapper.emitted('targetFocus')).toEqual([[focusResult]])
})
it('忽略旧渲染版本的 WebP 回退事件', async () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [{ id: 'L1', label: '1F' }, { id: 'L2', label: '2F' }],
activeFloor: 'L1',
indoorView: 'floor',
sceneRevision: 2
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
const renderer = wrapper.getComponent(ThreeMapStub)
renderer.vm.$emit('render-mode-fallback', {
mode: 'two-d',
view: 'floor',
floorId: 'L2',
reason: 'model-load-timeout',
sceneRevision: 1
})
await wrapper.vm.$nextTick()
expect(wrapper.emitted('indoorRenderModeFallback')).toBeUndefined()
})
it('动态楼层业务视图不会覆盖首次外观模型初始化视图', () => {
const wrapper = mount(GuideMapShell, {
props: {
@@ -131,4 +239,137 @@ describe('GuideMapShell 点位过滤契约', () => {
await wrapper.vm.$nextTick()
expect(wrapper.emitted('indoorViewChange')).toEqual([['floor']])
})
it('measures a manual floor switch until ThreeMap commits the target floor', async () => {
clearGuidePerformanceRecords()
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [
{ id: 'L1', label: '1F' },
{ id: 'L2', label: '2F' }
],
activeFloor: 'L1',
indoorView: 'floor'
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
const renderer = wrapper.getComponent(ThreeMapStub)
;(wrapper.vm as any).switchFloor('L2')
renderer.vm.$emit('floor-change', 'L2')
await wrapper.vm.$nextTick()
expect(getGuidePerformanceRecords()).toEqual(expect.arrayContaining([
expect.objectContaining({
kind: 'interaction',
name: 'floor-switch',
outcome: 'success',
detail: expect.objectContaining({ floorId: 'L2', source: 'manual' })
})
]))
})
it('起点选择阶段处于外观视图时仍隐藏室内楼层栏', () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [
{ id: 'L1', label: '1F' },
{ id: 'L2', label: '2F' }
],
activeFloor: 'L1',
indoorView: 'overview',
showFloor: true,
routeStartSelectionActive: true
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
expect(wrapper.find('.floor-switcher').exists()).toBe(false)
})
it('ThreeMap 自动切换由父级提交后隐藏楼层栏', async () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [
{ id: 'L1', label: '1F' },
{ id: 'L2', label: '2F' }
],
activeFloor: 'L1',
indoorView: 'floor',
showFloor: true
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
const renderer = wrapper.getComponent(ThreeMapStub)
expect(wrapper.find('.floor-switcher').exists()).toBe(true)
renderer.vm.$emit('auto-switch', {
from: 'floor',
to: 'overview',
trigger: 'zoom-out',
distance: 320
})
await wrapper.vm.$nextTick()
expect(wrapper.find('.floor-switcher').exists()).toBe(true)
expect(wrapper.emitted('autoSwitch')).toHaveLength(1)
await wrapper.setProps({ indoorView: 'overview' })
expect(wrapper.find('.floor-switcher').exists()).toBe(false)
})
it('多层视图只显示单层切换按钮,不显示单层楼层列表', () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [
{ id: 'L1', label: '1F' },
{ id: 'L2', label: '2F' }
],
activeFloor: 'L2',
indoorView: 'multi',
layerMode: 'multi',
showFloor: true,
showFloorHeader: true
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
expect(wrapper.find('.floor-header-label').text()).toBe('单层')
expect(wrapper.find('.floor-list').exists()).toBe(false)
})
it('父组件楼层短暂为空时,仍用最后提交的楼层返回单层', async () => {
const wrapper = mount(GuideMapShell, {
props: {
mapType: 'indoor',
indoorModelSource: modelSource,
floors: [
{ id: 'L1', label: '1F' },
{ id: 'L2', label: '2F' }
],
activeFloor: 'L1',
indoorView: 'floor',
layerMode: 'single',
showFloor: true,
showFloorHeader: true
},
global: { stubs: { ThreeMap: ThreeMapStub } }
})
const renderer = wrapper.getComponent(ThreeMapStub)
await (wrapper.vm as any).setLayerMode('multi')
await wrapper.setProps({ indoorView: 'multi', layerMode: 'multi', activeFloor: '' })
await (wrapper.vm as any).setLayerMode('single')
await new Promise((resolve) => setTimeout(resolve, 0))
expect((renderer.vm as any).switchFloor).toHaveBeenCalledWith('L1')
})
})