This commit is contained in:
2025-05-09 00:54:10 +09:00
parent 744a0db3bd
commit 486ae6de6b
15 changed files with 295 additions and 248 deletions
@@ -7,70 +7,81 @@
:modal="true"
class="event-details-dialog"
>
<TabView>
<Tabs value="기본정보">
<TabList>
<Tab value="기본정보"><i class="pi pi-info-circle mr-2" />기본정보</Tab>
<Tab value="참가자 관리"><i class="pi pi-users mr-2" />참가자 관리</Tab>
<Tab value="점수 관리"><i class="pi pi-chart-bar mr-2" />점수 관리</Tab>
<Tab value="팀 편성"><i class="pi pi-sitemap mr-2" /> 편성</Tab>
</TabList>
<TabPanels>
<!-- 기본 정보 -->
<TabPanel header="기본 정보">
<div class="event-details">
<div class="event-details-header">
<Badge :value="getEventTypeName(eventModel.eventType)" :severity="getStatusSeverity(eventModel.status)" />
<Badge :value="getStatusName(eventModel.status)" :severity="getStatusSeverity(eventModel.status)" />
</div>
<div class="event-details-content">
<div class="event-details-section">
<h4>이벤트 정보</h4>
<TabPanel value="기본정보">
<div class="event-details p-3">
<div class="flex align-items-center gap-2 mb-3">
<Badge :value="getEventTypeName(eventModel.eventType)" :severity="getStatusSeverity(eventModel.status)" />
<Badge :value="getStatusName(eventModel.status)" :severity="getStatusSeverity(eventModel.status)" />
</div>
<div class="card surface-100 p-3 mb-3">
<div class="grid">
<div class="col-12 md:col-6">
<p><strong>시작일:</strong> {{ formattedStartDate }}</p>
<p><strong>종료일:</strong> {{ formattedEndDate }}</p>
<p><strong>장소:</strong> {{ eventModel.location }}</p>
<p v-if="eventModel.publicHash">
<strong>공개 URL:</strong>
<InputText :value="publicEventUrl" readonly style="width:70%" class="mr-2" />
<Button icon="pi pi-copy" @click="copyPublicUrl" class="p-button-sm" v-tooltip.bottom="'복사'" />
</p>
<p v-if="eventModel.accessPassword">
<strong>공개 비밀번호:</strong> {{ eventModel.accessPassword }}
</p>
<div class="col-12 md:col-6 mb-2">
<span class="font-bold text-color-secondary">시작일:</span>
<span class="ml-2">{{ formattedStartDate }}</span>
</div>
<div class="col-12 md:col-6">
<p><strong>최대 참가자 :</strong> {{ eventModel.maxParticipants || '제한 없음' }}</p>
<p><strong>현재 참가자 :</strong> {{ eventModel.participants?.length || 0 }}</p>
<div class="col-12 md:col-6 mb-2">
<span class="font-bold text-color-secondary">종료일:</span>
<span class="ml-2">{{ formattedEndDate }}</span>
</div>
<div class="col-12 md:col-6 mb-2">
<span class="font-bold text-color-secondary">장소:</span>
<span class="ml-2">{{ eventModel.location }}</span>
</div>
<div class="col-12 md:col-6 mb-2">
<span class="font-bold text-color-secondary">참가자 :</span>
<span class="ml-2">{{ eventModel.currentParticipants }} / {{ eventModel.maxParticipants }}</span>
</div>
<div class="col-12 md:col-6 mb-2 flex align-items-center">
<span class="font-bold text-color-secondary">공개 URL:</span>
<InputText :value="publicEventUrl" class="ml-2 w-full" readonly />
<Button icon="pi pi-copy" class="ml-2" @click="copyPublicUrl" />
</div>
<div class="col-12 md:col-6 mb-2">
<span class="font-bold text-color-secondary">공개 비밀번호:</span>
<span class="ml-2">{{ eventModel.publicPassword }}</span>
</div>
</div>
</div>
<div class="event-details-section">
<h4>설명</h4>
<p>{{ eventModel.description || '설명이 없습니다.' }}</p>
<div class="card surface-100 p-3">
<span class="font-bold text-color-secondary">설명</span>
<div class="mt-2">{{ eventModel.description }}</div>
</div>
</div>
</div>
</TabPanel>
</TabPanel>
<!-- 참가자 관리 -->
<TabPanel header="참가자 관리">
<ParticipantManagement
:eventId="eventModel.id"
:availableMembers="availableMembers"
@participant-updated="handleParticipantUpdated"
/>
</TabPanel>
<!-- 참가자 관리 -->
<TabPanel value="참가자 관리">
<ParticipantManagement
:eventId="eventModel.id"
:availableMembers="availableMembers"
@participant-updated="handleParticipantUpdated"
/>
</TabPanel>
<!-- 점수 관리 -->
<TabPanel header="점수 관리">
<ScoreManagement
:eventId="eventModel.id"
:participants="eventModel.participants || []"
:maxGames="eventModel.gameCount"
@score-updated="$emit('score-updated')"
/>
</TabPanel>
<!-- 편성 -->
<TabPanel header="팀 편성">
<TeamGeneration :participants="confirmedParticipants" :teams="teams" @update:teams="teams = $event" @teams-generated="teams = $event" @save-teams="handleSaveTeams" />
</TabPanel>
</TabView>
<!-- 점수 관리 -->
<TabPanel value="점수 관리">
<ScoreManagement
:eventId="eventModel.id"
:participants="eventModel.participants || []"
:maxGames="eventModel.gameCount"
@score-updated="$emit('score-updated')"
/>
</TabPanel>
<!-- 편성 -->
<TabPanel value="팀 편성">
<TeamGeneration :participants="confirmedParticipants" :teams="teams" @save-teams="handleSaveTeams" />
</TabPanel>
</TabPanels>
</Tabs>
<template #footer>
<div class="dialog-footer">
@@ -84,15 +95,8 @@
import { ref, computed, watch } from 'vue';
import TeamGeneration from './TeamGeneration.vue';
import Dialog from 'primevue/dialog';
import TabView from 'primevue/tabview';
import TabPanel from 'primevue/tabpanel';
import Badge from 'primevue/badge';
import Button from 'primevue/button';
import InputNumber from 'primevue/inputnumber';
import InputText from 'primevue/inputtext';
import ParticipantManagement from './ParticipantManagement.vue';
import ScoreManagement from './ScoreManagement.vue';
import dayjs from 'dayjs';
const props = defineProps({
visible: { type: Boolean, required: true },
@@ -144,11 +148,13 @@ watch(() => eventModel.value.id, async (eventId) => {
}, { immediate: true });
// 참가확정 참가자 목록을 계산하는 computed 속성
const confirmedParticipants = computed(() => {
const confirmedParticipants = ref([]);
function updateConfirmedParticipants() {
const arr = eventModel.value.EventParticipants?.filter(p => p.status === '참가확정' || p.status === '참가예정') || [];
console.log('[상위] 참가확정:', arr);
return arr;
});
confirmedParticipants.value = arr;
}
// 최초 및 eventModel 변경 시 동기화
watch(() => eventModel.value.EventParticipants, updateConfirmedParticipants, { immediate: true, deep: true });
// 참가확정 인원 수
const confirmedCount = computed(() => confirmedParticipants.value.length);
@@ -176,11 +182,12 @@ async function handleSaveTeams(savedTeams) {
function handleParticipantUpdated(data) {
// 부모 컴포넌트에 이벤트 전달
emit('participant-updated', data);
// 전체 참가자 목록이 있는 경우 직접 업데이트
if (data.allParticipants) {
// EventParticipants 속성을 완전히 대체
eventModel.value.EventParticipants = [...data.allParticipants];
// 참가확정 참가자도 즉시 반영
updateConfirmedParticipants();
}
};
@@ -55,7 +55,7 @@
<Dialog v-model:visible="participantDialog" :header="dialogTitle" modal class="p-fluid" :style="{width: '450px'}">
<div class="field">
<label for="member">회원</label>
<Dropdown
<Select
id="member"
v-model="editingParticipant.memberId"
:options="props.availableMembers"
@@ -69,7 +69,7 @@
</div>
<div class="field">
<label for="status">참가 상태</label>
<Dropdown
<Select
id="status"
v-model="editingParticipant.status"
:options="participantStatusOptions"
@@ -82,7 +82,7 @@
</div>
<div class="field">
<label for="paymentStatus">결제 상태</label>
<Dropdown
<Select
id="paymentStatus"
v-model="editingParticipant.paymentStatus"
:options="paymentStatusOptions"
@@ -118,13 +118,6 @@ import { ref, computed, onMounted } from 'vue';
import { useToast } from 'primevue/usetoast';
import eventService from '@/services/eventService';
import dayjs from 'dayjs';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import Dialog from 'primevue/dialog';
import Button from 'primevue/button';
import Dropdown from 'primevue/dropdown';
import Badge from 'primevue/badge';
import Toast from 'primevue/toast';
const props = defineProps({
eventId: {
@@ -47,7 +47,7 @@
<Dialog v-model:visible="scoreDialog" :header="scoreDialogTitle" modal class="p-fluid" :style="{width: '600px'}">
<div class="field">
<label for="participant">참가자</label>
<Dropdown
<Select
id="participant"
v-model="editingScore.participantId"
:options="participants"
@@ -122,7 +122,6 @@
import { ref, onMounted, computed } from 'vue';
import { useToast } from 'primevue/usetoast';
import eventService from '@/services/eventService';
import dayjs from 'dayjs';
const props = defineProps({
eventId: {
@@ -50,7 +50,7 @@
</draggable>
</ul>
<div class="flex align-items-center gap-2 mt-2">
<Dropdown
<Select
v-model="team._selectedMember"
:options="availableMembersForTeam(idx)"
optionLabel="name"
@@ -71,7 +71,7 @@
</span>
</span>
</template>
</Dropdown>
</Select>
<Button icon="pi pi-plus" class="p-button-text p-0" :disabled="!team._selectedMember" @click="addMemberToTeam(idx)" />
</div>
</div>
@@ -89,11 +89,7 @@
<script setup>
import draggable from 'vuedraggable'; // npm install vuedraggable@next 필요 (vue3)
import { ref, computed, watch, unref } from 'vue';
import InputNumber from 'primevue/inputnumber';
import Button from 'primevue/button';
import Dropdown from 'primevue/dropdown';
// 참가자 에버리지 구하기
function getMemberAverage(member) {