diff --git a/app/pages/cas/clubs/[id].vue b/app/pages/cas/clubs/[id].vue index 973a9c82..dcb44e05 100644 --- a/app/pages/cas/clubs/[id].vue +++ b/app/pages/cas/clubs/[id].vue @@ -6,21 +6,24 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com import { Separator } from '@/components/ui/separator' import sanitizeHtml from 'sanitize-html' import { useRoute } from 'vue-router' +import type { GroupInfo } from '@prisma/client' +import { useUser } from 'vue-clerk' const { data } = await useFetch('/api/club/all_details') const clubs = data.value! const route = useRoute() -const id = route.params.id // Fetch current Club ID via route params +const id = route.params.id + +const { user } = useUser() -// Filter clubs based on C_GroupsID and include information at the same level as groups const filteredClubs = Object.values(clubs).flatMap(clubCategory => clubCategory.filter((club: Club) => club.groups.some(group => group.C_GroupsID === id), ).map((club: Club) => ({ - ...club, // Spread to include all same-level information - groups: club.groups.filter(group => group.C_GroupsID === id), // Filter groups to only include those that match the ID + ...club, + groups: club.groups.filter(group => group.C_GroupsID === id), })), ) as Club[] @@ -41,6 +44,53 @@ if (filteredClubs[0] && filteredClubs[0].groups[0].C_DescriptionC) { } } +const { data: groupInfo } = await useQuery({ + queryKey: ['/api/cas/info/get', { club: id }], + enabled: !!id, +}) + +const isPresident = computed(() => { + if (!user.value || !filteredClubs.length) return false + const club = filteredClubs[0] + return club.presidentByTsimsStudentId === Number(user.value.tsimsStudentId) +}) + +// Group info editing +const isEditing = ref(false) +const newGroupUrl = ref('') +const newExpiration = ref('') + +async function updateGroupInfo() { + if (!newGroupUrl.value || !newExpiration.value) return + + try { + if (!groupInfo.value) { + // Create + await $fetch('/api/cas/info/new', { + method: 'POST', + body: { + clubId: Number(id), + wechatGroupUrl: newGroupUrl.value, + wechatGroupExpiration: newExpiration.value, + }, + }) + } else { + // Update + await $fetch('/api/cas/info/update', { + method: 'POST', + body: { + clubId: Number(id), + wechatGroupUrl: newGroupUrl.value, + wechatGroupExpiration: newExpiration.value, + }, + }) + } + isEditing.value = false + } catch (error) { + console.error('Failed to update group info:', error) + } +} + definePageMeta({ middleware: ['auth'], breadcrumb: '社团详情', @@ -55,90 +105,171 @@ useHead({
-
- - - -
- {{ group.C_NameC }} +
+
+ + + +
+ {{ group.C_NameC }} +
+ + 已解散 + +
+ + + +
+ {{ group.C_NameE }} +
+
+ Club Description +
+
+
+ +
+ 简介 +
+
+
+ 暂无简介 ;-(
- - 已解散 - - - - - -
- {{ group.C_NameE }} + + +
+ 成员
-
- Club Description +
+ 暂无成员 ;-(
- - - -
- 简介 -
-
-
- 暂无简介 ;-( -
- - -
- 成员 -
-
- 暂无成员 ;-( -
-
-
-
-
- {{ member.S_Name }} - ({{ member.S_Nickname }}) - - 社长 - - - 副社 - - / +
+
+
+
+ {{ member.S_Name }} + ({{ member.S_Nickname }}) + + 社长 + + + 副社 + + / +
-
- - - - - - 社团属性 - - - -
- Club Information + + +
+ + +
+ + + + 社团属性 + + + +
+ Club Information +
+
+
+ +
+ 社团类型: {{ group.C_Category }} +
+
+ 社团人数: {{ groupMemberCounts }} 人 +
+
+ 指导老师: + + {{ supervisor.T_Name }} ({{ supervisor.T_Nickname }}) + +
+
+
+ + + + + 招新信息 + + + +
+ Recruitment +
+
+
+ +
+
+ 扫描下方二维码加入微信群 +
+
+ WeChat QR Code +
+
+ 二维码有效期至: {{ new Date(groupInfo.wechatGroupExpiration).toLocaleDateString() }} +
+ +
+ +
+
+ + 微信群二维码链接 + + + + + 请粘贴微信群二维码链接 + + + + + 有效期 + + + + + +
+ + +
+
+
+ +
+

该社团暂未开放招新

- - - -
- 社团类型: {{ group.C_Category }} -
-
- 社团人数: {{ groupMemberCounts }} 人 -
-
- 指导老师: - - {{ supervisor.T_Name }} ({{ supervisor.T_Nickname }}) - -
-
-
+ + +
diff --git a/server/api/cas/info/get.get.ts b/server/api/cas/info/get.get.ts index a53e9821..8bfd0256 100644 --- a/server/api/cas/info/get.get.ts +++ b/server/api/cas/info/get.get.ts @@ -4,7 +4,7 @@ import * as z from 'zod' const prisma = new PrismaClient() const requestSchema = z.object({ - club: z.number(), + club: z.coerce.number(), }) export default eventHandler(async (event) => { @@ -15,16 +15,17 @@ export default eventHandler(async (event) => { return } - // get clubId from request body - const requestBody = await readValidatedBody(event, body => requestSchema.parse(body)) + const query = await getValidatedQuery(event, query => requestSchema.parse(query)) - return await prisma.groupInfo.findUnique({ + const groupInfo = await prisma.groupInfo.findUnique({ where: { - clubId: Number(requestBody.club), + clubId: query.club, }, - // only use include if the value required is not a scalar - // include: { - // wechatGroupUrl: true, - // }, }) + + if (groupInfo && groupInfo.wechatGroupExpiration < new Date()) { + return null + } + + return groupInfo }) diff --git a/server/api/cas/info/new.post.ts b/server/api/cas/info/new.post.ts index 24a2b141..b54e4450 100644 --- a/server/api/cas/info/new.post.ts +++ b/server/api/cas/info/new.post.ts @@ -5,8 +5,13 @@ const prisma = new PrismaClient() const requestSchema = z.object({ clubId: z.number(), - wechatGroupUrl: z.string().startsWith('https://weixin.qq.com/g/', { message: 'WeChat Group URL required' }), - wechatGroupExpiration: z.string().datetime(), + wechatGroupUrl: z.string().startsWith('https://weixin.qq.com/g/', { + message: 'WeChat Group URL required' + }), + wechatGroupExpiration: z.string().datetime().refine( + (date) => new Date(date) > new Date(), + { message: "Expiration date must be in the future" } + ), }) export default eventHandler(async (event) => {