출근
This commit is contained in:
parent
b08e72b813
commit
1384ae571d
@ -5,27 +5,41 @@
|
|||||||
<div class="col-3 border-end text-center">
|
<div class="col-3 border-end text-center">
|
||||||
<div class="card-body pb-0">
|
<div class="card-body pb-0">
|
||||||
<img v-if="user" :src="`${baseUrl}upload/img/profile/${user.profile}`" alt="Profile Image" class="w-px-50 h-auto rounded-circle" @error="$event.target.src = '/img/icons/icon.png'"/>
|
<img v-if="user" :src="`${baseUrl}upload/img/profile/${user.profile}`" alt="Profile Image" class="w-px-50 h-auto rounded-circle" @error="$event.target.src = '/img/icons/icon.png'"/>
|
||||||
<p class="mt-2">
|
<p class="mt-2 fw-bold">
|
||||||
{{ user.name }}
|
{{ user.name }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="row g-0">
|
<div class="row g-0">
|
||||||
<div class="col-6 pe-1">
|
<div class="col-6 pe-1">
|
||||||
<p>출근시간</p>
|
<p class="mb-1">출근시간</p>
|
||||||
<button class="btn btn-outline-primary border-3 w-100 py-0">
|
<button class="btn btn-outline-primary border-3 w-100 py-0 h-px-50" :class="workTime ? 'p-0' : ''" @click="setWorkTime">
|
||||||
<i class='bx bx-run fs-2'></i>
|
<i v-if="!workTime" class="bx bx-run fs-2"></i>
|
||||||
|
<span v-if="workTime" class="ql-size-12px ">{{ workTime }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-6 ps-1">
|
<div class="col-6 ps-1">
|
||||||
<p>퇴근시간</p>
|
<p class="mb-1">퇴근시간</p>
|
||||||
<button class="btn btn-outline-secondary border-3 w-100 py-0">
|
<button class="btn btn-outline-secondary border-3 w-100 py-0 h-px-50">
|
||||||
<i class='bx bxs-door-open fs-2'></i>
|
<i class='bx bxs-door-open fs-2'></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="post in project" :key="post.PROJCTSEQ" class="border border-2 mt-3" :style="`border-color: ${post.projctcolor} !important; color: ${post.projctcolor} !important;`">
|
<div v-for="post in project" :key="post.PROJCTSEQ"
|
||||||
|
class="border border-2 mt-3"
|
||||||
|
:style="`border-color: ${post.projctcolor} !important; color: ${post.projctcolor} !important;`"
|
||||||
|
@dragover="allowDrop($event)"
|
||||||
|
@drop="handleDrop($event, post)">
|
||||||
{{ post.PROJCTNAM }}
|
{{ post.PROJCTNAM }}
|
||||||
|
<div v-if="checkedInProject && checkedInProject.PROJCTSEQ === post.PROJCTSEQ && user && workTime" class="mt-2">
|
||||||
|
<img :src="`${baseUrl}upload/img/profile/${user.profile}`"
|
||||||
|
alt="User Profile"
|
||||||
|
class="rounded-circle"
|
||||||
|
width="50"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="dragStart($event, post)"
|
||||||
|
@error="$event.target.src = '/img/icons/icon.png'">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -50,26 +64,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<center-modal :display="isModalVisible" @close="isModalVisible = $event">
|
<center-modal :display="isModalVisible" @close="isModalVisible = $event">
|
||||||
<template #title> Add Event </template>
|
<template #title> 상세보기 </template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<FormInput
|
|
||||||
title="이벤트 제목"
|
|
||||||
name="event"
|
|
||||||
:is-essential="true"
|
|
||||||
:is-alert="eventAlert"
|
|
||||||
@update:data="eventTitle = $event"
|
|
||||||
/>
|
|
||||||
<FormInput
|
|
||||||
title="이벤트 날짜"
|
|
||||||
type="date"
|
|
||||||
name="eventDate"
|
|
||||||
:is-essential="true"
|
|
||||||
:is-alert="eventDateAlert"
|
|
||||||
@update:data="eventDate = $event"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<button @click="addEvent">추가</button>
|
<BackBtn @click="closeModal" />
|
||||||
</template>
|
</template>
|
||||||
</center-modal>
|
</center-modal>
|
||||||
</template>
|
</template>
|
||||||
@ -81,38 +81,123 @@ import interactionPlugin from '@fullcalendar/interaction';
|
|||||||
import CenterModal from '@c/modal/CenterModal.vue';
|
import CenterModal from '@c/modal/CenterModal.vue';
|
||||||
import { inject, onMounted, reactive, ref, watch } from 'vue';
|
import { inject, onMounted, reactive, ref, watch } from 'vue';
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
import { isEmpty } from '@/common/utils';
|
|
||||||
import FormInput from '../input/FormInput.vue';
|
|
||||||
import 'flatpickr/dist/flatpickr.min.css';
|
import 'flatpickr/dist/flatpickr.min.css';
|
||||||
import '@/assets/css/app-calendar.css';
|
import '@/assets/css/app-calendar.css';
|
||||||
import { fetchHolidays } from '@c/calendar/holiday';
|
import { fetchHolidays } from '@c/calendar/holiday';
|
||||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
import { useProjectStore } from '@/stores/useProjectStore';
|
import { useProjectStore } from '@/stores/useProjectStore';
|
||||||
|
import BackBtn from '@c/button/BackBtn.vue';
|
||||||
|
import { useToastStore } from '@/stores/toastStore';
|
||||||
|
|
||||||
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
||||||
const user = ref({});
|
const user = ref({});
|
||||||
const project = ref({});
|
const project = ref({});
|
||||||
const userStore = useUserInfoStore();
|
const userStore = useUserInfoStore();
|
||||||
const projectStore = useProjectStore();
|
const projectStore = useProjectStore();
|
||||||
|
const toastStore = useToastStore();
|
||||||
|
|
||||||
const dayjs = inject('dayjs');
|
const dayjs = inject('dayjs');
|
||||||
const fullCalendarRef = ref(null);
|
const fullCalendarRef = ref(null);
|
||||||
const calendarEvents = ref([]);
|
const calendarEvents = ref([]);
|
||||||
const isModalVisible = ref(false);
|
const isModalVisible = ref(false);
|
||||||
const eventAlert = ref(false);
|
|
||||||
const eventDateAlert = ref(false);
|
|
||||||
const eventTitle = ref('');
|
|
||||||
const eventDate = ref('');
|
const eventDate = ref('');
|
||||||
const selectedDate = ref(null);
|
|
||||||
|
|
||||||
|
const workTime = ref(null);
|
||||||
|
const selectedProject = ref(null);
|
||||||
|
const checkedInProject = ref(null);
|
||||||
|
|
||||||
// 날짜 선택 핸들러
|
const draggedProject = ref(null);
|
||||||
const handleDateSelect = (selectedDates) => {
|
|
||||||
if (selectedDates.length > 0) {
|
// 드래그 시작 이벤트 핸들러
|
||||||
// 선택된 첫 번째 날짜를 YYYY-MM-DD 형식으로 변환
|
const dragStart = (event, project) => {
|
||||||
const selectedDate = dayjs(selectedDates[0]).format('YYYY-MM-DD');
|
draggedProject.value = project;
|
||||||
eventDate.value = selectedDate;
|
// 드래그 데이터 설정
|
||||||
showModal(); // 모달 표시
|
event.dataTransfer.setData('application/json', JSON.stringify(project));
|
||||||
|
event.dataTransfer.effectAllowed = 'copy';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 드래그 오버 드롭 허용
|
||||||
|
const allowDrop = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 드롭
|
||||||
|
const handleDrop = (event, targetProject) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// 드래그한 프로젝트와 드롭한 프로젝트가 같으면 아무 동작 안 함
|
||||||
|
if (draggedProject.value.PROJCTSEQ === targetProject.PROJCTSEQ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 선택된 프로젝트 변경
|
||||||
|
checkedInProject.value = targetProject;
|
||||||
|
projectStore.setSelectedProject(targetProject);
|
||||||
|
|
||||||
|
// select 값도 변경
|
||||||
|
selectedProject.value = targetProject.PROJCTSEQ;
|
||||||
|
|
||||||
|
// 프로필 테두리 색상 업데이트
|
||||||
|
addProfileToCalendar();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 출근 시간
|
||||||
|
const setWorkTime = () => {
|
||||||
|
// 이미 출근 시간이 설정된 경우 중복 실행 방지
|
||||||
|
if (workTime.value) return;
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
workTime.value = now.toLocaleTimeString('ko-KR', { hour12: false });
|
||||||
|
|
||||||
|
// 현재 선택된 프로젝트 가져오기
|
||||||
|
const currentProject = projectStore.selectedProject || projectStore.getSelectedProject();
|
||||||
|
if (currentProject) {
|
||||||
|
checkedInProject.value = currentProject;
|
||||||
|
|
||||||
|
// 캘린더에 오늘 날짜에 프로필 이미지 추가하기
|
||||||
|
addProfileToCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
$api.post('commuters/insert', {
|
||||||
|
memberSeq: user.value.id,
|
||||||
|
projctSeq: checkedInProject.value.PROJCTSEQ,
|
||||||
|
commutCmt: workTime.value,
|
||||||
|
commutLvt: null,
|
||||||
|
commutArr: null,
|
||||||
|
}).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
toastStore.onToast('출근 등록되었습니다.', 's');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 캘린더의 오늘 날짜에 프로필 이미지 추가
|
||||||
|
const addProfileToCalendar = () => {
|
||||||
|
const calendarApi = fullCalendarRef.value?.getApi();
|
||||||
|
if (!calendarApi || !user.value) return;
|
||||||
|
|
||||||
|
// 오늘 날짜 셀 찾기
|
||||||
|
const today = dayjs().format('YYYY-MM-DD');
|
||||||
|
const todayCell = document.querySelector(`.fc-day[data-date="${today}"]`) || document.querySelector(`.fc-daygrid-day[data-date="${today}"]`);
|
||||||
|
|
||||||
|
if (todayCell) {
|
||||||
|
const dayFrame = todayCell.querySelector('.fc-daygrid-day-events');
|
||||||
|
|
||||||
|
if (dayFrame) {
|
||||||
|
const existingProfileImg = dayFrame.querySelector('.profile-img');
|
||||||
|
if (existingProfileImg) {
|
||||||
|
dayFrame.removeChild(existingProfileImg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const profileImg = document.createElement('img');
|
||||||
|
profileImg.src = `${baseUrl}upload/img/profile/${user.value.profile}`;
|
||||||
|
profileImg.className = 'profile-img rounded-circle w-px-20 h-px-20';
|
||||||
|
profileImg.style.border = `2px solid ${checkedInProject.value.projctcolor}`;
|
||||||
|
|
||||||
|
profileImg.onerror = () => { profileImg.src = '/img/icons/icon.png'; };
|
||||||
|
|
||||||
|
dayFrame.appendChild(profileImg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,6 +224,11 @@ const fetchData = async () => {
|
|||||||
const existingEvents = calendarEvents.value.filter(event => !event.classNames?.includes('holiday-event'));
|
const existingEvents = calendarEvents.value.filter(event => !event.classNames?.includes('holiday-event'));
|
||||||
// 필터링된 이벤트와 새로 가져온 공휴일 이벤트 병합
|
// 필터링된 이벤트와 새로 가져온 공휴일 이벤트 병합
|
||||||
calendarEvents.value = [...existingEvents, ...holidayEvents];
|
calendarEvents.value = [...existingEvents, ...holidayEvents];
|
||||||
|
|
||||||
|
// 출근 시간이 있으면 프로필 이미지 다시 추가
|
||||||
|
if (workTime.value && checkedInProject.value) {
|
||||||
|
setTimeout(addProfileToCalendar, 100); // 달력이 렌더링된 후 실행
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('공휴일 정보 로딩 실패:', error);
|
console.error('공휴일 정보 로딩 실패:', error);
|
||||||
}
|
}
|
||||||
@ -160,72 +250,108 @@ const moveCalendar = async (value = 0) => {
|
|||||||
await fetchData();
|
await fetchData();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 모달 표시 함수
|
// 날짜 선택 가능 여부를 확인하는 공통 함수
|
||||||
const showModal = () => {
|
const isSelectableDate = (date) => {
|
||||||
isModalVisible.value = true;
|
const checkDate = dayjs(date);
|
||||||
|
const today = dayjs().startOf('day');
|
||||||
|
const isWeekend = checkDate.day() === 0 || checkDate.day() === 6;
|
||||||
|
// 공휴일 체크
|
||||||
|
const isHoliday = calendarEvents.value.some(event =>
|
||||||
|
event.classNames?.includes('holiday-event') &&
|
||||||
|
dayjs(event.start).format('YYYY-MM-DD') === checkDate.format('YYYY-MM-DD')
|
||||||
|
);
|
||||||
|
|
||||||
|
return !checkDate.isBefore(today) && !isWeekend && !isHoliday;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 모달 닫기 함수
|
|
||||||
const closeModal = () => {
|
|
||||||
isModalVisible.value = false;
|
|
||||||
// 입력 필드 초기화
|
|
||||||
eventTitle.value = '';
|
|
||||||
eventDate.value = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
// 이벤트 추가 함수
|
// 날짜 클릭 이벤트 함수
|
||||||
const addEvent = () => {
|
let todayElement = null;
|
||||||
// 이벤트 유효성 검사
|
const handleDateClick = (info) => {
|
||||||
if (!checkEvent()) {
|
if (isSelectableDate(info.date)) {
|
||||||
// 유효성 검사 통과 시 이벤트 추가
|
const isToday = dayjs(info.date).isSame(dayjs(), 'day');
|
||||||
calendarEvents.value.push({
|
|
||||||
title: eventTitle.value,
|
if (isToday) {
|
||||||
start: eventDate.value,
|
// 오늘 날짜 클릭 시 클래스 제거하고 요소 저장
|
||||||
backgroundColor: '#4CAF50' // 일반 이벤트 색상
|
todayElement = info.dayEl;
|
||||||
});
|
todayElement.classList.remove('fc-day-today');
|
||||||
closeModal(); // 모달 닫기
|
} else if (todayElement) {
|
||||||
|
// 다른 날짜 클릭 시 저장된 오늘 요소에 클래스 다시 추가
|
||||||
|
todayElement.classList.add('fc-day-today');
|
||||||
|
todayElement = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventDate.value = dayjs(info.date).format('YYYY-MM-DD');
|
||||||
|
showModal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 유효성 검사 함수
|
// 바깥 클릭 시 todayElement 클래스 복구
|
||||||
const checkEvent = () => {
|
document.addEventListener('click', (event) => {
|
||||||
// 제목과 날짜가 비어있는지 확인
|
if (todayElement && !event.target.closest('.fc-daygrid-day')) {
|
||||||
eventAlert.value = isEmpty(eventTitle.value);
|
todayElement.classList.add('fc-day-today');
|
||||||
eventDateAlert.value = isEmpty(eventDate.value);
|
todayElement = null;
|
||||||
// 하나라도 비어있으면 true 반환 (유효성 검사 실패)
|
}
|
||||||
return eventAlert.value || eventDateAlert.value;
|
}, true);
|
||||||
|
|
||||||
|
// 날짜 셀 클래스 추가 함수
|
||||||
|
const getCellClassNames = (arg) => {
|
||||||
|
const cellDate = dayjs(arg.date);
|
||||||
|
const today = dayjs().startOf('day');
|
||||||
|
const classes = [];
|
||||||
|
|
||||||
|
// 선택 불가능한 날짜(과거, 주말, 공휴일)에 동일한 클래스 추가
|
||||||
|
if (!isSelectableDate(cellDate) || cellDate.isBefore(today)) {
|
||||||
|
classes.push('fc-day-sat-sun');
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 캘린더 옵션 설정
|
// 캘린더 옵션 설정
|
||||||
const calendarOptions = reactive({
|
const calendarOptions = reactive({
|
||||||
plugins: [dayGridPlugin, interactionPlugin], // 사용할 플러그인
|
plugins: [dayGridPlugin, interactionPlugin],
|
||||||
initialView: 'dayGridMonth', // 초기 뷰 (월간)
|
initialView: 'dayGridMonth',
|
||||||
headerToolbar: { // 상단 툴바 구성
|
headerToolbar: {
|
||||||
left: 'today', // 왼쪽: 오늘 버튼
|
left: 'today',
|
||||||
center: 'title', // 중앙: 제목(연월)
|
center: 'title',
|
||||||
right: 'prev,next', // 오른쪽: 이전/다음 버튼
|
right: 'prev,next',
|
||||||
|
},
|
||||||
|
locale: 'kr',
|
||||||
|
events: calendarEvents,
|
||||||
|
eventOrder: 'sortIdx',
|
||||||
|
// 날짜 선택 관련 옵션 수정
|
||||||
|
selectable: true,
|
||||||
|
selectAllow: (selectInfo) => isSelectableDate(selectInfo.start),
|
||||||
|
dateClick: handleDateClick,
|
||||||
|
dayCellClassNames: getCellClassNames,
|
||||||
|
|
||||||
|
// 날짜 클릭 비활성화를 위한 추가 설정
|
||||||
|
unselectAuto: true,
|
||||||
|
droppable: false,
|
||||||
|
eventDisplay: 'block',
|
||||||
|
|
||||||
|
// 캘린더 렌더링 완료 이벤트
|
||||||
|
datesSet: () => {
|
||||||
|
// 캘린더가 렌더링 된 후 프로필 이미지 다시 추가 (월 변경 시)
|
||||||
|
if (workTime.value && checkedInProject.value) {
|
||||||
|
setTimeout(addProfileToCalendar, 100);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
locale: 'kr', // 한국어 지역화
|
|
||||||
events: calendarEvents, // 표시할 이벤트 데이터
|
|
||||||
eventOrder: 'sortIdx', // 이벤트 정렬 기준
|
|
||||||
selectable: true, // 날짜 선택 가능 여부
|
|
||||||
dateClick: handleDateSelect, // 날짜 클릭 이벤트 핸들러
|
|
||||||
droppable: false, // 드래그 앤 드롭 비활성화
|
|
||||||
eventDisplay: 'block', // 이벤트 표시 방식
|
|
||||||
|
|
||||||
// 커스텀 버튼 정의
|
// 커스텀 버튼 정의
|
||||||
customButtons: {
|
customButtons: {
|
||||||
prev: {
|
prev: {
|
||||||
text: 'PREV', // 이전 버튼 텍스트
|
text: 'PREV',
|
||||||
click: () => moveCalendar(1), // 클릭 시 이전 달로 이동
|
click: () => moveCalendar(1),
|
||||||
},
|
},
|
||||||
today: {
|
today: {
|
||||||
text: 'TODAY', // 오늘 버튼 텍스트
|
text: 'TODAY',
|
||||||
click: () => moveCalendar(3), // 클릭 시 오늘로 이동
|
click: () => moveCalendar(3),
|
||||||
},
|
},
|
||||||
next: {
|
next: {
|
||||||
text: 'NEXT', // 다음 버튼 텍스트
|
text: 'NEXT',
|
||||||
click: () => moveCalendar(2), // 클릭 시 다음 달로 이동
|
click: () => moveCalendar(2),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -235,13 +361,44 @@ watch(() => fullCalendarRef.value?.getApi().currentData.viewTitle, async () => {
|
|||||||
await fetchData();
|
await fetchData();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 모달 표시 함수
|
||||||
|
const showModal = () => {
|
||||||
|
isModalVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 모달 닫기 함수
|
||||||
|
const closeModal = () => {
|
||||||
|
isModalVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// selectedProject 변경 감지
|
||||||
|
watch(() => projectStore.selectedProject, (newProject) => {
|
||||||
|
if (newProject) {
|
||||||
|
selectedProject.value = newProject.PROJCTSEQ;
|
||||||
|
checkedInProject.value = newProject;
|
||||||
|
addProfileToCalendar();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
console.log(project)
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
await userStore.userInfo();
|
await userStore.userInfo();
|
||||||
user.value = userStore.user;
|
user.value = userStore.user;
|
||||||
await projectStore.getProjectList();
|
await projectStore.getProjectList();
|
||||||
project.value = projectStore.projectList;
|
project.value = projectStore.projectList;
|
||||||
|
|
||||||
|
// 저장된 선택 프로젝트 가져오기
|
||||||
|
const storedProject = projectStore.getSelectedProject();
|
||||||
|
if (storedProject) {
|
||||||
|
selectedProject.value = storedProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 캘린더가 완전히 로드된 후 프로필 추가를 위한 지연 설정
|
||||||
|
setTimeout(() => {
|
||||||
|
// 이미 출근 시간이 있는 경우 (페이지 새로고침 등) 프로필 이미지 표시
|
||||||
|
if (workTime.value && checkedInProject.value) {
|
||||||
|
addProfileToCalendar();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -8,6 +8,12 @@
|
|||||||
|
|
||||||
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
|
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
|
||||||
<ul class="navbar-nav flex-row align-items-center ms-auto">
|
<ul class="navbar-nav flex-row align-items-center ms-auto">
|
||||||
|
<select class="form-select py-1" id="name" v-model="selectedProject" @change="updateSelectedProject">
|
||||||
|
<option v-for="item in memberProject" :key="item.PROJCTSEQ" :value="item.PROJCTSEQ">
|
||||||
|
{{ item.PROJCTNAM }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<!-- <button class="btn p-1" @click="switchToLightMode"><i class="bx bxs-sun link-warning"></i></button> -->
|
<!-- <button class="btn p-1" @click="switchToLightMode"><i class="bx bxs-sun link-warning"></i></button> -->
|
||||||
<!-- <button class="btn p-1" @click="switchToDarkMode"><i class="bx bxs-moon"></i></button> -->
|
<!-- <button class="btn p-1" @click="switchToDarkMode"><i class="bx bxs-moon"></i></button> -->
|
||||||
|
|
||||||
@ -234,36 +240,79 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useAuthStore } from '@s/useAuthStore';
|
import { useAuthStore } from '@s/useAuthStore';
|
||||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
|
import { useProjectStore } from '@/stores/useProjectStore';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useThemeStore } from '@s/darkmode';
|
import { useThemeStore } from '@s/darkmode';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
|
|
||||||
const user = ref(null);
|
|
||||||
//const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
|
||||||
const baseUrl = import.meta.env.VITE_SERVER;
|
const baseUrl = import.meta.env.VITE_SERVER;
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const userStore = useUserInfoStore();
|
const userStore = useUserInfoStore();
|
||||||
|
const projectStore = useProjectStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { isDarkMode, switchToDarkMode, switchToLightMode } = useThemeStore();
|
const user = ref(null);
|
||||||
|
const memberProject = ref({});
|
||||||
|
const selectedProject = ref(null);
|
||||||
|
|
||||||
|
// 프로젝트 선택 변경 시 스토어에 저장
|
||||||
|
const updateSelectedProject = () => {
|
||||||
|
if (!selectedProject.value) return;
|
||||||
|
|
||||||
|
const selected = memberProject.value.find(
|
||||||
|
project => project.PROJCTSEQ === selectedProject.value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
projectStore.setSelectedProject(selected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMemberProjects = async () => {
|
||||||
|
const res = await $api.get(`project/${user.value.id}`);
|
||||||
|
memberProject.value = res.data.data;
|
||||||
|
projectStore.projectList = memberProject.value; // 스토어에도 저장
|
||||||
|
|
||||||
|
// 이전에 선택된 프로젝트가 있으면 불러오기
|
||||||
|
const storedProject = projectStore.getSelectedProject();
|
||||||
|
if (storedProject) {
|
||||||
|
selectedProject.value = storedProject.PROJCTSEQ;
|
||||||
|
} else if (memberProject.value.length > 0) {
|
||||||
|
// 없으면 첫 번째 프로젝트 선택
|
||||||
|
selectedProject.value = memberProject.value[0].PROJCTSEQ;
|
||||||
|
updateSelectedProject();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// const { isDarkMode, switchToDarkMode, switchToLightMode } = useThemeStore();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (isDarkMode) {
|
// if (isDarkMode) {
|
||||||
switchToDarkMode();
|
// switchToDarkMode();
|
||||||
} else {
|
// } else {
|
||||||
switchToLightMode();
|
// switchToLightMode();
|
||||||
}
|
// }
|
||||||
|
|
||||||
await userStore.userInfo();
|
await userStore.userInfo();
|
||||||
user.value = userStore.user;
|
user.value = userStore.user;
|
||||||
|
|
||||||
|
await getMemberProjects();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => projectStore.selectedProject, (newProject) => {
|
||||||
|
if (newProject) {
|
||||||
|
selectedProject.value = newProject.PROJCTSEQ; // select 값 강제 변경
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
await authStore.logout();
|
await authStore.logout();
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -6,11 +6,12 @@
|
|||||||
설명 : 프로젝트 목록
|
설명 : 프로젝트 목록
|
||||||
*/
|
*/
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { ref } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
|
|
||||||
export const useProjectStore = defineStore('project', () => {
|
export const useProjectStore = defineStore('project', () => {
|
||||||
const projectList = ref([]);
|
const projectList = ref([]);
|
||||||
|
const selectedProject = ref(null);
|
||||||
|
|
||||||
const getProjectList = async (searchText = '', selectedYear = '') => {
|
const getProjectList = async (searchText = '', selectedYear = '') => {
|
||||||
const res = await $api.get('project/select', {
|
const res = await $api.get('project/select', {
|
||||||
@ -22,6 +23,36 @@ export const useProjectStore = defineStore('project', () => {
|
|||||||
projectList.value = res.data.data.projectList;
|
projectList.value = res.data.data.projectList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setSelectedProject = (project) => {
|
||||||
|
selectedProject.value = { ...project };
|
||||||
|
|
||||||
return { projectList, getProjectList };
|
if (project) {
|
||||||
|
localStorage.setItem('selectedProject', JSON.stringify(project));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSelectedProject = () => {
|
||||||
|
if (!selectedProject.value) {
|
||||||
|
const storedProject = localStorage.getItem('selectedProject');
|
||||||
|
if (storedProject) {
|
||||||
|
selectedProject.value = JSON.parse(storedProject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedProject.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 프로젝트 리스트가 변경될 때 자동으로 반응
|
||||||
|
watch(projectList, (newList) => {
|
||||||
|
if (!selectedProject.value && newList.length > 0) {
|
||||||
|
setSelectedProject(newList[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
projectList,
|
||||||
|
selectedProject,
|
||||||
|
getProjectList,
|
||||||
|
setSelectedProject,
|
||||||
|
getSelectedProject
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user