timeline.vue 8.41 KB
<template>
  <div class="timeline-page w-full h-screen relative overflow-hidden">
    <!-- Shared Background -->
    <StarryBackground />

    <!-- Swiper -->
    <swiper :direction="'vertical'" :modules="[Mousewheel]" :mousewheel="true" :speed="800"
      class="h-full w-full relative z-10" @swiper="onSwiper" @slideChange="onSlideChange">
      <!-- Slide 1: Welcome Back -->
      <swiper-slide>
        <div class="flex flex-col items-center h-full w-full px-6 pt-16 pb-8 relative">

          <!-- Title Section -->
          <div class="flex flex-col items-center mb-8 animate-fade-in-down">
            <h2 class="text-[#FFDD01] text-2xl font-bold mb-4 tracking-wider">@{{ userInfo.name }}</h2>
            <img :src="title03" class="w-64 object-contain" alt="Welcome Back" />
          </div>

          <!-- Card Section -->
          <FrostedGlass
            class="w-full max-w-sm p-8 !rounded-2xl !border-white/20 flex flex-col items-center justify-center text-center mb-auto animate-zoom-in"
            :bg-opacity="15" blur-level="md">
            <p class="text-white text-sm mb-6 tracking-wide opacity-90">您加入BEHALO星球的时间</p>
            <h1 class="text-[#FFDD01] text-3xl font-bold mb-4 tracking-wider">{{ joinDateFormatted }}</h1>
            <p class="text-white text-lg tracking-wide font-medium">已有{{ durationString }}</p>
          </FrostedGlass>

          <!-- Bottom Section -->
          <div class="mt-auto flex flex-col items-center text-center animate-fade-in-up">
            <p class="text-white/80 text-xs mb-2 tracking-wider leading-relaxed">
              从{{ joinYear }}年起,每一段旅程都被珍藏。<br>
              欢迎回家,继续书写我们共有的星球诗篇。
            </p>
            <div class="mt-4 cursor-pointer animate-bounce" @click="slideNext">
              <img :src="arrowDown" class="w-6 h-6" alt="Scroll Down" />
            </div>
          </div>

        </div>
      </swiper-slide>

      <!-- Slide 2: Footprints -->
      <swiper-slide>
        <div class="flex flex-col items-center h-full w-full px-6 pt-16 pb-8 relative">

          <!-- Title Section -->
          <div class="flex flex-col items-center mb-10 animate-fade-in-down">
            <img :src="title04" class="w-64 object-contain mb-4" alt="My Footprints" />
            <h2 class="text-[#FFDD01] text-2xl font-bold tracking-wider">@{{ userInfo.name }}</h2>
          </div>

          <!-- Card Section -->
          <FrostedGlass
            class="w-full max-w-sm p-8 !rounded-2xl !border-white/20 flex flex-col items-center justify-center text-center mb-auto animate-zoom-in delay-100"
            :bg-opacity="15" blur-level="md">

            <div class="flex flex-col items-center mb-8">
              <p class="text-white text-sm mb-2 tracking-wide opacity-90">参与星球活动</p>
              <h1 class="text-[#FFDD01] text-4xl font-bold tracking-wider">{{ activityCount }}次</h1>
            </div>

            <div class="flex flex-col items-center">
              <p class="text-white text-sm mb-2 tracking-wide opacity-90">义工服务记录</p>
              <h1 class="text-[#FFDD01] text-4xl font-bold tracking-wider">{{ volunteerCount }}次</h1>
            </div>

          </FrostedGlass>

          <!-- Bottom Section -->
          <div class="mt-auto w-full flex flex-col items-center text-center animate-fade-in-up delay-200">
            <p class="text-white/80 text-xs mb-6 tracking-wider leading-relaxed">
              每一次参与,<br>
              都是这片星球上不灭的星光。
            </p>
            <van-button block
              class="submit-btn !rounded-lg !bg-transparent !border-[#FFDD01] !text-[#FFDD01] !font-bold !text-lg !h-[48px] !max-w-xs"
              @click="handleViewHistory">
              我的星光
            </van-button>
          </div>

        </div>
      </swiper-slide>
    </swiper>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useTitle } from '@vueuse/core'
import dayjs from 'dayjs'
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Mousewheel } from 'swiper/modules'
import 'swiper/css'

