feat(home-banner): 轮播支持 PC/移动两端分图与热区跳转,热区图悬浮放大;修复上传压缩压白透明 PNG
This commit is contained in:
@@ -17,9 +17,45 @@ describe('mapDistributionHomeBanners', () => {
|
||||
[{ image_url: 'https://cdn.example/poster.webp', title: '海报标题' }],
|
||||
'天域商行'
|
||||
)
|
||||
expect(slide?.image_url).toBe('https://cdn.example/poster.webp')
|
||||
expect(slide?.pc.image_url).toBe('https://cdn.example/poster.webp')
|
||||
expect(slide?.mobile.image_url).toBe('https://cdn.example/poster.webp')
|
||||
expect(slide?.title).toBe('')
|
||||
expect(slide?.eyebrow).toBe('')
|
||||
expect(slide?.pill).toBe('')
|
||||
})
|
||||
|
||||
it('falls back to the copy card when the banner has no image', () => {
|
||||
const [slide] = mapDistributionHomeBanners([{ image_url: '', title: '精选账号' }], '天域商行')
|
||||
expect(slide?.pc.image_url).toBe('')
|
||||
expect(slide?.title).toBe('精选账号')
|
||||
expect(slide?.eyebrow).toBe('天域商行')
|
||||
})
|
||||
|
||||
it('turns link_url into a clickable banner action', () => {
|
||||
const [external] = mapDistributionHomeBanners(
|
||||
[{ image_url: '/poster.png', link_url: 'https://cdn.example/act' }],
|
||||
'天域商行'
|
||||
)
|
||||
expect(external?.pc.action).toEqual({
|
||||
type: 'link',
|
||||
target: 'https://cdn.example/act',
|
||||
open_new_tab: true,
|
||||
})
|
||||
|
||||
const [internal] = mapDistributionHomeBanners(
|
||||
[{ image_url: '/poster.png', link_url: '/m/announcements' }],
|
||||
'天域商行'
|
||||
)
|
||||
expect(internal?.pc.action).toEqual({
|
||||
type: 'route',
|
||||
target: '/m/announcements',
|
||||
open_new_tab: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps banners clickable for preview when no link is configured', () => {
|
||||
const [slide] = mapDistributionHomeBanners([{ image_url: '/poster.png' }], '天域商行')
|
||||
expect(slide?.pc.action.type).toBe('none')
|
||||
expect(slide?.pc.hotspots).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,6 +7,13 @@ import {
|
||||
mergeStorefrontText,
|
||||
type StorefrontText,
|
||||
} from '@/shared/utils/storefrontText'
|
||||
import {
|
||||
createEmptyBannerAction,
|
||||
createEmptyBannerVisual,
|
||||
type BannerAction,
|
||||
type BannerVisual,
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
|
||||
export interface DistributionBanner {
|
||||
image_url: string
|
||||
@@ -14,13 +21,36 @@ export interface DistributionBanner {
|
||||
title?: string
|
||||
}
|
||||
|
||||
export interface DistributionHomeBanner {
|
||||
eyebrow: string
|
||||
title: string
|
||||
badge: string
|
||||
pill: string
|
||||
tone: string
|
||||
image_url?: string
|
||||
/** 分站首页轮播:有图时不再叠标题,避免整幅压暗。 */
|
||||
export function mapDistributionHomeBanners(
|
||||
banners: DistributionBanner[],
|
||||
siteName: string
|
||||
): HomeBannerSlide[] {
|
||||
return banners.map(banner => {
|
||||
const imageUrl = banner.image_url?.trim() || ''
|
||||
const action = resolveDistributionBannerAction(banner.link_url)
|
||||
const visual: BannerVisual = { ...createEmptyBannerVisual(), image_url: imageUrl, action }
|
||||
return {
|
||||
eyebrow: imageUrl ? '' : siteName,
|
||||
title: imageUrl ? '' : banner.title?.trim() || '精选游戏账号 · 随租随玩',
|
||||
badge: '本店精选',
|
||||
pill: imageUrl ? '' : '官方保障',
|
||||
tone: 'gold',
|
||||
enabled: true,
|
||||
// 分站装修只配一张图,两端共用,避免移动端丢图
|
||||
pc: { ...visual, hotspots: [] },
|
||||
mobile: { ...visual, hotspots: [] },
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 分站轮播的 link_url:绝对地址走外链新窗口,站内路径走路由。 */
|
||||
function resolveDistributionBannerAction(linkUrl?: string): BannerAction {
|
||||
const target = linkUrl?.trim() || ''
|
||||
if (!target) return createEmptyBannerAction()
|
||||
if (/^https?:\/\//i.test(target)) return { type: 'link', target, open_new_tab: true }
|
||||
if (target.startsWith('/')) return { type: 'route', target, open_new_tab: false }
|
||||
return createEmptyBannerAction()
|
||||
}
|
||||
|
||||
/** 分站首页主标题:站名与主站联名。主站或站名已含主站名时保持原样。 */
|
||||
@@ -31,33 +61,6 @@ export function formatDistributionCoBrandName(siteName: string, isDistribution:
|
||||
return `${name}×大锤商行`
|
||||
}
|
||||
|
||||
/** 分站首页轮播:有图时不再叠标题,避免整幅压暗。 */
|
||||
export function mapDistributionHomeBanners(
|
||||
banners: DistributionBanner[],
|
||||
siteName: string
|
||||
): DistributionHomeBanner[] {
|
||||
return banners.map(banner => {
|
||||
const imageUrl = banner.image_url?.trim() || ''
|
||||
if (imageUrl) {
|
||||
return {
|
||||
eyebrow: '',
|
||||
title: '',
|
||||
badge: '本店精选',
|
||||
pill: '',
|
||||
tone: 'gold',
|
||||
image_url: imageUrl,
|
||||
}
|
||||
}
|
||||
return {
|
||||
eyebrow: siteName,
|
||||
title: banner.title?.trim() || '精选游戏账号 · 随租随玩',
|
||||
badge: '本店精选',
|
||||
pill: '官方保障',
|
||||
tone: 'gold',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export interface DistributionFooterInfo {
|
||||
icp?: string
|
||||
copyright?: string
|
||||
|
||||
Reference in New Issue
Block a user