Files
inkreach-official-website/apps/website/app/components/FeatureCards.vue
T
yeuimu 79fabd85f7 feat(product-center): implement Figma-designed UI, upload module, and website tests
- Redesign website homepage & product-center per Figma (fonts, logos, hero/footer/customer cases)
- Add API upload module (multer) with static serving for uploads/public assets
- Add OriginGood.delisted flag and SDS request retry logic
- Add admin ImageUpload component and goods import/upload flows
- Add vitest suite for website components and composables (32 tests)
- Add skills, docs, plans and PRODUCT.md
2026-08-20 14:32:03 +08:00

78 lines
2.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';
const activeFeature = ref(0);
const FEATURE_INTERVAL_MS = 2000;
const features = [
{ title: '设计工具', desc: '轻松设计,快速定制', image: '/设计工具.png' },
{ title: '自动化履约', desc: '从生产到配送,全程无忧,准时交付', image: '/自动化履约.png' },
{ title: '全球配送', desc: '全球20+国家本土工厂', image: '/全球配送.png' },
{ title: '店铺集成', desc: '与Shopify、Amazon等平台无缝对接', image: '/店铺集成.png' },
];
const selectFeature = (idx: number) => {
activeFeature.value = idx;
};
let featureTimer: ReturnType<typeof setInterval> | null = null;
onMounted(() => {
featureTimer = setInterval(() => {
activeFeature.value = (activeFeature.value + 1) % features.length;
}, FEATURE_INTERVAL_MS);
});
onBeforeUnmount(() => {
if (featureTimer) clearInterval(featureTimer);
});
</script>
<template>
<section class="feature-section w-full flex flex-col gap-8 lg:gap-10 items-center p-6 lg:p-10">
<div class="text-[48px] font-extrabold md:text-4xl lg:text-5xl text-center">用强大功能开启盈利快车道</div>
<div class="flex flex-col lg:flex-row gap-5 w-full max-w-7xl items-stretch">
<div class="feature-list flex flex-row gap-3 overflow-x-auto lg:overflow-visible">
<div
v-for="(feat, idx) in features"
:key="idx"
@click="selectFeature(idx)"
@mouseenter="activeFeature = idx"
class="flex-shrink-0 flex flex-col justify-center gap-2 lg:gap-4 pl-4 lg:pl-5 w-40 lg:w-100 h-20 lg:h-auto rounded-lg cursor-pointer transition-colors duration-300"
:class="activeFeature === idx ? 'bg-primary text-white' : 'bg-inkreach-homepage-2'"
>
<p class="feature-item-title text-xl lg:text-3xl">{{ feat.title }}</p>
<p class="text-sm lg:text-base indent-1">{{ feat.desc }}</p>
</div>
</div>
<div class="flex-1 overflow-hidden rounded-xl relative">
<img
v-for="(feat, idx) in features"
:key="'feat-img-' + idx"
:src="feat.image"
:alt="feat.title"
:data-testid="`feature-image-${idx}`"
class="w-full h-full object-contain transition-opacity duration-500 absolute inset-0"
:class="activeFeature === idx ? 'opacity-100' : 'opacity-0 pointer-events-none'"
/>
</div>
</div>
</section>
</template>
<style scoped>
@media (min-width: 1024px) {
.feature-section { height: 754px; padding-top: 54px; }
.feature-section > div:nth-child(2) { height: 550px; }
.feature-list {
display: grid;
grid-template-rows: repeat(4, minmax(0, 1fr));
width: 400px;
height: 100%;
gap: 12px;
}
}
</style>