| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- <template>
- <section
- id="solution"
- ref="solutionRef"
- class="solution transition-all duration-1000 ease-out"
- :class="[isSolutionVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-50px']"
- >
- <div class="solution-header">
- <h2 class="solution-title">物业管理正面临这些挑战</h2>
- <p class="solution-desc">
- 传统物业管理模式效率低下、成本高昂、服务体验差,急需数字化转型
- </p>
- </div>
- <div ref="solutionListRef" class="solution-list" @scroll="handleSolutionScroll">
- <div
- v-for="(solution, index) in solutions"
- :key="solution.id"
- class="solution-card"
- :class="[
- index === activeIndex
- ? 'active bg-[linear-gradient(0deg,#E5E9F5_0%,#EFF2FB_100%)]'
- : 'bg-[linear-gradient(180deg,#E8F6FD_50.48%,#A5D7FD_100%)] lt-sm:bg-[linear-gradient(0deg,#E5E9F5_0%,#EFF2FB_100%)]',
- ]"
- @mouseenter="activeIndex = index"
- @click="scrollToSolution(index)"
- >
- <div
- class="solution-card-hover"
- :class="[
- index === activeIndex
- ? 'opacity-100 translate-y-0 duration-500'
- : 'opacity-0 translate-y-20px pointer-events-none duration-300 mobile-show',
- ]"
- >
- <div
- class="solution-card-title pf-sc-semibold text-overflow"
- :class="[
- index === activeIndex
- ? 'opacity-100 translate-y-0 delay-100 duration-500'
- : 'opacity-0 translate-y-20px delay-0 duration-200',
- ]"
- >
- <span class="lt-sm:hidden">{{ solution.hoverTitle }}</span>
- <h3 class="inline">{{ solution.title }}解决方案</h3>
- </div>
- <div
- class="solution-card-desc pf-sc-regular"
- :class="[
- index === activeIndex
- ? 'opacity-100 translate-y-0 delay-150 duration-500'
- : 'opacity-0 translate-y-20px delay-0 duration-200',
- ]"
- >
- <p>{{ solution.hoverDesc }}</p>
- </div>
- <div
- class="solution-card-items"
- :class="[
- index === activeIndex
- ? 'opacity-100 translate-y-0 delay-400 duration-700'
- : 'opacity-0 translate-y-20px delay-0 duration-300',
- ]"
- >
- <div v-for="item in solution.hoverItems" :key="item.title" class="solution-card-item">
- <div class="solution-card-item-header">
- <i class="i-custom-check-one solution-card-item-icon"></i>
- <div class="solution-card-item-content">
- <span class="text-#091221 pf-sc-semibold">
- {{ item.title }}
- </span>
- <span class="text-#091221/70 pf-sc-regular line-clamp-1">
- {{ item.itemDesc }}
- </span>
- </div>
- </div>
- </div>
- </div>
- <button
- class="solution-card-btn pf-sc-regular"
- :class="[
- index === activeIndex
- ? 'opacity-100 translate-y-0 delay-500 duration-700'
- : 'opacity-0 translate-y-20px delay-0 duration-200',
- ]"
- @click="openConsultation"
- >
- <span class="font-s-16px lt-sm:font-s-26px">立即咨询</span>
- <i class="i-custom-arrow-right wh-18px lt-sm:wh-28px"></i>
- </button>
- <img
- :src="solution.hoverImg"
- alt=""
- class="solution-card-img"
- :class="[
- index === activeIndex
- ? 'opacity-100 scale-100 delay-200 duration-500'
- : 'opacity-0 scale-50 delay-0 duration-300',
- ]"
- />
- </div>
- <div
- class="solution-card-normal"
- :class="[
- index === activeIndex
- ? 'opacity-0 pointer-events-none duration-300'
- : 'opacity-100 duration-500',
- ]"
- >
- <div
- class="solution-card-icon-wrapper"
- :class="[
- index === activeIndex
- ? 'scale-150 opacity-0 delay-0 duration-300'
- : 'scale-100 opacity-100 delay-0 duration-500',
- ]"
- >
- <img :src="solution.img" alt="" class="wh-35px" />
- </div>
- <div
- class="solution-card-normal-title pf-sc-semibold"
- :class="[
- index === activeIndex
- ? 'opacity-0 translate-y-10px delay-0 duration-200'
- : 'opacity-100 translate-y-0 delay-100 duration-500',
- ]"
- >
- {{ solution.title }}
- </div>
- <div
- class="solution-card-normal-desc pf-sc-regular"
- :class="[
- index === activeIndex
- ? 'opacity-0 translate-y-10px delay-0 duration-200'
- : 'opacity-100 translate-y-0 delay-150 duration-500',
- ]"
- >
- {{ solution.desc }}
- </div>
- <i
- class="i-custom-circle-right-up solution-card-normal-arrow"
- :class="[
- index === activeIndex
- ? 'opacity-0 scale-50 delay-0 duration-200'
- : 'opacity-100 scale-100 delay-100 duration-500',
- ]"
- ></i>
- </div>
- </div>
- </div>
- <div class="solution-dots lt-sm:flex hidden">
- <div
- v-for="(_, index) in solutions"
- :key="index"
- class="dot"
- :class="{ active: index === activeIndex }"
- @click="scrollToSolution(index)"
- ></div>
- </div>
- </section>
- </template>
- <script setup lang="ts">
- import { solutions } from '@/constants/common'
- const solutionRef = ref<HTMLElement | null>(null)
- const { isVisible: isSolutionVisible } = useScrollReveal(solutionRef)
- const { openConsultation } = useConsultation()
- const activeIndex = ref(0)
- const solutionListRef = ref<HTMLElement | null>(null)
- const handleSolutionScroll = (e: Event) => {
- const el = e.target as HTMLElement
- const scrollLeft = el.scrollLeft
- const width = el.offsetWidth
- const cardWidth = width * 0.85
- const gap = 16
- const newIndex = Math.round(scrollLeft / (cardWidth + gap))
- if (newIndex !== activeIndex.value) {
- activeIndex.value = newIndex
- }
- }
- const scrollToSolution = (index: number) => {
- if (window.innerWidth >= 640) return
- if (!solutionListRef.value) return
- activeIndex.value = index
- const width = solutionListRef.value.offsetWidth
- const cardWidth = width * 0.85
- const gap = 16
- solutionListRef.value.scrollTo({
- left: index * (cardWidth + gap),
- behavior: 'smooth',
- })
- }
- </script>
- <style scoped lang="scss">
- .solution {
- @extend %landing-container;
- @apply py-120px lt-sm:py-120px lt-sm:px-0;
- }
- .solution-header {
- @apply text-center mb-45px;
- }
- .solution-title {
- @apply font-s-36px font-semibold text-#000000 mb-4px lh-60px;
- @apply lt-sm:font-s-48px lt-sm:lh-60px;
- }
- .solution-desc {
- @apply font-s-16px text-#091221/70 lh-30px;
- @apply lt-sm:font-s-24px lt-sm:px-110px lt-sm:mt-16px lt-sm:lh-40px;
- }
- .solution-list {
- @apply flex h-365px w-full gap-24px;
- @apply lt-sm:h-auto lt-sm:gap-16px lt-sm:overflow-x-auto lt-sm:overflow-y-hidden lt-sm:px-24px;
- @apply lt-sm:[scroll-snap-type:x_mandatory] lt-sm:[scrollbar-width:none];
- &::-webkit-scrollbar {
- @apply lt-sm:hidden;
- }
- }
- .solution-card {
- position: relative;
- display: flex;
- height: 100%;
- cursor: pointer;
- overflow: hidden;
- border-radius: 24px;
- will-change: transform, opacity;
- transition:
- transform 600ms cubic-bezier(0.34, 1.56, 0.64, 1),
- opacity 600ms ease,
- flex 600ms ease-in-out,
- background-color 600ms ease-in-out;
- @media (min-width: 768px) {
- &.active {
- flex: 1 1 0%;
- }
- &:not(.active) {
- flex: 0 0 220px;
- }
- }
- @apply lt-sm:flex-[0_0_90%] lt-sm:min-h-750px lt-sm:w-630px;
- @apply lt-sm:[scroll-snap-align:center];
- &:not(.active) {
- @apply lt-sm:scale-96 lt-sm:opacity-50;
- }
- &.active {
- @apply lt-sm:scale-100 lt-sm:opacity-100;
- }
- &:first-child {
- @apply lt-sm:ml-36px;
- }
- &:last-child {
- @apply lt-sm:mr-36px;
- }
- }
- .solution-card-hover {
- @apply h-full w-full pt-40px px-48px absolute left-0 top-0 transition-all ease-in-out;
- @apply lt-sm:relative lt-sm:pt-40px lt-sm:px-36px lt-sm:pb-32px lt-sm:opacity-100 lt-sm:translate-y-0 lt-sm:pointer-events-auto;
- &.mobile-show {
- @apply lt-sm:opacity-100 lt-sm:translate-y-0 lt-sm:pointer-events-auto;
- }
- }
- .solution-card-title {
- @apply font-s-22px text-#000000 transition-all;
- @apply lt-sm:font-s-32px;
- }
- .solution-card-desc {
- @apply font-s-14px lh-24px mt-8px text-#091221/70 pf-sc-regular text-overflow transition-all;
- @apply lt-sm:font-s-24px lt-sm:mt-8px lt-sm:lh-normal;
- }
- .solution-card-items {
- @apply mt-24px flex flex-col gap-8px transition-all;
- @apply lt-sm:mt-48px;
- }
- .solution-card-item {
- @apply flex flex-col;
- }
- .solution-card-item-header {
- @apply flex gap-8px items-center font-s-14px;
- @apply lt-sm:font-s-24px lt-sm:gap-12px;
- }
- .solution-card-item-icon {
- @apply wh-18px;
- @apply lt-sm:wh-32px;
- }
- .solution-card-item-content {
- @apply flex items-center gap-8px;
- @apply lt-sm:flex-col lt-sm:items-start lt-sm:gap-8px;
- }
- .solution-card-btn {
- @apply mt-56px h-48px w-268px bg-#0F67F8 text-white pf-sc-regular rounded-8px px-16px flex items-center justify-between hover:opacity-80 transition-all;
- @apply lt-sm:w-270px lt-sm:h-95px lt-sm:rounded-16px lt-sm:mt-102px;
- }
- .solution-card-img {
- @apply wh-280px absolute bottom--37px right-0 transition-all duration-300 ease-in-out;
- @apply lt-sm:wh-264px lt-sm:bottom--26px;
- }
- .solution-card-normal {
- @apply h-full w-220px pt-40px px-24px absolute left-0 top-0 transition-all ease-in-out;
- @apply lt-sm:hidden;
- }
- .solution-card-icon-wrapper {
- @apply wh-40px ml-2px bg-white rounded-10px flex-center transition-all ease-in-out;
- }
- .solution-card-normal-title {
- @apply mt-18px font-s-18px text-#091221 pf-sc-semibold transition-all;
- }
- .solution-card-normal-desc {
- @apply mt-8px font-s-14px lh-24px text-#091221/60 pf-sc-regular w-172px transition-all;
- }
- .solution-card-normal-arrow {
- @apply wh-48px absolute bottom-24px left-24px transition-all;
- }
- .solution-dots {
- @apply lt-sm:mt-40px flex-center lt-sm:gap-16px;
- .dot {
- @apply lt-sm:w-60px lt-sm:h-10px bg-#E5E9F5 rounded-full transition-all cursor-pointer;
- &.active {
- @apply bg-#0F67F8;
- }
- }
- }
- </style>
|