Переглянути джерело

feat: 首页功能+UI完成

chenpeng 1 місяць тому
батько
коміт
868fc43a73
43 змінених файлів з 881 додано та 295 видалено
  1. 1 0
      assets/icons/arrow_line_r.svg
  2. 1 0
      assets/icons/star.svg
  3. BIN
      assets/images/blog_icon01.png
  4. BIN
      assets/images/blog_icon02.png
  5. BIN
      assets/images/blog_icon03.png
  6. BIN
      assets/images/blog_icon04.png
  7. BIN
      assets/images/catalogs_img01.png
  8. BIN
      assets/images/category_item_bg.png
  9. BIN
      assets/images/footer_contact_bg.png
  10. BIN
      assets/images/footer_contact_icon01.png
  11. BIN
      assets/images/footer_contact_icon02.png
  12. BIN
      assets/images/footer_guide_facebook.png
  13. BIN
      assets/images/footer_guide_ins.png
  14. BIN
      assets/images/footer_guide_linkedin.png
  15. BIN
      assets/images/footer_guide_twitter.png
  16. BIN
      assets/images/footer_guide_youtube.png
  17. BIN
      assets/images/icon_face.png
  18. BIN
      assets/images/plus.png
  19. BIN
      assets/images/reduce.png
  20. BIN
      assets/images/swiper_icon2_l.png
  21. BIN
      assets/images/swiper_icon2_r.png
  22. BIN
      assets/images/title_bg.png
  23. BIN
      assets/images/title_bg02.png
  24. BIN
      assets/images/title_bg03.png
  25. BIN
      assets/images/title_bg04.png
  26. 0 1
      components/AppFooter.vue
  27. 1 1
      components/AppHeader.vue
  28. 16 4
      components/business/home/banner.vue
  29. 102 34
      components/business/home/solutions.vue
  30. 52 0
      components/common/block/blog.vue
  31. 166 0
      components/common/block/catalogs.vue
  32. 52 0
      components/common/block/exhibited.vue
  33. 168 0
      components/common/block/faq.vue
  34. 58 0
      components/common/block/partner.vue
  35. 44 0
      components/common/blog/item.vue
  36. 38 0
      components/common/catalogs/item.vue
  37. 0 29
      components/common/category/item.vue
  38. 0 79
      components/common/footer/consult.vue
  39. 154 143
      components/common/footer/guide.vue
  40. 2 1
      package.json
  41. 5 0
      pages/index.vue
  42. 5 0
      plugins/Vue3Marquee.client.ts
  43. 16 3
      pnpm-lock.yaml

+ 1 - 0
assets/icons/arrow_line_r.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="16" height="16" viewBox="0 0 16 16"><defs><clipPath id="master_svg0_308_9824"><rect x="0" y="0" width="16" height="16" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_308_9824)"><g><path d="M11.4,7L2,7L2,8.33333L11.4,8.33333L9.33333,10.4L10.26667,11.33333L13.9333,7.66667L10.33333,4L9.4,4.933333L11.4,7Z" fill="#9B6CFF" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

+ 1 - 0
assets/icons/star.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="24" height="24" viewBox="0 0 24 24"><g><path d="M24,12C15.0928,13.7099,13.7072,15.0956,12,24C10.2928,15.0956,8.90716,13.7099,0,12C8.90716,10.2928,10.2928,8.90716,12,0C13.7099,8.90716,15.0956,10.2928,24,12Z" fill="#FFFF66" fill-opacity="1"/></g></svg>

BIN
assets/images/blog_icon01.png


BIN
assets/images/blog_icon02.png


BIN
assets/images/blog_icon03.png


BIN
assets/images/blog_icon04.png


BIN
assets/images/catalogs_img01.png


BIN
assets/images/category_item_bg.png


BIN
assets/images/footer_contact_bg.png


BIN
assets/images/footer_contact_icon01.png


BIN
assets/images/footer_contact_icon02.png


BIN
assets/images/footer_guide_facebook.png


BIN
assets/images/footer_guide_ins.png


BIN
assets/images/footer_guide_linkedin.png


BIN
assets/images/footer_guide_twitter.png


BIN
assets/images/footer_guide_youtube.png


BIN
assets/images/icon_face.png


BIN
assets/images/plus.png


BIN
assets/images/reduce.png


BIN
assets/images/swiper_icon2_l.png


BIN
assets/images/swiper_icon2_r.png


BIN
assets/images/title_bg.png


BIN
assets/images/title_bg02.png


BIN
assets/images/title_bg03.png


BIN
assets/images/title_bg04.png


+ 0 - 1
components/AppFooter.vue

@@ -3,7 +3,6 @@
 
 <template>
   <div>
-    <common-footer-consult />
     <common-footer-guide />
   </div>
 </template>

+ 1 - 1
components/AppHeader.vue

@@ -15,7 +15,7 @@ const { t } = useI18n()
 
 <template>
   <div
-    class="pos-fixed left-50% translate-x--50% w-full py-20px custom-bg z-100"
+    class="pos-fixed left-50% translate-x--50% w-full py-20px custom-bg z-101"
   >
     <div class="flex justify-between items-center h-32px lh-32px w-1200-auto">
       <div class="flex items-center">

+ 16 - 4
components/business/home/banner.vue

@@ -2,16 +2,16 @@
 
 <script lang="ts" setup>
 import { Swiper, SwiperSlide } from 'swiper/vue'
-import { Navigation, Pagination } from 'swiper/modules'
+import { Autoplay, Navigation, Pagination } from 'swiper/modules'
 import { useUserStore } from '@/stores/modules/user'
 import 'swiper/css'
 import 'swiper/css/navigation'
+import 'swiper/css/autoplay'
 import { getHomeBrandListApi } from '~/api/model/brand'
-// import "swiper/css/pagination"
 
 const userStore = useUserStore()
 const { isLogin } = storeToRefs(userStore)
-const modules = [Navigation, Pagination]
+const modules = [Navigation, Pagination, Autoplay]
 const categoryList = ref<any>([])
 const swiperVertical = ref<any>(null)
 
@@ -41,6 +41,11 @@ function onClickRight() {
   // swiperVertical.value.slideTo(4)
   swiperVertical.value.slideNext()
 }
+function scrollToCatalogs() {
+  const catalogs = document.getElementById('catalogs')
+  if (catalogs)
+    catalogs.scrollIntoView({ behavior: 'smooth', block: 'start' })
+}
 </script>
 
 <template>
