diff --git a/src/common/commonApi.js b/src/common/commonApi.js index 27a5a7f..dcda0e8 100644 --- a/src/common/commonApi.js +++ b/src/common/commonApi.js @@ -8,28 +8,42 @@ import { ref, onMounted } from "vue"; import $api from '@api'; -const commonApi = (options = {}) => { - const colorList = ref([]); - const mbtiList = ref([]); - const pwhintList = ref([]); - const yearCategory = ref([]); - const cateList = ref([]); +const colorList = ref([]); +const mbtiList = ref([]); +const pwhintList = ref([]); +const yearCategory = ref([]); +const cateList = ref([]); - // type 파라미터를 추가로 받도록 수정 - 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 => ({ +const refreshColorList = async (type = 'YNP') => { + const response = await $api.get(`user/color`, { + params: { type } + }); + + if (response.data && response.data.data) { + colorList.value = response.data.data.map(item => ({ label: item.CMNCODNAM, 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 () => { // 요청할 데이터가 옵션으로 전달 -> 그에 맞게 호출 - // color 옵션에 type 포함 if (options.loadColor) { await CommonCode("user", "color", colorList, options.colorType); } @@ -39,7 +53,15 @@ const commonApi = (options = {}) => { 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; diff --git a/src/components/commuters/CommuterBtn.vue b/src/components/commuters/CommuterBtn.vue index ff46675..bd852b0 100644 --- a/src/components/commuters/CommuterBtn.vue +++ b/src/components/commuters/CommuterBtn.vue @@ -57,12 +57,13 @@ const getAddress = (lat, lng) => { const coord = new kakao.maps.LatLng(lat, lng); geocoder.coord2Address(coord.getLng(), coord.getLat(), (result, status) => { - if (status === kakao.maps.services.Status.OK) { - const address = result[0].address.address_name; - resolve(address); - } else { - reject('주소를 가져올 수 없습니다.'); - } + if (status === kakao.maps.services.Status.OK) { + const address = result[0].address.address_name; + resolve(address); + } else { + reject('주소를 가져올 수 없습니다.'); + return; + } }); }); }; diff --git a/src/components/commuters/CommuterCalendar.vue b/src/components/commuters/CommuterCalendar.vue index de30591..1c6a2b6 100644 --- a/src/components/commuters/CommuterCalendar.vue +++ b/src/components/commuters/CommuterCalendar.vue @@ -390,7 +390,7 @@ onMounted(async () => { await userStore.userInfo(); user.value = userStore.user; await projectStore.getProjectList('', '', 'true'); - project.value = projectStore.projectList; + project.value = projectStore.activeProjectList; await todaysCommuter(); diff --git a/src/components/input/FormSelect.vue b/src/components/input/FormSelect.vue index 915deaf..e535557 100644 --- a/src/components/input/FormSelect.vue +++ b/src/components/input/FormSelect.vue @@ -129,10 +129,11 @@ watch(selectData, (newValue) => { const selected = computed(() => { + // 현재 선택된 값에 해당하는 아이템 찾기 const selectedItem = props.data.find(item => props.isCommon ? item.value === selectData.value : props.data.indexOf(item) === selectData.value ); + return selectedItem ? selectedItem.label : null; }); - diff --git a/src/components/list/ProjectCard.vue b/src/components/list/ProjectCard.vue index 61a4dcf..5f841f9 100644 --- a/src/components/list/ProjectCard.vue +++ b/src/components/list/ProjectCard.vue @@ -7,7 +7,6 @@
{{ title }}
-

@@ -131,20 +130,17 @@
-
- -
-
- -
{ - 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 정의 const props = defineProps({ title: { @@ -250,6 +219,7 @@ const props = defineProps({ description: { type: String, required: false, + default: "", }, address: { type: String, @@ -282,6 +252,10 @@ const props = defineProps({ resetUserSelection: { type: Boolean, default: false + }, + searchParams: { + type: Object, + default: () => ({ text: '', year: null }) } }); @@ -302,6 +276,7 @@ const coordinates = ref(null); const isEditModalOpen = ref(false); const originalColor = ref(''); const nameAlert = ref(false); +const startDayAlert = ref(false); const user = ref(null); const editUserListRef = ref(null); @@ -312,6 +287,7 @@ const selectedUsers = ref({ disabledUsers: [] }); + // 사용자 목록 업데이트 핸들러 const handleEditUserListUpdate = (userLists) => { selectedUsers.value = userLists; @@ -356,12 +332,23 @@ const { colorList } = commonApi({ colorType: 'YNP', }); + // 기존 컬러 + 사용 가능 한 컬러 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 => { 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 basicChanges = selectedProject.value.PROJCTNAM !== props.title || selectedProject.value.PROJCTSTR !== props.strdate || selectedProject.value.PROJCTEND !== props.enddate || @@ -446,8 +440,8 @@ const hasChanges = computed(() => { selectedProject.value.PROJCTDES !== props.description || 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; }); @@ -473,8 +467,9 @@ watch(() => props.resetUserSelection, () => { // 프로젝트 수정 const handleUpdate = async () => { nameAlert.value = selectedProject.value.PROJCTNAM.trim() === ''; + startDayAlert.value = selectedProject.value.PROJCTSTR.trim() === ''; - if (nameAlert.value) { + if (nameAlert.value || startDayAlert.value) { return; } @@ -504,35 +499,44 @@ const handleUpdate = async () => { toastStore.onToast('수정이 완료 되었습니다.', 's'); // 프로젝트 목록 새로고침 - await projectStore.getProjectList(); + await projectStore.getProjectList(props.searchParams.text, props.searchParams.year, 'false'); await projectStore.getMemberProjects(); + await refreshColorList('YNP'); await editUserListRef.value.fetchProjectParticipation(); await userListRef.value.fetchProjectParticipation(); closeEditModal(); - emit('update'); + emit('update', props.searchParams); } }; // 주소를 좌표로 변환하는 함수 const convertAddressToCoordinates = () => { - const geocoder = new window.kakao.maps.services.Geocoder(); - - geocoder.addressSearch(props.address, (result, status) => { - if (status === window.kakao.maps.services.Status.OK) { - coordinates.value = { - lat: parseFloat(result[0].y), - lng: parseFloat(result[0].x) - }; - } else { - // 기본 좌표 설정 (본사) - coordinates.value = { - lat: 37.2108651707078, - lng: 127.089445559923 - }; - } - }); + // kakao maps API가 로드되었는지 확인 + if (window.kakao && window.kakao.maps) { + const geocoder = new window.kakao.maps.services.Geocoder(); + geocoder.addressSearch(props.address, (result, status) => { + if (status === window.kakao.maps.services.Status.OK) { + coordinates.value = { + lat: parseFloat(result[0].y), + lng: parseFloat(result[0].x) + }; + } else { + // 기본 좌표 설정 (본사) + coordinates.value = { + lat: 37.2108651707078, + lng: 127.089445559923 + }; + } + }); + } else { + // 기본 좌표로 설정 + coordinates.value = { + lat: 37.2108651707078, + lng: 127.089445559923 + }; + } }; const onLoadKakaoMap = (mapRef) => { @@ -581,13 +585,4 @@ onMounted(async () => { - + diff --git a/src/components/projectlist/ProjectList.vue b/src/components/projectlist/ProjectList.vue index 4aef41a..92baeea 100644 --- a/src/components/projectlist/ProjectList.vue +++ b/src/components/projectlist/ProjectList.vue @@ -25,7 +25,8 @@ :projctColor="post.projctcolor" :projctCreatorId="post.PROJCTCMB" :resetUserSelection="resetUserSelection" - @update="getProjectList" + :searchParams="{ text: searchText, year: selectedYear }" + @update="handleProjectUpdate" /> @@ -52,6 +53,7 @@ :is-label="true" :is-common="true" :is-color="true" + :value="color" :data="colorList" @update:data="color = $event" /> @@ -69,29 +71,24 @@ -
- - -
+ -
- - -
+ @@ -130,7 +127,7 @@ import FormInput from '@c/input/FormInput.vue'; import ArrInput from '@c/input/ArrInput.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 { useUserInfoStore } from '@/stores/useUserInfoStore'; import { useProjectStore } from '@/stores/useProjectStore'; @@ -159,38 +156,15 @@ // 등록 모달 상태 const isCreateModalOpen = ref(false); const name = ref(''); - const color = ref(''); + const color = ref('0'); const startDay = ref(today); const endDay = ref(''); const description = ref(''); const nameAlert = 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({ 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; }; @@ -251,8 +231,9 @@ }; const formReset = () => { + name.value = ''; - color.value = colorList.value.length > 0 ? colorList.value[0].value : ''; + color.value = colorList.value[0].value; addressData.value = { postcode: '', address: '', @@ -262,6 +243,8 @@ endDay.value = ''; description.value = ''; nameAlert.value = false; + addressAlert.value = false; + startDayAlert.value = false; selectedUsers.value = { activeUsers: [], @@ -271,6 +254,7 @@ if (userListRef.value) { 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 () => { nameAlert.value = name.value.trim() === ''; + startDayAlert.value = startDay.value.trim() === ''; addressAlert.value = addressData.value.address.trim() === ''; - if (nameAlert.value || addressAlert.value) { + if (nameAlert.value || startDayAlert.value || addressAlert.value) { return; } @@ -314,10 +315,15 @@ if (response.status === 200) { toastStore.onToast('프로젝트가 등록되었습니다.', 's'); - closeCreateModal(); - getProjectList(); - projectStore.getMemberProjects(); + + colorList.value = colorList.value.filter(c => c.value !== color.value); + formReset(); + + await getProjectList(); + await projectStore.getMemberProjects(); + + closeCreateModal(); resetUserSelection.value = !resetUserSelection.value; } }; @@ -326,5 +332,7 @@ await getProjectList(); await userStore.userInfo(); user.value = userStore.user; + + }); diff --git a/src/components/user/LoginForm.vue b/src/components/user/LoginForm.vue index 9c7ca7a..c14d8d3 100644 --- a/src/components/user/LoginForm.vue +++ b/src/components/user/LoginForm.vue @@ -32,7 +32,7 @@ diff --git a/src/stores/useProjectStore.js b/src/stores/useProjectStore.js index 152e35e..9580da7 100644 --- a/src/stores/useProjectStore.js +++ b/src/stores/useProjectStore.js @@ -9,7 +9,6 @@ import { defineStore } from 'pinia'; import { ref, watch } from 'vue'; import $api from '@api'; import { useUserInfoStore } from '@/stores/useUserInfoStore'; -import { useAuthStore } from '@/stores/useAuthStore'; export const useProjectStore = defineStore('project', () => { const projectList = ref([]); // 모든 프로젝트 (종료된 프로젝트 포함) @@ -18,7 +17,6 @@ export const useProjectStore = defineStore('project', () => { const activeMemberProjectList = ref([]); // 사용자가 속한 진행 중인 프로젝트 const selectedProject = ref(null); const userStore = useUserInfoStore(); - const authStore = useAuthStore(); // 전체 프로젝트 가져오기 (종료된 프로젝트 포함 여부에 따라 다른 배열에 저장) const getProjectList = async (searchText = '', selectedYear = '', excludeEnded = 'false') => {