feat(home): 替换首页轮播图实现为广告系统驱动
- 移除原有的硬编码轮播图组件和相关样式 - 新增 getAdByCode 方法用于获取广告数据 - 实现解析广告数据的工具函数 parseSlides 和 parsePx - 集成 useAsyncData 获取 flash 广告数据 - 添加备用图片以确保加载失败时的显示 - 更新页面样式适配新的轮播组件结构
This commit is contained in:
@@ -1,85 +1,6 @@
|
||||
<template>
|
||||
<main class="home">
|
||||
<section class="mx-auto max-w-screen-xl px-4 py-8">
|
||||
<div class="grid grid-cols-12 gap-6">
|
||||
<div class="col-span-12">
|
||||
<div class="panel hero">
|
||||
<div class="hero-bg" aria-hidden="true">
|
||||
<ClientOnly>
|
||||
<a-carousel class="hero-carousel" autoplay effect="fade" :autoplaySpeed="4500" :dots="false">
|
||||
<div
|
||||
v-for="src in heroSlides"
|
||||
:key="src"
|
||||
class="hero-slide"
|
||||
:style="{ backgroundImage: `url(${src})` }"
|
||||
></div>
|
||||
</a-carousel>
|
||||
<template #fallback>
|
||||
<div class="hero-carousel">
|
||||
<div class="hero-slide" :style="{ backgroundImage: `url(${heroSlides[0]})` }"></div>
|
||||
</div>
|
||||
</template>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
<div class="hero-inner">
|
||||
<!-- <div class="hero-badge">OFFICIAL</div>-->
|
||||
<!-- <div class="hero-title">{{ COMPANY.projectName }}</div>-->
|
||||
<!-- <div class="hero-sub">生物基材料技术研发 · 技术服务 · 食品与农产品流通</div>-->
|
||||
<!-- <div class="mt-6 flex flex-wrap gap-3">-->
|
||||
<!-- <a-button type="primary" size="large" @click="navigateTo('/contact')">-->
|
||||
<!-- <template #icon><PhoneOutlined /></template>-->
|
||||
<!-- 合作咨询-->
|
||||
<!-- </a-button>-->
|
||||
<!-- <a-button size="large" @click="scrollToCompany">-->
|
||||
<!-- <template #icon><IdcardOutlined /></template>-->
|
||||
<!-- 工商信息-->
|
||||
<!-- </a-button>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="mt-6 flex flex-wrap gap-2">-->
|
||||
<!-- <a-tag v-for="t in COMPANY.tags" :key="t" color="green">{{ t }}</a-tag>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="mt-6 grid grid-cols-12 gap-6">-->
|
||||
<!-- <div class="col-span-12 lg:col-span-7">-->
|
||||
<!-- <div class="panel">-->
|
||||
<!-- <div class="section-pill">-->
|
||||
<!-- <span class="pill-left">-->
|
||||
<!-- <AppstoreOutlined />-->
|
||||
<!-- 业务板块-->
|
||||
<!-- </span>-->
|
||||
<!-- <span class="pill-right">SERVICES</span>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">-->
|
||||
<!-- <a-card-->
|
||||
<!-- v-for="s in services"-->
|
||||
<!-- :key="s.title"-->
|
||||
<!-- class="guide-card service-card"-->
|
||||
<!-- :bordered="true"-->
|
||||
<!-- hoverable-->
|
||||
<!-- @click="navigateTo('/products')"-->
|
||||
<!-- >-->
|
||||
<!-- <a-space>-->
|
||||
<!-- <a-avatar :size="44" class="guide-icon service-icon">-->
|
||||
<!-- <component :is="s.icon" />-->
|
||||
<!-- </a-avatar>-->
|
||||
<!-- <div>-->
|
||||
<!-- <div class="guide-title">{{ s.title }}</div>-->
|
||||
<!-- <div class="guide-desc">{{ s.desc }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </a-space>-->
|
||||
<!-- </a-card>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
<!-- </div>-->
|
||||
</section>
|
||||
<Carousel class="px-4 py-8" :items="flashSlides" :height="flashHeight" />
|
||||
|
||||
<section class="banner">
|
||||
<div class="mx-auto max-w-screen-xl px-4 py-10">
|
||||
@@ -148,6 +69,8 @@ import {
|
||||
ShopOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
import { getAdByCode } from '@/api/cms/cmsAd'
|
||||
import type { CmsAd } from '@/api/cms/cmsAd/model'
|
||||
import { COMPANY } from '@/config/company'
|
||||
|
||||
usePageSeo({
|
||||
@@ -157,10 +80,78 @@ usePageSeo({
|
||||
path: '/'
|
||||
})
|
||||
|
||||
const heroSlides = [
|
||||
'https://file-cloud.yst.com.cn/photo/website/2024/11/28/5a5cc07336224e54a84561c80899bcac.jpg',
|
||||
'https://oss.wsdns.cn/20260115/75690dea8f064ceda03246b198a7d710.jpg'
|
||||
]
|
||||
function parsePx(value?: string) {
|
||||
if (!value) return undefined
|
||||
const m = String(value).match(/(\d+)/)
|
||||
if (!m) return undefined
|
||||
const n = Number(m[1])
|
||||
return Number.isFinite(n) ? n : undefined
|
||||
}
|
||||
|
||||
function parseSlides(ad?: CmsAd | null) {
|
||||
const raw = ad?.imageList
|
||||
const fallbackHref = ad?.path
|
||||
|
||||
function pickString(obj: Record<string, unknown>, keys: string[]) {
|
||||
for (const k of keys) {
|
||||
const v = obj[k]
|
||||
if (typeof v === 'string' && v.trim()) return v
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
function asArray(val: unknown): unknown[] {
|
||||
if (!val) return []
|
||||
if (Array.isArray(val)) return val
|
||||
if (typeof val === 'string') {
|
||||
const text = val.trim()
|
||||
if (!text) return []
|
||||
try {
|
||||
const parsed = JSON.parse(text)
|
||||
return Array.isArray(parsed) ? parsed : [parsed]
|
||||
} catch {
|
||||
return text.split(/[,;\n]+/g).map((s) => s.trim()).filter(Boolean)
|
||||
}
|
||||
}
|
||||
if (typeof val === 'object') {
|
||||
const obj = val as Record<string, unknown>
|
||||
if (Array.isArray(obj.list)) return obj.list
|
||||
if (Array.isArray(obj.imageList)) return obj.imageList
|
||||
if (Array.isArray(obj.images)) return obj.images
|
||||
return [obj]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
return asArray(raw)
|
||||
.map((it) => {
|
||||
if (typeof it === 'string') return { src: it, href: fallbackHref }
|
||||
if (it && typeof it === 'object') {
|
||||
const obj = it as Record<string, unknown>
|
||||
const src = pickString(obj, ['src', 'url', 'image', 'imageUrl', 'img', 'imgUrl', 'pic', 'picUrl'])
|
||||
const href = pickString(obj, ['href', 'link', 'path', 'to']) ?? fallbackHref
|
||||
if (!src) return null
|
||||
return { src, href }
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter(Boolean) as Array<{ src: string; href?: string }>
|
||||
}
|
||||
|
||||
const { data: flashAd } = await useAsyncData('cms-ad-flash', () =>
|
||||
getAdByCode('flash').catch(() => null)
|
||||
)
|
||||
|
||||
console.log(flashAd.value?.imageList,'flashAdflashAdflashAd');
|
||||
|
||||
const flashSlides = computed(() => {
|
||||
const slides = parseSlides(flashAd.value)
|
||||
return slides.length
|
||||
? slides
|
||||
: [{ src: 'https://file-cloud.yst.com.cn/photo/website/2024/11/28/5a5cc07336224e54a84561c80899bcac.jpg' }]
|
||||
})
|
||||
|
||||
const flashHeight = computed(() => parsePx(flashAd.value?.height) ?? 360)
|
||||
|
||||
function splitScope(text: string) {
|
||||
return text
|
||||
@@ -274,75 +265,6 @@ function scrollToCompany() {
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
min-height: 360px;
|
||||
}
|
||||
|
||||
.hero-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.hero-carousel {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hero-slide {
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.hero-carousel :deep(.slick-list),
|
||||
.hero-carousel :deep(.slick-track),
|
||||
.hero-carousel :deep(.slick-slide),
|
||||
.hero-carousel :deep(.slick-slide > div) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hero-inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
padding: 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
width: fit-content;
|
||||
padding: 4px 10px;
|
||||
border-radius: 9999px;
|
||||
background: rgba(22, 163, 74, 0.12);
|
||||
color: rgba(21, 128, 61, 0.95);
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.12em;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
margin-top: 14px;
|
||||
font-size: 42px;
|
||||
line-height: 1.1;
|
||||
font-weight: 900;
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.hero-sub {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.company {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -522,14 +444,4 @@ function scrollToCompany() {
|
||||
color: rgba(0, 0, 0, 0.55);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hero-inner {
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 34px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user