gcz 1 долоо хоног өмнө
parent
commit
728dd02220
1 өөрчлөгдсөн 463 нэмэгдсэн , 83 устгасан
  1. 463 83
      src/pages/home/Index.vue

+ 463 - 83
src/pages/home/Index.vue

@@ -2,18 +2,23 @@
   <DefaultLayout>
     <!-- banner -->
     <section class="banner-section">
-      <img src="@assets/banner.png" alt="" srcset="">
+      <div class="banner-image animate-fade-in">
+        <img src="@assets/banner.png" alt="" srcset="">
+      </div>
       <div class="info-row">
-        <div class="info-item">
+        <div class="info-item animate-scale-in" :class="{ 'animate-visible': isInfoVisible }"
+          style="animation-delay: 0.2s">
           <span class="text">覆盖</span>
           <span class="number" ref="number1">{{ animatedNumbers.number1 }}+</span>
           <span class="text">垂直行业</span>
         </div>
-        <div class="info-item">
+        <div class="info-item animate-scale-in" :class="{ 'animate-visible': isInfoVisible }"
+          style="animation-delay: 0.4s">
           <span class="number" ref="number2">{{ animatedNumbers.number2 }}</span>
           <span class="text">小时原型交付</span>
         </div>
-        <div class="info-item">
+        <div class="info-item animate-scale-in" :class="{ 'animate-visible': isInfoVisible }"
+          style="animation-delay: 0.6s">
           <span class="text">定制成本降低</span>
           <span class="number" ref="number3">{{ animatedNumbers.number3 }}%</span>
         </div>
@@ -21,23 +26,26 @@
     </section>
 
     <!-- 产品中心 -->
-    <section class="products-section">
+    <section class="products-section" ref="productsSection">
       <div class="container">
-        <div class="section-header">
+        <div class="section-header animate-fade-up" :class="{ 'animate-visible': isProductsVisible }">
           <h2 class="section-title">产品中心</h2>
           <p class="section-subtitle">SMART SOLUTION</p>
           <p class="section-description">智慧管理系统采用先进开发技术,为智慧产业提供一站式解决方案</p>
         </div>
 
-        <div class="products-content">
+        <div class="products-content animate-fade-up" :class="{ 'animate-visible': isProductsVisible }"
+          style="animation-delay: 0.3s">
           <div class="products-nav">
-            <div v-for="product in productList" :key="product.id" class="nav-item"
-              :class="{ active: activeProductId === product.id }" @click="setActiveProduct(product.id)">
+            <div v-for="(product, index) in productList" :key="product.id" class="nav-item animate-slide-right"
+              :class="{ active: activeProductId === product.id, 'animate-visible': isProductsVisible }"
+              :style="{ 'animation-delay': `${0.1 * index}s` }" @click="setActiveProduct(product.id)">
               {{ product.classifyName }}
             </div>
           </div>
 
