|
|
@@ -1,7 +1,7 @@
|
|
|
<!--
|
|
|
* @Author: LiZhiWei
|
|
|
* @LastEditors: LiZhiWei
|
|
|
- * @LastEditTime: 2026-01-15 17:43:24
|
|
|
+ * @LastEditTime: 2026-01-15 17:57:13
|
|
|
* @Description:
|
|
|
-->
|
|
|
<template>
|
|
|
@@ -150,9 +150,7 @@
|
|
|
<!-- 滑块背景 -->
|
|
|
<div
|
|
|
class="absolute w-136px h-[calc(100%-12px)] transition-all duration-300 ease-out rounded-8px bg-#0F67F8"
|
|
|
- :style="{
|
|
|
- transform: `translateX(${abilityTabs.findIndex((tab) => tab.id === activeAbilityTab.id) * 136}px)`,
|
|
|
- }"
|
|
|
+ :style="abilityTabIndicatorStyle"
|
|
|
></div>
|
|
|
|
|
|
<div
|
|
|
@@ -373,36 +371,19 @@
|
|
|
v-for="(item, index) in historyYears"
|
|
|
:key="item.year"
|
|
|
class="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 flex flex-col items-center cursor-pointer group z-2"
|
|
|
- :style="{ left: `${(index / (historyYears.length - 1)) * 100}%` }"
|
|
|
+ :style="getTimelineNodePositionStyle(index)"
|
|
|
@click="selectYear(index)"
|
|
|
>
|
|
|
<!-- 圆点 -->
|
|
|
<div
|
|
|
class="rounded-full transition-all duration-300 relative bg-white"
|
|
|
- :class="[
|
|
|
- index < currentYearIndex
|
|
|
- ? 'wh-13px'
|
|
|
- : 'wh-16px border-#0F67F8 group-hover:border-[#2563EB] border-1',
|
|
|
- index === currentYearIndex
|
|
|
- ? 'wh-16px scale-150 outline-6px outline-#CEE0FF outline-solid border-none'
|
|
|
- : '',
|
|
|
- ]"
|
|
|
- :style="
|
|
|
- index === currentYearIndex
|
|
|
- ? { background: 'linear-gradient(90deg, #779EFF 0%, #0A50FF 100%)' }
|
|
|
- : index < currentYearIndex
|
|
|
- ? { background: '#FFFFFF' }
|
|
|
- : {}
|
|
|
- "
|
|
|
+ :class="getTimelineDotClasses(index)"
|
|
|
+ :style="getTimelineDotStyle(index)"
|
|
|
></div>
|
|
|
<!-- 年份文字 -->
|
|
|
<span
|
|
|
class="absolute top-24px text-16px transition-all duration-300 whitespace-nowrap"
|
|
|
- :class="[
|
|
|
- index === currentYearIndex
|
|
|
- ? 'text-#2563EB font-bold pf-sc-bold scale-110'
|
|
|
- : 'text-#94A3B8 group-hover:text-[#64748B]',
|
|
|
- ]"
|
|
|
+ :class="getTimelineYearTextClasses(index)"
|
|
|
>
|
|
|
{{ item.year }}
|
|
|
</span>
|
|
|
@@ -533,29 +514,33 @@
|
|
|
|
|
|
const activeAbilityTab = ref<AbilityTab>(abilityTabs[0] as AbilityTab)
|
|
|
|
|
|
+ const abilityTabIndicatorStyle = computed(() => {
|
|
|
+ const activeTabIndex = abilityTabs.findIndex((tab) => tab.id === activeAbilityTab.value.id)
|
|
|
+ return {
|
|
|
+ transform: `translateX(${activeTabIndex * 136}px)`,
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
const handleAbilityTabClick = (tab: AbilityTab) => {
|
|
|
activeAbilityTab.value = tab
|
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
|
+ const revealSections = [
|
|
|
+ { elRef: solutionRef, visible: isSolutionVisible },
|
|
|
+ { elRef: abilityRef, visible: isAbilityVisible },
|
|
|
+ { elRef: partnershipRef, visible: isPartnershipVisible },
|
|
|
+ { elRef: casesRef, visible: isCasesVisible },
|
|
|
+ { elRef: timelineRef, visible: isTimelineVisible },
|
|
|
+ ]
|
|
|
+
|
|
|
const observer = new IntersectionObserver(
|
|
|
(entries) => {
|
|
|
entries.forEach((entry) => {
|
|
|
if (entry.isIntersecting) {
|
|
|
- if (entry.target === solutionRef.value) {
|
|
|
- isSolutionVisible.value = true
|
|
|
- }
|
|
|
- if (entry.target === abilityRef.value) {
|
|
|
- isAbilityVisible.value = true
|
|
|
- }
|
|
|
- if (entry.target === partnershipRef.value) {
|
|
|
- isPartnershipVisible.value = true
|
|
|
- }
|
|
|
- if (entry.target === casesRef.value) {
|
|
|
- isCasesVisible.value = true
|
|
|
- }
|
|
|
- if (entry.target === timelineRef.value) {
|
|
|
- isTimelineVisible.value = true
|
|
|
+ const matched = revealSections.find((item) => item.elRef.value === entry.target)
|
|
|
+ if (matched) {
|
|
|
+ matched.visible.value = true
|
|
|
}
|
|
|
observer.unobserve(entry.target)
|
|
|
}
|
|
|
@@ -564,22 +549,45 @@
|
|
|
{ threshold: 0.1 }
|
|
|
)
|
|
|
|
|
|
- if (solutionRef.value) {
|
|
|
- observer.observe(solutionRef.value)
|
|
|
- }
|
|
|
- if (abilityRef.value) {
|
|
|
- observer.observe(abilityRef.value)
|
|
|
- }
|
|
|
- if (partnershipRef.value) {
|
|
|
- observer.observe(partnershipRef.value)
|
|
|
- }
|
|
|
- if (casesRef.value) {
|
|
|
- observer.observe(casesRef.value)
|
|
|
+ revealSections.forEach(({ elRef }) => {
|
|
|
+ if (elRef.value) {
|
|
|
+ observer.observe(elRef.value)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ const getTimelineNodePositionStyle = (index: number) => {
|
|
|
+ return { left: `${(index / (historyYears.length - 1)) * 100}%` }
|
|
|
+ }
|
|
|
+
|
|
|
+ const getTimelineDotClasses = (index: number) => {
|
|
|
+ return [
|
|
|
+ index < currentYearIndex.value
|
|
|
+ ? 'wh-13px'
|
|
|
+ : 'wh-16px border-#0F67F8 group-hover:border-[#2563EB] border-1',
|
|
|
+ index === currentYearIndex.value
|
|
|
+ ? 'wh-16px scale-150 outline-6px outline-#CEE0FF outline-solid border-none'
|
|
|
+ : '',
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ const getTimelineDotStyle = (index: number) => {
|
|
|
+ if (index === currentYearIndex.value) {
|
|
|
+ return { background: 'linear-gradient(90deg, #779EFF 0%, #0A50FF 100%)' }
|
|
|
}
|
|
|
- if (timelineRef.value) {
|
|
|
- observer.observe(timelineRef.value)
|
|
|
+ if (index < currentYearIndex.value) {
|
|
|
+ return { background: '#FFFFFF' }
|
|
|
}
|
|
|
- })
|
|
|
+ return {}
|
|
|
+ }
|
|
|
+
|
|
|
+ const getTimelineYearTextClasses = (index: number) => {
|
|
|
+ return [
|
|
|
+ index === currentYearIndex.value
|
|
|
+ ? 'text-#2563EB font-bold pf-sc-bold scale-110'
|
|
|
+ : 'text-#94A3B8 group-hover:text-[#64748B]',
|
|
|
+ ]
|
|
|
+ }
|
|
|
</script>
|
|
|
<style scoped lang="scss">
|
|
|
.landing {
|