Files
xk-gw/src/views/index/index.vue
2026-07-24 16:52:39 +08:00

320 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { RouterLink } from 'vue-router'
import { ArrowLeft, ArrowRight, Calendar, CheckCircle2, Clock3, Play, ShieldCheck, Sparkles, Star } from 'lucide-vue-next'
import { homeCaseCards, homeMarqueeItems, homeServiceItems, metrics, siteConfig } from '@/site.config'
import AnimatedContent from '@/components/vue-bits/AnimatedContent.vue'
import DecryptedText from '@/components/vue-bits/DecryptedText.vue'
import BlurText from '@/components/vue-bits/BlurText.vue'
import Magnet from '@/components/vue-bits/Magnet.vue'
import Silk from '@/components/vue-bits/Silk.vue'
import SplitText from '@/components/vue-bits/SplitText.vue'
const aboutRef = ref(null)
const aboutProgress = ref(0)
const aboutSegments = [
'萧康云医把患者、医生、机构和运营管理连接成同一个实时协作系统。',
'我们服务医共体、医疗集团、互联网医院与连锁诊所,',
'让复杂的医疗流程在云端变得更轻、更稳、更可信。'
]
const marqueeRowOne = computed(() => homeMarqueeItems.slice(0, 3))
const marqueeRowTwo = computed(() => homeMarqueeItems.slice(3))
const repeatedRowOne = computed(() => [...marqueeRowOne.value, ...marqueeRowOne.value, ...marqueeRowOne.value])
const repeatedRowTwo = computed(() => [...marqueeRowTwo.value, ...marqueeRowTwo.value, ...marqueeRowTwo.value])
let ticking = false
let reduceMotion = false
function updateScrollMotion() {
ticking = false
if (reduceMotion) return
if (aboutRef.value) {
const rect = aboutRef.value.getBoundingClientRect()
const distance = window.innerHeight * 0.78 - rect.top
const range = rect.height + window.innerHeight * 0.2
aboutProgress.value = Math.min(1, Math.max(0, distance / range))
}
}
function requestScrollUpdate() {
if (ticking) return
ticking = true
window.requestAnimationFrame(updateScrollMotion)
}
function segmentOpacity(index) {
if (reduceMotion) return 1
const start = index / aboutSegments.length
const progress = (aboutProgress.value - start) * 2.6
return Math.min(1, Math.max(0.5, progress))
}
onMounted(() => {
reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
updateScrollMotion()
window.addEventListener('scroll', requestScrollUpdate, { passive: true })
window.addEventListener('resize', requestScrollUpdate)
})
onBeforeUnmount(() => {
window.removeEventListener('scroll', requestScrollUpdate)
window.removeEventListener('resize', requestScrollUpdate)
})
</script>
<template>
<main class="home-page">
<section class="cinematic-hero">
<video
class="cinematic-video"
autoplay
muted
loop
playsinline
:poster="siteConfig.hero.video.poster"
>
<source :src="siteConfig.hero.video.src" type="video/mp4">
</video>
<div class="hero-silk-layer" aria-hidden="true">
<Silk color="#14B8A6" :speed="2.6" :scale="1.2" :noise-intensity="0.78" :rotation="0.16" />
</div>
<div class="bottom-blur-overlay" aria-hidden="true"></div>
<div class="cinematic-content">
<div class="hero-copy">
<div class="hero-meta animate-blur-fade-up" style="animation-delay: 300ms">
<span>
<Star :size="16" fill="currentColor" aria-hidden="true" />
99.95% SLA
</span>
<span>
<Clock3 :size="16" aria-hidden="true" />
7x24 医疗级运维
</span>
<span>
<Calendar :size="16" aria-hidden="true" />
2026 云医协同平台
</span>
</div>
<BlurText
:text="siteConfig.brand.name"
tag="h1"
class-name="cinematic-title"
animate-by="chars"
direction="bottom"
:delay="90"
:duration="980"
:threshold="0.05"
root-margin="0px"
/>
<p class="cinematic-subtitle animate-blur-fade-up" style="animation-delay: 500ms">
<DecryptedText
text="Step Through. Work Smarter."
animate-on="view"
reveal-direction="center"
:speed="34"
:max-iterations="12"
encrypted-class-name="decrypted-ghost"
class-name="decrypted-final"
/>
<span> 让区域诊疗慢病随访远程会诊和运营治理在云端自然协作</span>
</p>
<div class="hero-actions">
<Magnet :padding="80" :magnet-strength="5" wrapper-class-name="animate-blur-fade-up" style="animation-delay: 600ms">
<RouterLink to="/product#contact" class="watch-button">
<Play :size="18" fill="currentColor" aria-hidden="true" />
免费试用
</RouterLink>
</Magnet>
<Magnet :padding="72" :magnet-strength="5.5" wrapper-class-name="animate-blur-fade-up" style="animation-delay: 700ms">
<RouterLink to="/product#demo" class="learn-button liquid-glass">
观看演示
</RouterLink>
</Magnet>
</div>
</div>
<div class="hero-arrows">
<Magnet :padding="64" :magnet-strength="6" wrapper-class-name="animate-blur-fade-up" style="animation-delay: 800ms">
<RouterLink to="/#business" class="arrow-pill liquid-glass">
<ArrowLeft :size="18" aria-hidden="true" />
业务介绍
</RouterLink>
</Magnet>
<Magnet :padding="64" :magnet-strength="6" wrapper-class-name="animate-blur-fade-up" style="animation-delay: 900ms">
<RouterLink to="/product" class="arrow-pill liquid-glass">
产品页
<ArrowRight :size="18" aria-hidden="true" />
</RouterLink>
</Magnet>
</div>
</div>
</section>
<section id="business" class="home-marquee-section">
<AnimatedContent class-name="marquee-heading" :distance="44" :duration="0.9" ease="power3.out">
<span>Business Flow</span>
<h2 class="mega-heading home-heading-cn">云端医疗协同现场</h2>
</AnimatedContent>
<div class="marquee-rows" aria-label="萧康云医业务场景">
<div class="marquee-track marquee-track-forward">
<article v-for="(item, index) in repeatedRowOne" :key="`${item.title}-top-${index}`" class="marquee-card glare-card">
<img :src="item.image" :alt="item.title" loading="lazy">
<div>
<span>{{ item.meta }}</span>
<strong>{{ item.title }}</strong>
</div>
</article>
</div>
<div class="marquee-track marquee-track-reverse">
<article v-for="(item, index) in repeatedRowTwo" :key="`${item.title}-bottom-${index}`" class="marquee-card glare-card">
<img :src="item.image" :alt="item.title" loading="lazy">
<div>
<span>{{ item.meta }}</span>
<strong>{{ item.title }}</strong>
</div>
</article>
</div>
</div>
</section>
<section id="intro" ref="aboutRef" class="creator-about-section">
<div class="floating-medical-chip chip-a">
<Sparkles :size="20" aria-hidden="true" />
AI Alert
</div>
<div class="floating-medical-chip chip-b">
<ShieldCheck :size="20" aria-hidden="true" />
Data Safe
</div>
<div class="floating-medical-chip chip-c">
<CheckCircle2 :size="20" aria-hidden="true" />
Follow-up
</div>
<div class="floating-medical-chip chip-d">
<Star :size="20" aria-hidden="true" />
99.95%
</div>
<AnimatedContent class-name="about-inner" :distance="52" :duration="1" ease="power4.out">
<SplitText
text="关于萧康云医"
tag="h2"
class-name="mega-heading home-heading-cn"
split-type="lines"
:delay="80"
:duration="1"
ease="power3.out"
:from="{ opacity: 0, y: 34, filter: 'blur(12px)' }"
:to="{ opacity: 1, y: 0, filter: 'blur(0px)' }"
/>
<p class="animated-copy" aria-label="萧康云医介绍">
<span
v-for="(segment, index) in aboutSegments"
:key="segment"
class="about-segment"
:style="{ opacity: segmentOpacity(index) }"
>{{ segment }}</span>
</p>
<Magnet :padding="90" :magnet-strength="5">
<RouterLink to="/product#contact" class="creator-contact-button">联系顾问</RouterLink>
</Magnet>
</AnimatedContent>
</section>
<section class="creator-services-section">
<SplitText
text="Services"
tag="h2"
class-name="services-heading"
split-type="chars"
:delay="42"
:duration="0.9"
ease="power3.out"
:from="{ opacity: 0, y: 46, filter: 'blur(12px)' }"
:to="{ opacity: 1, y: 0, filter: 'blur(0px)' }"
/>
<div class="services-list">
<AnimatedContent
v-for="(item, index) in homeServiceItems"
:key="item.number"
class-name="service-reveal"
:distance="56"
direction="horizontal"
:reverse="index % 2 === 1"
:delay="index * 0.08"
:duration="0.85"
>
<article class="service-item">
<span>{{ item.number }}</span>
<div>
<h3>{{ item.name }}</h3>
<p>{{ item.description }}</p>
</div>
</article>
</AnimatedContent>
</div>
</section>
<section id="cases" class="creator-projects-section">
<AnimatedContent class-name="case-section-heading" :distance="48" :duration="0.9">
<span>Case Study</span>
<h2 class="mega-heading home-heading-cn">客户案例</h2>
</AnimatedContent>
<div class="stable-case-list">
<article
v-for="(item, index) in homeCaseCards"
:key="item.name"
class="stable-case-card"
:style="{ top: `${104 + index * 18}px` }"
>
<div class="case-card-head">
<span>{{ item.number }}</span>
<div class="case-card-copy">
<small>{{ item.category }}</small>
<h3>{{ item.name }}</h3>
<p>{{ item.summary }}</p>
</div>
<Magnet :padding="64" :magnet-strength="6" wrapper-class-name="case-card-action">
<RouterLink to="/product#contact" class="live-project-button">预约演示</RouterLink>
</Magnet>
</div>
<div class="case-image-grid">
<div>
<img :src="item.images[0]" :alt="`${item.name} 业务图一`" loading="lazy">
<img :src="item.images[1]" :alt="`${item.name} 业务图二`" loading="lazy">
</div>
<img :src="item.images[2]" :alt="`${item.name} 场景图`" loading="lazy">
</div>
</article>
</div>
</section>
<section id="contact" class="home-contact-section">
<AnimatedContent class-name="home-contact-copy" :distance="50" :duration="0.9">
<span>Contact</span>
<h2 class="mega-heading home-heading-cn">让医疗协同真正跑起来</h2>
<p>告诉我们你的机构规模系统现状和重点场景萧康云医团队会给出一份可落地的演示方案</p>
<Magnet :padding="90" :magnet-strength="5" wrapper-class-name="contact-action">
<RouterLink to="/product#contact" class="creator-contact-button">立即咨询</RouterLink>
</Magnet>
</AnimatedContent>
<AnimatedContent class-name="contact-metrics" :distance="50" direction="horizontal" :reverse="true" :duration="0.9">
<div v-for="item in metrics" :key="item.label">
<strong>{{ item.value }}</strong>
<span>{{ item.label }}</span>
</div>
</AnimatedContent>
</section>
</main>
</template>