This commit is contained in:
2025-04-17 23:32:39 +09:00
commit 5b719b6766
105 changed files with 25653 additions and 0 deletions
@@ -0,0 +1,233 @@
<template>
<Dialog
:visible="visible"
@update:visible="$emit('update:visible', $event)"
:header="isNew ? '이벤트 추가' : '이벤트 수정'"
:style="{ width: '650px' }"
:modal="true"
class="p-fluid"
>
<div class="grid">
<div class="col-12">
<div class="field">
<label for="title">제목 *</label>
<InputText id="title" v-model="eventModel.title" :class="{'p-invalid': submitted && !eventModel.title}" required autofocus />
<small class="p-error" v-if="submitted && !eventModel.title">제목은 필수입니다.</small>
</div>
</div>
<div class="col-12">
<div class="field">
<label for="description">설명</label>
<Textarea id="description" v-model="eventModel.description" rows="3" autoResize />
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="eventType">이벤트 유형 *</label>
<Dropdown id="eventType" v-model="eventModel.eventType" :options="eventTypeOptions" optionLabel="name" optionValue="value" placeholder="유형 선택" :class="{'p-invalid': submitted && !eventModel.eventType}" />
<small class="p-error" v-if="submitted && !eventModel.eventType">이벤트 유형은 필수입니다.</small>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="status">상태 *</label>
<Dropdown id="status" v-model="eventModel.status" :options="statusOptions" optionLabel="name" optionValue="value" placeholder="상태 선택" :class="{'p-invalid': submitted && !eventModel.status}" />
<small class="p-error" v-if="submitted && !eventModel.status">상태는 필수입니다.</small>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="startDate">시작일 *</label>
<Calendar id="startDate" v-model="eventModel.startDate" :showTime="true" dateFormat="yy-mm-dd" timeFormat="24" hourFormat="24" :showIcon="true" :class="{'p-invalid': submitted && !eventModel.startDate}" />
<small class="p-error" v-if="submitted && !eventModel.startDate">시작일은 필수입니다.</small>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="endDate">종료일</label>
<Calendar id="endDate" v-model="eventModel.endDate" :showTime="true" dateFormat="yy-mm-dd" timeFormat="24" hourFormat="24" :showIcon="true" :class="{'p-invalid': submitted && !eventModel.endDate}" />
</div>
</div>
<div class="col-12">
<div class="field">
<label for="location">장소</label>
<InputText id="location" v-model="eventModel.location" :class="{'p-invalid': submitted && !eventModel.location}" />
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="maxParticipants">최대 참가자 </label>
<InputNumber id="maxParticipants" v-model="eventModel.maxParticipants" :min="0" showButtons />
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="gameCount">게임 </label>
<InputNumber id="gameCount" v-model="eventModel.gameCount" :min="1" showButtons />
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="participantFee">참가비</label>
<InputNumber id="participantFee" v-model="eventModel.entryFee" :min="0" mode="currency" currency="KRW" locale="ko-KR" />
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label for="registrationDeadline">등록 마감일</label>
<Calendar id="registrationDeadline" v-model="eventModel.registrationDeadline" :showTime="true" dateFormat="yy-mm-dd" timeFormat="24" hourFormat="24" :showIcon="true" />
</div>
</div>
</div>
<template #footer>
<Button label="취소" icon="pi pi-times" class="p-button-text" @click="hideDialog" />
<Button label="저장" icon="pi pi-check" class="p-button-text" @click="saveEvent" />
</template>
</Dialog>
</template>
<script setup>
import { ref, watch, toRefs, computed } from 'vue';
const statusOptions = [
{ name: '준비', value: '준비' },
{ name: '활성', value: '활성' },
{ name: '완료', value: '완료' },
{ name: '취소', value: '취소' },
{ name: '삭제', value: '삭제' }
];
const props = defineProps({
visible: {
type: Boolean,
required: true
},
event: {
type: Object,
required: true
},
isNew: {
type: Boolean,
required: true
},
submitted: {
type: Boolean,
required: true
}
});
const emit = defineEmits(['update:visible', 'save', 'hide']);
// 이벤트 타입 옵션
const eventTypeOptions = [
{ name: '정기전', value: '정기전' },
{ name: '번개', value: '번개' },
{ name: '연습', value: '연습' },
{ name: '교류전', value: '교류전' },
{ name: '이벤트', value: '이벤트' },
{ name: '기타', value: '기타' }
];
// 이벤트 모델
const eventModel = ref({ ...props.event });
// 날짜 형식 변환
const formatDate = (date) => {
if (!date) return null;
const d = new Date(date);
d.setHours(d.getHours() + 9); // UTC to KST
return d;
};
// props 변경 시 이벤트 모델 업데이트
watch(() => props.event, (newValue) => {
const formattedEvent = {
...newValue,
startDate: formatDate(newValue.startDate),
endDate: formatDate(newValue.endDate),
registrationDeadline: formatDate(newValue.registrationDeadline)
};
eventModel.value = formattedEvent;
}, { deep: true });
// 이벤트 저장 시 UTC로 변환
const saveEvent = () => {
const eventData = { ...eventModel.value };
if (eventData.startDate) {
const d = new Date(eventData.startDate);
d.setHours(d.getHours() - 9); // KST to UTC
eventData.startDate = d;
}
if (eventData.endDate) {
const d = new Date(eventData.endDate);
d.setHours(d.getHours() - 9); // KST to UTC
eventData.endDate = d;
}
if (eventData.registrationDeadline) {
const d = new Date(eventData.registrationDeadline);
d.setHours(d.getHours() - 9); // KST to UTC
eventData.registrationDeadline = d;
}
emit('save', eventData);
};
// 다이얼로그 닫기
const hideDialog = () => {
emit('hide');
};
</script>
<style scoped>
.field {
margin-bottom: 0.75rem;
}
.grid {
display: flex;
flex-wrap: wrap;
margin: -0.25rem;
}
.col-12 {
width: 100%;
padding: 0.25rem;
}
.md\:col-6 {
width: 50%;
padding: 0.25rem;
}
.dialog-footer {
padding: 0.5rem;
}
.p-dialog-content {
padding: 1rem;
}
.p-dialog-footer {
padding: 0.5rem;
}
:deep(.p-dropdown),
:deep(.p-calendar),
:deep(.p-inputnumber) {
width: 100%;
}
:deep(.p-inputtext) {
width: 100%;
}
</style>