feat: add GameGroup2 project with frontend and backend
- Add .gitignore for Node.js and PocketBase projects - Add frontend (Vue 3 + Vite + TypeScript) - Add backend (PocketBase) - Add deployment scripts and Docker compose configs Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
<!-- src/components/team/InvitationCard.vue -->
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import type { Invitation } from '@/types'
|
||||
import { respondInvitation } from '@/api/invitations'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
interface Props {
|
||||
invitation: Invitation
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<{
|
||||
responded: [id: string, accepted: boolean]
|
||||
}>()
|
||||
|
||||
const rejectReason = ref('')
|
||||
const showRejectInput = ref(false)
|
||||
|
||||
async function acceptInvitation() {
|
||||
try {
|
||||
await respondInvitation(props.invitation.id, 'accepted')
|
||||
ElMessage.success('已接受邀请')
|
||||
emit('responded', props.invitation.id, true)
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.message || '接受邀请失败')
|
||||
}
|
||||
}
|
||||
|
||||
async function rejectInvitation() {
|
||||
if (!showRejectInput.value) {
|
||||
showRejectInput.value = true
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await respondInvitation(props.invitation.id, 'rejected', rejectReason.value)
|
||||
ElMessage.success('已拒绝邀请')
|
||||
emit('responded', props.invitation.id, false)
|
||||
showRejectInput.value = false
|
||||
rejectReason.value = ''
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.message || '拒绝邀请失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="invitation-card">
|
||||
<div class="invitation-header">
|
||||
<img
|
||||
:src="invitation.expand?.from?.avatar || '/default-avatar.png'"
|
||||
:alt="invitation.expand?.from?.username"
|
||||
class="avatar"
|
||||
/>
|
||||
<div class="invitation-info">
|
||||
<span class="inviter-name">{{ invitation.expand?.from?.username }}</span>
|
||||
<span class="invitation-text">邀请你加入</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="invitation.expand?.teamSession" class="session-info">
|
||||
<span class="game-name">{{ invitation.expand.teamSession.gameName }}</span>
|
||||
<span class="session-name">{{ invitation.expand.teamSession.name }}</span>
|
||||
</div>
|
||||
|
||||
<div class="invitation-actions">
|
||||
<button class="action-btn accept" @click="acceptInvitation">
|
||||
接受
|
||||
</button>
|
||||
<button class="action-btn reject" @click="rejectInvitation">
|
||||
{{ showRejectInput ? '确认拒绝' : '拒绝' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="showRejectInput" class="reject-input">
|
||||
<textarea
|
||||
v-model="rejectReason"
|
||||
placeholder="填写拒绝原因(可选)"
|
||||
rows="2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.invitation-card {
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
.invitation-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.invitation-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.inviter-name {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.invitation-text {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.session-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 12px;
|
||||
background: var(--el-bg-color-page);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.game-name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.session-name {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.invitation-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.accept {
|
||||
background: var(--el-color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.accept:hover {
|
||||
background: var(--el-color-primary-light-3);
|
||||
}
|
||||
|
||||
.reject {
|
||||
background: var(--el-fill-color);
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.reject:hover {
|
||||
background: var(--el-fill-color-dark);
|
||||
}
|
||||
|
||||
.reject-input {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.reject-input textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.reject-input textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user