feat(home-banner): 轮播支持 PC/移动两端分图与热区跳转,热区图悬浮放大;修复上传压缩压白透明 PNG
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
BANNER_HOTSPOT_DEFAULT_HOVER_SCALE,
|
||||
createBannerHotspot,
|
||||
hasBannerImage,
|
||||
mergeHomeConfig,
|
||||
normalizeHomeBanner,
|
||||
} from './homeConfig'
|
||||
|
||||
describe('normalizeHomeBanner', () => {
|
||||
it('把旧的扁平 image_url 结构升级为 PC / 移动两端共用同一张图', () => {
|
||||
const banner = normalizeHomeBanner({
|
||||
title: '旧结构',
|
||||
eyebrow: '首页',
|
||||
tone: 'green',
|
||||
image_url: ' https://cdn.example/legacy.png ',
|
||||
})
|
||||
|
||||
expect(banner.pc.image_url).toBe('https://cdn.example/legacy.png')
|
||||
expect(banner.mobile.image_url).toBe('https://cdn.example/legacy.png')
|
||||
expect(banner.tone).toBe('green')
|
||||
expect(banner.enabled).toBe(true)
|
||||
expect(banner.pc.hotspots).toEqual([])
|
||||
})
|
||||
|
||||
it('两端分别配图时互不覆盖', () => {
|
||||
const banner = normalizeHomeBanner({
|
||||
title: '两端分图',
|
||||
pc: { image_url: 'https://cdn.example/pc.png' },
|
||||
mobile: { image_url: 'https://cdn.example/mobile.png' },
|
||||
})
|
||||
|
||||
expect(banner.pc.image_url).toBe('https://cdn.example/pc.png')
|
||||
expect(banner.mobile.image_url).toBe('https://cdn.example/mobile.png')
|
||||
})
|
||||
|
||||
it('只配移动图时 PC 端不会误用移动图', () => {
|
||||
const banner = normalizeHomeBanner({
|
||||
title: '仅移动图',
|
||||
mobile: { image_url: 'https://cdn.example/mobile.png' },
|
||||
})
|
||||
|
||||
expect(banner.pc.image_url).toBe('')
|
||||
expect(banner.mobile.image_url).toBe('https://cdn.example/mobile.png')
|
||||
expect(hasBannerImage(banner.pc)).toBe(false)
|
||||
})
|
||||
|
||||
it('收敛热区坐标并丢弃无效热区', () => {
|
||||
const banner = normalizeHomeBanner({
|
||||
title: '热区',
|
||||
pc: {
|
||||
image_url: '/pc.png',
|
||||
hotspots: [
|
||||
{
|
||||
id: ' h1 ',
|
||||
x: 90,
|
||||
y: 95,
|
||||
width: 20,
|
||||
height: 20,
|
||||
action: { type: 'route', target: '/x' },
|
||||
},
|
||||
{ id: 'zero', y: 10, width: 0, height: 10, action: { type: 'route', target: '/x' } },
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
expect(banner.pc.hotspots).toHaveLength(1)
|
||||
expect(banner.pc.hotspots[0]).toMatchObject({ id: 'h1', x: 80, y: 80 })
|
||||
})
|
||||
|
||||
it('缺失目标的跳转退化为不跳转,避免死热区', () => {
|
||||
const banner = normalizeHomeBanner({
|
||||
title: '死区',
|
||||
pc: { image_url: '/pc.png', action: { type: 'route', target: ' ' } },
|
||||
mobile: { image_url: '/m.png', action: { type: 'link', target: 'https://a.example' } },
|
||||
})
|
||||
|
||||
expect(banner.pc.action).toEqual({ type: 'none', target: '', open_new_tab: false })
|
||||
expect(banner.mobile.action).toEqual({
|
||||
type: 'link',
|
||||
target: 'https://a.example',
|
||||
open_new_tab: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('热区按钮图去空格,悬浮倍数默认与收敛', () => {
|
||||
const banner = normalizeHomeBanner({
|
||||
title: '按钮图',
|
||||
pc: {
|
||||
image_url: '/pc.png',
|
||||
hotspots: [
|
||||
{ id: 'a', width: 20, height: 20, image_url: ' https://cdn.example/btn.png ' },
|
||||
{ id: 'b', width: 20, height: 20, hover_scale: 9 },
|
||||
{ id: 'c', width: 20, height: 20, hover_scale: 0.5 },
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
expect(banner.pc.hotspots[0]?.image_url).toBe('https://cdn.example/btn.png')
|
||||
expect(banner.pc.hotspots[0]?.hover_scale).toBe(BANNER_HOTSPOT_DEFAULT_HOVER_SCALE)
|
||||
expect(banner.pc.hotspots[1]?.hover_scale).toBe(1.5)
|
||||
expect(banner.pc.hotspots[2]?.hover_scale).toBe(1)
|
||||
})
|
||||
|
||||
it('保留停用标记', () => {
|
||||
expect(normalizeHomeBanner({ title: '停用', enabled: false }).enabled).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('mergeHomeConfig', () => {
|
||||
it('过滤掉既无文案也无图片的空轮播', () => {
|
||||
const config = mergeHomeConfig({
|
||||
banners: [
|
||||
{ title: '有效' },
|
||||
{ title: ' ', pc: { image_url: 'https://cdn.example/pc.png' } },
|
||||
{ title: '' },
|
||||
],
|
||||
})
|
||||
|
||||
// 只有图片没有文案的轮播要保留,全空的条目被丢弃
|
||||
expect(config.banners.map(item => item.pc.image_url)).toEqual([
|
||||
'',
|
||||
'https://cdn.example/pc.png',
|
||||
])
|
||||
})
|
||||
|
||||
it('全部无效时回落到默认轮播', () => {
|
||||
const config = mergeHomeConfig({ banners: [{ title: '' }] })
|
||||
expect(config.banners.length).toBeGreaterThan(0)
|
||||
expect(config.banners[0]?.pc.image_url).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('createBannerHotspot', () => {
|
||||
it('生成带默认行为的热区,便于后台直接框选', () => {
|
||||
const hotspot = createBannerHotspot({ x: 10, y: 12 })
|
||||
|
||||
expect(hotspot.id).toBeTruthy()
|
||||
expect(hotspot.action).toEqual({ type: 'none', target: '', open_new_tab: false })
|
||||
expect(hotspot.image_url).toBe('')
|
||||
expect(hotspot.hover_scale).toBe(BANNER_HOTSPOT_DEFAULT_HOVER_SCALE)
|
||||
expect(hotspot).toMatchObject({ x: 10, y: 12, width: 24, height: 24 })
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user