-          <div class="product-detail" v-if="activeProduct">
+          <div class="product-detail animate-fade-left" v-if="activeProduct"
+            :class="{ 'animate-visible': isProductsVisible }" style="animation-delay: 0.5s">
             <div class="detail-content">
               <h3 class="product-title">{{ activeProduct.classifyName }}</h3>
               <p class="product-description">{{ activeProduct.description || activeProduct.classifyDesc || '为您提供专业的解决方案'
@@ -51,16 +59,19 @@
       </div>
     </section>
     <!-- 行业案例 -->
-    <section class="cases-section">
+    <section class="cases-section" ref="casesSection">
       <div class="container">
-        <div class="section-header">
+        <div class="section-header animate-fade-up" :class="{ 'animate-visible': isCasesVisible }">
           <h2 class="section-title">行业案例</h2>
           <p class="section-subtitle">SMART SOLUTION</p>
           <p class="section-description">智慧管理系统采用先进开发技术,为智慧产业提供一站式解决方案</p>
         </div>
 
-        <div class="cases-carousel">
-          <div class="nav-arrow nav-arrow-left" :class="{ disabled: currentCaseIndex === 0 }" @click="prevCase">
+        <div class="cases-carousel animate-fade-up" :class="{ 'animate-visible': isCasesVisible }"
+          style="animation-delay: 0.3s">
+          <div class="nav-arrow nav-arrow-left animate-bounce-in"
+            :class="{ disabled: currentCaseIndex === 0, 'animate-visible': isCasesVisible }" @click="prevCase"
+            style="animation-delay: 0.5s">
             <div class="arrow-icon">
               <img src="@assets/arrow-right.png" alt="Previous" />
             </div>
@@ -81,8 +92,9 @@
             </div>
           </div>
 
-          <div class="nav-arrow nav-arrow-right" :class="{ disabled: currentCaseIndex >= maxCaseIndex }"
-            @click="nextCase">
+          <div class="nav-arrow nav-arrow-right animate-bounce-in"
+            :class="{ disabled: currentCaseIndex >= maxCaseIndex, 'animate-visible': isCasesVisible }" @click="nextCase"
+            style="animation-delay: 0.7s">
             <div class="arrow-icon">
               <img src="@assets/arrow-right.png" alt="Next" />
             </div>
@@ -91,22 +103,25 @@
       </div>
     </section>
     <!-- 企业简介 -->
-    <section class="about-section">
+    <section class="about-section" ref="aboutSection">
       <div class="container">
-        <div class="section-header">
+        <div class="section-header animate-fade-up" :class="{ 'animate-visible': isAboutVisible }">
           <h2 class="section-title">企业简介</h2>
           <p class="section-subtitle">ENTERPRISE QUALIFICATION</p>
         </div>
 
         <div class="about-content">
-          <div class="about-tabs">
-            <div v-for="tab in aboutTabs" :key="tab.id" class="tab-item" :class="{ active: activeAboutTab === tab.id }"
-              @click="setActiveAboutTab(tab.id)">
+          <div class="about-tabs animate-fade-up" :class="{ 'animate-visible': isAboutVisible }"
+            style="animation-delay: 0.2s">
+            <div v-for="(tab, index) in aboutTabs" :key="tab.id" class="tab-item animate-slide-up"
+              :class="{ active: activeAboutTab === tab.id, 'animate-visible': isAboutVisible }"
+              :style="{ 'animation-delay': `${0.1 * index}s` }" @click="setActiveAboutTab(tab.id)">
               {{ tab.title }}
             </div>
           </div>
 
-          <div class="about-detail">
+          <div class="about-detail animate-fade-up" :class="{ 'animate-visible': isAboutVisible }"
+            style="animation-delay: 0.4s">
             <transition name="fade-slide" mode="out-in">
               <div :key="activeAboutTab" class="detail-content">
                 <div class="content-left">
@@ -126,16 +141,18 @@
       </div>
     </section>
     <!-- 合作伙伴 -->
-    <section class="cooperation-section">
+    <section class="cooperation-section" ref="cooperationSection">
       <div class="container">
-        <div class="section-header">
+        <div class="section-header animate-fade-up" :class="{ 'animate-visible': isCooperationVisible }">
           <h2 class="section-title">合作伙伴</h2>
           <p class="section-subtitle">BUSINESS PARTNER</p>
         </div>
 
-        <div class="partners-grid">
-          <a v-for="partner in partnersList" :key="partner.id" :href="partner.partnersUrl" target="_blank"
-            class="partner-item">
+        <div class="partners-grid animate-fade-up" :class="{ 'animate-visible': isCooperationVisible }"
+          style="animation-delay: 0.3s">
+          <a v-for="(partner, index) in partnersList" :key="partner.id" :href="partner.partnersUrl" target="_blank"
+            class="partner-item animate-scale-in" :class="{ 'animate-visible': isCooperationVisible }"
+            :style="{ 'animation-delay': `${0.1 * (index % 6)}s` }">
             <img :src="imgHost + partner.partnersLogo" :alt="partner.partnersName" />
           </a>
         </div>
@@ -166,6 +183,19 @@ export default {
     // 环境变量
     const imgHost = import.meta.env.VITE_APP_IMG_HOST
 
+    // 动画状态管理
+    const isInfoVisible = ref(false)
+    const isProductsVisible = ref(false)
+    const isCasesVisible = ref(false)
+    const isAboutVisible = ref(false)
+    const isCooperationVisible = ref(false)
+
+    // 元素引用
+    const productsSection = ref(null)
+    const casesSection = ref(null)
+    const aboutSection = ref(null)
+    const cooperationSection = ref(null)
+
     // 数字滚动动画相关
     const animatedNumbers = ref({
       number1: 0,
@@ -215,6 +245,43 @@ export default {
       })
     }
 
+    // 设置滚动动画观察器
+    const setupScrollAnimations = () => {
+      const observerOptions = {
+        threshold: 0.2,
+        rootMargin: '0px 0px -50px 0px'
+      }
+
+      const observer = new IntersectionObserver((entries) => {
+        entries.forEach(entry => {
+          if (entry.isIntersecting) {
+            const target = entry.target
+            if (target.classList.contains('banner-section')) {
+              isInfoVisible.value = true
+            } else if (target.classList.contains('products-section')) {
+              isProductsVisible.value = true
+            } else if (target.classList.contains('cases-section')) {
+              isCasesVisible.value = true
+            } else if (target.classList.contains('about-section')) {
+              isAboutVisible.value = true
+            } else if (target.classList.contains('cooperation-section')) {
+              isCooperationVisible.value = true
+            }
+          }
+        })
+      }, observerOptions)
+
+      // 观察各个区域
+      nextTick(() => {
+        const bannerSection = document.querySelector('.banner-section')
+        if (bannerSection) observer.observe(bannerSection)
+        if (productsSection.value) observer.observe(productsSection.value)
+        if (casesSection.value) observer.observe(casesSection.value)
+        if (aboutSection.value) observer.observe(aboutSection.value)
+        if (cooperationSection.value) observer.observe(cooperationSection.value)
+      })
+    }
+
     // 产品分类列表
     let productList = ref([])
     // 当前选中分类的产品列表
@@ -282,36 +349,6 @@ export default {
         projectName: '智慧农业(种植+养殖)',
         projectProfile: '通过物联网技术实现农业自动化管理,利用传感器监控土壤、水质等环境参数,提高农业生产效率。',
         projectImage: 'https://unsplash.it/300/200'
-      },
-      {
-        id: 2,
-        projectName: '智慧停车',
-        projectProfile: '通过车牌识别技术及物联网设备实现停车场智能化管理,实现无感支付和车位引导等功能。',
-        projectImage: 'https://unsplash.it/300/200'
-      },
-      {
-        id: 3,
-        projectName: '副控票务系统',
-        projectProfile: '为景区提供智能化票务管理,智能闸机一体化管理系统,提升游客体验,优化景区运营。',
-        projectImage: 'https://unsplash.it/300/200'
-      },
-      {
-        id: 4,
-        projectName: '智慧校园',
-        projectProfile: '集成学生管理、教学管理、安全监控等功能,为教育机构提供全方位数字化解决方案。',
-        projectImage: 'https://unsplash.it/300/200'
-      },
-      {
-        id: 5,
-        projectName: '智慧医疗',
-        projectProfile: '通过数字化技术提升医疗服务效率,实现患者信息管理、远程诊疗等智能化医疗服务。',
-        projectImage: 'https://unsplash.it/300/200'
-      },
-      {
-        id: 6,
-        projectName: '智慧物流',
-        projectProfile: '利用物联网和大数据技术优化物流配送,实现货物追踪、路径优化等智能化物流管理。',
-        projectImage: 'https://unsplash.it/300/200'
       }
     ])
 
@@ -510,7 +547,13 @@ export default {
       // 设置数字滚动动画的观察器
       nextTick(() => {
         setupIntersectionObserver()
+        setupScrollAnimations()
       })
+
+      // 延迟显示banner信息区域
+      setTimeout(() => {
+        isInfoVisible.value = true
+      }, 800)
     })
 
     onUnmounted(() => {
@@ -537,19 +580,217 @@ export default {
       partnersList,
       goToCaseDetail,
       imgHost,
-      animatedNumbers
+      animatedNumbers,
+      // 动画状态
+      isInfoVisible,
+      isProductsVisible,
+      isCasesVisible,
+      isAboutVisible,
+      isCooperationVisible,
+      // 元素引用
+      productsSection,
+      casesSection,
+      aboutSection,
+      cooperationSection
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
+// 动画定义
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+
+  to {
+    opacity: 1;
+  }
+}
+
+@keyframes slideUp {
+  from {
+    opacity: 0;
+    transform: translateY(30px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+@keyframes slideRight {
+  from {
+    opacity: 0;
+    transform: translateX(-30px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+@keyframes slideLeft {
+  from {
+    opacity: 0;
+    transform: translateX(30px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+@keyframes scaleIn {
+  from {
+    opacity: 0;
+    transform: scale(0.8);
+  }
+
+  to {
+    opacity: 1;
+    transform: scale(1);
+  }
+}
+
+@keyframes bounceIn {
+  0% {
+    opacity: 0;
+    transform: scale(0.3);
+  }
+
+  50% {
+    transform: scale(1.05);
+  }
+
+  70% {
+    transform: scale(0.9);
+  }
+
+  100% {
+    opacity: 1;
+    transform: scale(1);
+  }
+}
+
+@keyframes fadeUp {
+  from {
+    opacity: 0;
+    transform: translateY(40px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+@keyframes fadeLeft {
+  from {
+    opacity: 0;
+    transform: translateX(40px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+// 动画类
+.animate-fade-in {
+  animation: fadeIn 1s ease-out;
+}
+
+.animate-slide-up {
+  opacity: 0;
+  transform: translateY(30px);
+  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+
+  &.animate-visible {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.animate-slide-right {
+  opacity: 0;
+  transform: translateX(-30px);
+  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+
+  &.animate-visible {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+.animate-slide-left {
+  opacity: 0;
+  transform: translateX(30px);
+  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+
+  &.animate-visible {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+.animate-scale-in {
+  opacity: 1;
+  transform: scale(0.95);
+  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+
+  &.animate-visible {
+    opacity: 1;
+    transform: scale(1);
+  }
+}
+
+.animate-bounce-in {
+  opacity: 0;
+  transform: scale(0.3);
+  transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+
+  &.animate-visible {
+    opacity: 1;
+    transform: scale(1);
+  }
+}
+
+.animate-fade-up {
+  opacity: 0;
+  transform: translateY(40px);
+  transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
+
+  &.animate-visible {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.animate-fade-left {
+  opacity: 0;
+  transform: translateX(40px);
+  transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
+
+  &.animate-visible {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
 // banner区域
 .banner-section {
   position: relative;
 
-  img {
-    width: 100%;
+  .banner-image {
+    img {
+      width: 100%;
+    }
   }
 }
 
@@ -591,10 +832,28 @@ export default {
     margin: 0 5px;
     font-family: 'Arial', monospace;
     letter-spacing: 1px;
-    transition: all 0.1s ease;
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
     display: inline-block;
     min-width: 1.2em;
     text-align: center;
+    position: relative;
+    text-shadow: 0 2px 4px rgba(0, 102, 204, 0.2);
+
+    &::after {
+      content: '';
+      position: absolute;
+      bottom: -2px;
+      left: 50%;
+      width: 0;
+      height: 2px;
+      background: linear-gradient(90deg, #0066cc, #00aaff);
+      transform: translateX(-50%);
+      transition: width 0.6s ease;
+    }
+  }
+
+  .info-item:hover .number::after {
+    width: 100%;
   }
 
   .text {
@@ -658,21 +917,37 @@ export default {
       font-size: 24px;
       font-weight: 500;
       color: #343434;
-      transition: all 0.3s ease;
-      // border-radius: 8px;
+      transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+      position: relative;
+      overflow: hidden;
       box-sizing: border-box;
 
+      &::before {
+        content: '';
+        position: absolute;
+        top: 0;
+        left: -100%;
+        width: 100%;
+        height: 100%;
+        background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
+        transition: left 0.6s ease;
+      }
+
       &:hover {
         background: rgba(0, 102, 204, 0.1);
-        border-color: #0066cc;
         color: #0066cc;
+        transform: translateX(5px);
+
+        &::before {
+          left: 100%;
+        }
       }
 
       &.active {
         background: linear-gradient(to right, #CAE0FF, #E5F0FF);
         color: #0054FF;
-        // border-color: #0066cc;
-        // box-shadow: 0 4px 12px rgba(0, 102, 204, 0.3);
+        transform: translateX(8px);
+        box-shadow: 0 4px 15px rgba(0, 102, 204, 0.2);
       }
     }
   }
@@ -759,13 +1034,36 @@ export default {
     align-items: center;
     justify-content: center;
     cursor: pointer;
-    transition: all 0.3s ease;
+    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
     box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
     flex-shrink: 0;
+    position: relative;
+    overflow: hidden;
+
+    &::before {
+      content: '';
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      background: linear-gradient(45deg, rgba(0, 102, 204, 0.1), transparent);
+      opacity: 0;
+      transition: opacity 0.3s ease;
+    }
 
     &:hover {
       background: rgba(255, 255, 255, 1);
-      box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
+      box-shadow: 0 8px 20px rgba(0, 102, 204, 0.15);
+      transform: scale(1.05);
+
+      &::before {
+        opacity: 1;
+      }
+    }
+
+    &:active {
+      transform: scale(0.95);
     }
 
     &.disabled {
@@ -780,16 +1078,28 @@ export default {
       display: flex;
       align-items: center;
       justify-content: center;
+      transition: transform 0.3s ease;
 
       img {
         width: 100%;
         height: 100%;
         object-fit: contain;
+        filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));
       }
     }
 
-    &.nav-arrow-left .arrow-icon {
-      transform: rotate(180deg);
+    &:hover .arrow-icon {
+      transform: translateX(2px);
+    }
+
+    &.nav-arrow-left {
+      .arrow-icon {
+        transform: rotate(180deg);
+      }
+
+      &:hover .arrow-icon {
+        transform: rotate(180deg) translateX(2px);
+      }
     }
   }
 
@@ -809,6 +1119,12 @@ export default {
     flex: 0 0 calc(100% / 3);
     padding: 0 15px;
     box-sizing: border-box;
+    cursor: pointer;
+    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+
+    &:hover {
+      transform: translateY(-8px);
+    }
 
     .case-image {
       width: 100%;
@@ -816,16 +1132,35 @@ export default {
       border-radius: 12px 12px 0 0;
       overflow: hidden;
       background: #fff;
+      position: relative;
+
+      &::after {
+        content: '';
+        position: absolute;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        background: linear-gradient(45deg, rgba(0, 102, 204, 0.1), transparent);
+        opacity: 0;
+        transition: opacity 0.3s ease;
+      }
 
       img {
         width: 100%;
         height: 100%;
         object-fit: cover;
-        transition: transform 0.3s ease;
+        transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+      }
+    }
+
+    &:hover .case-image {
+      &::after {
+        opacity: 1;
       }
 
-      &:hover img {
-        transform: scale(1.05);
+      img {
+        transform: scale(1.08);
       }
     }
 
@@ -835,6 +1170,7 @@ export default {
       box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
       backdrop-filter: blur(10px);
       border-radius: 0 0 12px 12px;
+      transition: box-shadow 0.3s ease;
 
       .case-title {
         text-align: center;
@@ -843,6 +1179,7 @@ export default {
         color: #333;
         margin: 0 0 15px 0;
         line-height: 1.4;
+        transition: color 0.3s ease;
       }
 
       .case-description {
@@ -859,6 +1196,14 @@ export default {
         -webkit-box-orient: vertical;
       }
     }
+
+    &:hover .case-content {
+      box-shadow: 0 8px 25px rgba(0, 102, 204, 0.15);
+
+      .case-title {
+        color: #0066cc;
+      }
+    }
   }
 }
 
@@ -1010,16 +1355,34 @@ export default {
           font-size: 16px;
           font-weight: 500;
           cursor: pointer;
-          transition: all 0.3s ease;
+          transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
           box-shadow: 0 4px 12px rgba(0, 102, 204, 0.3);
+          position: relative;
+          overflow: hidden;
+
+          &::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: -100%;
+            width: 100%;
+            height: 100%;
+            background: linear-gradient(90deg, transparent, rgba(0, 84, 255, 0.1), transparent);
+            transition: left 0.6s ease;
+          }
 
           &:hover {
-            transform: translateY(-2px);
-            box-shadow: 0 6px 20px rgba(0, 102, 204, 0.4);
+            transform: translateY(-3px);
+            box-shadow: 0 8px 25px rgba(0, 102, 204, 0.4);
+            background: rgba(0, 84, 255, 0.05);
+
+            &::before {
+              left: 100%;
+            }
           }
 
           &:active {
-            transform: translateY(0);
+            transform: translateY(-1px);
           }
         }
       }
@@ -1083,28 +1446,45 @@ export default {
       background: rgba(255, 255, 255, 0.9);
       border: 2px solid #E5E5E5;
       border-radius: 8px;
-      transition: all 0.3s ease;
+      transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
       text-decoration: none;
       backdrop-filter: blur(5px);
       overflow: hidden;
+      position: relative;
+
+      &::before {
+        content: '';
+        position: absolute;
+        top: 0;
+        left: -100%;
+        width: 100%;
+        height: 100%;
+        background: linear-gradient(90deg, transparent, rgba(0, 102, 204, 0.1), transparent);
+        transition: left 0.6s ease;
+      }
 
       &:hover {
         background: rgba(255, 255, 255, 1);
         border-color: #0066cc;
-        transform: translateY(-5px);
-        box-shadow: 0 8px 25px rgba(0, 102, 204, 0.15);
+        transform: translateY(-8px) scale(1.02);
+        box-shadow: 0 12px 30px rgba(0, 102, 204, 0.2);
+
+        &::before {
+          left: 100%;
+        }
       }
 
       img {
         max-width: 100%;
         max-height: 84px;
         object-fit: contain;
-        // filter: grayscale(100%);
-        transition: filter 0.3s ease;
+        transition: all 0.4s ease;
+        filter: grayscale(20%);
       }
 
       &:hover img {
-        filter: grayscale(0%);
+        filter: grayscale(0%) brightness(1.1);
+        transform: scale(1.05);
       }
     }
   }