date type input 달력, 데이트피커 추가
This commit is contained in:
parent
9249610442
commit
7050709c31
@ -40,6 +40,7 @@
|
||||
class="flatpickr-calendar-only"
|
||||
>
|
||||
</full-calendar>
|
||||
<input ref="calendarDatepicker" type="text" class="d-none" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -79,7 +80,7 @@ import FullCalendar from '@fullcalendar/vue3';
|
||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||
import interactionPlugin from '@fullcalendar/interaction';
|
||||
import CenterModal from '@c/modal/CenterModal.vue';
|
||||
import { computed, inject, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { computed, inject, nextTick, onMounted, reactive, ref, watch } from 'vue';
|
||||
import $api from '@api';
|
||||
import 'flatpickr/dist/flatpickr.min.css';
|
||||
import '@/assets/css/app-calendar.css';
|
||||
@ -89,6 +90,9 @@ import { useProjectStore } from '@/stores/useProjectStore';
|
||||
import CommuterBtn from '@c/commuters/CommuterBtn.vue';
|
||||
import CommuterProjectList from '@c/commuters/CommuterProjectList.vue';
|
||||
import BackBtn from '@c/button/BackBtn.vue';
|
||||
import flatpickr from 'flatpickr';
|
||||
import monthSelectPlugin from 'flatpickr/dist/plugins/monthSelect/index';
|
||||
import 'flatpickr/dist/plugins/monthSelect/style.css';
|
||||
|
||||
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
||||
const user = ref({});
|
||||
@ -110,6 +114,8 @@ const isModalOpen = ref(false);
|
||||
const commuters = ref([]);
|
||||
const monthlyCommuters = ref([]);
|
||||
|
||||
const calendarDatepicker = ref(null);
|
||||
let fpInstance = null;
|
||||
|
||||
// 출퇴근 컴포넌트 이벤트 핸들러
|
||||
const handleWorkTimeUpdate = () => {
|
||||
@ -400,5 +406,66 @@ onMounted(async () => {
|
||||
selectedProject.value = storedProject.PROJCTSEQ;
|
||||
checkedInProject.value = storedProject;
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
// 달력 데이트피커를 위한 input 요소 동적 생성
|
||||
const datePickerInput = document.createElement('input');
|
||||
datePickerInput.type = 'text';
|
||||
datePickerInput.style.display = 'none';
|
||||
document.body.appendChild(datePickerInput);
|
||||
calendarDatepicker.value = datePickerInput;
|
||||
|
||||
// Flatpickr 초기화 (달 선택)
|
||||
fpInstance = flatpickr(calendarDatepicker.value, {
|
||||
dateFormat: "Y-m",
|
||||
plugins: [
|
||||
new monthSelectPlugin({
|
||||
shorthand: true,
|
||||
dateFormat: "Y-m",
|
||||
altFormat: "F Y"
|
||||
})
|
||||
],
|
||||
onOpen: function() {
|
||||
document.querySelector('.flatpickr-input').style.visibility = 'hidden';
|
||||
},
|
||||
onChange: function(selectedDatesArr, dateStr) {
|
||||
// 선택한 달의 첫날로 달력을 이동
|
||||
fullCalendarRef.value.getApi().gotoDate(dateStr + "-01");
|
||||
const [year, month] = dateStr.split("-");
|
||||
lastRemainingYear.value = parseInt(year, 10);
|
||||
lastRemainingMonth.value = month;
|
||||
loadCalendarData(lastRemainingYear.value, lastRemainingMonth.value);
|
||||
},
|
||||
onClose: function() {
|
||||
calendarDatepicker.value.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
// FullCalendar 년월월(.fc-toolbar-title) 클릭 시 데이트피커 열기
|
||||
const titleEl = document.querySelector('.fc-toolbar-title');
|
||||
if (titleEl) {
|
||||
titleEl.style.cursor = 'pointer';
|
||||
titleEl.addEventListener('click', () => {
|
||||
const rect = titleEl.getBoundingClientRect();
|
||||
const dpEl = calendarDatepicker.value;
|
||||
|
||||
dpEl.style.display = 'block';
|
||||
dpEl.style.position = 'fixed';
|
||||
dpEl.style.top = `${rect.bottom + window.scrollY}px`;
|
||||
dpEl.style.left = `${rect.left + window.scrollX}px`;
|
||||
dpEl.style.transform = 'translate(-50%, -50%)';
|
||||
dpEl.style.zIndex = '9999';
|
||||
dpEl.style.border = 'none';
|
||||
dpEl.style.outline = 'none';
|
||||
dpEl.style.backgroundColor = 'transparent';
|
||||
// 제목의 중앙 아래에 위치하도록 계산
|
||||
// 또는 CSS transform 사용
|
||||
// dpEl.style.setProperty('--left-position', `${rect.left + window.scrollX}px`);
|
||||
// dpEl.style.transform = 'translateX(-50%)';
|
||||
fpInstance.open();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
:maxLength="maxlength"
|
||||
:placeholder="title"
|
||||
@blur="$emit('blur')"
|
||||
@click="handleDateClick"
|
||||
ref="inputElement"
|
||||
/>
|
||||
</div>
|
||||
<div class="invalid-feedback" :class="isAlert ? 'd-block' : ''">{{ title }}를 확인해주세요.</div>
|
||||
@ -39,7 +41,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, computed } from 'vue';
|
||||
import { inject, computed, ref } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
@ -95,6 +97,7 @@
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:data', 'update:alert', 'blur']);
|
||||
const inputElement = ref(null);
|
||||
|
||||
// dayjs 인스턴스 가져오기
|
||||
const dayjs = inject('dayjs');
|
||||
@ -123,4 +126,12 @@
|
||||
emits('update:alert', false);
|
||||
}
|
||||
};
|
||||
|
||||
// date 타입일 때 input 클릭 시 달력 열기
|
||||
const handleDateClick = (event) => {
|
||||
if (props.type === 'date' && inputElement.value) {
|
||||
// 프로그래매틱하게 달력 열기: 날짜 선택기 UI를 표시
|
||||
inputElement.value.showPicker();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -129,27 +129,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 시작일 -->
|
||||
<FormInput
|
||||
title="시작일"
|
||||
type="date"
|
||||
name="startDay"
|
||||
:is-essential="true"
|
||||
:is-alert="startDayAlert"
|
||||
:modelValue="selectedProject.PROJCTSTR"
|
||||
@update:modelValue="selectedProject.PROJCTSTR = $event"
|
||||
/>
|
||||
|
||||
<!-- 종료일 -->
|
||||
<FormInput
|
||||
title="종료일"
|
||||
type="date"
|
||||
name="endDay"
|
||||
:min="selectedProject.PROJCTSTR"
|
||||
:modelValue="selectedProject.PROJCTEND"
|
||||
@update:modelValue="selectedProject.PROJCTEND = $event"
|
||||
/>
|
||||
|
||||
<!-- 시작일 -->
|
||||
<div @click="openStartDatePicker">
|
||||
<FormInput
|
||||
title="시작일"
|
||||
type="date"
|
||||
name="startDay"
|
||||
:is-essential="true"
|
||||
:is-alert="startDayAlert"
|
||||
:modelValue="selectedProject.PROJCTSTR"
|
||||
@update:modelValue="selectedProject.PROJCTSTR = $event"
|
||||
ref="startDateInput"
|
||||
/>
|
||||
</div>
|
||||
<!-- 종료일 -->
|
||||
<div @click="openEndDatePicker">
|
||||
<FormInput
|
||||
title="종료일"
|
||||
type="date"
|
||||
name="endDay"
|
||||
:min="selectedProject.PROJCTSTR"
|
||||
:modelValue="selectedProject.PROJCTEND"
|
||||
@update:modelValue="selectedProject.PROJCTEND = $event"
|
||||
ref="endDateInput"
|
||||
/>
|
||||
</div>
|
||||
<FormInput
|
||||
title="설명"
|
||||
name="description"
|
||||
@ -288,6 +292,27 @@ const selectedUsers = ref({
|
||||
});
|
||||
|
||||
|
||||
const startDateInput = ref(null);
|
||||
const endDateInput = ref(null);
|
||||
|
||||
// DOM 요소에 직접 접근하기 위한 변수들
|
||||
let startInputElement = null;
|
||||
let endInputElement = null;
|
||||
|
||||
|
||||
const openStartDatePicker = () => {
|
||||
if (startInputElement) {
|
||||
startInputElement.showPicker();
|
||||
}
|
||||
};
|
||||
|
||||
const openEndDatePicker = () => {
|
||||
if (endInputElement) {
|
||||
endInputElement.showPicker();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 사용자 목록 업데이트 핸들러
|
||||
const handleEditUserListUpdate = (userLists) => {
|
||||
selectedUsers.value = userLists;
|
||||
@ -581,8 +606,18 @@ onMounted(async () => {
|
||||
user.value = userStore.user;
|
||||
|
||||
convertAddressToCoordinates();
|
||||
|
||||
if (startDateInput.value) {
|
||||
// FormInput 내부 input 찾기
|
||||
startInputElement = startDateInput.value.$el.querySelector('input[type="date"]');
|
||||
}
|
||||
|
||||
if (endDateInput.value) {
|
||||
endInputElement = endDateInput.value.$el.querySelector('input[type="date"]');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@ -71,25 +71,29 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FormInput
|
||||
title="시작 일"
|
||||
name="startDay"
|
||||
:type="'date'"
|
||||
:is-alert="startDayAlert"
|
||||
:is-essential="true"
|
||||
:modelValue="startDay"
|
||||
v-model="startDay"
|
||||
/>
|
||||
|
||||
<FormInput
|
||||
title="종료 일"
|
||||
name="endDay"
|
||||
:type="'date'"
|
||||
:modelValue="endDay"
|
||||
:min="startDay"
|
||||
@update:modelValue="endDay = $event"
|
||||
/>
|
||||
|
||||
<div @click="openStartDatePicker">
|
||||
<FormInput
|
||||
title="시작 일"
|
||||
name="startDay"
|
||||
:type="'date'"
|
||||
:is-alert="startDayAlert"
|
||||
:is-essential="true"
|
||||
:modelValue="startDay"
|
||||
v-model="startDay"
|
||||
ref="startDateInput"
|
||||
/>
|
||||
</div>
|
||||
<div @click="openEndDatePicker">
|
||||
<FormInput
|
||||
title="종료 일"
|
||||
name="endDay"
|
||||
:type="'date'"
|
||||
:modelValue="endDay"
|
||||
:min="startDay"
|
||||
@update:modelValue="endDay = $event"
|
||||
ref="endDateInput"
|
||||
/>
|
||||
</div>
|
||||
<FormInput
|
||||
title="설명"
|
||||
name="description"
|
||||
@ -165,6 +169,26 @@
|
||||
const addressAlert = ref(false);
|
||||
const startDayAlert = ref(false);
|
||||
|
||||
const startDateInput = ref(null);
|
||||
const endDateInput = ref(null);
|
||||
|
||||
// DOM 요소에 직접 접근하기 위한 변수들
|
||||
let startInputElement = null;
|
||||
let endInputElement = null;
|
||||
|
||||
|
||||
const openStartDatePicker = () => {
|
||||
if (startInputElement) {
|
||||
startInputElement.showPicker();
|
||||
}
|
||||
};
|
||||
|
||||
const openEndDatePicker = () => {
|
||||
if (endInputElement) {
|
||||
endInputElement.showPicker();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const addressData = ref({
|
||||
postcode: '',
|
||||
@ -333,6 +357,13 @@
|
||||
await userStore.userInfo();
|
||||
user.value = userStore.user;
|
||||
|
||||
if (startDateInput.value) {
|
||||
// FormInput 내부 input 찾기
|
||||
startInputElement = startDateInput.value.$el.querySelector('input[type="date"]');
|
||||
}
|
||||
|
||||
});
|
||||
if (endDateInput.value) {
|
||||
endInputElement = endDateInput.value.$el.querySelector('input[type="date"]');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user