1
1
<script setup lang="ts">
2
+ import type { AllClubs } from ' @@/types/api/user/all_clubs'
3
+ import type { MyRecords } from ' @@/types/api/cas/record/my'
2
4
import Announcements from ' @/components/custom/Index/announcements.vue'
5
+ import { Card , CardContent , CardDescription , CardHeader , CardTitle } from ' @/components/ui/card'
6
+ import { Skeleton } from ' @/components/ui/skeleton'
7
+ import { useUser } from ' vue-clerk'
3
8
4
9
definePageMeta ({
5
10
middleware: [' auth' ],
@@ -10,26 +15,181 @@ useHead({
10
15
title: ' Home | Enspire' ,
11
16
})
12
17
18
+ const { user } = useUser ()
13
19
const now = new Date ().getHours ()
20
+
21
+ // Get user's clubs
22
+ const { data : clubs } = useQuery <AllClubs >({
23
+ queryKey: [' /api/user/all_clubs' ],
24
+ })
25
+
26
+ // Track total CAS hours
27
+ const isLoading = ref (true )
28
+ const totalCASHours = ref (0 )
29
+
30
+ watch (clubs , async () => {
31
+ isLoading .value = true
32
+ if (clubs .value ?.president ?.length || clubs .value ?.vice ?.length ) {
33
+ let total = 0
34
+ for (const club of [... (clubs .value .president || []), ... (clubs .value .vice || [])]) {
35
+ const { data } = await useFetch <MyRecords >(` /api/cas/record/my?club=${club .id } ` )
36
+ if (data .value ) {
37
+ total += data .value .data .reduce ((sum , record ) => {
38
+ return sum + record .cTime + record .aTime + record .sTime
39
+ }, 0 )
40
+ }
41
+ }
42
+ totalCASHours .value = total
43
+ }
44
+ isLoading .value = false
45
+ }, { immediate: true })
14
46
</script >
15
47
16
48
<template >
17
- <div class =" text-3xl font-bold" >
18
- {{
19
- now < 5 ? '晚上好!'
20
- : now < 12 ? '早上好!'
21
- : now < 13 ? '中午好!'
22
- : now < 18 ? '下午好!' : '晚上好!'
23
- }}
24
- </div >
25
- <div class =" text-muted-foreground" >
26
- Welcome to Enspire!
27
- </div >
28
- <div class =" mt-7 space-y-2" >
29
- <Announcements />
30
- </div >
31
- </template >
49
+ <div class =" space-y-6" >
50
+
51
+ <!-- Welcome Section -->
52
+ <div >
53
+ <div class =" text-3xl font-bold" >
54
+ {{
55
+ now < 5 ? '晚上好!'
56
+ : now < 12 ? '早上好!'
57
+ : now < 13 ? '中午好!'
58
+ : now < 18 ? '下午好!' : '晚上好!'
59
+ }}
60
+ </div >
61
+ <div class =" text-muted-foreground" >
62
+ Welcome to Enspire!
63
+ </div >
64
+ </div >
32
65
33
- <style scoped>
66
+ <!-- Quick Stats -->
67
+ <div class =" grid gap-4 md:grid-cols-2 lg:grid-cols-3" >
68
+ <Card class =" transition-all hover:shadow-md hover:bg-muted/50" >
69
+ <CardHeader >
70
+ <CardTitle class =" flex items-center gap-2" >
71
+ <Icon name =" lucide:users" class =" h-5 w-5 text-primary" />
72
+ 我的社团
73
+ </CardTitle >
74
+ </CardHeader >
75
+ <CardContent >
76
+ <div v-if =" isLoading" class =" space-y-2" >
77
+ <Skeleton class =" h-8 w-16" />
78
+ <Skeleton class =" h-4 w-32" />
79
+ </div >
80
+ <div v-else >
81
+ <div class =" text-2xl font-bold" >
82
+ {{ (clubs?.president?.length || 0) + (clubs?.vice?.length || 0) + (clubs?.member?.length || 0) }}
83
+ </div >
84
+ <p class =" mt-1 text-xs text-muted-foreground" >总计参与社团数量</p >
85
+ </div >
86
+ </CardContent >
87
+ </Card >
34
88
35
- </style >
89
+ <Card class =" transition-all hover:shadow-md hover:bg-muted/50" >
90
+ <CardHeader >
91
+ <CardTitle class =" flex items-center gap-2" >
92
+ <Icon name =" lucide:star" class =" h-5 w-5 text-primary" />
93
+ 管理社团
94
+ </CardTitle >
95
+ </CardHeader >
96
+ <CardContent >
97
+ <div v-if =" isLoading" class =" space-y-2" >
98
+ <Skeleton class =" h-8 w-16" />
99
+ <Skeleton class =" h-4 w-32" />
100
+ </div >
101
+ <div v-else >
102
+ <div class =" text-2xl font-bold" >
103
+ {{ (clubs?.president?.length || 0) + (clubs?.vice?.length || 0) }}
104
+ </div >
105
+ <p class =" mt-1 text-xs text-muted-foreground" >担任社长或副社长的社团数量</p >
106
+ </div >
107
+ </CardContent >
108
+ </Card >
109
+
110
+ <Card class =" transition-all hover:shadow-md hover:bg-muted/50" >
111
+ <CardHeader >
112
+ <CardTitle class =" flex items-center gap-2" >
113
+ <Icon name =" lucide:clock" class =" h-5 w-5 text-primary" />
114
+ 活动记录时间
115
+ </CardTitle >
116
+ </CardHeader >
117
+ <CardContent >
118
+ <div v-if =" isLoading" class =" space-y-2" >
119
+ <Skeleton class =" h-8 w-16" />
120
+ <Skeleton class =" h-4 w-32" />
121
+ </div >
122
+ <div v-else >
123
+ <div class =" text-2xl font-bold" >
124
+ {{ totalCASHours }}
125
+ </div >
126
+ <p class =" mt-1 text-xs text-muted-foreground" >总计活动时间(小时)</p >
127
+ </div >
128
+ </CardContent >
129
+ </Card >
130
+ </div >
131
+
132
+ <!-- Quick Actions -->
133
+ <div >
134
+ <h2 class =" mb-4 text-lg font-semibold flex items-center gap-2" >
135
+ <Icon name =" lucide:zap" class =" h-5 w-5" />
136
+ 快捷操作
137
+ </h2 >
138
+ <div class =" grid gap-4 md:grid-cols-2 lg:grid-cols-3" >
139
+ <NuxtLink to =" /cas/clubs" class =" group" >
140
+ <Card class =" transition-all hover:bg-muted/50 hover:shadow-md" >
141
+ <CardHeader >
142
+ <CardTitle class =" flex items-center gap-2" >
143
+ <Icon name =" lucide:map" class =" h-5 w-5" />
144
+ 浏览社团
145
+ </CardTitle >
146
+ <CardDescription class =" flex items-center" >
147
+ 查看所有社团信息
148
+ <Icon name =" lucide:arrow-right" class =" ml-1 h-4 w-4 transition-transform group-hover:translate-x-1" />
149
+ </CardDescription >
150
+ </CardHeader >
151
+ </Card >
152
+ </NuxtLink >
153
+
154
+ <NuxtLink to =" /forms" class =" group" >
155
+ <Card class =" transition-all hover:bg-muted/50 hover:shadow-md" >
156
+ <CardHeader >
157
+ <CardTitle class =" flex items-center gap-2" >
158
+ <Icon name =" lucide:clipboard" class =" h-5 w-5" />
159
+ 填写表单
160
+ </CardTitle >
161
+ <CardDescription class =" flex items-center" >
162
+ 查看待填写的表单
163
+ <Icon name =" lucide:arrow-right" class =" ml-1 h-4 w-4 transition-transform group-hover:translate-x-1" />
164
+ </CardDescription >
165
+ </CardHeader >
166
+ </Card >
167
+ </NuxtLink >
168
+
169
+ <NuxtLink to =" /manage/statuses" class =" group" >
170
+ <Card class =" transition-all hover:bg-muted/50 hover:shadow-md" >
171
+ <CardHeader >
172
+ <CardTitle class =" flex items-center gap-2" >
173
+ <Icon name =" lucide:door-open" class =" h-5 w-5" />
174
+ 教室状态
175
+ </CardTitle >
176
+ <CardDescription class =" flex items-center" >
177
+ 查看教室预约状态
178
+ <Icon name =" lucide:arrow-right" class =" ml-1 h-4 w-4 transition-transform group-hover:translate-x-1" />
179
+ </CardDescription >
180
+ </CardHeader >
181
+ </Card >
182
+ </NuxtLink >
183
+ </div >
184
+ </div >
185
+
186
+ <!-- Announcements Section -->
187
+ <div >
188
+ <h2 class =" mb-4 text-lg font-semibold flex items-center gap-2" >
189
+ <Icon name =" lucide:megaphone" class =" h-5 w-5" />
190
+ 公告
191
+ </h2 >
192
+ <Announcements />
193
+ </div >
194
+ </div >
195
+ </template >
0 commit comments