Merge branch 'main' of http://192.168.0.251:3000/localhost/localhost-front
All checks were successful
LocalNet_front/pipeline/head This commit looks good
All checks were successful
LocalNet_front/pipeline/head This commit looks good
This commit is contained in:
commit
a72eb1f81a
@ -8,28 +8,42 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
|
|
||||||
const commonApi = (options = {}) => {
|
const colorList = ref([]);
|
||||||
const colorList = ref([]);
|
const mbtiList = ref([]);
|
||||||
const mbtiList = ref([]);
|
const pwhintList = ref([]);
|
||||||
const pwhintList = ref([]);
|
const yearCategory = ref([]);
|
||||||
const yearCategory = ref([]);
|
const cateList = ref([]);
|
||||||
const cateList = ref([]);
|
|
||||||
|
|
||||||
// type 파라미터를 추가로 받도록 수정
|
const refreshColorList = async (type = 'YNP') => {
|
||||||
const CommonCode = async (path, endpoint, targetList, type = null) => {
|
const response = await $api.get(`user/color`, {
|
||||||
const params = type ? { type } : {};
|
params: { type }
|
||||||
const response = await $api.get(`${path}/${endpoint}`, {
|
});
|
||||||
params
|
|
||||||
});
|
if (response.data && response.data.data) {
|
||||||
targetList.value = response.data.data.map(item => ({
|
colorList.value = response.data.data.map(item => ({
|
||||||
label: item.CMNCODNAM,
|
label: item.CMNCODNAM,
|
||||||
value: item.CMNCODVAL,
|
value: item.CMNCODVAL,
|
||||||
}));
|
}));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
return colorList.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// CommonCode 함수를 외부에서도 접근할 수 있게 변경
|
||||||
|
const CommonCode = async (path, endpoint, targetList, type = null) => {
|
||||||
|
const params = type ? { type } : {};
|
||||||
|
const response = await $api.get(`${path}/${endpoint}`, {
|
||||||
|
params
|
||||||
|
});
|
||||||
|
targetList.value = response.data.data.map(item => ({
|
||||||
|
label: item.CMNCODNAM,
|
||||||
|
value: item.CMNCODVAL,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const commonApi = (options = {}) => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 요청할 데이터가 옵션으로 전달 -> 그에 맞게 호출
|
// 요청할 데이터가 옵션으로 전달 -> 그에 맞게 호출
|
||||||
// color 옵션에 type 포함
|
|
||||||
if (options.loadColor) {
|
if (options.loadColor) {
|
||||||
await CommonCode("user", "color", colorList, options.colorType);
|
await CommonCode("user", "color", colorList, options.colorType);
|
||||||
}
|
}
|
||||||
@ -39,7 +53,15 @@ const commonApi = (options = {}) => {
|
|||||||
if (options.loadCateList) await CommonCode("worddict", "getWordCategory", cateList);
|
if (options.loadCateList) await CommonCode("worddict", "getWordCategory", cateList);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { colorList, mbtiList, pwhintList, yearCategory, cateList };
|
return {
|
||||||
|
colorList,
|
||||||
|
mbtiList,
|
||||||
|
pwhintList,
|
||||||
|
yearCategory,
|
||||||
|
cateList,
|
||||||
|
refreshColorList
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { refreshColorList };
|
||||||
export default commonApi;
|
export default commonApi;
|
||||||
|
|||||||
@ -57,12 +57,13 @@ const getAddress = (lat, lng) => {
|
|||||||
const coord = new kakao.maps.LatLng(lat, lng);
|
const coord = new kakao.maps.LatLng(lat, lng);
|
||||||
|
|
||||||
geocoder.coord2Address(coord.getLng(), coord.getLat(), (result, status) => {
|
geocoder.coord2Address(coord.getLng(), coord.getLat(), (result, status) => {
|
||||||
if (status === kakao.maps.services.Status.OK) {
|
if (status === kakao.maps.services.Status.OK) {
|
||||||
const address = result[0].address.address_name;
|
const address = result[0].address.address_name;
|
||||||
resolve(address);
|
resolve(address);
|
||||||
} else {
|
} else {
|
||||||
reject('주소를 가져올 수 없습니다.');
|
reject('주소를 가져올 수 없습니다.');
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -390,7 +390,7 @@ onMounted(async () => {
|
|||||||
await userStore.userInfo();
|
await userStore.userInfo();
|
||||||
user.value = userStore.user;
|
user.value = userStore.user;
|
||||||
await projectStore.getProjectList('', '', 'true');
|
await projectStore.getProjectList('', '', 'true');
|
||||||
project.value = projectStore.projectList;
|
project.value = projectStore.activeProjectList;
|
||||||
|
|
||||||
await todaysCommuter();
|
await todaysCommuter();
|
||||||
|
|
||||||
|
|||||||
@ -129,10 +129,11 @@ watch(selectData, (newValue) => {
|
|||||||
|
|
||||||
|
|
||||||
const selected = computed(() => {
|
const selected = computed(() => {
|
||||||
|
// 현재 선택된 값에 해당하는 아이템 찾기
|
||||||
const selectedItem = props.data.find(item =>
|
const selectedItem = props.data.find(item =>
|
||||||
props.isCommon ? item.value === selectData.value : props.data.indexOf(item) === selectData.value
|
props.isCommon ? item.value === selectData.value : props.data.indexOf(item) === selectData.value
|
||||||
);
|
);
|
||||||
|
|
||||||
return selectedItem ? selectedItem.label : null;
|
return selectedItem ? selectedItem.label : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
<h5 class="card-title fw-bold">
|
<h5 class="card-title fw-bold">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h5>
|
</h5>
|
||||||
<p v-if="isProjectExpired" class="btn-icon btn-danger rounded-2 pe-none"><i class='bx bx-power-off'></i></p>
|
|
||||||
<div v-if="!isProjectExpired" class="d-flex gap-1">
|
<div v-if="!isProjectExpired" class="d-flex gap-1">
|
||||||
<EditBtn @click.stop="openEditModal" />
|
<EditBtn @click.stop="openEditModal" />
|
||||||
<DeleteBtn v-if="isProjectCreator" @click.stop="handleDelete" class="ms-1"/>
|
<DeleteBtn v-if="isProjectCreator" @click.stop="handleDelete" class="ms-1"/>
|
||||||
@ -131,20 +130,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 시작일 -->
|
<!-- 시작일 -->
|
||||||
<div class="date-picker-wrapper" @click="focusStartDateInput">
|
|
||||||
<FormInput
|
<FormInput
|
||||||
title="시작일"
|
title="시작일"
|
||||||
type="date"
|
type="date"
|
||||||
name="startDay"
|
name="startDay"
|
||||||
:is-essential="true"
|
:is-essential="true"
|
||||||
|
:is-alert="startDayAlert"
|
||||||
:modelValue="selectedProject.PROJCTSTR"
|
:modelValue="selectedProject.PROJCTSTR"
|
||||||
@update:modelValue="selectedProject.PROJCTSTR = $event"
|
@update:modelValue="selectedProject.PROJCTSTR = $event"
|
||||||
/>
|
/>
|
||||||
<input ref="startDateInput" type="date" v-model="selectedProject.PROJCTSTR" class="hidden-start-input">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 종료일 -->
|
<!-- 종료일 -->
|
||||||
<div class="date-picker-wrapper" @click="focusEndDateInput">
|
|
||||||
<FormInput
|
<FormInput
|
||||||
title="종료일"
|
title="종료일"
|
||||||
type="date"
|
type="date"
|
||||||
@ -153,8 +149,6 @@
|
|||||||
:modelValue="selectedProject.PROJCTEND"
|
:modelValue="selectedProject.PROJCTEND"
|
||||||
@update:modelValue="selectedProject.PROJCTEND = $event"
|
@update:modelValue="selectedProject.PROJCTEND = $event"
|
||||||
/>
|
/>
|
||||||
<input ref="endDateInput" type="date" v-model="selectedProject.PROJCTEND" class="hidden-end-input">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormInput
|
<FormInput
|
||||||
title="설명"
|
title="설명"
|
||||||
@ -199,7 +193,7 @@ import FormSelect from '@c/input/FormSelect.vue';
|
|||||||
import ArrInput from '@c/input/ArrInput.vue';
|
import ArrInput from '@c/input/ArrInput.vue';
|
||||||
import { useToastStore } from '@s/toastStore';
|
import { useToastStore } from '@s/toastStore';
|
||||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
import commonApi from '@/common/commonApi';
|
import commonApi, { refreshColorList } from '@/common/commonApi';
|
||||||
import { useProjectStore } from '@/stores/useProjectStore';
|
import { useProjectStore } from '@/stores/useProjectStore';
|
||||||
|
|
||||||
// 스토어
|
// 스토어
|
||||||
@ -207,31 +201,6 @@ const toastStore = useToastStore();
|
|||||||
const userStore = useUserInfoStore();
|
const userStore = useUserInfoStore();
|
||||||
const projectStore = useProjectStore();
|
const projectStore = useProjectStore();
|
||||||
|
|
||||||
const startDateInput = ref(null);
|
|
||||||
const endDateInput = ref(null);
|
|
||||||
|
|
||||||
const focusStartDateInput = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
if (startDateInput.value) {
|
|
||||||
startDateInput.value.focus();
|
|
||||||
setTimeout(() => {
|
|
||||||
startDateInput.value.showPicker?.();
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const focusEndDateInput = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
if (endDateInput.value) {
|
|
||||||
endDateInput.value.focus();
|
|
||||||
setTimeout(() => {
|
|
||||||
endDateInput.value.showPicker?.();
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Props 정의
|
// Props 정의
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
@ -250,6 +219,7 @@ const props = defineProps({
|
|||||||
description: {
|
description: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
|
default: "",
|
||||||
},
|
},
|
||||||
address: {
|
address: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -282,6 +252,10 @@ const props = defineProps({
|
|||||||
resetUserSelection: {
|
resetUserSelection: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
searchParams: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({ text: '', year: null })
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -302,6 +276,7 @@ const coordinates = ref(null);
|
|||||||
const isEditModalOpen = ref(false);
|
const isEditModalOpen = ref(false);
|
||||||
const originalColor = ref('');
|
const originalColor = ref('');
|
||||||
const nameAlert = ref(false);
|
const nameAlert = ref(false);
|
||||||
|
const startDayAlert = ref(false);
|
||||||
const user = ref(null);
|
const user = ref(null);
|
||||||
|
|
||||||
const editUserListRef = ref(null);
|
const editUserListRef = ref(null);
|
||||||
@ -312,6 +287,7 @@ const selectedUsers = ref({
|
|||||||
disabledUsers: []
|
disabledUsers: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 사용자 목록 업데이트 핸들러
|
// 사용자 목록 업데이트 핸들러
|
||||||
const handleEditUserListUpdate = (userLists) => {
|
const handleEditUserListUpdate = (userLists) => {
|
||||||
selectedUsers.value = userLists;
|
selectedUsers.value = userLists;
|
||||||
@ -356,12 +332,23 @@ const { colorList } = commonApi({
|
|||||||
colorType: 'YNP',
|
colorType: 'YNP',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 기존 컬러 + 사용 가능 한 컬러
|
// 기존 컬러 + 사용 가능 한 컬러
|
||||||
const allColors = computed(() => {
|
const allColors = computed(() => {
|
||||||
const existingColor = { value: selectedProject.value.PROJCTCOL, label: selectedProject.value.projctcolor };
|
// 먼저 기존 컬러 객체를 생성 (이 컬러는 항상 목록에 포함되어야 함)
|
||||||
return [existingColor, ...colorList.value];
|
const existingColor = {
|
||||||
|
value: props.projctCol, // 원래 프로젝트의 컬러 값 사용
|
||||||
|
label: props.projctColor // 원래 프로젝트의 컬러 레이블 사용
|
||||||
|
};
|
||||||
|
|
||||||
|
// 중복 제거를 위해 기존 컬러 값과 다른 컬러만 필터링
|
||||||
|
const otherColors = colorList.value.filter(color => color.value !== existingColor.value);
|
||||||
|
|
||||||
|
// 기존 컬러를 첫 번째로 놓고 나머지 컬러 추가
|
||||||
|
return [existingColor, ...otherColors];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 수정 :: 주소
|
// 수정 :: 주소
|
||||||
const updateAddress = addressData => {
|
const updateAddress = addressData => {
|
||||||
selectedProject.value = {
|
selectedProject.value = {
|
||||||
@ -434,9 +421,16 @@ const closeEditModal = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// selectedUsers 값 변경 감지
|
||||||
|
watch(() => selectedUsers.value.activeUsers, (newVal, oldVal) => {
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
watch(() => selectedUsers.value.disabledUsers, (newVal, oldVal) => {
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
// 변경된 내용 있는지 확인
|
// 변경된 내용 있는지 확인
|
||||||
const hasChanges = computed(() => {
|
const hasChanges = computed(() => {
|
||||||
// 기존 변경 확인 코드
|
// 기본 변경 확인 코드
|
||||||
const basicChanges = selectedProject.value.PROJCTNAM !== props.title ||
|
const basicChanges = selectedProject.value.PROJCTNAM !== props.title ||
|
||||||
selectedProject.value.PROJCTSTR !== props.strdate ||
|
selectedProject.value.PROJCTSTR !== props.strdate ||
|
||||||
selectedProject.value.PROJCTEND !== props.enddate ||
|
selectedProject.value.PROJCTEND !== props.enddate ||
|
||||||
@ -446,8 +440,8 @@ const hasChanges = computed(() => {
|
|||||||
selectedProject.value.PROJCTDES !== props.description ||
|
selectedProject.value.PROJCTDES !== props.description ||
|
||||||
selectedProject.value.PROJCTCOL !== props.projctCol;
|
selectedProject.value.PROJCTCOL !== props.projctCol;
|
||||||
|
|
||||||
const userChanges = selectedUsers.value.activeUsers.length > 0 ||
|
// 사용자 목록 변경 확인
|
||||||
selectedUsers.value.disabledUsers.length > 0;
|
const userChanges = editUserListRef.value?.hasUserChanges() || false;
|
||||||
|
|
||||||
return basicChanges || userChanges;
|
return basicChanges || userChanges;
|
||||||
});
|
});
|
||||||
@ -473,8 +467,9 @@ watch(() => props.resetUserSelection, () => {
|
|||||||
// 프로젝트 수정
|
// 프로젝트 수정
|
||||||
const handleUpdate = async () => {
|
const handleUpdate = async () => {
|
||||||
nameAlert.value = selectedProject.value.PROJCTNAM.trim() === '';
|
nameAlert.value = selectedProject.value.PROJCTNAM.trim() === '';
|
||||||
|
startDayAlert.value = selectedProject.value.PROJCTSTR.trim() === '';
|
||||||
|
|
||||||
if (nameAlert.value) {
|
if (nameAlert.value || startDayAlert.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,35 +499,44 @@ const handleUpdate = async () => {
|
|||||||
toastStore.onToast('수정이 완료 되었습니다.', 's');
|
toastStore.onToast('수정이 완료 되었습니다.', 's');
|
||||||
|
|
||||||
// 프로젝트 목록 새로고침
|
// 프로젝트 목록 새로고침
|
||||||
await projectStore.getProjectList();
|
await projectStore.getProjectList(props.searchParams.text, props.searchParams.year, 'false');
|
||||||
await projectStore.getMemberProjects();
|
await projectStore.getMemberProjects();
|
||||||
|
await refreshColorList('YNP');
|
||||||
|
|
||||||
await editUserListRef.value.fetchProjectParticipation();
|
await editUserListRef.value.fetchProjectParticipation();
|
||||||
await userListRef.value.fetchProjectParticipation();
|
await userListRef.value.fetchProjectParticipation();
|
||||||
|
|
||||||
closeEditModal();
|
closeEditModal();
|
||||||
emit('update');
|
emit('update', props.searchParams);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 주소를 좌표로 변환하는 함수
|
// 주소를 좌표로 변환하는 함수
|
||||||
const convertAddressToCoordinates = () => {
|
const convertAddressToCoordinates = () => {
|
||||||
const geocoder = new window.kakao.maps.services.Geocoder();
|
// kakao maps API가 로드되었는지 확인
|
||||||
|
if (window.kakao && window.kakao.maps) {
|
||||||
geocoder.addressSearch(props.address, (result, status) => {
|
const geocoder = new window.kakao.maps.services.Geocoder();
|
||||||
if (status === window.kakao.maps.services.Status.OK) {
|
geocoder.addressSearch(props.address, (result, status) => {
|
||||||
coordinates.value = {
|
if (status === window.kakao.maps.services.Status.OK) {
|
||||||
lat: parseFloat(result[0].y),
|
coordinates.value = {
|
||||||
lng: parseFloat(result[0].x)
|
lat: parseFloat(result[0].y),
|
||||||
};
|
lng: parseFloat(result[0].x)
|
||||||
} else {
|
};
|
||||||
// 기본 좌표 설정 (본사)
|
} else {
|
||||||
coordinates.value = {
|
// 기본 좌표 설정 (본사)
|
||||||
lat: 37.2108651707078,
|
coordinates.value = {
|
||||||
lng: 127.089445559923
|
lat: 37.2108651707078,
|
||||||
};
|
lng: 127.089445559923
|
||||||
}
|
};
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 기본 좌표로 설정
|
||||||
|
coordinates.value = {
|
||||||
|
lat: 37.2108651707078,
|
||||||
|
lng: 127.089445559923
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLoadKakaoMap = (mapRef) => {
|
const onLoadKakaoMap = (mapRef) => {
|
||||||
@ -581,13 +585,4 @@ onMounted(async () => {
|
|||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
.hidden-date-input {
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 40px;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -25,7 +25,8 @@
|
|||||||
:projctColor="post.projctcolor"
|
:projctColor="post.projctcolor"
|
||||||
:projctCreatorId="post.PROJCTCMB"
|
:projctCreatorId="post.PROJCTCMB"
|
||||||
:resetUserSelection="resetUserSelection"
|
:resetUserSelection="resetUserSelection"
|
||||||
@update="getProjectList"
|
:searchParams="{ text: searchText, year: selectedYear }"
|
||||||
|
@update="handleProjectUpdate"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -52,6 +53,7 @@
|
|||||||
:is-label="true"
|
:is-label="true"
|
||||||
:is-common="true"
|
:is-common="true"
|
||||||
:is-color="true"
|
:is-color="true"
|
||||||
|
:value="color"
|
||||||
:data="colorList"
|
:data="colorList"
|
||||||
@update:data="color = $event"
|
@update:data="color = $event"
|
||||||
/>
|
/>
|
||||||
@ -69,29 +71,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="date-picker-wrapper" @click="focusStartDateInput">
|
<FormInput
|
||||||
<FormInput
|
title="시작 일"
|
||||||
title="시작 일"
|
name="startDay"
|
||||||
name="startDay"
|
:type="'date'"
|
||||||
:type="'date'"
|
:is-alert="startDayAlert"
|
||||||
:is-essential="true"
|
:is-essential="true"
|
||||||
:modelValue="startDay"
|
:modelValue="startDay"
|
||||||
v-model="startDay"
|
v-model="startDay"
|
||||||
/>
|
/>
|
||||||
<input ref="startDateInput" type="date" v-model="startDay" class="hidden-start-input">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="date-picker-wrapper" @click="focusEndDateInput">
|
<FormInput
|
||||||
<FormInput
|
title="종료 일"
|
||||||
title="종료 일"
|
name="endDay"
|
||||||
name="endDay"
|
:type="'date'"
|
||||||
:type="'date'"
|
:modelValue="endDay"
|
||||||
:modelValue="endDay"
|
:min="startDay"
|
||||||
:min="startDay"
|
@update:modelValue="endDay = $event"
|
||||||
@update:modelValue="endDay = $event"
|
/>
|
||||||
/>
|
|
||||||
<input ref="endDateInput" type="date" v-model="endDay" class="hidden-end-input">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormInput
|
<FormInput
|
||||||
title="설명"
|
title="설명"
|
||||||
@ -113,7 +110,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<BackButton type="reset" @click="closeCreateModal" />
|
<BackButton type="reset" @click="closeCreateModal" />
|
||||||
<SaveButton :disabled="!color" @click="handleCreate" />
|
<SaveButton @click="handleCreate" />
|
||||||
</template>
|
</template>
|
||||||
</CenterModal>
|
</CenterModal>
|
||||||
</form>
|
</form>
|
||||||
@ -130,7 +127,7 @@
|
|||||||
import FormInput from '@c/input/FormInput.vue';
|
import FormInput from '@c/input/FormInput.vue';
|
||||||
import ArrInput from '@c/input/ArrInput.vue';
|
import ArrInput from '@c/input/ArrInput.vue';
|
||||||
import UserList from '@c/user/UserList.vue';
|
import UserList from '@c/user/UserList.vue';
|
||||||
import commonApi from '@/common/commonApi';
|
import commonApi, { refreshColorList } from '@/common/commonApi';
|
||||||
import { useToastStore } from '@s/toastStore';
|
import { useToastStore } from '@s/toastStore';
|
||||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
import { useProjectStore } from '@/stores/useProjectStore';
|
import { useProjectStore } from '@/stores/useProjectStore';
|
||||||
@ -159,38 +156,15 @@
|
|||||||
// 등록 모달 상태
|
// 등록 모달 상태
|
||||||
const isCreateModalOpen = ref(false);
|
const isCreateModalOpen = ref(false);
|
||||||
const name = ref('');
|
const name = ref('');
|
||||||
const color = ref('');
|
const color = ref('0');
|
||||||
|
|
||||||
const startDay = ref(today);
|
const startDay = ref(today);
|
||||||
const endDay = ref('');
|
const endDay = ref('');
|
||||||
const description = ref('');
|
const description = ref('');
|
||||||
const nameAlert = ref(false);
|
const nameAlert = ref(false);
|
||||||
const addressAlert = ref(false);
|
const addressAlert = ref(false);
|
||||||
|
const startDayAlert = ref(false);
|
||||||
|
|
||||||
const startDateInput = ref(null);
|
|
||||||
const endDateInput = ref(null);
|
|
||||||
|
|
||||||
const focusStartDateInput = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
if (startDateInput.value) {
|
|
||||||
startDateInput.value.focus();
|
|
||||||
setTimeout(() => {
|
|
||||||
startDateInput.value.showPicker?.();
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const focusEndDateInput = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
if (endDateInput.value) {
|
|
||||||
endDateInput.value.focus();
|
|
||||||
setTimeout(() => {
|
|
||||||
endDateInput.value.showPicker?.();
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const addressData = ref({
|
const addressData = ref({
|
||||||
postcode: '',
|
postcode: '',
|
||||||
@ -241,7 +215,13 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 등록 모달 관리
|
// 등록 모달 관리
|
||||||
const openCreateModal = () => {
|
const openCreateModal = async () => {
|
||||||
|
const updatedColors = await refreshColorList('YNP');
|
||||||
|
|
||||||
|
if (updatedColors && updatedColors.length > 0) {
|
||||||
|
color.value = updatedColors[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
isCreateModalOpen.value = true;
|
isCreateModalOpen.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -251,8 +231,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const formReset = () => {
|
const formReset = () => {
|
||||||
|
|
||||||
name.value = '';
|
name.value = '';
|
||||||
color.value = colorList.value.length > 0 ? colorList.value[0].value : '';
|
color.value = colorList.value[0].value;
|
||||||
addressData.value = {
|
addressData.value = {
|
||||||
postcode: '',
|
postcode: '',
|
||||||
address: '',
|
address: '',
|
||||||
@ -262,6 +243,8 @@
|
|||||||
endDay.value = '';
|
endDay.value = '';
|
||||||
description.value = '';
|
description.value = '';
|
||||||
nameAlert.value = false;
|
nameAlert.value = false;
|
||||||
|
addressAlert.value = false;
|
||||||
|
startDayAlert.value = false;
|
||||||
|
|
||||||
selectedUsers.value = {
|
selectedUsers.value = {
|
||||||
activeUsers: [],
|
activeUsers: [],
|
||||||
@ -271,6 +254,7 @@
|
|||||||
if (userListRef.value) {
|
if (userListRef.value) {
|
||||||
userListRef.value.resetSelection();
|
userListRef.value.resetSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -286,13 +270,30 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleProjectUpdate = async (params) => {
|
||||||
|
if (params) {
|
||||||
|
await projectStore.getProjectList(params.text, params.year, 'false');
|
||||||
|
} else {
|
||||||
|
await projectStore.getProjectList(searchText.value, selectedYear.value, 'false');
|
||||||
|
}
|
||||||
|
await projectStore.getMemberProjects();
|
||||||
|
|
||||||
|
// 컬러 목록 새로고침 및 결과 확인
|
||||||
|
const updatedColors = await refreshColorList('YNP');
|
||||||
|
|
||||||
|
// 컬러 선택값 초기화 (필요시)
|
||||||
|
if (updatedColors && updatedColors.length > 0) {
|
||||||
|
color.value = updatedColors[0].value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 프로젝트 등록
|
// 프로젝트 등록
|
||||||
const handleCreate = async () => {
|
const handleCreate = async () => {
|
||||||
nameAlert.value = name.value.trim() === '';
|
nameAlert.value = name.value.trim() === '';
|
||||||
|
startDayAlert.value = startDay.value.trim() === '';
|
||||||
addressAlert.value = addressData.value.address.trim() === '';
|
addressAlert.value = addressData.value.address.trim() === '';
|
||||||
|
|
||||||
if (nameAlert.value || addressAlert.value) {
|
if (nameAlert.value || startDayAlert.value || addressAlert.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,10 +315,15 @@
|
|||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
toastStore.onToast('프로젝트가 등록되었습니다.', 's');
|
toastStore.onToast('프로젝트가 등록되었습니다.', 's');
|
||||||
closeCreateModal();
|
|
||||||
getProjectList();
|
colorList.value = colorList.value.filter(c => c.value !== color.value);
|
||||||
projectStore.getMemberProjects();
|
|
||||||
formReset();
|
formReset();
|
||||||
|
|
||||||
|
await getProjectList();
|
||||||
|
await projectStore.getMemberProjects();
|
||||||
|
|
||||||
|
closeCreateModal();
|
||||||
resetUserSelection.value = !resetUserSelection.value;
|
resetUserSelection.value = !resetUserSelection.value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -326,5 +332,7 @@
|
|||||||
await getProjectList();
|
await getProjectList();
|
||||||
await userStore.userInfo();
|
await userStore.userInfo();
|
||||||
user.value = userStore.user;
|
user.value = userStore.user;
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import { nextTick, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import UserFormInput from '@c/input/UserFormInput.vue';
|
import UserFormInput from '@c/input/UserFormInput.vue';
|
||||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
|
|
||||||
@ -79,8 +79,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 로그인 성공 처리
|
// 로그인 성공 처리
|
||||||
userStore.userInfo();
|
await userStore.userInfo();
|
||||||
await nextTick();
|
|
||||||
router.push('/');
|
router.push('/');
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|||||||
@ -54,6 +54,10 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 원래 비활성화된 사용자 목록 저장
|
||||||
|
const originalDisabledUsers = ref([]);
|
||||||
|
|
||||||
|
|
||||||
const resetSelection = async () => {
|
const resetSelection = async () => {
|
||||||
// 모든 사용자를 활성화 상태로 초기화
|
// 모든 사용자를 활성화 상태로 초기화
|
||||||
if (props.projctSeq) {
|
if (props.projctSeq) {
|
||||||
@ -107,11 +111,16 @@ const fetchProjectParticipation = async () => {
|
|||||||
...user,
|
...user,
|
||||||
PROJCTYON: projectMembers.find(pm => pm.MEMBERSEQ === user.MEMBERSEQ)?.PROJCTYON ?? '1'
|
PROJCTYON: projectMembers.find(pm => pm.MEMBERSEQ === user.MEMBERSEQ)?.PROJCTYON ?? '1'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 원래 비활성화된 사용자 목록 저장
|
||||||
|
originalDisabledUsers.value = userList.value
|
||||||
|
.filter(user => user.PROJCTYON === '0')
|
||||||
|
.map(user => user.MEMBERSEQ);
|
||||||
|
|
||||||
emitUserListUpdate();
|
emitUserListUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 사용자별 프로젝트 참여 기간 조회
|
// 사용자별 프로젝트 참여 기간 조회
|
||||||
const fetchUserProjectPeriods = async () => {
|
const fetchUserProjectPeriods = async () => {
|
||||||
if (props.projctSeq) {
|
if (props.projctSeq) {
|
||||||
@ -223,9 +232,29 @@ const getTooltipTitle = (user) => {
|
|||||||
return userName;
|
return userName;
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
resetSelection, fetchProjectParticipation
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const hasUserChanges = () => {
|
||||||
|
if (!props.projctSeq) return false;
|
||||||
|
|
||||||
|
const currentDisabledUserIds = userList.value
|
||||||
|
.filter(user => user.PROJCTYON === '0')
|
||||||
|
.map(user => user.MEMBERSEQ);
|
||||||
|
|
||||||
|
// 길이가 다르면 변경된 것임
|
||||||
|
if (currentDisabledUserIds.length !== originalDisabledUsers.value.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 길이가 같더라도 포함된 ID가 다르면 변경된 것임
|
||||||
|
return currentDisabledUserIds.some(id => !originalDisabledUsers.value.includes(id)) ||
|
||||||
|
originalDisabledUsers.value.some(id => !currentDisabledUserIds.includes(id));
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose에 메서드 추가
|
||||||
|
defineExpose({
|
||||||
|
resetSelection,
|
||||||
|
fetchProjectParticipation,
|
||||||
|
hasUserChanges
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import { defineStore } from 'pinia';
|
|||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
import { useAuthStore } from '@/stores/useAuthStore';
|
|
||||||
|
|
||||||
export const useProjectStore = defineStore('project', () => {
|
export const useProjectStore = defineStore('project', () => {
|
||||||
const projectList = ref([]); // 모든 프로젝트 (종료된 프로젝트 포함)
|
const projectList = ref([]); // 모든 프로젝트 (종료된 프로젝트 포함)
|
||||||
@ -18,7 +17,6 @@ export const useProjectStore = defineStore('project', () => {
|
|||||||
const activeMemberProjectList = ref([]); // 사용자가 속한 진행 중인 프로젝트
|
const activeMemberProjectList = ref([]); // 사용자가 속한 진행 중인 프로젝트
|
||||||
const selectedProject = ref(null);
|
const selectedProject = ref(null);
|
||||||
const userStore = useUserInfoStore();
|
const userStore = useUserInfoStore();
|
||||||
const authStore = useAuthStore();
|
|
||||||
|
|
||||||
// 전체 프로젝트 가져오기 (종료된 프로젝트 포함 여부에 따라 다른 배열에 저장)
|
// 전체 프로젝트 가져오기 (종료된 프로젝트 포함 여부에 따라 다른 배열에 저장)
|
||||||
const getProjectList = async (searchText = '', selectedYear = '', excludeEnded = 'false') => {
|
const getProjectList = async (searchText = '', selectedYear = '', excludeEnded = 'false') => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user