import { userInfoAPI, searchOldActivityAPI } from '@/api/recall_users'


const title03 = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title03@2x.png'
const title04 = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title04@2x.png'
const arrowDown = 'https://cdn.ipadbiz.cn/mlaj/recall/img/xia@2x.png'

// Context (Mocking auth for now as we might be in a detached flow,
// but try to use useAuth if available or fallback to local storage/mock)
import { useAuth } from '@/contexts/auth'

const router = useRouter()
useTitle('时光机')

const { currentUser } = useAuth()

// Swiper logic
const swiperInstance = ref(null)
const onSwiper = (swiper) => {
  swiperInstance.value = swiper
}
const slideNext = () => {
  swiperInstance.value?.slideNext()
}
const onSlideChange = () => {
  // Can add tracking or animation triggers here
}

// Data Logic
const recordDate = ref('')
const lastActivityDate = ref('')
const activityCount = ref(0)
const volunteerCount = ref(0)

const joinDate = computed(() => {
  return recordDate.value || currentUser.value?.created_at || currentUser.value?.reg_time || '2020-09-12' // Fallback to design mock date
})

const joinYear = computed(() => dayjs(joinDate.value).year())

const joinDateFormatted = computed(() => {
  return dayjs(joinDate.value).format('YYYY年M月D日')
})

const durationString = computed(() => {
  const start = dayjs(joinDate.value)
  const end = lastActivityDate.value ? dayjs(lastActivityDate.value) : dayjs()
  const years = end.diff(start, 'year')
  const months = end.diff(start, 'month') % 12

  if (years === 0 && months === 0) {
    const days = end.diff(start, 'day');
    return `${days}天`;
  }

  if (years > 0) {
    return `${years}年${months}个月`
  } else {
    return `${months}个月`
  }
})

const handleViewHistory = () => {
  router.push('/recall/activity-history')
}

const userInfo = ref({})

onMounted(async () => {
  // 从缓存获取用户信息
  const cachedUserInfo = localStorage.getItem('cached_user_info')
  if (cachedUserInfo) {
    userInfo.value = JSON.parse(cachedUserInfo)

    // 检查是否有历史数据
    if (userInfo.value.name && userInfo.value.phone && userInfo.value.idCard) {
      const res = await searchOldActivityAPI({
        name: userInfo.value.name,
        mobile: userInfo.value.phone,
        idcard: userInfo.value.idCard
      })
      if (res.code) {
        activityCount.value = res.data?.jh_payment_qty || 0
        volunteerCount.value = res.data?.jh_volunteers_qty || 0
        recordDate.value = res.data?.record_date || ''
        lastActivityDate.value = res.data?.last_activity_date || ''
      }
    }
  } else {
    // 如果是收集完成没有缓存字段的情况, 直接查接口
    const res = await searchOldActivityAPI()
    if (res.code) {
      activityCount.value = res.data?.jh_payment_qty || 0
      volunteerCount.value = res.data?.jh_volunteers_qty || 0
      recordDate.value = res.data?.record_date || ''
      lastActivityDate.value = res.data?.last_activity_date || ''
    }
    const resUserInfo = await userInfoAPI()
      // 登录之后需要判断是否有完善个人信息
      if (resUserInfo.code) {
        userInfo.value = resUserInfo.data?.user || {}
      }
  }
})

</script>

<style lang="less" scoped>
.timeline-page {
  // Custom animations if needed, or use Tailwind utility classes
}

.submit-btn {
  background: linear-gradient(180deg, rgba(249, 243, 157, 0.19) 0%, rgba(219, 243, 48, 0.3) 100%) !important;
  backdrop-filter: blur(4px);
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);

  &:active {
    transform: scale(0.99);
  }
}

// Simple fade/zoom animations
@keyframes fadeInDown {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.animate-fade-in-down {
  animation: fadeInDown 0.8s ease-out forwards;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.animate-fade-in-up {
  animation: fadeInUp 0.8s ease-out forwards;
}

@keyframes zoomIn {
  from {
    opacity: 0;
    transform: scale(0.95);
  }

  to {
    opacity: 1;
    transform: scale(1);
  }
}

.animate-zoom-in {
  animation: zoomIn 0.8s ease-out forwards;
}

.delay-100 {
  animation-delay: 0.1s;
}

.delay-200 {
  animation-delay: 0.2s;
}
</style>