date type input 달력, 데이트피커 추가
This commit is contained in:
parent
9249610442
commit
7050709c31
@ -40,6 +40,7 @@
|
|||||||
class="flatpickr-calendar-only"
|
class="flatpickr-calendar-only"
|
||||||
>
|
>
|
||||||
</full-calendar>
|
</full-calendar>
|
||||||
|
<input ref="calendarDatepicker" type="text" class="d-none" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -79,7 +80,7 @@ import FullCalendar from '@fullcalendar/vue3';
|
|||||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
import interactionPlugin from '@fullcalendar/interaction';
|
import interactionPlugin from '@fullcalendar/interaction';
|
||||||
import CenterModal from '@c/modal/CenterModal.vue';
|
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 $api from '@api';
|
||||||
import 'flatpickr/dist/flatpickr.min.css';
|
import 'flatpickr/dist/flatpickr.min.css';
|
||||||
import '@/assets/css/app-calendar.css';
|
import '@/assets/css/app-calendar.css';
|
||||||
@ -89,6 +90,9 @@ import { useProjectStore } from '@/stores/useProjectStore';
|
|||||||
import CommuterBtn from '@c/commuters/CommuterBtn.vue';
|
import CommuterBtn from '@c/commuters/CommuterBtn.vue';
|
||||||
import CommuterProjectList from '@c/commuters/CommuterProjectList.vue';
|
import CommuterProjectList from '@c/commuters/CommuterProjectList.vue';
|
||||||
import BackBtn from '@c/button/BackBtn.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 baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
||||||
const user = ref({});
|
const user = ref({});
|
||||||
@ -110,6 +114,8 @@ const isModalOpen = ref(false);
|
|||||||
const commuters = ref([]);
|
const commuters = ref([]);
|
||||||
const monthlyCommuters = ref([]);
|
const monthlyCommuters = ref([]);
|
||||||
|
|
||||||
|
const calendarDatepicker = ref(null);
|
||||||
|
let fpInstance = null;
|
||||||
|
|
||||||
// 출퇴근 컴포넌트 이벤트 핸들러
|
// 출퇴근 컴포넌트 이벤트 핸들러
|
||||||
const handleWorkTimeUpdate = () => {
|
const handleWorkTimeUpdate = () => {
|
||||||
@ -400,5 +406,66 @@ onMounted(async () => {
|
|||||||
selectedProject.value = storedProject.PROJCTSEQ;
|
selectedProject.value = storedProject.PROJCTSEQ;
|
||||||
checkedInProject.value = storedProject;
|
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>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,8 @@
|
|||||||
:maxLength="maxlength"
|
:maxLength="maxlength"
|
||||||
:placeholder="title"
|
:placeholder="title"
|
||||||
@blur="$emit('blur')"
|
@blur="$emit('blur')"
|
||||||
|
@click="handleDateClick"
|
||||||
|
ref="inputElement"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback" :class="isAlert ? 'd-block' : ''">{{ title }}를 확인해주세요.</div>
|
<div class="invalid-feedback" :class="isAlert ? 'd-block' : ''">{{ title }}를 확인해주세요.</div>
|
||||||
@ -39,7 +41,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { inject, computed } from 'vue';
|
import { inject, computed, ref } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
@ -95,6 +97,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['update:data', 'update:alert', 'blur']);
|
const emits = defineEmits(['update:data', 'update:alert', 'blur']);
|
||||||
|
const inputElement = ref(null);
|
||||||
|
|
||||||
// dayjs 인스턴스 가져오기
|
// dayjs 인스턴스 가져오기
|
||||||
const dayjs = inject('dayjs');
|
const dayjs = inject('dayjs');
|
||||||
@ -123,4 +126,12 @@
|
|||||||
emits('update:alert', false);
|
emits('update:alert', false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// date 타입일 때 input 클릭 시 달력 열기
|
||||||
|
const handleDateClick = (event) => {
|
||||||
|
if (props.type === 'date' && inputElement.value) {
|
||||||
|
// 프로그래매틱하게 달력 열기: 날짜 선택기 UI를 표시
|
||||||
|
inputElement.value.showPicker();
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -129,27 +129,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 시작일 -->
|
<!-- 시작일 -->
|
||||||
<FormInput
|
<div @click="openStartDatePicker">
|
||||||
title="시작일"
|
<FormInput
|
||||||
type="date"
|
title="시작일"
|
||||||
name="startDay"
|
type="date"
|
||||||
:is-essential="true"
|
name="startDay"
|
||||||
:is-alert="startDayAlert"
|
:is-essential="true"
|
||||||
:modelValue="selectedProject.PROJCTSTR"
|
:is-alert="startDayAlert"
|
||||||
@update:modelValue="selectedProject.PROJCTSTR = $event"
|
:modelValue="selectedProject.PROJCTSTR"
|
||||||
/>
|
@update:modelValue="selectedProject.PROJCTSTR = $event"
|
||||||
|
ref="startDateInput"
|
||||||
<!-- 종료일 -->
|
/>
|
||||||
<FormInput
|
</div>
|
||||||
title="종료일"
|
<!-- 종료일 -->
|
||||||
type="date"
|
<div @click="openEndDatePicker">
|
||||||
name="endDay"
|
<FormInput
|
||||||
:min="selectedProject.PROJCTSTR"
|
title="종료일"
|
||||||
:modelValue="selectedProject.PROJCTEND"
|
type="date"
|
||||||
@update:modelValue="selectedProject.PROJCTEND = $event"
|
name="endDay"
|
||||||
/>
|
:min="selectedProject.PROJCTSTR"
|
||||||
|
:modelValue="selectedProject.PROJCTEND"
|
||||||
|
@update:modelValue="selectedProject.PROJCTEND = $event"
|
||||||
|
ref="endDateInput"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<FormInput
|
<FormInput
|
||||||
title="설명"
|
title="설명"
|
||||||
name="description"
|
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) => {
|
const handleEditUserListUpdate = (userLists) => {
|
||||||
selectedUsers.value = userLists;
|
selectedUsers.value = userLists;
|
||||||
@ -581,8 +606,18 @@ onMounted(async () => {
|
|||||||
user.value = userStore.user;
|
user.value = userStore.user;
|
||||||
|
|
||||||
convertAddressToCoordinates();
|
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>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -71,25 +71,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormInput
|
<div @click="openStartDatePicker">
|
||||||
title="시작 일"
|
<FormInput
|
||||||
name="startDay"
|
title="시작 일"
|
||||||
:type="'date'"
|
name="startDay"
|
||||||
:is-alert="startDayAlert"
|
:type="'date'"
|
||||||
:is-essential="true"
|
:is-alert="startDayAlert"
|
||||||
:modelValue="startDay"
|
:is-essential="true"
|
||||||
v-model="startDay"
|
:modelValue="startDay"
|
||||||
/>
|
v-model="startDay"
|
||||||
|
ref="startDateInput"
|
||||||
<FormInput
|
/>
|
||||||
title="종료 일"
|
</div>
|
||||||
name="endDay"
|
<div @click="openEndDatePicker">
|
||||||
:type="'date'"
|
<FormInput
|
||||||
:modelValue="endDay"
|
title="종료 일"
|
||||||
:min="startDay"
|
name="endDay"
|
||||||
@update:modelValue="endDay = $event"
|
:type="'date'"
|
||||||
/>
|
:modelValue="endDay"
|
||||||
|
:min="startDay"
|
||||||
|
@update:modelValue="endDay = $event"
|
||||||
|
ref="endDateInput"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<FormInput
|
<FormInput
|
||||||
title="설명"
|
title="설명"
|
||||||
name="description"
|
name="description"
|
||||||
@ -165,6 +169,26 @@
|
|||||||
const addressAlert = ref(false);
|
const addressAlert = ref(false);
|
||||||
const startDayAlert = 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({
|
const addressData = ref({
|
||||||
postcode: '',
|
postcode: '',
|
||||||
@ -333,6 +357,13 @@
|
|||||||
await userStore.userInfo();
|
await userStore.userInfo();
|
||||||
user.value = userStore.user;
|
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>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user