localhost-front/src/components/commuters/CommuterBtn.vue
2025-04-04 19:21:39 +09:00

224 lines
6.7 KiB
Vue

<template>
<div class="row g-0">
<div class="col-6 pe-1">
<button
class="btn border-3 w-100 py-0 h-px-50"
:class="workTime ? 'p-0 btn-primary pe-none' : 'btn-outline-primary'"
@click="setWorkTime"
>
<i v-if="!workTime" class="bx bx-run fs-2"></i>
<span v-if="workTime" class="ql-size-12px">{{ workTime }}</span>
</button>
</div>
<div class="col-6 ps-1">
<button
class="btn border-3 w-100 py-0 h-px-50"
:class="!workTime ? 'btn-outline-secondary pe-none disabled' : 'btn-outline-secondary'"
@click="setLeaveTime"
:disabled="!workTime"
>
<i v-if="!leaveTime" class='bx bxs-door-open fs-2'></i>
<span v-if="leaveTime" class="ql-size-12px">{{ leaveTime }}</span>
</button>
</div>
</div>
</template>
<script setup>
import { ref, defineProps, defineEmits, onMounted, watch } from 'vue';
import $api from '@api';
import { useGeolocation } from '@vueuse/core';
const props = defineProps({
userId: {
type: Number,
required: false
},
checkedInProject: {
type: Object,
required: false
},
pendingProjectChange: {
type: Object,
default: null
}
});
const emit = defineEmits(['workTimeUpdated', 'leaveTimeUpdated', 'projectChangeComplete', 'update:pendingProjectChange']);
const workTime = ref(null);
const leaveTime = ref(null)
const userLocation = ref(null);
// 위치 정보 가져오기 설정
const { coords, isSupported, error } = useGeolocation({
enableHighAccuracy: true,
});
// 주소 변환 함수
const getAddress = async (lat, lng) => {
return new Promise((resolve, reject) => {
if (typeof kakao === 'undefined' || !kakao.maps) {
reject('Kakao Maps API가 로드되지 않았습니다.');
return;
}
const geocoder = new kakao.maps.services.Geocoder();
geocoder.coord2Address(lng, lat, (result, status) => {
if (status === kakao.maps.services.Status.OK) {
if (result && result.length > 0 && result[0].address) {
const address = result[0].address.address_name;
resolve(address);
} else {
// 결과가 있지만 주소가 없는 경우
reject('주소 정보가 없습니다.');
}
} else if (status === kakao.maps.services.Status.ZERO_RESULT) {
// ZERO_RESULT 상태 처리
// 좌표로 주소를 찾지 못했을 때 도로명 주소로 시도
geocoder.coord2RegionCode(lng, lat, (regionResult, regionStatus) => {
if (regionStatus === kakao.maps.services.Status.OK && regionResult.length > 0) {
// 행정구역 정보로 대체
const region = regionResult[0].address_name;
resolve(`[대략적 위치] ${region}`);
} else {
// 행정구역 정보도 없는 경우 좌표 자체를 반환
resolve(`위도: ${lat}, 경도: ${lng} (주소 정보 없음)`);
}
});
} else {
reject(`주소를 가져올 수 없습니다. 상태: ${status}`);
}
});
});
};
// 위치 정보 가져오기 함수
const getLocation = async () => {
if (!isSupported.value) {
alert('브라우저가 위치 정보를 지원하지 않습니다.');
return null;
}
if (error.value) {
alert(`위치 정보를 가져오는데 실패했습니다: ${error.value.message}`);
return null;
}
if (!coords.value) {
return null;
}
userLocation.value = {
lat: coords.value.latitude,
lng: coords.value.longitude,
};
try {
const address = await getAddress(coords.value.latitude, coords.value.longitude);
return address;
} catch (error) {
alert(error);
return null;
}
};
// 오늘 사용자의 출근 정보 조회
const todayCommuterInfo = async () => {
if (!props.userId) return;
const res = await $api.get(`commuters/today/${props.userId}`);
if (res.status === 200) {
const commuterInfo = res.data.data[0];
if (commuterInfo) {
workTime.value = commuterInfo.COMMUTCMT;
leaveTime.value = commuterInfo.COMMUTLVE;
// 부모 컴포넌트에 상태 업데이트 알림
emit('workTimeUpdated', workTime.value);
emit('leaveTimeUpdated', leaveTime.value);
}
}
};
// 출근 시간
const setWorkTime = async () => {
// 이미 출근 시간이 설정된 경우 중복 실행 방지
if (workTime.value) return;
// 현재 위치 주소 가져오기
const address = await getLocation();
if (!address) {
// 주소를 가져오지 못했을 때도 계속 진행할지 사용자에게 확인
if (!confirm('위치 정보를 가져오지 못했습니다. 위치 없이 출근 처리하시겠습니까?')) {
return;
}
}
$api.post('commuters/insert', {
memberSeq: props.userId,
projctSeq: props.checkedInProject.PROJCTSEQ,
commutLve: null,
commutArr: address,
commutOut: null,
}).then(res => {
if (res.status === 200) {
todayCommuterInfo();
emit('workTimeUpdated', true);
}
});
};
// 퇴근
const setLeaveTime = async () => {
// 현재 위치 주소 가져오기
const address = await getLocation();
if (!address && !leaveTime.value) {
// 주소를 가져오지 못했을 때도 계속 진행할지 사용자에게 확인
if (!confirm('위치 정보를 가져오지 못했습니다. 위치 없이 퇴근 처리하시겠습니까?')) {
return;
}
}
$api.patch('commuters/updateLve', {
memberSeq: props.userId,
commutLve: leaveTime.value || null,
projctLve: props.pendingProjectChange ? props.pendingProjectChange.projctSeq : props.checkedInProject.PROJCTSEQ,
commutOut: address,
}).then(res => {
if (res.status === 200) {
todayCommuterInfo();
emit('leaveTimeUpdated');
emit('update:pendingProjectChange', null);
}
});
};
// props 변경 감지
watch(() => props.userId, async () => {
if (props.userId) {
await todayCommuterInfo();
}
});
onMounted(async () => {
await todayCommuterInfo();
});
// 외부에서 접근할 메서드 노출
defineExpose({
todayCommuterInfo,
workTime,
leaveTime
});
</script>