feat(WIP)
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div class="home-view">
|
||||
<AboutSection
|
||||
v-for="section in aboutSections"
|
||||
:key="section.title"
|
||||
:reverse="section.reverse"
|
||||
:title="$t(section.title)"
|
||||
:description="$t(section.description)"
|
||||
:background-image="section.backgroundImage"
|
||||
:buttonshow="section.buttonShow"
|
||||
:targetPath="section.targetPath"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <script>
|
||||
export default {
|
||||
name: 'HomeView',
|
||||
}
|
||||
</script> -->
|
||||
<script setup lang="ts">
|
||||
import AboutSection from '@/components/AboutSection.vue'
|
||||
import { ref } from 'vue'
|
||||
import logoImage from '/images/logo.png'
|
||||
import product2 from '/images/product2.png'
|
||||
|
||||
const aboutSections = ref([
|
||||
{
|
||||
title: 'company.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: logoImage,
|
||||
reverse: true,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'property',
|
||||
description: 'company.property',
|
||||
backgroundImage: '', // or whatever the default is
|
||||
reverse: false,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'areas.individual.name',
|
||||
description: 'areas.individual.intro',
|
||||
backgroundImage: product2,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '/waterlife',
|
||||
},
|
||||
{
|
||||
title: 'areas.aged.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: product2,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '',
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home-view {
|
||||
background-color: rgb(241, 244, 247);
|
||||
}
|
||||
</style>
|
||||
@@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div class="home-view">
|
||||
<AboutSection
|
||||
v-for="section in aboutSections"
|
||||
:key="section.title"
|
||||
:reverse="section.reverse"
|
||||
:title="$t(section.title)"
|
||||
:description="$t(section.description)"
|
||||
:background-image="section.backgroundImage"
|
||||
:buttonshow="section.buttonShow"
|
||||
:targetPath="section.targetPath"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <script>
|
||||
export default {
|
||||
name: 'HomeView',
|
||||
}
|
||||
</script> -->
|
||||
<script setup lang="ts">
|
||||
import AboutSection from '@/components/AboutSection.vue'
|
||||
import { ref } from 'vue'
|
||||
import logoImage from '/images/logo.png'
|
||||
import product2 from '/images/product2.png'
|
||||
|
||||
const aboutSections = ref([
|
||||
{
|
||||
title: 'company.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: logoImage,
|
||||
reverse: true,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'property',
|
||||
description: 'company.property',
|
||||
backgroundImage: '', // or whatever the default is
|
||||
reverse: false,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'areas.individual.name',
|
||||
description: 'areas.individual.intro',
|
||||
backgroundImage: product2,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '/waterlife',
|
||||
},
|
||||
{
|
||||
title: 'areas.aged.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: product2,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '',
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home-view {
|
||||
background-color: rgb(241, 244, 247);
|
||||
}
|
||||
</style>
|
||||
@@ -21,14 +21,16 @@ export default {
|
||||
<script setup lang="ts">
|
||||
import AboutSection from '@/components/AboutSection.vue'
|
||||
import { ref } from 'vue'
|
||||
import logoImage from '/images/logo.png'
|
||||
import product2 from '/images/product2.png'
|
||||
import background_1 from '/images/background_1.jpg'
|
||||
import background_2 from '/images/background_2.jpg'
|
||||
import background_3 from '/images/background_3.jpg'
|
||||
import background_4 from '/images/background_4.jpg'
|
||||
|
||||
const aboutSections = ref([
|
||||
{
|
||||
title: 'company.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: logoImage,
|
||||
backgroundImage: background_1,
|
||||
reverse: true,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
@@ -36,28 +38,29 @@ const aboutSections = ref([
|
||||
{
|
||||
title: 'property',
|
||||
description: 'company.property',
|
||||
backgroundImage: '', // or whatever the default is
|
||||
backgroundImage: background_2,
|
||||
reverse: false,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'areas.individual.name',
|
||||
description: 'areas.individual.intro',
|
||||
backgroundImage: product2,
|
||||
title: 'areas.waterlife.name',
|
||||
description: 'areas.waterlife.intro',
|
||||
backgroundImage: background_3,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '/waterlife',
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'areas.aged.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: product2,
|
||||
description: 'areas.aged.intro',
|
||||
backgroundImage: background_4,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '',
|
||||
targetPath: '/todo',
|
||||
},
|
||||
])
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div class="home-view">
|
||||
<AboutSection
|
||||
v-for="section in aboutSections"
|
||||
:key="section.title"
|
||||
:reverse="section.reverse"
|
||||
:title="$t(section.title)"
|
||||
:description="$t(section.description)"
|
||||
:background-image="section.backgroundImage"
|
||||
:buttonshow="section.buttonShow"
|
||||
:targetPath="section.targetPath"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <script>
|
||||
export default {
|
||||
name: 'HomeView',
|
||||
}
|
||||
</script> -->
|
||||
<script setup lang="ts">
|
||||
import AboutSection from '@/components/AboutSection.vue'
|
||||
import { ref } from 'vue'
|
||||
import logoImage from '/images/logo.png'
|
||||
import product2 from '/images/product2.png'
|
||||
|
||||
const aboutSections = ref([
|
||||
{
|
||||
title: 'company.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: logoImage,
|
||||
reverse: true,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'property',
|
||||
description: 'company.property',
|
||||
backgroundImage: '', // or whatever the default is
|
||||
reverse: false,
|
||||
buttonShow: false,
|
||||
targetPath: '',
|
||||
},
|
||||
{
|
||||
title: 'areas.individual.name',
|
||||
description: 'areas.individual.intro',
|
||||
backgroundImage: product2,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '/waterlife',
|
||||
},
|
||||
{
|
||||
title: 'areas.aged.name',
|
||||
description: 'company.introduction',
|
||||
backgroundImage: product2,
|
||||
reverse: false,
|
||||
buttonShow: true,
|
||||
targetPath: '',
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home-view {
|
||||
background-color: rgb(241, 244, 247);
|
||||
}
|
||||
</style>
|
||||
77
src/views/StoreView.vue
Normal file
77
src/views/StoreView.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="purchase-methods">
|
||||
<h2>购买方式</h2>
|
||||
<div class="methods-container">
|
||||
<!-- 微信 -->
|
||||
<div class="method">
|
||||
<h3>微信</h3>
|
||||
<img :src="WeChat" alt="微信二维码" />
|
||||
</div>
|
||||
|
||||
<!-- 淘宝 -->
|
||||
<div class="method">
|
||||
<h3>淘宝</h3>
|
||||
<img :src="TaoBao" alt="淘宝二维码" />
|
||||
</div>
|
||||
|
||||
<!-- 小红书 -->
|
||||
<div class="method">
|
||||
<h3>小红书</h3>
|
||||
<img :src="RedNote" alt="小红书二维码" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import WeChat from '/images/WeChat.jpg'
|
||||
import TaoBao from '/images/TaoBao.jpg'
|
||||
import RedNote from '/images/RedNote.jpg'
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.purchase-methods {
|
||||
font-family: 'Arial', sans-serif;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.purchase-methods h2 {
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 30px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.methods-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
gap: 40px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.method {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
background-color: #f9f9f9;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.method h3 {
|
||||
margin-top: 0;
|
||||
font-size: 1.2rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.method img {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: 10px auto;
|
||||
display: block;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
26
src/views/TodoView.vue
Normal file
26
src/views/TodoView.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="home-view">
|
||||
<AboutSection
|
||||
key="Todo"
|
||||
:title="$t('pages.todo.name')"
|
||||
:description="$t('pages.todo.content')"
|
||||
:background-image="background_4"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <script>
|
||||
export default {
|
||||
name: 'HomeView',
|
||||
}
|
||||
</script> -->
|
||||
<script setup lang="ts">
|
||||
import AboutSection from '@/components/AboutSection.vue'
|
||||
import background_4 from '/images/background_4.jpg'
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home-view {
|
||||
background-color: rgb(241, 244, 247);
|
||||
}
|
||||
</style>
|
||||
@@ -1,3 +1,5 @@
|
||||
<!-- TODO: 拆分为独立的三个页面,后续产品种类提升可以合并 -->
|
||||
|
||||
<template>
|
||||
<div class="product-display">
|
||||
<ProductDetail
|
||||
@@ -44,26 +46,11 @@ import { ref, computed } from 'vue'
|
||||
import ProductDetail from '@/components/ProductDetail.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import seekDetail from '@/components/seekDetail.vue'
|
||||
|
||||
const { tm } = useI18n()
|
||||
|
||||
// import { useI18n } from 'vue-i18n'
|
||||
// const { t } = useI18n()
|
||||
interface DetailItem {
|
||||
key: string
|
||||
value: string
|
||||
}
|
||||
|
||||
// products 数据
|
||||
interface DetailItem {
|
||||
key: string
|
||||
value: string
|
||||
}
|
||||
interface ProductInfoData {
|
||||
notice: string
|
||||
usage: string
|
||||
features: string
|
||||
introduction: string
|
||||
}
|
||||
|
||||
const selectedProductData = computed(() => {
|
||||
return products.value.find((p) => p.name === selectedProduct.value)
|
||||
@@ -71,27 +58,29 @@ const selectedProductData = computed(() => {
|
||||
|
||||
import cyqImage from '@/assets/water/cyq.png'
|
||||
import cjqImage from '@/assets/water/cjq.png'
|
||||
|
||||
import cjbImage from '@/assets/water/cjb.png'
|
||||
import type { DetailItem, ProductInfoData } from '@/types/product'
|
||||
|
||||
const products = ref([
|
||||
{
|
||||
name: 'cyq',
|
||||
detailList: tm('cyq.detail') as unknown as DetailItem[],
|
||||
// detailList: tm('cyq.detail') as unknown as DetailItem[],
|
||||
detailList: computed(() => tm('cyq.detail') as DetailItem[]),
|
||||
imageUrl: cyqImage,
|
||||
infoData: tm('cyq') as unknown as ProductInfoData,
|
||||
// infoData: tm('cyq') as unknown as ProductInfoData,
|
||||
infoData: computed(() => tm('cyq') as ProductInfoData),
|
||||
},
|
||||
{
|
||||
name: 'cjb',
|
||||
detailList: tm('cyq.detail') as unknown as DetailItem[],
|
||||
detailList: computed(() => tm('cjb.detail') as DetailItem[]),
|
||||
imageUrl: cjbImage,
|
||||
infoData: tm('cjb') as unknown as ProductInfoData,
|
||||
infoData: computed(() => tm('cjb') as ProductInfoData),
|
||||
},
|
||||
{
|
||||
name: 'cjq',
|
||||
detailList: tm('cyq.detail') as unknown as DetailItem[],
|
||||
detailList: computed(() => tm('cjq.detail') as DetailItem[]),
|
||||
imageUrl: cjqImage,
|
||||
infoData: tm('cjq') as unknown as ProductInfoData,
|
||||
infoData: computed(() => tm('cjq') as ProductInfoData),
|
||||
},
|
||||
])
|
||||
const selectedProduct = ref('')
|
||||
|
||||
178
src/views/WaterLife_bottle.vue
Normal file
178
src/views/WaterLife_bottle.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<!-- 小喷瓶 -->
|
||||
|
||||
<template>
|
||||
<div class="product-display">
|
||||
<ProductDetail
|
||||
:key="product.name"
|
||||
reverse
|
||||
:title="$t(`${product.name}.name`)"
|
||||
:content="$t(`${product.name}.info`)"
|
||||
:imagetitle="$t(`${product.name}.name`)"
|
||||
:info="$t(`${product.name}.info`)"
|
||||
:detailList="product.detailList"
|
||||
:imageUrl="product.imageUrl"
|
||||
:videoUrl="$t(`${product.name}.video-url`)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="product-move">
|
||||
<div class="product-list">
|
||||
<div :key="product.name" class="product-card">
|
||||
<img :src="product.imageUrl" class="product-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<transition name="fade" mode="out-in">
|
||||
<seekDetail :key="product.name" :productData="product.infoData" />
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import ProductDetail from '@/components/ProductDetail.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import seekDetail from '@/components/seekDetail.vue'
|
||||
import cjqImage from '@/assets/water/cjq.png'
|
||||
import type { DetailItem, ProductInfoData } from '@/types/product'
|
||||
|
||||
// import { useI18n } from 'vue-i18n'
|
||||
// const { t } = useI18n()
|
||||
const { tm } = useI18n()
|
||||
|
||||
const product = ref({
|
||||
name: 'cjq',
|
||||
detailList: computed(() => tm('cjq.detail') as DetailItem[]),
|
||||
imageUrl: cjqImage,
|
||||
infoData: computed(() => tm('cjq') as ProductInfoData),
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 产品展示区域样式 */
|
||||
.product-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.product-move {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.product-list {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 20%;
|
||||
height: auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.product-card:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg, rgba(106, 17, 203, 0.1) 0%, rgba(37, 117, 252, 0.1) 100%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.product-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.product-card:hover:before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.product-card.active {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(106, 17, 203, 0.2);
|
||||
}
|
||||
|
||||
.product-card.active:before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 80%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.product-card:hover .product-image {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 过渡动画 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition:
|
||||
opacity 0.5s ease,
|
||||
transform 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.product-list {
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.product-display {
|
||||
gap: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.product-list {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
178
src/views/WaterLife_cup.vue
Normal file
178
src/views/WaterLife_cup.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<!-- 除菌杯 -->
|
||||
|
||||
<template>
|
||||
<div class="product-display">
|
||||
<ProductDetail
|
||||
:key="product.name"
|
||||
reverse
|
||||
:title="$t(`${product.name}.name`)"
|
||||
:content="$t(`${product.name}.info`)"
|
||||
:imagetitle="$t(`${product.name}.name`)"
|
||||
:info="$t(`${product.name}.info`)"
|
||||
:detailList="product.detailList"
|
||||
:imageUrl="product.imageUrl"
|
||||
:videoUrl="$t(`${product.name}.video-url`)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="product-move">
|
||||
<div class="product-list">
|
||||
<div :key="product.name" class="product-card">
|
||||
<img :src="product.imageUrl" class="product-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<transition name="fade" mode="out-in">
|
||||
<seekDetail :key="product.name" :productData="product.infoData" />
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import ProductDetail from '@/components/ProductDetail.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import seekDetail from '@/components/seekDetail.vue'
|
||||
import cjbImage from '@/assets/water/cjb.png'
|
||||
import type { DetailItem, ProductInfoData } from '@/types/product'
|
||||
|
||||
// import { useI18n } from 'vue-i18n'
|
||||
// const { t } = useI18n()
|
||||
const { tm } = useI18n()
|
||||
|
||||
const product = ref({
|
||||
name: 'cjb',
|
||||
detailList: computed(() => tm('cjb.detail') as DetailItem[]),
|
||||
imageUrl: cjbImage,
|
||||
infoData: computed(() => tm('cjb') as ProductInfoData),
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 产品展示区域样式 */
|
||||
.product-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.product-move {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.product-list {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 20%;
|
||||
height: auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.product-card:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg, rgba(106, 17, 203, 0.1) 0%, rgba(37, 117, 252, 0.1) 100%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.product-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.product-card:hover:before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.product-card.active {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(106, 17, 203, 0.2);
|
||||
}
|
||||
|
||||
.product-card.active:before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 80%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.product-card:hover .product-image {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 过渡动画 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition:
|
||||
opacity 0.5s ease,
|
||||
transform 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.product-list {
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.product-display {
|
||||
gap: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.product-list {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
180
src/views/WaterLife_flosser.vue
Normal file
180
src/views/WaterLife_flosser.vue
Normal file
@@ -0,0 +1,180 @@
|
||||
<!-- 冲牙器 -->
|
||||
|
||||
<template>
|
||||
<div class="product-display">
|
||||
<ProductDetail
|
||||
:key="product.name"
|
||||
reverse
|
||||
:title="$t(`${product.name}.name`)"
|
||||
:content="$t(`${product.name}.info`)"
|
||||
:imagetitle="$t(`${product.name}.name`)"
|
||||
:info="$t(`${product.name}.info`)"
|
||||
:detailList="product.detailList"
|
||||
:imageUrl="product.imageUrl"
|
||||
:videoUrl="$t(`${product.name}.video-url`)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="product-move">
|
||||
<div class="product-list">
|
||||
<div :key="product.name" class="product-card">
|
||||
<img :src="product.imageUrl" class="product-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<transition name="fade" mode="out-in">
|
||||
<seekDetail :key="product.name" :productData="product.infoData" />
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import ProductDetail from '@/components/ProductDetail.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import seekDetail from '@/components/seekDetail.vue'
|
||||
import cyqImage from '@/assets/water/cyq.png'
|
||||
import type { DetailItem, ProductInfoData } from '@/types/product'
|
||||
|
||||
// import { useI18n } from 'vue-i18n'
|
||||
// const { t } = useI18n()
|
||||
const { tm } = useI18n()
|
||||
|
||||
const product = ref({
|
||||
name: 'cyq',
|
||||
// detailList: tm('cyq.detail') as unknown as DetailItem[],
|
||||
detailList: computed(() => tm('cyq.detail') as DetailItem[]),
|
||||
imageUrl: cyqImage,
|
||||
// infoData: tm('cyq') as unknown as ProductInfoData,
|
||||
infoData: computed(() => tm('cyq') as ProductInfoData),
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 产品展示区域样式 */
|
||||
.product-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.product-move {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.product-list {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 20%;
|
||||
height: auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.product-card:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg, rgba(106, 17, 203, 0.1) 0%, rgba(37, 117, 252, 0.1) 100%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.product-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.product-card:hover:before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.product-card.active {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(106, 17, 203, 0.2);
|
||||
}
|
||||
|
||||
.product-card.active:before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 80%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.product-card:hover .product-image {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 过渡动画 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition:
|
||||
opacity 0.5s ease,
|
||||
transform 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.product-list {
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.product-display {
|
||||
gap: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.product-list {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user