diff --git a/frontend/src/api/groups.ts b/frontend/src/api/groups.ts index 87d2e05..cd9fa93 100644 --- a/frontend/src/api/groups.ts +++ b/frontend/src/api/groups.ts @@ -118,6 +118,20 @@ export async function getMyGroupsJoinRequests(): Promise { return result.items as unknown as JoinRequest[] } +// 获取当前用户的所有入群申请(包括所有状态) +export async function getMyJoinRequests(): Promise { + const user = pb.authStore.model + if (!user) return [] + + const result = await pb.collection('join_requests').getList(1, 50, { + filter: `user="${user.id}"`, + sort: '-created', + expand: 'group', + $autoCancel: false + }) + return result.items as unknown as JoinRequest[] +} + // 审批加入申请 export async function respondJoinRequest( requestId: string, diff --git a/frontend/src/components/group/GroupMembersPanel.vue b/frontend/src/components/group/GroupMembersPanel.vue index 68668b9..7bd1bac 100644 --- a/frontend/src/components/group/GroupMembersPanel.vue +++ b/frontend/src/components/group/GroupMembersPanel.vue @@ -377,6 +377,16 @@ async function handleRemoveAdmin(userId: string, username: string) { gap: 8px; } +.requests-section--highlight { + animation: highlight-pulse 2s ease; +} + +@keyframes highlight-pulse { + 0% { background: rgba(245, 158, 11, 0.06); } + 30% { background: rgba(245, 158, 11, 0.3); } + 100% { background: rgba(245, 158, 11, 0.06); } +} + .members-list { display: flex; flex-direction: column; diff --git a/frontend/src/views/GroupView.vue b/frontend/src/views/GroupView.vue index 152a3e5..2e3392a 100644 --- a/frontend/src/views/GroupView.vue +++ b/frontend/src/views/GroupView.vue @@ -7,6 +7,8 @@ import { useTeamStore } from '@/stores/team' import { pb } from '@/api/pocketbase' import { settlePoll } from '@/api/polls' import { closeBet } from '@/api/bets' +import { getGroupJoinRequests } from '@/api/groups' +import type { JoinRequest } from '@/types' import TeamSessionPanel from '@/components/team/TeamSessionPanel.vue' import IdleMembersList from '@/components/team/IdleMembersList.vue' import GroupMembersPanel from '@/components/group/GroupMembersPanel.vue' @@ -38,6 +40,10 @@ const groupId = route.params.id as string const group = computed(() => groupStore.currentGroup) const members = computed(() => groupStore.currentMembers) +const canManage = computed(() => groupStore.canManageGroup) + +const pendingJoinRequests = ref([]) +const showPendingRequests = computed(() => canManage.value && pendingJoinRequests.value.length > 0) const ownerName = computed(() => { const owner = members.value.find(m => m.id === group.value?.owner) @@ -79,6 +85,13 @@ const statusColors: Record = { onMounted(async () => { await groupStore.setCurrentGroup(groupId) + // 加载待审核入群申请(管理员可见) + if (canManage.value) { + try { + pendingJoinRequests.value = await getGroupJoinRequests(groupId) + } catch { /* ignore */ } + } + // 订阅用户状态变更 unsubFns.push(await pb.collection('users').subscribe('*', () => { groupStore.setCurrentGroup(groupId) @@ -171,6 +184,15 @@ async function checkExpiredBets() { console.error('检查过期竞猜失败:', e) } } + +function scrollToRequests() { + const el = document.querySelector('.requests-section') + if (el) { + el.scrollIntoView({ behavior: 'smooth', block: 'center' }) + el.classList.add('requests-section--highlight') + setTimeout(() => el.classList.remove('requests-section--highlight'), 2000) + } +}