hookehuyr

refactor(components): 替换Tabs组件为内联实现

在ActivityDetail.vue和UserProfile.vue中,将Tabs组件替换为内联实现,以提高代码的可读性和维护性。同时修复了路径中的空格问题,并调整了路由参数的命名。
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
10 "preview": "vite preview" 10 "preview": "vite preview"
11 }, 11 },
12 "dependencies": { 12 "dependencies": {
13 - "@vitejs/plugin-vue-jsx": "4.1.2",
14 "axios": "^1.8.4", 13 "axios": "^1.8.4",
15 "pinia": "^2.1.7", 14 "pinia": "^2.1.7",
16 "vue": "^3.4.21", 15 "vue": "^3.4.21",
...@@ -18,6 +17,7 @@ ...@@ -18,6 +17,7 @@
18 }, 17 },
19 "devDependencies": { 18 "devDependencies": {
20 "@vitejs/plugin-vue": "^5.0.4", 19 "@vitejs/plugin-vue": "^5.0.4",
20 + "@vitejs/plugin-vue-jsx": "4.1.2",
21 "@vue/compiler-sfc": "^3.4.21", 21 "@vue/compiler-sfc": "^3.4.21",
22 "autoprefixer": "^10.4.20", 22 "autoprefixer": "^10.4.20",
23 "eslint": "^9.9.0", 23 "eslint": "^9.9.0",
......
...@@ -8,9 +8,6 @@ importers: ...@@ -8,9 +8,6 @@ importers:
8 8
9 .: 9 .:
10 dependencies: 10 dependencies:
11 - '@vitejs/plugin-vue-jsx':
12 - specifier: 4.1.2
13 - version: 4.1.2(vite@5.4.18)(vue@3.5.13)
14 axios: 11 axios:
15 specifier: ^1.8.4 12 specifier: ^1.8.4
16 version: 1.8.4 13 version: 1.8.4
...@@ -27,6 +24,9 @@ importers: ...@@ -27,6 +24,9 @@ importers:
27 '@vitejs/plugin-vue': 24 '@vitejs/plugin-vue':
28 specifier: ^5.0.4 25 specifier: ^5.0.4
29 version: 5.2.3(vite@5.4.18)(vue@3.5.13) 26 version: 5.2.3(vite@5.4.18)(vue@3.5.13)
27 + '@vitejs/plugin-vue-jsx':
28 + specifier: 4.1.2
29 + version: 4.1.2(vite@5.4.18)(vue@3.5.13)
30 '@vue/compiler-sfc': 30 '@vue/compiler-sfc':
31 specifier: ^3.4.21 31 specifier: ^3.4.21
32 version: 3.5.13 32 version: 3.5.13
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
16 16
17 <!-- Tab content --> 17 <!-- Tab content -->
18 <div class="pt-4"> 18 <div class="pt-4">
19 - <component :is="tabs[currentTab]?.content" /> 19 + <component :is="tabs[currentTab]?.component" />
20 </div> 20 </div>
21 </div> 21 </div>
22 </template> 22 </template>
......
1 +/*
2 + * @Date: 2025-04-17 14:26:17
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-04-21 13:26:32
5 + * @FilePath: /mlaj-reading-club/src/main.js
6 + * @Description: 文件描述
7 + */
1 import { createApp } from 'vue' 8 import { createApp } from 'vue'
2 import { createPinia } from 'pinia' 9 import { createPinia } from 'pinia'
3 import { createRouter, createWebHistory } from 'vue-router' 10 import { createRouter, createWebHistory } from 'vue-router'
...@@ -16,7 +23,7 @@ const router = createRouter({ ...@@ -16,7 +23,7 @@ const router = createRouter({
16 history: createWebHistory(), 23 history: createWebHistory(),
17 routes: [ 24 routes: [
18 { path: '/', component: () => import('./pages/HomePage.vue') }, 25 { path: '/', component: () => import('./pages/HomePage.vue') },
19 - { path: '/activity/:activityId', component: () => import('./pages/ActivityDetail.vue') }, 26 + { path: '/activity/:id', component: () => import('./pages/ActivityDetail.vue') },
20 { path: '/create-activity', component: () => import('./pages/CreateActivity.vue') }, 27 { path: '/create-activity', component: () => import('./pages/CreateActivity.vue') },
21 { path: '/profile', component: () => import('./pages/UserProfile.vue') }, 28 { path: '/profile', component: () => import('./pages/UserProfile.vue') },
22 { path: '/registration/:activityId', component: () => import('./pages/Registration.vue') }, 29 { path: '/registration/:activityId', component: () => import('./pages/Registration.vue') },
......
...@@ -75,7 +75,64 @@ ...@@ -75,7 +75,64 @@
75 </div> 75 </div>
76 76
77 <!-- Activity Tabs --> 77 <!-- Activity Tabs -->
78 - <Tabs :tabs="tabs" /> 78 + <div>
79 + <!-- Tab headers -->
80 + <div class="flex border-b border-gray-200">
81 + <button v-for="(tab, index) in tabs" :key="index"
82 + class="text-base py-2 px-4 font-medium transition-all duration-200 focus:outline-none border-b-2"
83 + :class="currentTab === index
84 + ? 'border-green-500 text-green-600'
85 + : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'"
86 + @click="currentTab = index" role="tab" :aria-selected="currentTab === index">
87 + {{ tab.label }}
88 + </button>
89 + </div>
90 +
91 + <!-- Tab content -->
92 + <div class="pt-4">
93 + <div v-if="tabs[currentTab].label === '活动详情'">
94 + <div class="space-y-4">
95 + <div v-for="(paragraph, idx) in activity.description.split('\n')" :key="idx"
96 + class="mb-4">
97 + {{ paragraph }}
98 + </div>
99 + </div>
100 + </div>
101 + <div v-if="tabs[currentTab].label === '参与须知'">
102 + <div class="space-y-4">
103 + <h3 class="font-medium text-lg">参与须知</h3>
104 + <ul class="list-disc pl-5 space-y-2">
105 + <li>请准时到达活动地点或登录线上会议</li>
106 + <li>请提前阅读相关书籍或材料</li>
107 + <li>活动开始后,请将手机调至静音模式</li>
108 + <li>尊重他人发言,不打断他人</li>
109 + <li>可携带笔记本进行记录</li>
110 + <li>如需取消参与,请提前24小时通知主办方</li>
111 + </ul>
112 + </div>
113 + </div>
114 + <div v-if="tabs[currentTab].label === '常见问题'">
115 +
116 + <div class="space-y-6">
117 + <div>
118 + <h4 class="font-medium text-gray-900">如何取消报名?</h4>
119 + <p class="mt-2 text-gray-600">
120 + 您可以在"我的活动"页面找到已报名的活动,点击"取消报名"按钮即可。请注意,活动开始前24小时内取消将无法获得退款。</p>
121 + </div>
122 + <div>
123 + <h4 class="font-medium text-gray-900">活动材料如何获取?</h4>
124 + <p class="mt-2 text-gray-600">报名成功后,您将在"我的活动"页面看到活动详情,相关材料可在页面底部下载或通过邮件接收。
125 + </p>
126 + </div>
127 + <div>
128 + <h4 class="font-medium text-gray-900">线上活动如何参加?</h4>
129 + <p class="mt-2 text-gray-600">
130 + 线上活动将在活动开始前30分钟发送会议链接到您的邮箱和手机短信,您也可以在"我的活动"页面找到入口链接。</p>
131 + </div>
132 + </div>
133 + </div>
134 + </div>
135 + </div>
79 </div> 136 </div>
80 137
81 <!-- Sidebar --> 138 <!-- Sidebar -->
...@@ -226,13 +283,17 @@ ...@@ -226,13 +283,17 @@
226 </template> 283 </template>
227 284
228 <script setup> 285 <script setup>
229 -import { ref, computed, onMounted } from 'vue' 286 +import { ref, computed, onMounted, h, defineComponent } from 'vue'
230 import { useRoute, useRouter } from 'vue-router' 287 import { useRoute, useRouter } from 'vue-router'
231 import { useAppStore } from '../stores/app' 288 import { useAppStore } from '../stores/app'
232 import Button from '../components/shared/Button.vue' 289 import Button from '../components/shared/Button.vue'
233 import Modal from '../components/shared/Modal.vue' 290 import Modal from '../components/shared/Modal.vue'
234 -import Tabs from '../components/shared/Tabs.vue'
235 import ActivityCard from '../components/shared/ActivityCard.vue' 291 import ActivityCard from '../components/shared/ActivityCard.vue'
292 +import activitiesData from '../data/activities.json'
293 +import registrationsData from '../data/registrations.json'
294 +
295 +const activities = ref(activitiesData.activities)
296 +const registrations = ref(registrationsData.registrations)
236 297
237 const route = useRoute() 298 const route = useRoute()
238 const router = useRouter() 299 const router = useRouter()
...@@ -246,6 +307,7 @@ const showRegisterModal = ref(false) ...@@ -246,6 +307,7 @@ const showRegisterModal = ref(false)
246 const similarActivities = ref([]) 307 const similarActivities = ref([])
247 const hasRegistered = ref(false) 308 const hasRegistered = ref(false)
248 const registrationStatus = ref(null) 309 const registrationStatus = ref(null)
310 +const currentTab = ref(0)
249 311
250 // Computed 312 // Computed
251 const activityStatus = computed(() => { 313 const activityStatus = computed(() => {
...@@ -305,44 +367,13 @@ const registrationStatusBadge = computed(() => { ...@@ -305,44 +367,13 @@ const registrationStatusBadge = computed(() => {
305 const tabs = computed(() => [ 367 const tabs = computed(() => [
306 { 368 {
307 label: '活动详情', 369 label: '活动详情',
308 - content: activity.value?.description.split('\n').map((paragraph, idx) => (
309 - `<p key="${idx}" class="mb-4">${paragraph}</p>`
310 - )).join('')
311 }, 370 },
312 { 371 {
313 label: '参与须知', 372 label: '参与须知',
314 - content: `
315 - <h3 class="font-medium text-lg mb-4">参与须知</h3>
316 - <ul class="list-disc pl-5 space-y-2">
317 - <li>请准时到达活动地点或登录线上会议</li>
318 - <li>请提前阅读相关书籍或材料</li>
319 - <li>活动开始后,请将手机调至静音模式</li>
320 - <li>尊重他人发言,不打断他人</li>
321 - <li>可携带笔记本进行记录</li>
322 - <li>如需取消参与,请提前24小时通知主办方</li>
323 - </ul>
324 - `
325 }, 373 },
326 { 374 {
327 label: '常见问题', 375 label: '常见问题',
328 - content: ` 376 + }
329 - <div className="py-4">
330 - <div className="space-y-6">
331 - <div>
332 - <h4 className="font-medium text-gray-900">如何取消报名?</h4>
333 - <p className="mt-2 text-gray-600">您可以在"我的活动"页面找到已报名的活动,点击"取消报名"按钮即可。请注意,活动开始前24小时内取消将无法获得退款。</p>
334 - </div>
335 - <div>
336 - <h4 className="font-medium text-gray-900">活动材料如何获取?</h4>
337 - <p className="mt-2 text-gray-600">报名成功后,您将在"我的活动"页面看到活动详情,相关材料可在页面底部下载或通过邮件接收。</p>
338 - </div>
339 - <div>
340 - <h4 className="font-medium text-gray-900">线上活动如何参加?</h4>
341 - <p className="mt-2 text-gray-600">线上活动将在活动开始前30分钟发送会议链接到您的邮箱和手机短信,您也可以在"我的活动"页面找到入口链接。</p>
342 - </div>
343 - </div>
344 - </div>
345 - `}
346 ]) 377 ])
347 378
348 // Functions 379 // Functions
...@@ -351,7 +382,7 @@ const goBack = () => { ...@@ -351,7 +382,7 @@ const goBack = () => {
351 } 382 }
352 383
353 const getActivityImage = (activityId) => { 384 const getActivityImage = (activityId) => {
354 - return `/ assets / images / activities / ${activityId}.jpg` 385 + return `/assets/images/activities/${activityId}.jpg`
355 } 386 }
356 387
357 const formatDate = (dateString) => { 388 const formatDate = (dateString) => {
......
...@@ -56,12 +56,170 @@ ...@@ -56,12 +56,170 @@
56 <!-- Profile Content --> 56 <!-- Profile Content -->
57 <div class="container mx-auto py-8 px-4"> 57 <div class="container mx-auto py-8 px-4">
58 <div class="bg-white rounded-lg shadow-sm overflow-hidden"> 58 <div class="bg-white rounded-lg shadow-sm overflow-hidden">
59 - <Tabs :tabs="profileTabs" /> 59 + <!-- Tab headers -->
60 + <div class="flex border-b border-gray-200">
61 + <button v-for="(tab, index) in ['个人资料', '我的活动', '报名记录']" :key="index"
62 + class="text-base py-2 px-4 font-medium transition-all duration-200 focus:outline-none border-b-2"
63 + :class="currentTab === index
64 + ? 'border-green-500 text-green-600'
65 + : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'"
66 + @click="currentTab = index" role="tab" :aria-selected="currentTab === index">
67 + {{ tab }}
68 + </button>
69 + </div>
70 + <!-- Tab content -->
71 + <div class="pt-4">
72 + <!-- 个人资料 -->
73 + <div v-show="currentTab === 0" class="p-6">
74 + <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
75 + <!-- Left column -->
76 + <div>
77 + <h3 class="text-lg font-medium text-gray-900 mb-4">基本信息</h3>
78 + <div class="space-y-4">
79 + <!-- Name -->
80 + <div>
81 + <h4 class="text-sm font-medium text-gray-500">姓名</h4>
82 + <p class="mt-1 text-gray-900">{{ currentUser?.name }}</p>
83 + </div>
84 + <!-- Location -->
85 + <div>
86 + <h4 class="text-sm font-medium text-gray-500">所在地</h4>
87 + <p class="mt-1 text-gray-900">{{ currentUser?.location || '未设置' }}</p>
88 + </div>
89 + <div>
90 + <h4 class="text-sm font-medium text-gray-500">性别</h4>
91 + <p class="mt-1 text-gray-900">{{ currentUser.gender || '未设置' }}</p>
92 + </div>
93 + <div>
94 + <h4 class="text-sm font-medium text-gray-500">年龄段</h4>
95 + <p class="mt-1 text-gray-900">{{ currentUser.age_group || '未设置' }}</p>
96 + </div>
97 + <div>
98 + <h4 class="text-sm font-medium text-gray-500">注册日期</h4>
99 + <p class="mt-1 text-gray-900">
100 + {{ formatRegistrationDate(currentUser.registration_date) }}
101 + </p>
102 + </div>
103 + </div>
104 + </div>
105 + <!-- Right column -->
106 + <div>
107 + <h3 class="text-lg font-medium text-gray-900 mb-4">联系方式</h3>
108 + <div class="space-y-4">
109 + <!-- Email -->
110 + <div>
111 + <h4 class="text-sm font-medium text-gray-500">电子邮箱</h4>
112 + <p class="mt-1 text-gray-900">{{ currentUser?.email }}</p>
113 + </div>
114 + <!-- Phone -->
115 + <div>
116 + <h4 class="text-sm font-medium text-gray-500">手机号码</h4>
117 + <p class="mt-1 text-gray-900">{{ currentUser?.phone }}</p>
118 + </div>
119 + </div>
120 +
121 + <h3 class="text-lg font-medium text-gray-900 mt-8 mb-4">个人简介</h3>
122 + <p class="text-gray-700 whitespace-pre-wrap">
123 + {{ currentUser.bio || '暂无个人简介' }}
124 + </p>
125 + </div>
126 + </div>
127 +
128 + <div class="mt-8">
129 + <h3 class="text-lg font-medium text-gray-900 mb-4">阅读兴趣</h3>
130 + <div v-if="currentUser.interests && currentUser.interests.length > 0">
131 + <div class="flex flex-wrap gap-2">
132 + <span v-for="(interest, index) in currentUser.interests" :key="index"
133 + class="bg-green-50 text-green-700 px-3 py-1 rounded-full text-sm">
134 + {{ interest }}
135 + </span>
136 + </div>
137 + </div>
138 + <div v-else>
139 + <p class="text-gray-500">暂无兴趣标签</p>
140 + </div>
141 + </div>
142 + </div>
143 + <!-- 我的活动 -->
144 + <div v-show="currentTab === 1" class="p-6">
145 + <div class="mb-8">
146 + <h3 class="text-lg font-medium text-gray-900 mb-4">
147 + <span class="inline-block w-3 h-3 bg-green-500 rounded-full mr-2"></span>
148 + <span>即将参加的活动</span>
149 + </h3>
150 + <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
151 + <ActivityCard v-for="activity in upcomingActivities" :key="activity.id"
152 + :activity="activity" />
153 + </div>
154 + </div>
155 + </div>
156 + <!-- 报名记录 -->
157 + <div v-show="currentTab === 2" class="p-6">
158 + <div class="overflow-x-auto">
159 + <table class="min-w-full divide-y divide-gray-200">
160 + <thead class="bg-gray-50">
161 + <tr>
162 + <th
163 + class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
164 + 活动信息</th>
165 + <th
166 + class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
167 + 报名时间</th>
168 + <th
169 + class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
170 + 状态</th>
171 + <th
172 + class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
173 + 操作</th>
174 + </tr>
175 + </thead>
176 + <tbody class="bg-white divide-y divide-gray-200">
177 + <tr v-for="registration in userRegistrations" :key="registration.id">
178 + <td class="px-6 py-4 whitespace-nowrap">
179 + <div class="flex items-center">
180 + <div class="text-sm font-medium text-gray-900">
181 + {{activities.find(a => a.id ===
182 + registration.activity_id)?.title || '未知活动'
183 + }}
184 + </div>
185 + </div>
186 + </td>
187 + <td class="px-6 py-4 whitespace-nowrap">
188 + <div class="text-sm text-gray-900">
189 + {{ formatRegistrationDate(registration.registration_time) }}
190 + </div>
191 + </td>
192 + <td class="px-6 py-4 whitespace-nowrap">
193 + <span :class="[
194 + 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium',
195 + registration.status === 'approved' ? 'bg-green-100 text-green-800' :
196 + registration.status === 'pending' ? 'bg-yellow-100 text-yellow-800' :
197 + 'bg-gray-100 text-gray-800'
198 + ]">
199 + {{ registration.status === 'approved' ? '已通过' :
200 + registration.status === 'pending' ? '审核中' :
201 + registration.status }}
202 + </span>
203 + </td>
204 + <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
205 + <router-link v-if="activities.find(a => a.id === registration.activity_id)" :to="`/activity/${registration.activity_id}`" class="text-green-600 hover:text-green-900 mr-4">
206 + 查看详情
207 + </router-link>
208 + <router-link v-if="registration.status === 'approved'" :to="`/check-in/${registration.activity_id}`" class="text-blue-600 hover:text-blue-900">
209 + 签到
210 + </router-link>
211 + </td>
212 + </tr>
213 + </tbody>
214 + </table>
215 + </div>
216 + </div>
217 + </div>
60 </div> 218 </div>
61 </div> 219 </div>
62 220
63 <!-- Edit Profile Modal --> 221 <!-- Edit Profile Modal -->
64 - <Modal v-model:show="isEditModalOpen" title="编辑个人资料"> 222 + <Modal :isOpen="isEditModalOpen" title="编辑个人资料">
65 <div class="space-y-4"> 223 <div class="space-y-4">
66 <Input v-model="editForm.name" label="姓名" placeholder="请输入姓名" /> 224 <Input v-model="editForm.name" label="姓名" placeholder="请输入姓名" />
67 <Input v-model="editForm.email" label="电子邮箱" type="email" placeholder="请输入电子邮箱" /> 225 <Input v-model="editForm.email" label="电子邮箱" type="email" placeholder="请输入电子邮箱" />
...@@ -107,18 +265,25 @@ import { ref, computed, onMounted } from 'vue' ...@@ -107,18 +265,25 @@ import { ref, computed, onMounted } from 'vue'
107 import { useAppStore } from '../stores/app' 265 import { useAppStore } from '../stores/app'
108 import Button from '../components/shared/Button.vue' 266 import Button from '../components/shared/Button.vue'
109 import Input from '../components/shared/Input.vue' 267 import Input from '../components/shared/Input.vue'
110 -import Tabs from '../components/shared/Tabs.vue'
111 import ActivityCard from '../components/shared/ActivityCard.vue' 268 import ActivityCard from '../components/shared/ActivityCard.vue'
112 import Modal from '../components/shared/Modal.vue' 269 import Modal from '../components/shared/Modal.vue'
113 270
114 -const store = useAppStore() 271 +
115 -const { currentUser, activities, registrations } = store 272 +import activitiesData from '../data/activities.json'
273 +import registrationsData from '../data/registrations.json'
274 +import usersData from '../data/users.json'
275 +
276 +
277 +const activities = ref(activitiesData.activities)
278 +const registrations = ref(registrationsData.registrations)
279 +const currentUser = ref(usersData.users[0])
116 280
117 const userRegistrations = ref([]) 281 const userRegistrations = ref([])
118 const registeredActivities = ref([]) 282 const registeredActivities = ref([])
119 const pastActivities = ref([]) 283 const pastActivities = ref([])
120 const upcomingActivities = ref([]) 284 const upcomingActivities = ref([])
121 const isEditModalOpen = ref(false) 285 const isEditModalOpen = ref(false)
286 +const currentTab = ref(0)
122 const editForm = ref({ 287 const editForm = ref({
123 name: '', 288 name: '',
124 bio: '', 289 bio: '',
...@@ -173,276 +338,6 @@ const formatRegistrationDate = (dateString) => { ...@@ -173,276 +338,6 @@ const formatRegistrationDate = (dateString) => {
173 }).format(date) 338 }).format(date)
174 } 339 }
175 340
176 -// Profile tabs configuration
177 -const profileTabs = computed(() => [
178 - {
179 - label: "个人资料",
180 - content: {
181 - component: 'div',
182 - class: 'p-6',
183 - children: [
184 - // Basic Info section
185 - {
186 - component: 'div',
187 - class: 'grid grid-cols-1 md:grid-cols-2 gap-8',
188 - children: [
189 - // Left column
190 - {
191 - component: 'div',
192 - children: [
193 - {
194 - component: 'h3',
195 - class: 'text-lg font-medium text-gray-900 mb-4',
196 - text: '基本信息'
197 - },
198 - // User info fields
199 - {
200 - component: 'div',
201 - class: 'space-y-4',
202 - children: [
203 - // Name
204 - {
205 - component: 'div',
206 - children: [
207 - {
208 - component: 'h4',
209 - class: 'text-sm font-medium text-gray-500',
210 - text: '姓名'
211 - },
212 - {
213 - component: 'p',
214 - class: 'mt-1 text-gray-900',
215 - text: currentUser.value?.name
216 - }
217 - ]
218 - },
219 - // Location
220 - {
221 - component: 'div',
222 - children: [
223 - {
224 - component: 'h4',
225 - class: 'text-sm font-medium text-gray-500',
226 - text: '所在地'
227 - },
228 - {
229 - component: 'p',
230 - class: 'mt-1 text-gray-900',
231 - text: currentUser.value?.location || '未设置'
232 - }
233 - ]
234 - }
235 - ]
236 - }
237 - ]
238 - },
239 - // Right column
240 - {
241 - component: 'div',
242 - children: [
243 - {
244 - component: 'h3',
245 - class: 'text-lg font-medium text-gray-900 mb-4',
246 - text: '联系方式'
247 - },
248 - // Contact info
249 - {
250 - component: 'div',
251 - class: 'space-y-4',
252 - children: [
253 - // Email
254 - {
255 - component: 'div',
256 - children: [
257 - {
258 - component: 'h4',
259 - class: 'text-sm font-medium text-gray-500',
260 - text: '电子邮箱'
261 - },
262 - {
263 - component: 'p',
264 - class: 'mt-1 text-gray-900',
265 - text: currentUser.value?.email
266 - }
267 - ]
268 - },
269 - // Phone
270 - {
271 - component: 'div',
272 - children: [
273 - {
274 - component: 'h4',
275 - class: 'text-sm font-medium text-gray-500',
276 - text: '手机号码'
277 - },
278 - {
279 - component: 'p',
280 - class: 'mt-1 text-gray-900',
281 - text: currentUser.value?.phone
282 - }
283 - ]
284 - }
285 - ]
286 - }
287 - ]
288 - }
289 - ]
290 - }
291 - ]
292 - }
293 - },
294 - {
295 - label: "我的活动",
296 - content: {
297 - component: 'div',
298 - class: 'p-6',
299 - children: [
300 - // Upcoming activities section
301 - {
302 - component: 'div',
303 - class: 'mb-8',
304 - children: [
305 - {
306 - component: 'h3',
307 - class: 'text-lg font-medium text-gray-900 mb-4',
308 - children: [
309 - {
310 - component: 'span',
311 - class: 'inline-block w-3 h-3 bg-green-500 rounded-full mr-2'
312 - },
313 - {
314 - component: 'span',
315 - text: '即将参加的活动'
316 - }
317 - ]
318 - },
319 - // Activity cards
320 - {
321 - component: 'div',
322 - class: 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6',
323 - children: upcomingActivities.value.map(activity => ({
324 - component: ActivityCard,
325 - props: { activity }
326 - }))
327 - }
328 - ]
329 - }
330 - ]
331 - }
332 - },
333 - {
334 - label: "报名记录",
335 - content: {
336 - component: 'div',
337 - class: 'p-6',
338 - children: [
339 - {
340 - component: 'div',
341 - class: 'overflow-x-auto',
342 - children: [
343 - // Registration table
344 - {
345 - component: 'table',
346 - class: 'min-w-full divide-y divide-gray-200',
347 - children: [
348 - // Table header
349 - {
350 - component: 'thead',
351 - class: 'bg-gray-50',
352 - children: [
353 - {
354 - component: 'tr',
355 - children: [
356 - {
357 - component: 'th',
358 - class: 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider',
359 - text: '活动信息'
360 - },
361 - {
362 - component: 'th',
363 - class: 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider',
364 - text: '报名时间'
365 - },
366 - {
367 - component: 'th',
368 - class: 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider',
369 - text: '状态'
370 - }
371 - ]
372 - }
373 - ]
374 - },
375 - // Table body
376 - {
377 - component: 'tbody',
378 - class: 'bg-white divide-y divide-gray-200',
379 - children: userRegistrations.value.map(registration => ({
380 - component: 'tr',
381 - key: registration.id,
382 - children: [
383 - // Activity info
384 - {
385 - component: 'td',
386 - class: 'px-6 py-4 whitespace-nowrap',
387 - children: [
388 - {
389 - component: 'div',
390 - class: 'flex items-center',
391 - children: [
392 - {
393 - component: 'div',
394 - class: 'text-sm font-medium text-gray-900',
395 - text: activities.value.find(a => a.id === registration.activity_id)?.title || '未知活动'
396 - }
397 - ]
398 - }
399 - ]
400 - },
401 - // Registration time
402 - {
403 - component: 'td',
404 - class: 'px-6 py-4 whitespace-nowrap',
405 - children: [
406 - {
407 - component: 'div',
408 - class: 'text-sm text-gray-900',
409 - text: formatRegistrationDate(registration.registration_time)
410 - }
411 - ]
412 - },
413 - // Status
414 - {
415 - component: 'td',
416 - class: 'px-6 py-4 whitespace-nowrap',
417 - children: [
418 - {
419 - component: 'span',
420 - class: `inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${registration.status === 'approved'
421 - ? 'bg-green-100 text-green-800'
422 - : registration.status === 'pending'
423 - ? 'bg-yellow-100 text-yellow-800'
424 - : 'bg-gray-100 text-gray-800'
425 - }`,
426 - text: registration.status === 'approved'
427 - ? '已通过'
428 - : registration.status === 'pending'
429 - ? '审核中'
430 - : registration.status
431 - }
432 - ]
433 - }
434 - ]
435 - }))
436 - }
437 - ]
438 - }
439 - ]
440 - }
441 - ]
442 - }
443 - }
444 -])
445 -
446 // Lifecycle hooks 341 // Lifecycle hooks
447 onMounted(() => { 342 onMounted(() => {
448 if (currentUser.value) { 343 if (currentUser.value) {
...@@ -456,6 +351,8 @@ onMounted(() => { ...@@ -456,6 +351,8 @@ onMounted(() => {
456 } 351 }
457 } 352 }
458 353
354 + console.warn(registrations.value);
355 + console.warn(activities.value);
459 if (currentUser.value && registrations.value && activities.value) { 356 if (currentUser.value && registrations.value && activities.value) {
460 // Filter user registrations 357 // Filter user registrations
461 const userRegs = registrations.value.filter(reg => reg.user_id === currentUser.value.id) 358 const userRegs = registrations.value.filter(reg => reg.user_id === currentUser.value.id)
......