출퇴근
This commit is contained in:
parent
2ec81f274d
commit
1eba161060
@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div class="row g-0">
|
||||
<div class="col-6 pe-1">
|
||||
<p class="mb-1">출근시간</p>
|
||||
<button
|
||||
class="btn border-3 w-100 py-0 h-px-50"
|
||||
:class="workTime ? 'p-0 btn-primary pe-none' : 'btn-outline-primary'"
|
||||
@ -13,7 +12,6 @@
|
||||
</div>
|
||||
|
||||
<div class="col-6 ps-1">
|
||||
<p class="mb-1">퇴근시간</p>
|
||||
<button
|
||||
class="btn btn-outline-secondary border-3 w-100 py-0 h-px-50"
|
||||
@click="setLeaveTime"
|
||||
@ -29,7 +27,6 @@
|
||||
import { ref, defineProps, defineEmits, onMounted, watch } from 'vue';
|
||||
import $api from '@api';
|
||||
import { useGeolocation } from '@vueuse/core';
|
||||
import { useToastStore } from '@/stores/toastStore';
|
||||
|
||||
const props = defineProps({
|
||||
userId: {
|
||||
@ -47,7 +44,6 @@ const emit = defineEmits(['workTimeUpdated', 'leaveTimeUpdated']);
|
||||
const workTime = ref(null);
|
||||
const leaveTime = ref(null)
|
||||
const userLocation = ref(null);
|
||||
const toastStore = useToastStore();
|
||||
|
||||
// 위치 정보 가져오기 설정
|
||||
const { coords, isSupported, error } = useGeolocation({
|
||||
@ -74,12 +70,12 @@ const getAddress = (lat, lng) => {
|
||||
// 위치 정보 가져오기 함수
|
||||
const getLocation = async () => {
|
||||
if (!isSupported.value) {
|
||||
toastStore.onToast('브라우저가 위치 정보를 지원하지 않습니다.', 'e');
|
||||
alert('브라우저가 위치 정보를 지원하지 않습니다.');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (error.value) {
|
||||
toastStore.onToast(`위치 정보를 가져오는데 실패했습니다: ${error.value.message}`, 'e');
|
||||
alert(`위치 정보를 가져오는데 실패했습니다: ${error.value.message}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -93,7 +89,7 @@ const getLocation = async () => {
|
||||
const address = await getAddress(coords.value.latitude, coords.value.longitude);
|
||||
return address;
|
||||
} catch (error) {
|
||||
toastStore.onToast(error, 'e');
|
||||
alert(error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -135,7 +131,6 @@ const setWorkTime = async () => {
|
||||
commutArr: address,
|
||||
}).then(res => {
|
||||
if (res.status === 200) {
|
||||
toastStore.onToast('출근 완료.', 's');
|
||||
todayCommuterInfo();
|
||||
|
||||
emit('workTimeUpdated', true);
|
||||
@ -150,11 +145,6 @@ const setLeaveTime = () => {
|
||||
commutLve: leaveTime.value || null,
|
||||
}).then(res => {
|
||||
if (res.status === 200) {
|
||||
if (leaveTime.value) {
|
||||
toastStore.onToast('퇴근 시간 초기화', 'e');
|
||||
} else {
|
||||
toastStore.onToast('퇴근 완료', 's');
|
||||
}
|
||||
todayCommuterInfo();
|
||||
// 부모 컴포넌트에 업데이트 이벤트 발생
|
||||
emit('leaveTimeUpdated', true);
|
||||
|
||||
@ -86,7 +86,6 @@ import '@/assets/css/app-calendar.css';
|
||||
import { fetchHolidays } from '@c/calendar/holiday';
|
||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||
import { useProjectStore } from '@/stores/useProjectStore';
|
||||
import { useToastStore } from '@/stores/toastStore';
|
||||
import CommuterBtn from '@c/commuters/CommuterBtn.vue';
|
||||
import CommuterProjectList from '@c/commuters/CommuterProjectList.vue';
|
||||
import BackBtn from '@c/button/BackBtn.vue';
|
||||
@ -96,7 +95,6 @@ const user = ref({});
|
||||
const project = ref({});
|
||||
const userStore = useUserInfoStore();
|
||||
const projectStore = useProjectStore();
|
||||
const toastStore = useToastStore();
|
||||
|
||||
const dayjs = inject('dayjs');
|
||||
const fullCalendarRef = ref(null);
|
||||
@ -134,19 +132,6 @@ const handleProjectDrop = ({ event, targetProject }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// select값에 드롭한 프로젝트가 없는 경우
|
||||
if (!selectedProject.value) {
|
||||
$api.patch('project/updateYon', {
|
||||
projctSeq: targetProject.PROJCTSEQ,
|
||||
memberSeq: user.value.id,
|
||||
projctYon: '1'
|
||||
}).then(res => {
|
||||
if (res.status === 200) {
|
||||
projectStore.getProjectList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 선택된 프로젝트 변경
|
||||
checkedInProject.value = targetProject;
|
||||
projectStore.setSelectedProject(targetProject);
|
||||
@ -159,8 +144,6 @@ const handleProjectDrop = ({ event, targetProject }) => {
|
||||
memberSeq: user.value.id,
|
||||
}).then(res => {
|
||||
if (res.status === 200) {
|
||||
toastStore.onToast('출근 프로젝트가 변경 되었습니다.', 's');
|
||||
|
||||
todaysCommuter();
|
||||
loadCommuters();
|
||||
}
|
||||
@ -317,15 +300,15 @@ const loadCommuters = async () => {
|
||||
monthlyCommuters.value.forEach(commuter => {
|
||||
const date = commuter.COMMUTDAY;
|
||||
const dateCell = document.querySelector(`.fc-day[data-date="${date}"]`) ||
|
||||
document.querySelector(`.fc-daygrid-day[data-date="${date}"]`);
|
||||
|
||||
document.querySelector(`.fc-daygrid-day[data-date="${date}"]`);
|
||||
if (dateCell) {
|
||||
const dayEvents = dateCell.querySelector('.fc-daygrid-day-events');
|
||||
if (dayEvents) {
|
||||
dayEvents.classList.add('text-center');
|
||||
// 프로필 이미지 생성
|
||||
const profileImg = document.createElement('img');
|
||||
profileImg.src = `${baseUrl}upload/img/profile/${commuter.profile}`;
|
||||
profileImg.className = 'rounded-circle w-px-20 h-px-20 ms-1 position-relative z-5';
|
||||
profileImg.className = 'rounded-circle w-px-20 h-px-20 mx-1 mb-1 position-relative z-5 m-auto';
|
||||
profileImg.style.border = `2px solid ${commuter.projctcolor}`;
|
||||
profileImg.onerror = () => { profileImg.src = '/img/icons/icon.png'; };
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
<script setup>
|
||||
import { onMounted, ref, nextTick, computed } from 'vue';
|
||||
import { useUserStore } from '@s/userList';
|
||||
import { useProjectStore } from '@s/useProjectStore';
|
||||
import $api from '@api';
|
||||
|
||||
const emit = defineEmits(['user-list-update']);
|
||||
@ -106,7 +107,7 @@ const isUserDisabled = (user) => {
|
||||
// 클릭 시 활성화/비활성화 및 DB 업데이트
|
||||
// showOnlyActive가 true일 때는 toggleDisable 함수가 실행되지 않음
|
||||
const toggleDisable = async (index) => {
|
||||
if (props.showOnlyActive) return; // showOnlyActive가 true이면 함수 실행 중지
|
||||
if (props.showOnlyActive) return;
|
||||
|
||||
const user = displayedUserList.value[index];
|
||||
if (user) {
|
||||
@ -125,6 +126,11 @@ const toggleDisable = async (index) => {
|
||||
if (originalIndex !== -1) {
|
||||
userList.value[originalIndex].PROJCTYON = newParticipationStatus ? '0' : '1';
|
||||
}
|
||||
|
||||
// 변경 후 프로젝트 목록 새로고침
|
||||
const projectStore = useProjectStore();
|
||||
await projectStore.getProjectList('', '', 'true');
|
||||
await projectStore.getMemberProjects();
|
||||
}
|
||||
} else {
|
||||
// 원래 userList에서 해당 사용자를 찾아 업데이트
|
||||
|
||||
@ -9,8 +9,13 @@
|
||||
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
|
||||
<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 projectStore.memberProjectList" :key="item.PROJCTSEQ" :value="item.PROJCTSEQ">
|
||||
{{ item.PROJCTNAM }}
|
||||
<!-- 내가 참여하고 있는 프로젝트 그룹 -->
|
||||
<option v-for="item in myProjects" :key="item.PROJCTSEQ" :value="item.PROJCTSEQ">
|
||||
{{ item.PROJCTNAM }}
|
||||
</option>
|
||||
<!-- 전체 프로젝트 그룹 -->
|
||||
<option v-for="item in otherProjects" :key="item.PROJCTSEQ" :value="item.PROJCTSEQ">
|
||||
{{ item.PROJCTNAM }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
@ -243,7 +248,7 @@
|
||||
import { useProjectStore } from '@/stores/useProjectStore';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useThemeStore } from '@s/darkmode';
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import $api from '@api';
|
||||
|
||||
const baseUrl = import.meta.env.VITE_SERVER;
|
||||
@ -256,11 +261,28 @@
|
||||
const user = ref(null);
|
||||
const selectedProject = ref(null);
|
||||
|
||||
// 내가 참여하고 있는 프로젝트 목록
|
||||
const myProjects = computed(() => {
|
||||
return projectStore.memberProjectList || [];
|
||||
});
|
||||
|
||||
// 내가 참여하고 있지 않은 프로젝트 목록
|
||||
const otherProjects = computed(() => {
|
||||
if (!projectStore.projectList || !projectStore.memberProjectList) return [];
|
||||
|
||||
// 내 프로젝트 ID 목록
|
||||
const myProjectIds = projectStore.memberProjectList.map(p => p.PROJCTSEQ);
|
||||
|
||||
// 내 프로젝트가 아닌 프로젝트만 필터링
|
||||
return projectStore.projectList.filter(p => !myProjectIds.includes(p.PROJCTSEQ));
|
||||
});
|
||||
|
||||
// 프로젝트 선택 변경 시 스토어에 저장
|
||||
const updateSelectedProject = () => {
|
||||
if (!selectedProject.value) return;
|
||||
|
||||
const selected = projectStore.memberProjectList.find(
|
||||
// 전체 프로젝트 리스트에서 선택된 프로젝트 찾기
|
||||
const selected = projectStore.projectList.find(
|
||||
project => project.PROJCTSEQ === selectedProject.value
|
||||
);
|
||||
|
||||
@ -269,6 +291,13 @@
|
||||
}
|
||||
};
|
||||
|
||||
// 선택된 프로젝트 변경 감지
|
||||
watch(() => projectStore.selectedProject, (newProject) => {
|
||||
if (newProject) {
|
||||
selectedProject.value = newProject.PROJCTSEQ;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// const { isDarkMode, switchToDarkMode, switchToLightMode } = useThemeStore();
|
||||
|
||||
@ -282,25 +311,23 @@
|
||||
await userStore.userInfo();
|
||||
user.value = userStore.user;
|
||||
|
||||
await projectStore.getProjectList('', '', 'true');
|
||||
|
||||
// 사용자가 참여하고 있는 프로젝트 목록
|
||||
await projectStore.getMemberProjects();
|
||||
|
||||
// memberProjectList가 로드된 후 selectedProject 업데이트
|
||||
if (projectStore.selectedProject) {
|
||||
selectedProject.value = projectStore.selectedProject.PROJCTSEQ;
|
||||
// 저장된 선택 프로젝트
|
||||
const storedProject = projectStore.getSelectedProject();
|
||||
if (storedProject) {
|
||||
selectedProject.value = storedProject.PROJCTSEQ;
|
||||
} else if (projectStore.memberProjectList.length > 0) {
|
||||
// 저장된 선택 프로젝트가 없으면 첫 번째 참여 프로젝트 선택
|
||||
selectedProject.value = projectStore.memberProjectList[0].PROJCTSEQ;
|
||||
projectStore.setSelectedProject(projectStore.memberProjectList[0]);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// projectStore.selectedProject 변경 감지
|
||||
watch(() => projectStore.selectedProject, (newProject) => {
|
||||
if (newProject) {
|
||||
selectedProject.value = newProject.PROJCTSEQ;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const handleLogout = async () => {
|
||||
await authStore.logout();
|
||||
|
||||
@ -35,7 +35,6 @@ export const useProjectStore = defineStore('project', () => {
|
||||
const res = await $api.get(`project/${userStore.user.id}`);
|
||||
memberProjectList.value = res.data.data;
|
||||
|
||||
// 로그인 직후 자동으로 프로젝트 선택 (watch와 별개로 직접 처리)
|
||||
if (memberProjectList.value.length > 0 && !selectedProject.value) {
|
||||
setSelectedProject(memberProjectList.value[0]);
|
||||
}
|
||||
@ -62,32 +61,34 @@ export const useProjectStore = defineStore('project', () => {
|
||||
|
||||
// 프로젝트 리스트가 변경될 때 자동으로 반응
|
||||
watch(projectList, (newList) => {
|
||||
|
||||
// 선택된 프로젝트가 없고 목록이 있는 경우
|
||||
if (!selectedProject.value && newList.length > 0) {
|
||||
setSelectedProject(newList[0]);
|
||||
// 사용자가 속한 프로젝트가 있는지 먼저 확인
|
||||
if (memberProjectList.value.length > 0) {
|
||||
setSelectedProject(memberProjectList.value[0]);
|
||||
} else {
|
||||
setSelectedProject(newList[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(memberProjectList, (newList) => {
|
||||
if (newList.length > 0) {
|
||||
// 현재 선택된 프로젝트가 없거나 목록에 없는 경우 첫 번째 항목 선택
|
||||
// 현재 선택된 프로젝트가 없는 경우 첫 번째 항목 선택
|
||||
if (!selectedProject.value) {
|
||||
setSelectedProject(newList[0]);
|
||||
} else {
|
||||
// 선택된 프로젝트가 있는 경우 목록에 있는지 확인
|
||||
const exists = newList.some(project =>
|
||||
project.PROJCTSEQ === selectedProject.value.PROJCTSEQ);
|
||||
const exists = newList.some(project => project.PROJCTSEQ === selectedProject.value.PROJCTSEQ);
|
||||
|
||||
if (!exists) {
|
||||
setSelectedProject(newList[0]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 목록이 비어있으면 선택된 프로젝트를 null로 설정
|
||||
setSelectedProject(null);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
projectList,
|
||||
selectedProject,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user