@@ -65,7 +70,8 @@ function onClickRight() {
             #Wholesale
           </div>
         </div>
-        <el-button class="my-80px !b-#fff !text-#fff !bg-#878490" round>
+
+        <el-button class="my-80px !b-#fff !text-#fff !bg-#878490" round @click="scrollToCatalogs">
           View Catalogs
         </el-button>
       </div>
@@ -101,6 +107,11 @@ function onClickRight() {
           :modules="modules"
           :centered-slides="true"
           :loop="true"
+          :autoplay="{
+            delay: 3000,
+            disableOnInteraction: false,
+            pauseOnMouseEnter: true,
+          }"
           :navigation="false"
           :pagination="true"
           class="pos-relative"
@@ -135,6 +146,7 @@ function onClickRight() {
   transition: 300ms;
   transform: scale(0.835);
 }
+
 .swiper-slide-active,
 .swiper-slide-duplicate-active {
   transform: scale(1);

+ 102 - 34
components/business/home/solutions.vue

@@ -11,49 +11,107 @@ const list = ref([
   {
     key: 'ecommerce',
     title: 'Ecommerce',
-  },
-  {
-    key: 'brands',
-    title: 'Brands',
-  },
-  {
-    key: 'retailers',
-    title: 'Retailers',
-  },
-])
-const solutions = ref([
-  {
-    title: 'Real-Time Trend Curation',
-    img: solutionIcon01,
-    subTitle:
+    description: 'Scale Smarter with Viral-Ready Products for Online Growth',
+    list: [
+      {
+        title: 'Real-Time Trend Curation',
+        img: solutionIcon01,
+        subTitle:
       'Our team constantly monitors market shifts, viral demand, and emerging bestsellers to deliver high-potential products to you.',
-  },
-  {
-    img: solutionIcon02,
-    title: 'Real-Time Trend Curation',
-    subTitle:
+      },
+      {
+        img: solutionIcon02,
+        title: 'Real-Time Trend Curation',
+        subTitle:
+      'Our team constantly monitors market shifts, viral demand, and emerging bestsellers to deliver high-potential products to you.',
+      },
+      {
+        img: solutionIcon03,
+        title: 'Real-Time Trend Curation',
+        subTitle:
+      'Our team constantly monitors market shifts, viral demand, and emerging bestsellers to deliver high-potential products to you.',
+      },
+      {
+        img: solutionIcon04,
+        title: 'Real-Time Trend Curation',
+        subTitle:
       'Our team constantly monitors market shifts, viral demand, and emerging bestsellers to deliver high-potential products to you.',
+      },
+    ],
   },
   {
-    img: solutionIcon03,
-    title: 'Real-Time Trend Curation',
-    subTitle:
-      'Our team constantly monitors market shifts, viral demand, and emerging bestsellers to deliver high-potential products to you.',
+    key: 'brands',
+    title: 'Brands & Distributors',
+    description: 'Power Your Product Line with Trend Intelligence & Agile Supply',
+    list: [
+      {
+        title: 'OEM/ODM Trend Support',
+        img: solutionIcon01,
+        subTitle:
+      'We provide trend-based design, packaging, and product development to help brands create unique, market-driven products.',
+      },
+      {
+        img: solutionIcon02,
+        title: 'Co-Branded Development',
+        subTitle:
+      'Quick-turn co-branded collections to help brands launch exclusive, limited-edition products and increase market impact.',
+      },
+      {
+        img: solutionIcon03,
+        title: 'Flexible Logistic Solution',
+        subTitle:
+      'Whether it’s bulk shipments, mixed containers, our flexible logistics solutions adapt to your business model and market goals.',
+      },
+      {
+        img: solutionIcon04,
+        title: 'Exclusive Channel Protection',
+        subTitle:
+      'We protect your brand with exclusive regional rights, limited distribution agreements, and secure your market position.',
+      },
+    ],
   },
   {
-    img: solutionIcon04,
-    title: 'Real-Time Trend Curation',
-    subTitle:
-      'Our team constantly monitors market shifts, viral demand, and emerging bestsellers to deliver high-potential products to you.',
+    key: 'retailers',
+    title: 'Retailers & Chain Stores',
+    description: 'Upgrade Your Shelves with Trendy, High-Margin Products',
+    list: [
+      {
+        title: 'Ready-to-Display Portfolios',
+        img: solutionIcon01,
+        subTitle:
+      'Curated product bundles that align with current trends, ready for effortless shelf display and enhanced retail appeal.',
+      },
+      {
+        img: solutionIcon02,
+        title: 'Trend-Aligned Launch Plan',
+        subTitle:
+      'Tailored product launch plans based on market cycles to create a differentiated product portfolio that engages customers.',
+      },
+      {
+        img: solutionIcon03,
+        title: 'Store Display Solution',
+        subTitle:
+      'Strategic display guides that show what to place where — helping your team position products by zone and boost visual appeal.',
+      },
+      {
+        img: solutionIcon04,
+        title: 'Go-to Market Support',
+        subTitle:
+      'Customizable marketing assets to support both online and offline promotions — helping you boost visibility and drive sales.',
+      },
+    ],
   },
 ])
+const solutionList = computed(() => {
+  return list.value.find((item: any) => item.key === solution.value)?.list
+})
 </script>
 
 <template>
   <div class="bg-#F3F4FB pt-250px pb-120px">
     <div class="w-1200-auto text-center">
       <h2 class="text-36px fw-800 text-#333 !mb-20px">
-        Creative, Trend-Driven Solutions
+        Creative, Trend-Driven <span class="custom-title-bg">Solutions</span>
       </h2>
       <div class="text-#999 text-22px mb-40px">
         EJET SPARK FOR
@@ -62,7 +120,7 @@ const solutions = ref([
         <div
           v-for="(item, index) in list"
           :key="index"
-          class="py-12px w-170px b-rd-200px text-18px cursor-pointer hover:bg-#9B6CFF hover:text-#fff transition-all duration-300"
+          class="py-12px px-30px b-rd-200px text-18px cursor-pointer hover:bg-#9B6CFF hover:text-#fff transition-all duration-300"
           :class="
             solution === item.key
               ? '!bg-#9B6CFF !text-#fff'
@@ -84,10 +142,10 @@ const solutions = ref([
             class="py-20px px-30px b-rd-tl-10px b-rd-tr-10px mt--60px bg-#fff pos-relative z-100"
           >
             <h3 class="text-24px fw-bold text-#333">
-              Ecommerce
+              {{ list.find(item => item.key === solution)?.title }}
             </h3>
             <div class="my-22px lh-24px text-#666">
-              Scale Smarter with Viral-Ready Products for Online Growth
+              {{ list.find(item => item.key === solution)?.description }}
             </div>
             <el-button class="!bg-#fff !b-rd-6px !h-40px">
               <nuxt-link to="/solutions">
@@ -98,7 +156,7 @@ const solutions = ref([
         </div>
         <div class="flex-1">
           <div class="grid grid-cols-2 gap-col-80px gap-row-50px">
-            <div v-for="(item, index) in solutions" :key="index">
+            <div v-for="(item, index) in solutionList" :key="index">
               <img :src="item.img" class="w-50px h-50px" alt="" srcset="">
               <h4 class="!mt-20px !mb-10px text-#333 text-18px fw-800">
                 {{ item.title }}
@@ -114,4 +172,14 @@ const solutions = ref([
   </div>
 </template>
 
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.custom-title-bg{
+  position: relative;
+  display: inline-block;
+  background: url(~/assets/images/title_bg.png);
+  background-repeat: no-repeat;
+  background-position: center 100%;
+  background-size: 100% auto;
+  padding-bottom: 8px;
+}
+</style>

+ 52 - 0
components/common/block/blog.vue

@@ -0,0 +1,52 @@
+<script lang='ts' setup>
+import {
+  getBlogsListApi,
+} from '~/api/model/blogs'
+
+const list = ref<any>([])
+async function getVideoOrBlogsList(pageNo = 1, pageSize = 3) {
+  const params = {
+    pageNo,
+    pageSize,
+    categoryId: '',
+    orderBy: 'createTime',
+    orderType: 'desc',
+  }
+  const res: any = await getBlogsListApi(params)
+  list.value = res.records
+}
+getVideoOrBlogsList()
+</script>
+
+<template>
+  <div class="bg-#fff pt-160px pb-120px">
+    <div class="w-1200-auto text-center">
+      <h2 class="!text-36px !fw-800 text-#333 !mb-44px">
+        EJET Spark <span class="custom-title-bg">Blog</span>
+      </h2>
+      <div class="flex items-center justify-end text-#9B6CFF cursor-pointer text-14px fw-bold mb-20px">
+        View All
+        <svgo-arrow-line-r class="w-16px h-16px ml-10px" />
+      </div>
+      <div class=" grid grid-cols-3 gap-40px text-left">
+        <div v-for="item, index in list" :key="index">
+          <NuxtLink to="/register">
+            <common-blog-item :item="item" />
+          </NuxtLink>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang='less' scoped>
+.custom-title-bg{
+  position: relative;
+  display: inline-block;
+  background: url(~/assets/images/title_bg03.png);
+  background-repeat: no-repeat;
+  background-position: center 100%;
+  background-size: 100% auto;
+  padding-bottom: 8px;
+}
+</style>

+ 166 - 0
components/common/block/catalogs.vue

@@ -0,0 +1,166 @@
+<!-- @format -->
+
+<script lang="ts" setup>
+import { Swiper, SwiperSlide } from 'swiper/vue'
+import { Navigation, Pagination } from 'swiper/modules'
+import 'swiper/css'
+import 'swiper/css/navigation'
+import { getHomeBrandListApi } from '~/api/model/brand'
+
+const modules = [Navigation, Pagination]
+const categoryList = ref<any>([])
+const swiperVertical = ref<any>(null)
+
+const solution = ref('category')
+const list = ref([
+  {
+    key: 'category',
+    title: 'By Category',
+  },
+  {
+    key: 'trend',
+    title: 'By Trend',
+  },
+])
+
+getHomeBrandList()
+async function getHomeBrandList() {
+  try {
+    const params = {
+      pageNo: 1,
+      pageSize: 8,
+    }
+    const data: any = await getHomeBrandListApi(params)
+    categoryList.value = data.records
+  }
+  catch (error) {
+    console.log('error', error)
+  }
+}
+
+function onVerticalSwiper(swiper: any) {
+  swiperVertical.value = swiper
+}
+function onClickLeft() {
+  // swiperVertical.value.slideTo()
+  swiperVertical.value.slidePrev()
+}
+function onClickRight() {
+  // swiperVertical.value.slideTo(4)
+  swiperVertical.value.slideNext()
+}
+function setTranslate(swiper: any, _translate: any) {
+  // 设置第一个位置的背景色为#D7C4FF
+  if (swiper) {
+    swiper.slides.forEach((_slide: any, _i: number) => {
+      const slider = swiper.slides[_i]
+      if (_i === 1)
+        slider.style.backgroundColor = '#D7C4FF'
+
+      else
+        slider.style.backgroundColor = ''
+    })
+  }
+}
+// function setTransition(swiper: any, _transition: any) {
+//   if (!swiper)
+//     return
+//   for (let i = 0; i < swiper.slides.length; i++) {
+//     const slider = swiper.slides[i]
+//     // console.log('slide------222', slider)
+//     slider.style.transition = `${_transition}ms`
+//   }
+// }
+</script>
+
+<template>
+  <div id="catalogs" class="bg-#0F0820 pt-100px pb-160px">
+    <div class="w-1200-auto text-left pos-relative">
+      <h2 class="text-36px fw-800 text-#fff !mb-40px">
+        Download EJET Spark  <span class="custom-title-bg">Catalogs</span>
+      </h2>
+      <div class="flex gap-20px mb-30px text-center">
+        <div
+          v-for="(item, index) in list"
+          :key="index"
+          class="py-8px w-132px b-rd-6px text-14px fw-bold b-solid b-1px cursor-pointer hover:bg-#fff hover:text-#000 transition-all duration-300"
+          :class="
+            solution === item.key
+              ? '!bg-#fff !text-#000 b-#fff'
+              : 'bg-#0F0820 text-#fff b-#fff'
+          "
+          @click="solution = item.key"
+        >
+          <div>{{ item.title }}</div>
+        </div>
+      </div>
+      <div class="w-1200-auto pos-relative">
+        <div class="flex items-center justify-end text-#fff text-14px fw-bold mb-20px cursor-pointer">
+          View All
+          <svgo-arrow-line-r class="w-16px h-16px ml-10px" />
+        </div>
+        <div
+          class="pos-absolute cursor-pointer left-48% bottom--60px w-30px h-30px transform-translate-x--50% cursor-not-allowed !cursor-pointer flex justify-center items-center"
+          @click="onClickLeft()"
+        >
+          <img
+            src="~/assets/images/swiper_icon2_l.png"
+            alt=""
+            class="!w-2430px !h-30px"
+            srcset=""
+          >
+        </div>
+        <div
+          class="pos-absolute cursor-pointer left-52% bottom--60px w-28px h-28px transform-translate-x--50% cursor-not-allowed !cursor-pointer flex justify-center items-center"
+          @click="onClickRight()"
+        >
+          <img
+            src="~/assets/images/swiper_icon2_r.png"
+            alt=""
+            class="!w-30px !h-30px"
+            srcset=""
+          >
+        </div>
+        <!-- @set-transition="setTransition" -->
+        <Swiper
+          v-if="categoryList.length"
+          :slides-per-view="3"
+          :space-between="20"
+          :modules="modules"
+          :centered-slides="true"
+          :loop="true"
+          :navigation="false"
+          :pagination="true"
+          class="pos-relative"
+          @set-translate="setTranslate"
+          @swiper="onVerticalSwiper"
+        >
+          <SwiperSlide v-for="(item, index) in categoryList" :key="index">
+            <common-catalogs-item :item="item" />
+          </SwiperSlide>
+        </Swiper>
+      </div>
+      <img
+        class="w-240px h-148px pos-absolute right-0 bottom--160px z-101"
+        src="~/assets/images/catalogs_img01.png"
+        alt=""
+      >
+    </div>
+  </div>
+</template>
+
+<style lang="less" scoped>
+.swiper-slide{
+  border-radius: 10px;
+  background-color: #fff;
+}
+.custom-title-bg{
+  position: relative;
+  display: inline-block;
+  background: url(~/assets/images/title_bg02.png);
+  background-repeat: no-repeat;
+  background-position: center 100%;
+  background-size: 100% auto;
+  padding-bottom: 8px;
+}
+</style>

+ 52 - 0
components/common/block/exhibited.vue

@@ -0,0 +1,52 @@
+<script lang='ts' setup>
+import icon_01 from '~/assets/images/blog_icon01.png'
+import icon_02 from '~/assets/images/blog_icon02.png'
+import icon_03 from '~/assets/images/blog_icon03.png'
+import icon_04 from '~/assets/images/blog_icon04.png'
+
+const list = [
+  {
+    icon: icon_01,
+    title: 'Products In Stock',
+    total: '20,000',
+  },
+  {
+    icon: icon_02,
+    title: 'Monthly Updating',
+    total: '5,000',
+  },
+  {
+    icon: icon_03,
+    title: 'Product Portfolios',
+    total: '2,000',
+  },
+  {
+    icon: icon_04,
+    title: 'Display Solutions',
+    total: '200',
+  },
+]
+</script>
+
+<template>
+  <div class="bg-#0F0820 pt-110px pb-120px">
+    <div class="w-1200-auto text-center flex gap-190px justify-between">
+      <div v-for="item, index in list" :key="index">
+        <img
+          :src="item.icon"
+          alt=""
+          class="w-80px h-80px mx-auto"
+        >
+        <div class="text-#fff text-36px fw-900 mt-20px mb-10px ls-2">
+          {{ item.total }}+
+        </div>
+        <div class="text-#fff text-20px fw-500">
+          {{ item.title }}
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang='less' scoped>
+</style>

+ 168 - 0
components/common/block/faq.vue

@@ -0,0 +1,168 @@
+<!-- @format -->
+
+<script lang="ts" setup>
+const activeName = ref()
+</script>
+
+<template>
+  <div class="bg-#F3F4FB py-120px">
+    <div class="w-1200-auto flex justify-between">
+      <div>
+        <div
+          class="py-5px mb-20px w-70px text-center text-#9B6CFF b-rd-200px bg-#EAE5FA"
+        >
+          FAQ
+        </div>
+        <h2 class="!mb-10px text-#333 text-36px !fw-800">
+          Frequently
+        </h2>
+        <h2 class="!mb-20px text-#333 text-36px !fw-800">
+          Asked <span class="custom-title-bg">Questions</span>
+        </h2>
+        <div
+          class="py-14px text-14px w-128px text-center text-#fff b-rd-200px bg-#0F0820 hover:bg-#9B6CFF hover:text-#fff cursor-pointer"
+        >
+          Learn More
+        </div>
+      </div>
+      <div class="custom-collapse w-680px pos-relative">
+        <el-collapse v-model="activeName" accordion>
+          <el-collapse-item
+            name="1"
+          >
+            <template #title>
+              <div class="flex">
+                <div class="w-36px mt-6px h-36px text-16px lh-36px text-center b-rd-50% bg-#9B6CFF text-#fff mr-20px">
+                  1
+                </div>
+                <h3 class="flex-1 text-24px fw-bold text-#333 text-left lh-34px w-520px">
+                  What is the suggested strategy to manage creative fatigue?
+                </h3>
+              </div>
+            </template>
+            <template #icon="{ isActive }">
+              <img v-if="!isActive" src="@/assets/images/plus.png" class="!w-20px !h-20px mt-12px">
+              <img v-else src="@/assets/images/reduce.png" class="!w-20px !h-20px mt-12px ">
+            </template>
+            <div class="text-#999 fw-500 lh-24px mt-10px px-60px">
+              Consistent with real life: in line with the process and logic of
+              real life, and comply with languages and habits that the users are
+              used to;
+            </div>
+          </el-collapse-item>
+          <el-collapse-item
+            name="2"
+          >
+            <template #title>
+              <div class="flex">
+                <div class="w-36px mt-6px h-36px text-16px lh-36px text-center b-rd-50% bg-#9B6CFF text-#fff mr-20px">
+                  2
+                </div>
+                <h3 class="flex-1 text-24px fw-bold text-#333 text-left lh-34px w-520px">
+                  What is the suggested strategy to manage creative fatigue?
+                </h3>
+              </div>
+            </template>
+            <template #icon="{ isActive }">
+              <img v-if="!isActive" src="@/assets/images/plus.png" class="!w-20px !h-20px mt-12px">
+              <img v-else src="@/assets/images/reduce.png" class="!w-20px !h-20px mt-12px ">
+            </template>
+            <h3 class="text-#999 fw-500 lh-24px mt-10px px-60px">
+              Consistent with real life: in line with the process and logic of
+              real life, and comply with languages and habits that the users are
+              used to;
+            </h3>
+          </el-collapse-item>
+          <el-collapse-item
+            name="3"
+          >
+            <template #title>
+              <div class="flex">
+                <div class="w-36px mt-6px h-36px text-16px lh-36px text-center b-rd-50% bg-#9B6CFF text-#fff mr-20px">
+                  3
+                </div>
+                <div class="flex-1 text-24px fw-bold text-#333 text-left lh-34px w-520px">
+                  What is the suggested strategy to manage creative fatigue?
+                </div>
+              </div>
+            </template>
+            <template #icon="{ isActive }">
+              <img v-if="!isActive" src="@/assets/images/plus.png" class="!w-20px !h-20px mt-12px">
+              <img v-else src="@/assets/images/reduce.png" class="!w-20px !h-20px mt-12px ">
+            </template>
+            <h3 class="text-#999 fw-500 lh-24px mt-10px px-60px">
+              Consistent with real life: in line with the process and logic of
+              real life, and comply with languages and habits that the users are
+              used to;
+            </h3>
+          </el-collapse-item>
+          <el-collapse-item
+            name="4"
+          >
+            <template #title>
+              <div class="flex">
+                <div class="w-36px mt-6px h-36px text-16px lh-36px text-center b-rd-50% bg-#9B6CFF text-#fff mr-20px">
+                  4
+                </div>
+                <div class="flex-1 text-24px fw-bold text-#333 text-left lh-34px w-520px">
+                  What is the suggested strategy to manage creative fatigue?
+                </div>
+              </div>
+            </template>
+            <template #icon="{ isActive }">
+              <img v-if="!isActive" src="@/assets/images/plus.png" class="!w-20px !h-20px mt-12px">
+              <img v-else src="@/assets/images/reduce.png" class="!w-20px !h-20px mt-12px ">
+            </template>
+            <h3 class="text-#999 fw-500 lh-24px mt-10px px-60px">
+              Consistent with real life: in line with the process and logic of
+              real life, and comply with languages and habits that the users are
+              used to;
+            </h3>
+          </el-collapse-item>
+        </el-collapse>
+        <img src="@/assets/images/icon_face.png" class="w-70px h-70px pos-absolute top--50px right-0px" alt="" srcset="">
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="less">
+.custom-collapse {
+  .el-collapse {
+    .el-collapse-item {
+      margin-bottom: 20px;
+      border-radius: 12px;
+      background-color: #fff;
+      box-sizing: border-box;
+      border: 1px solid #e0e4ea;
+      overflow: hidden;
+      padding: 30px;
+
+      .el-collapse-item__header {
+          border-bottom: unset !important;
+          display: flex;
+          justify-content: space-between;
+            align-items: start;
+            height:  unset !important;
+            line-height: unset !important;
+        }
+        &.is-active{
+            .el-collapse-item__wrap{
+                border-bottom: unset !important;
+            }
+        }
+        .el-collapse-item__content{
+            padding: 0px !important;
+        }
+    }
+  }
+}
+.custom-title-bg{
+  position: relative;
+  display: inline-block;
+  background: url(~/assets/images/title_bg04.png);
+  background-repeat: no-repeat;
+  background-position: 88% 150%;
+  background-size: 94% auto;
+}
+</style>

+ 58 - 0
components/common/block/partner.vue

@@ -0,0 +1,58 @@
+<script lang='ts' setup>
+const avatarArray = [
+  ['https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70'],
+  ['https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70'],
+  ['https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70', 'https://picsum.photos/240/70'],
+]
+const colorMode = useColorMode()
+</script>
+
+<template>
+  <div class="bg-#fff py-120px">
+    <div class="w-1200-auto text-center">
+      <h2 class="text-36px fw-800 text-#333 !mb-86px">
+        Our Bussiness <span class="custom-title-bg">Partners</span>
+      </h2>
+      <Vue3Marquee
+        :pause-on-hover="true"
+        :gradient="true"
+        :gradient-color="colorMode !== 'light' ? [255, 255, 255] : [0, 0, 0]"
+        gradient-length="10%"
+      >
+        <div v-for="avatar, i in avatarArray[0]" :key="i">
+          <img :src="avatar" class="w-220px h-70px mr-30px mb-40px b-rd-6px">
+        </div>
+      </Vue3Marquee>
+      <Vue3Marquee
+        :pause-on-hover="true"
+        :gradient="true"
+        gradient-length="10%"
+      >
+        <div v-for="avatar, i in avatarArray[1]" :key="i">
+          <img :src="avatar" class="w-220px h-70px mr-30px mb-40px b-rd-6px">
+        </div>
+      </Vue3Marquee>
+      <Vue3Marquee
+        :pause-on-hover="true"
+        :gradient="true"
+        gradient-length="10%"
+      >
+        <div v-for="avatar, i in avatarArray[2]" :key="i">
+          <img :src="avatar" class="w-220px h-70px mr-30px b-rd-6px">
+        </div>
+      </Vue3Marquee>
+    </div>
+  </div>
+</template>
+
+<style lang='less' scoped>
+.custom-title-bg{
+  position: relative;
+  display: inline-block;
+  background: url(~/assets/images/title_bg.png);
+  background-repeat: no-repeat;
+  background-position: center 100%;
+  background-size: 100% auto;
+  padding-bottom: 8px;
+}
+</style>

+ 44 - 0
components/common/blog/item.vue

@@ -0,0 +1,44 @@
+<!-- @format -->
+
+<script lang="ts" setup>
+defineProps({
+  item: Object as any,
+})
+</script>
+
+<template>
+  <div class="pos-relative">
+    <nuxt-link :to="{ name: 'blog-slug', params: { slug: item?.slug } }">
+      <img :src="item.thumbnailUrl" alt="" srcset="" class="w-375px h-240px b-rd-10px object-cover">
+      <div class="pos-absolute top-10px b-rd-400px left-10px text-center w-138px py-10px bg-#f0f1f3 text-#9B6CFF text-14px b-1px b-solid b-#e7e7e7">
+        {{ item.category_dictText }}
+      </div>
+      <h3
+        class="!mb-15px !mt-30px fw-800 text-24px text-#333 line-clamp-2"
+      >
+        {{ item.contentTitle }}
+      </h3>
+      <div class="text-14px text-#999 lh-22px line-clamp-2">
+        {{ item.contentSubhead }}
+      </div>
+    </nuxt-link>
+  </div>
+</template>
+
+<style lang="less" scoped>
+.read-more {
+  &:after {
+    position: absolute;
+    content: "";
+    bottom: -4px;
+    left: 0;
+    width: 20%;
+    height: 2px;
+    background: #cda274;
+    border-radius: 1dvb;
+    transition:
+      height 0.3s,
+      background 0.3s; /* 明确过渡效果 */
+  }
+}
+</style>

+ 38 - 0
components/common/catalogs/item.vue

@@ -0,0 +1,38 @@
+<script lang='ts' setup>
+defineProps({
+  item: Object as any,
+  isFavorite: {
+    type: Boolean,
+    default: false,
+  },
+})
+</script>
+
+<template>
+  <div class="custom-main mx-auto  overflow-hidden pos-relative">
+    <svgo-star class="pos-absolute top-20px right-20px w-20px h-20px" />
+    <div class="p-20px pb-30px">
+      <h2 class="!mb-15px w-250px text-24px fw-800 text-#333 line-clamp-2">
+        {{ item.brandName }}
+      </h2>
+      <div class="text-#666 lh-24px ">
+        {{ item.brandName }}
+      </div>
+    </div>
+    <img
+      :src="item.thumbnail || item.masterImage"
+      alt=""
+      srcset=""
+      class="w-100% b-rd-tl-10px h-100% b-rd-tr-10px object-cover"
+    >
+  </div>
+</template>
+
+<style lang="less" scoped>
+.custom-main{
+  width: 386px;
+  height: 468px;
+  border-radius: 10px;
+//   background: #fff;
+}
+</style>

+ 0 - 29
components/common/category/item.vue

@@ -1,8 +1,4 @@
 <script lang='ts' setup>
-import { computed, defineAsyncComponent, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
-
-import { setBrandFavoriteApi } from '~/api/model/brand'
-
 defineProps({
   item: Object as any,
   isFavorite: {
@@ -10,31 +6,6 @@ defineProps({
     default: false,
   },
 })
-
-const emit = defineEmits(['update:favorite', 'click:detail'])
-const { openLoginModal } = useLoginModal()
-
-const hoverStatus = ref<any>()
-
-async function onFavorite(item: any) {
-  try {
-    const { status } = await openLoginModal()
-    if (status) {
-      const params = { bid: item.id, type: item.isFavorite ? 2 : 1 }
-      await setBrandFavoriteApi(params)
-      item.isFavorite = !item.isFavorite
-      ElMessage({
-        message: `${item.isFavorite ? 'Add' : 'Remove'} to My Favourites Successfully`,
-        type: 'success',
-        plain: true,
-      })
-      emit('update:favorite', item)
-    }
-  }
-  catch (error) {
-    console.log(error)
-  }
-}
 </script>
 
 <template>

+ 0 - 79
components/common/footer/consult.vue

@@ -1,79 +0,0 @@
-<script lang='ts' setup>
-// import { useUserStore } from '@/stores/modules/user'
-import { submitSubscribeApi } from '~/api/model/common'
-
-// const userStore = useUserStore()
-// const { isLogin } = storeToRefs(userStore)
-const form = ref<any>({
-  mail: '',
-})
-async function submitSubscribe() {
-  try {
-    await submitSubscribeApi(form.value)
-    ElMessage.success(`You've subscribed successfully.`)
-    form.value.mail = ''
-  }
-  catch (error) {
-    console.log(error)
-  }
-}
-const validateEmail = computed(() => {
-  const emailReg = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/
-  if (!form.value.mail)
-    return true
-  return emailReg.test(form.value.mail)
-})
-</script>
-
-<template>
-  <div class="p-40px pb-0 pt-58px mb-216px pr-150px w-1400px mx-auto bg-#F8F5F3">
-    <div class="flex justify-between pos-relative">
-      <div class="w-620px">
-        <div class="text-#999999 mb-10px">
-          QUALITY WHOLESALE
-        </div>
-        <h2 class="text-40px fw-600 lh-56px text-#333 !mb-30px custom-title-font">
-          Subscribe for Exclusive Wholesale Offers and Updates!
-        </h2>
-        <div class="pos-relative w-500px">
-          <el-input v-model.trim="form.mail" class="custom-input h-50px  " placeholder="Enter your email here" />
-          <el-button :disabled="!validateEmail || !form.mail" type="primary" class="!bg-#fff pos-absolute top-50% transform-translate-y--50% right-10px w-140px !h-40px !text-16px !b-rd-150px" @click="submitSubscribe">
-            Subscribe
-          </el-button>
-        </div>
-        <div v-if="!validateEmail" class="text-red mt-4px">
-          Please enter a valid email address.
-        </div>
-      </div>
-      <div class="flex items-end">
-        <img src="@/assets/images/footer_consult.png" class="w-450px h-250px" alt="" srcset="">
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang='less' scoped>
-.consult-item{
-  &::before{
-    position: absolute;
-    content: "";
-    bottom:  10%;
-    top:  10%;
-    right: 0px;
-    width: 1px;
-    background: #5B463E;
-  }
-  &:last-child::before{
-    display: none;
-  }
-}
-::v-deep(.custom-input){
-  .el-input__wrapper{
-    border-radius:4px!important;
-    padding-left: 20px!important;
-    color: #999;
-    font-size: 16px;
-    box-shadow: unset!important;
-  }
-}
-</style>

+ 154 - 143
components/common/footer/guide.vue

@@ -4,159 +4,170 @@
 
 <template>
   <div>
-    <div class="w-1400px mx-auto pb-40px flex justify-between">
-      <div class="w-50%">
-        <img
-          src="~/assets/images/ejet_logo.png"
-          class="w-200px h-31px"
-          alt=""
-          srcset=""
-        >
-        <div class="mt-40px mb-40px text-#000 lh-24px w-380px">
-          To bridge international retailers with premium Chinese manufacturing
-          brands
-        </div>
-        <div class="flex gap-20px justify-start">
-          <a href="https://www.youtube.com/@EJETSelection" target="_blank">
-            <img
-              src="~/assets/images/footer_guide_youtube.png"
-              alt=""
-              class="w-28px h-28px"
-              srcset=""
-            ></a>
-          <a href="https://www.facebook.com/profile.php?id=61573209305275" target="_blank">
-            <img
-              src="~/assets/images/footer_guide_facebook.png"
-              alt=""
-              class="w-28px h-28px"
-              srcset=""
-            ></a>
-          <a href="https://www.instagram.com/ejetselection.official/" target="_blank">
-            <img
-              src="~/assets/images/footer_guide_ins.png"
-              alt=""
-              class="w-28px h-28px"
-              srcset=""
-            ></a>
-          <a href="https://www.linkedin.com/company/ejet-selection" target="_blank">
-            <img
-              src="~/assets/images/footer_guide_linkedin.png"
-              alt=""
-              class="w-28px h-28px"
-              srcset=""
-            ></a>
-          <a href="https://www.pinterest.com/ejetselection/" target="_blank">
-            <img
-              src="~/assets/images/footer_guide_pinterest.png"
-              class="w-28px h-28px"
-              alt=""
-              srcset=""
-            ></a>
-          <a href="https://api.whatsapp.com/send/?phone=8619005896286" target="_blank">
-            <img
-              src="~/assets/images/footer_guide_whatsApp.png"
-              class="w-28px h-28px"
-              alt=""
-              srcset=""
-            ></a>
-        </div>
-      </div>
-      <div class="w-50% flex">
-        <div class="w-33% text-#666666">
-          <h4 class="!mb-40px fw-500 text-22px text-#333333 footer-font">
-            Discover
-          </h4>
-          <div class="mb-30px">
-            <NuxtLink to="/about" class="hover:text-#CC9879">
-              About Us
-            </NuxtLink>
-          </div>
-          <div class="mb-30px">
-            <NuxtLink to="/blog" class="hover:text-#CC9879">
-              Blog
-            </NuxtLink>
+    <div class="h-300px bg-#fff pos-relative">
+      <div class="w-1200-auto pos-absolute left-50% translate-x--50% top-50% h-300px pl-40px pr-80px bg-#D7C4FF b-rd-10px flex items-center justify-between">
+        <div class="w-540px">
+          <img src="@/assets/images/footer_contact_icon01.png" class="w-50px h-50px mb-10px" alt="">
+          <h2 class="text-36px fw-bold lh-60px">
+            Ready to Start with EJET Spark?
+          </h2>
+          <div class="text-24px mt-10px">
+            Contact us to get exclusive catalogs!
           </div>
-          <div class="mb-30px">
-            <NuxtLink to="/contact" class="hover:text-#CC9879">
-              Sourcing
-            </NuxtLink>
-          </div>
-          <div>
-            <NuxtLink to="https://www.ejet-group.com/service/ejet-selection" class="hover:text-#CC9879">
-              Sell on EJET
-            </NuxtLink>
+          <div
+            class="py-8px mt-30px text-14px fw-500 w-128px text-center text-#fff b-rd-200px flex justify-center items-center bg-#0F0820 hover:bg-#9B6CFF hover:text-#fff cursor-pointer"
+          >
+            Contact Us
+            <img src="@/assets/images/footer_contact_icon02.png" class="w-24px h-24px ml-6px" alt="">
           </div>
         </div>
-        <div class="w-33% text-#666666">
-          <h4 class="!mb-40px fw-500 text-22px text-#333333 footer-font">
-            Support
-          </h4>
-          <div class="mb-30px">
-            <NuxtLink to="/contact" class="hover:text-#CC9879">
-              Contact Us
-            </NuxtLink>
+        <img src="@/assets/images/footer_contact_bg.png" class="w-420px h-100%" alt="">
+      </div>
+    </div>
+    <div class="flex bg-#0F0820 pt-236px pb-50px">
+      <div class="w-1200-auto ">
+        <div class="flex mb-80px">
+          <div class="w-25% text-#fff text-16px">
+            <h4 class="!mb-30px fw-500 text-24px">
+              Company
+            </h4>
+            <div class="mb-30px">
+              <NuxtLink to="/about" class="hover:text-#9B6CFF">
+                About Us
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/" class="hover:text-#9B6CFF">
+                EJET Selection
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/" class="hover:text-#9B6CFF">
+                EJET Procurement
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/contact" class="hover:text-#9B6CFF">
+                Contact Us
+              </NuxtLink>
+            </div>
+            <div>
+              <NuxtLink
+                to="/"
+                class="hover:text-#9B6CFF"
+              >
+                Become a Partner
+              </NuxtLink>
+            </div>
           </div>
-          <!-- <div class="mb-30px">
-            <NuxtLink to="/" class="hover:text-#CC9879">
-              FAQs
-            </NuxtLink>
-          </div> -->
-          <!-- <div class="mb-30px">
-            <NuxtLink to="/service" class=" hover:text-#CC9879">
-              Terms of Service
-            </NuxtLink>
+          <div class="w-25% text-#fff text-16px">
+            <h4 class="!mb-30px fw-500 text-24px">
+              Product
+            </h4>
+            <div class="mb-30px">
+              <NuxtLink to="/solutions" class="hover:text-#9B6CFF">
+                Solutions
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/" class="hover:text-#9B6CFF">
+                Catalogs by Category
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/" class="hover:text-#9B6CFF">
+                Catalogs by Trend
+              </NuxtLink>
+            </div>
           </div>
-          <div class="mb-30px">
-            <NuxtLink to="/policy" class=" hover:text-#CC9879 mb-30px">
-              Privacy Service
-            </NuxtLink>
+          <div class="w-25% text-#fff text-16px">
+            <h4 class="!mb-30px fw-500 text-24px">
+              Resources
+            </h4>
+            <div class="mb-30px">
+              <NuxtLink to="/blog" class="hover:text-#9B6CFF">
+                Blog
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/" class="hover:text-#9B6CFF">
+                EJET Selection
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/faq" class="hover:text-#9B6CFF">
+                FAQ
+              </NuxtLink>
+            </div>
+            <div class="mb-30px">
+              <NuxtLink to="/contact" class="hover:text-#9B6CFF">
+                2025 Trend Forcast
+              </NuxtLink>
+            </div>
+          </div>
+          <div class="w-25% text-right flex justify-end">
+            <img
+              class="w-240px h-148px"
+              src="~/assets/images/catalogs_img01.png"
+              alt=""
+            >
           </div>
-          <div>
-            <NuxtLink to="/" class=" hover:text-#CC9879">
-              Refund Policy
-            </NuxtLink>
-          </div> -->
         </div>
-        <div class="w-33% text-#666666">
-          <h4 class="!mb-40px fw-500 text-22px text-#333333 footer-font">
-            Contacts
-          </h4>
-          <div class="mb-30px">
-            7th Floor, Tianbo International Building,<br> 55 Jiangdong Middle Road,<br> Yiwu, Zhejiang, China
+        <div class=" bg-#575262 h-1px" />
+        <div class="pt-30px flex justify-between items-center">
+          <div class="flex items-center">
+            <svgo-spark-logo
+              class="!w-132px !h-32px text-#fff"
+            />
+            <div class="flex gap-20px justify-start ml-40px">
+              <a href="https://www.facebook.com/profile.php?id=61573209305275" target="_blank">
+                <img
+                  src="~/assets/images/footer_guide_facebook.png"
+                  alt=""
+                  class="w-24px h-24px"
+                  srcset=""
+                ></a>
+              <a href="https://www.instagram.com/ejetselection.official/" target="_blank">
+                <img
+                  src="~/assets/images/footer_guide_ins.png"
+                  alt=""
+                  class="w-24px h-24px"
+                  srcset=""
+                ></a>
+              <a href="https://www.youtube.com/@EJETSelection" target="_blank">
+                <img
+                  src="~/assets/images/footer_guide_youtube.png"
+                  alt=""
+                  class="w-24px h-24px"
+                  srcset=""
+                ></a>
+              <a href="https://www.linkedin.com/company/ejet-selection" target="_blank">
+                <img
+                  src="~/assets/images/footer_guide_linkedin.png"
+                  alt=""
+                  class="w-24px h-24px"
+                  srcset=""
+                ></a>
+            </div>
           </div>
-          <div class="mb-30px">
-            selection@ejet.com
+          <div class="flex text-#fff">
+            <div>
+              © 2025 EJET Spark. All rights reserved.
+              <!-- <a
+                href="https://beian.miit.gov.cn/#/Integrated/index"
+                target="_blank"
+                class="hover:text-#CC9879"
+              >
+                ICP备案:浙ICP备2021012316号-3
+              </a> -->
+            </div>
+            <a href="/service" class="hover:underline ml-10px"><div>Terms of Service</div></a>
+            <div class="mx-10px">
+              |
+            </div>
+            <a href="/policy" class="hover:underline"><div>Privacy Policy</div></a>
           </div>
-          <div>+86 150 8821 0909</div>
-        </div>
-      </div>
-    </div>
-    <div class="w-1400px mx-auto bg-#D8D8D8 h-1px" />
-    <div class="w-100%">
-      <div
-        class="w-1400px mx-auto flex items-center pos-relative gap-42px py-40px text-#666666"
-      >
-        <div>
-          Copyright © EJET Sourcing Ltd. All Rights Reserved. &nbsp;&nbsp;&nbsp;
-          <a
-            href="https://beian.miit.gov.cn/#/Integrated/index"
-            target="_blank"
-            class="hover:text-#CC9879"
-          >
-            ICP备案:浙ICP备2021012316号-3
-          </a>
         </div>
-        <a href="/service"><div>Terms of Service</div></a>
-        <a href="/policy"><div>Privacy Policy</div></a>
-        <!-- <div>
-          Refund Policy
-        </div> -->
-        <img
-          src="~/assets/images/footer_guide_img.png"
-          class="pos-absolute right-0 bottom-0 w-200px h-68px"
-          alt=""
-          srcset=""
-        >
       </div>
     </div>
   </div>

+ 2 - 1
package.json

@@ -31,7 +31,8 @@
     "nuxt-svgo": "^4.0.6",
     "swiper": "^11.1.14",
     "unocss": "0.59.4",
-    "vue-router-better-scroller": "^0.0.0"
+    "vue-router-better-scroller": "^0.0.0",
+    "vue3-marquee": "^4.2.2"
   },
   "devDependencies": {
     "@antfu/eslint-config": "^2.15.0",

+ 5 - 0
pages/index.vue

@@ -7,6 +7,11 @@
   <div>
     <business-home-banner />
     <business-home-solutions />
+    <common-block-catalogs />
+    <common-block-partner />
+    <common-block-exhibited />
+    <common-block-blog />
+    <common-block-faq />
     <AppFooter />
   </div>
 </template>

+ 5 - 0
plugins/Vue3Marquee.client.ts

@@ -0,0 +1,5 @@
+import Vue3Marquee from 'vue3-marquee'
+
+export default defineNuxtPlugin((nuxtApp) => {
+  nuxtApp.vueApp.use(Vue3Marquee, { name: 'Vue3Marquee' })
+})

+ 16 - 3
pnpm-lock.yaml

@@ -55,7 +55,10 @@ importers:
         version: 0.59.4(@unocss/webpack@0.59.4(rollup@4.14.0)(webpack@5.91.0))(postcss@8.4.38)(rollup@4.14.0)(vite@5.2.8(@types/node@20.12.4)(less@4.2.0)(terser@5.39.0))
       vue-router-better-scroller:
         specifier: ^0.0.0
-        version: 0.0.0(vue-router@4.5.1(vue@3.4.21(typescript@5.4.5)))(vue@3.4.21(typescript@5.4.5))
+        version: 0.0.0(vue-router@4.3.0(vue@3.4.21(typescript@5.4.5)))(vue@3.4.21(typescript@5.4.5))
+      vue3-marquee:
+        specifier: ^4.2.2
+        version: 4.2.2(vue@3.4.21(typescript@5.4.5))
     devDependencies:
       '@antfu/eslint-config':
         specifier: ^2.15.0
@@ -5759,6 +5762,12 @@ packages:
     peerDependencies:
       vue: ^3.2.0
 
+  vue3-marquee@4.2.2:
+    resolution: {integrity: sha512-FeFvGUVInKfFilXFcnl8sDRBJBZCZSNLlQDquJErB9db6W2xICRVqbRV/jtdzsEP0rftarLQhx9MeEAU0+TPuQ==}
+    engines: {node: '>=12'}
+    peerDependencies:
+      vue: ^3.2
+
   vue@3.4.21:
     resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
     peerDependencies:
@@ -12623,10 +12632,10 @@ snapshots:
     dependencies:
       vue: 3.4.21(typescript@5.4.5)
 
-  vue-router-better-scroller@0.0.0(vue-router@4.5.1(vue@3.4.21(typescript@5.4.5)))(vue@3.4.21(typescript@5.4.5)):
+  vue-router-better-scroller@0.0.0(vue-router@4.3.0(vue@3.4.21(typescript@5.4.5)))(vue@3.4.21(typescript@5.4.5)):
     dependencies:
       vue: 3.4.21(typescript@5.4.5)
-      vue-router: 4.5.1(vue@3.4.21(typescript@5.4.5))
+      vue-router: 4.3.0(vue@3.4.21(typescript@5.4.5))
 
   vue-router@4.3.0(vue@3.4.21(typescript@5.4.5)):
     dependencies:
@@ -12657,6 +12666,10 @@ snapshots:
       vue-observe-visibility: 2.0.0-alpha.1(vue@3.4.21(typescript@5.4.5))
       vue-resize: 2.0.0-alpha.1(vue@3.4.21(typescript@5.4.5))
 
+  vue3-marquee@4.2.2(vue@3.4.21(typescript@5.4.5)):
+    dependencies:
+      vue: 3.4.21(typescript@5.4.5)
+
   vue@3.4.21(typescript@5.4.5):
     dependencies:
       '@vue/compiler-dom': 3.4.21