Index.vue
9.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<!--
* @Date: 2025-12-19 15:40:34
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-12-19 16:24:51
* @FilePath: /mlaj/src/views/recall/Index.vue
* @Description: 文件描述
-->
<template>
<div class="h-screen bg-[#F0FBF9] overflow-hidden relative">
<!-- Swiper Container -->
<swiper
:direction="'vertical'"
:modules="[Mousewheel]"
:mousewheel="true"
class="h-full w-full"
@slideChange="onSlideChange"
:speed="800"
@swiper="onSwiper"
>
<!-- 第一屏 -->
<swiper-slide>
<div class="flex flex-col items-center pt-20 pb-10 px-6 relative h-full w-full">
<!-- 头像 -->
<div class="relative mb-6 opacity-0 translate-y-4 transition-all duration-700 delay-100" :class="{ 'opacity-100 translate-y-0': activeIndex === 0 }">
<img
:src="userAvatar || defaultAvatar"
class="w-24 h-24 rounded-full border-4 border-white shadow-lg object-cover"
alt="User Avatar"
/>
</div>
<!-- 欢迎语 -->
<h1 class="text-2xl font-bold text-[#1A3B34] mb-2 text-center opacity-0 translate-y-4 transition-all duration-700 delay-200" :class="{ 'opacity-100 translate-y-0': activeIndex === 0 }">{{ userName }}</h1>
<h2 class="text-xl font-bold text-[#1A3B34] mb-4 text-center opacity-0 translate-y-4 transition-all duration-700 delay-300" :class="{ 'opacity-100 translate-y-0': activeIndex === 0 }">欢迎回归美乐爱觉宇宙</h2>
<p class="text-slate-500 text-sm mb-12 text-center opacity-0 translate-y-4 transition-all duration-700 delay-400" :class="{ 'opacity-100 translate-y-0': activeIndex === 0 }">您与Behalo的故事从这里开始</p>
<!-- 时间卡片 -->
<div class="bg-white rounded-3xl p-8 shadow-xl w-full max-w-sm text-center mb-auto relative z-10 opacity-0 scale-95 transition-all duration-700 delay-500" :class="{ 'opacity-100 scale-100': activeIndex === 0 }">
<p class="text-slate-500 mb-4">您加入Behalo的时间</p>
<div class="text-3xl font-bold text-[#1A3B34] mb-4 tracking-wide">{{ joinDateFormatted }}</div>
<div class="text-slate-500">
已有 <span class="text-[#1A3B34] font-bold text-lg">{{ durationString }}</span>
</div>
</div>
<!-- 底部引导 -->
<div class="flex flex-col items-center mt-12 animate-bounce cursor-pointer opacity-0 transition-opacity duration-1000 delay-1000" :class="{ 'opacity-100': activeIndex === 0 }" @click="slideNext">
<ChevronDoubleDownIcon class="w-6 h-6 text-[#4ADE80] mb-2" />
<span class="text-[#4ADE80] font-medium text-sm">向上滑动,探索更多历程</span>
</div>
</div>
</swiper-slide>
<!-- 第二屏 -->
<swiper-slide>
<div class="flex flex-col items-center pt-10 pb-10 px-6 relative h-full w-full overflow-y-auto overflow-x-hidden">
<h2 class="text-2xl font-bold text-[#1A3B34] mb-2 text-center opacity-0 translate-y-4 transition-all duration-700 delay-100" :class="{ 'opacity-100 translate-y-0': activeIndex === 1 }">您的Behalo足迹</h2>
<p class="text-slate-500 text-sm mb-8 text-center opacity-0 translate-y-4 transition-all duration-700 delay-200" :class="{ 'opacity-100 translate-y-0': activeIndex === 1 }">2016~2025,您在Behalo留下的印记</p>
<!-- 活动参与卡片 -->
<div class="bg-white rounded-3xl p-6 shadow-md w-full max-w-sm mb-4 opacity-0 translate-y-4 transition-all duration-700 delay-300" :class="{ 'opacity-100 translate-y-0': activeIndex === 1 }">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-[#E0F2F1] flex items-center justify-center mr-3 text-[#26A69A]">
<CalendarIcon class="w-5 h-5" />
</div>
<span class="font-bold text-[#1A3B34]">参与宇宙活动</span>
</div>
<div class="mb-2">
<span class="text-5xl font-bold text-[#1A3B34]">{{ activityCount }}</span>
<span class="text-slate-500 ml-1">次</span>
</div>
<p class="text-slate-500 text-xs">您积极参与各类教育活动,累计参与{{ activityCount }}次</p>
</div>
<!-- 义工服务卡片 -->
<div class="bg-white rounded-3xl p-6 shadow-md w-full max-w-sm mb-8 opacity-0 translate-y-4 transition-all duration-700 delay-500" :class="{ 'opacity-100 translate-y-0': activeIndex === 1 }">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-[#E8F5E9] flex items-center justify-center mr-3 text-[#4CAF50]">
<HeartIcon class="w-5 h-5" />
</div>
<span class="font-bold text-[#1A3B34]">义工服务活动</span>
</div>
<div class="mb-2">
<span class="text-5xl font-bold text-[#1A3B34]">{{ volunteerCount }}</span>
<span class="text-slate-500 ml-1">次</span>
</div>
<p class="text-slate-500 text-xs">您热心公益,作为义工服务了{{ volunteerCount }}次活动,贡献时长超过{{ volunteerHours }}小时</p>
</div>
<!-- 荣誉徽章 -->
<!--<div class="w-full max-w-sm opacity-0 translate-y-4 transition-all duration-700 delay-700" :class="{ 'opacity-100 translate-y-0': activeIndex === 1 }">
<h3 class="font-bold text-[#1A3B34] mb-4">获得的荣誉徽章</h3>
<div class="flex justify-between px-2">
<!~~ 徽章1 ~~>
<div class="w-16 h-16 rounded-full bg-[#FFF9C4] flex items-center justify-center shadow-sm">
<TrophyIcon class="w-8 h-8 text-[#FBC02D]" />
</div>
<!~~ 徽章2 ~~>
<div class="w-16 h-16 rounded-full bg-[#F3E5F5] flex items-center justify-center shadow-sm">
<StarIcon class="w-8 h-8 text-[#AB47BC]" />
</div>
<!~~ 徽章3 ~~>
<div class="w-16 h-16 rounded-full bg-[#E3F2FD] flex items-center justify-center shadow-sm">
<CheckBadgeIcon class="w-8 h-8 text-[#42A5F5]" />
</div>
<!~~ 徽章4 (锁定) ~~>
<div class="w-16 h-16 rounded-full bg-[#F5F5F5] flex items-center justify-center shadow-sm">
<LockClosedIcon class="w-8 h-8 text-[#BDBDBD]" />
</div>
</div>
</div>-->
</div>
</swiper-slide>
</swiper>
</div>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue';
import { useAuth } from '@/contexts/auth';
import { ChevronDoubleDownIcon, CalendarIcon, HeartIcon, TrophyIcon, StarIcon, CheckBadgeIcon, LockClosedIcon } from '@heroicons/vue/24/solid'; // Added icons
import dayjs from 'dayjs';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Mousewheel } from 'swiper/modules';
import 'swiper/css';
// 状态
const { currentUser } = useAuth();
// 使用一个通用的默认头像URL,实际项目中应替换为本地资源或配置的默认图
const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/default_avatar.png';
// Swiper 实例和状态
const swiperInstance = ref(null);
const activeIndex = ref(0);
const onSwiper = (swiper) => {
swiperInstance.value = swiper;
};
const onSlideChange = (swiper) => {
activeIndex.value = swiper.activeIndex;
};
const slideNext = () => {
swiperInstance.value?.slideNext();
};
const userAvatar = computed(() => {
let avatar = currentUser.value?.avatar;
if (avatar && avatar.includes('cdn.ipadbiz.cn')) {
avatar += '?imageMogr2/thumbnail/200x/strip/quality/70';
}
return avatar;
});
const userName = computed(() => currentUser.value?.name || '旅行者');
// 加入时间逻辑
const joinDate = computed(() => {
return currentUser.value?.created_at || currentUser.value?.reg_time || new Date();
});
const joinDateFormatted = computed(() => {
return dayjs(joinDate.value).format('YYYY年M月D日');
});
const durationString = computed(() => {
const start = dayjs(joinDate.value);
const now = dayjs();
const years = now.diff(start, 'year');
const months = now.diff(start, 'month') % 12;
if (years === 0 && months === 0) {
const days = now.diff(start, 'day');
return `${days} 天`;
}
if (years > 0) {
return `${years} 年 ${months} 个月`;
} else {
return `${months} 个月`;
}
});
// Mock Data for Second Screen
const activityCount = ref(28);
const volunteerCount = ref(12);
const volunteerHours = ref(100);
onMounted(() => {
console.log('Recall Page - Current User:', currentUser.value);
});
</script>
<style scoped>
/* 针对不同屏幕尺寸的微调可以放在这里,或者直接使用 Tailwind */
</style>