205 lines
6.1 KiB
Vue
205 lines
6.1 KiB
Vue
<template>
|
||
<div class="event-modal position-fixed bg-white shadow rounded" :style="modalStyle">
|
||
<!-- 이벤트 선택 화면 -->
|
||
<div v-if="!selectedEventType" class="d-flex flex-wrap gap-2 p-2">
|
||
<div v-for="event in eventTypes" :key="event.code" class="event-icon-wrapper position-relative">
|
||
<img
|
||
:src="`${baseUrl}img/main-category-img/main-${event.code}.png`"
|
||
class="event-icon-select"
|
||
style="width: 25px; height: 25px; cursor: pointer"
|
||
@click="handleEventClick(event)"
|
||
/>
|
||
<!-- X 표시 수정 -->
|
||
<span v-if="isEventExists(event.type)" class="cancel-mark"> × </span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 입력 폼 화면 -->
|
||
<div v-else class="p-2" style="min-width: 200px">
|
||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||
<small>{{ getEventTitle(selectedEventType) }}</small>
|
||
<button class="btn-close btn-close-sm" style="font-size: 8px" @click="resetForm"></button>
|
||
</div>
|
||
<div class="mb-2">
|
||
<input
|
||
type="text"
|
||
class="form-control form-control-sm py-1"
|
||
style="height: 25px; font-size: 12px"
|
||
placeholder="장소"
|
||
v-model="eventPlace"
|
||
maxlength="20"
|
||
/>
|
||
</div>
|
||
<div class="mb-2">
|
||
<input type="time" class="form-control form-control-sm py-1" style="height: 25px; font-size: 12px" v-model="eventTime" />
|
||
</div>
|
||
<div class="text-end">
|
||
<button class="btn btn-primary btn-sm py-1" style="font-size: 12px; height: 25px; line-height: 1" @click="handleSubmit">
|
||
등록
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from 'vue';
|
||
|
||
const props = defineProps({
|
||
position: {
|
||
type: Object,
|
||
required: true,
|
||
default: () => ({ x: 0, y: 0 }),
|
||
},
|
||
selectedDate: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
baseUrl: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
dateEvents: {
|
||
type: Array,
|
||
},
|
||
});
|
||
|
||
const emit = defineEmits(['select', 'delete', 'insert']);
|
||
|
||
// 폼 관련 상태
|
||
const selectedEventType = ref(null);
|
||
const eventPlace = ref('');
|
||
const eventTime = ref('');
|
||
|
||
const eventTypes = [
|
||
{ type: 'birthdayParty', code: '300203', title: '생일파티' },
|
||
{ type: 'dinner', code: '300204', title: '회식' },
|
||
{ type: 'teaTime', code: '300205', title: '티타임' },
|
||
{ type: 'workshop', code: '300206', title: '워크샵' },
|
||
];
|
||
|
||
const getEventTitle = type => {
|
||
console.log('type: ', type);
|
||
console.log('event.type: ', eventTypes);
|
||
return eventTypes.find(event => event.code === type)?.title || '';
|
||
};
|
||
|
||
const isEventExists = type => {
|
||
return props.dateEvents?.some(event => event.type === type);
|
||
};
|
||
|
||
const handleEventClick = event => {
|
||
if (isEventExists(event.type)) {
|
||
if (confirm('이벤트를 취소하시겠습니까?')) {
|
||
emit('delete', {
|
||
date: props.selectedDate,
|
||
code: event.code,
|
||
title: event.title,
|
||
});
|
||
}
|
||
} else {
|
||
selectedEventType.value = event.code;
|
||
}
|
||
};
|
||
|
||
const handleSubmit = () => {
|
||
if (!eventPlace.value || !eventTime.value) {
|
||
alert('장소와 시간을 모두 입력해주세요');
|
||
return;
|
||
}
|
||
|
||
emit('insert', {
|
||
date: props.selectedDate,
|
||
code: selectedEventType.value,
|
||
title: getEventTitle(selectedEventType.value),
|
||
place: eventPlace.value,
|
||
time: eventTime.value,
|
||
});
|
||
};
|
||
|
||
const resetForm = () => {
|
||
selectedEventType.value = null;
|
||
eventPlace.value = '';
|
||
eventTime.value = '';
|
||
};
|
||
|
||
// 모달 스타일 계산을 computed로 변경
|
||
const modalStyle = computed(() => {
|
||
const modalWidth = 200; // 모달의 예상 너비
|
||
const modalHeight = 150; // 모달의 예상 높이
|
||
const viewportWidth = window.innerWidth;
|
||
const viewportHeight = window.innerHeight;
|
||
|
||
let x = props.position?.x || 0;
|
||
let y = props.position?.y || 0;
|
||
|
||
// 모달이 뷰포트를 벗어나지 않도록 조정
|
||
if (x + modalWidth > viewportWidth) {
|
||
x = viewportWidth - modalWidth - 10;
|
||
}
|
||
if (x < 0) {
|
||
x = 10;
|
||
}
|
||
if (y + modalHeight > viewportHeight) {
|
||
y = viewportHeight - modalHeight - 10;
|
||
}
|
||
if (y < 0) {
|
||
y = 10;
|
||
}
|
||
|
||
return {
|
||
left: `${x}px`,
|
||
top: `${y}px`,
|
||
zIndex: 1050,
|
||
maxWidth: '90vw', // 뷰포트 너비의 90%를 넘지 않도록
|
||
maxHeight: '90vh', // 뷰포트 높이의 90%를 넘지 않도록
|
||
};
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.event-icon-wrapper {
|
||
position: relative;
|
||
display: inline-block;
|
||
}
|
||
|
||
.event-icon-select {
|
||
transition: transform 0.2s;
|
||
}
|
||
|
||
.event-icon-select:hover {
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.cancel-mark {
|
||
position: absolute;
|
||
top: -8px;
|
||
right: -8px;
|
||
width: 16px;
|
||
height: 16px;
|
||
background-color: #dc3545;
|
||
color: white;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
line-height: 1;
|
||
}
|
||
|
||
.event-modal {
|
||
min-width: 120px;
|
||
max-width: 300px;
|
||
overflow: auto;
|
||
}
|
||
|
||
/* 작은 화면에서의 스타일 */
|
||
@media (max-width: 576px) {
|
||
.event-modal {
|
||
min-width: 100px;
|
||
font-size: 0.9em;
|
||
}
|
||
}
|
||
</style>
|