From 15e7b42fd8693a27feb7523eb9ab9c8a1fff7413 Mon Sep 17 00:00:00 2001 From: seorang42 Date: Thu, 6 Feb 2025 02:17:12 +0900 Subject: [PATCH 01/10] =?UTF-8?q?:recycle:=20[refactor]=20:=20=ED=83=91?= =?UTF-8?q?=EB=B0=94=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EB=B0=8F=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=9D=BD=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/common.ts | 2 - src/components/TopBar.vue | 55 -------- .../top-bar/NotificationMessage.vue | 63 +++++++++ src/components/top-bar/NotificationModal.vue | 121 ++++++++---------- src/components/top-bar/ProfileModal.vue | 78 +++++------ src/components/top-bar/TopBar.vue | 67 ++++++---- src/constants/iconPath.ts | 8 +- src/types/common.ts | 18 +++ src/utils/getNotification.ts | 0 9 files changed, 214 insertions(+), 198 deletions(-) delete mode 100644 src/components/TopBar.vue create mode 100644 src/components/top-bar/NotificationMessage.vue create mode 100644 src/utils/getNotification.ts diff --git a/src/api/common.ts b/src/api/common.ts index 73c05ae7..0952c336 100644 --- a/src/api/common.ts +++ b/src/api/common.ts @@ -8,13 +8,11 @@ export const getNotification = async (pageNum: number, sizeNum: number) => { export const patchNotificationRead = async (notificationId: number) => { const response = await axiosInstance.patch(`/api/notification/${notificationId}`) - console.log(notificationId) return response.data } export const getNotifiCount = async () => { const response = await axiosInstance.get(`/api/notifications/count`) - console.log(response.data) return response.data } diff --git a/src/components/TopBar.vue b/src/components/TopBar.vue deleted file mode 100644 index 5f74dcba..00000000 --- a/src/components/TopBar.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/src/components/top-bar/NotificationMessage.vue b/src/components/top-bar/NotificationMessage.vue new file mode 100644 index 00000000..e0768d49 --- /dev/null +++ b/src/components/top-bar/NotificationMessage.vue @@ -0,0 +1,63 @@ + + + diff --git a/src/components/top-bar/NotificationModal.vue b/src/components/top-bar/NotificationModal.vue index 9027748c..35622a31 100644 --- a/src/components/top-bar/NotificationModal.vue +++ b/src/components/top-bar/NotificationModal.vue @@ -1,91 +1,74 @@ diff --git a/src/components/top-bar/ProfileModal.vue b/src/components/top-bar/ProfileModal.vue index f5e1088b..3f0f7f11 100644 --- a/src/components/top-bar/ProfileModal.vue +++ b/src/components/top-bar/ProfileModal.vue @@ -1,54 +1,47 @@ diff --git a/src/constants/iconPath.ts b/src/constants/iconPath.ts index ad957c46..88617697 100644 --- a/src/constants/iconPath.ts +++ b/src/constants/iconPath.ts @@ -77,10 +77,10 @@ export const deleteIcon = { } export const smallCheckIcon = { - path: 'M7.35497 0.605052C7.30849 0.558188 7.25319 0.520991 7.19226 0.495607C7.13133 0.470222 7.06598 0.457153 6.99997 0.457153C6.93397 0.457153 6.86862 0.470222 6.80769 0.495607C6.74676 0.520991 6.69146 0.558188 6.64498 0.605052L2.91998 4.33505L1.35497 2.76505C1.30671 2.71843 1.24974 2.68178 1.18732 2.65717C1.12489 2.63257 1.05823 2.62051 0.991136 2.62167C0.924046 2.62283 0.857841 2.63719 0.796302 2.66394C0.734763 2.69069 0.679094 2.72929 0.632475 2.77755C0.585856 2.82581 0.549199 2.88278 0.524597 2.94521C0.499995 3.00764 0.487929 3.0743 0.48909 3.14139C0.490251 3.20848 0.504615 3.27469 0.531362 3.33623C0.558108 3.39776 0.596714 3.45343 0.644975 3.50005L2.56498 5.42005C2.61146 5.46692 2.66676 5.50411 2.72769 5.5295C2.78862 5.55488 2.85397 5.56795 2.91998 5.56795C2.98598 5.56795 3.05133 5.55488 3.11226 5.5295C3.17319 5.50411 3.22849 5.46692 3.27498 5.42005L7.35497 1.34005C7.40573 1.29323 7.44623 1.23641 7.47393 1.17316C7.50164 1.10991 7.51594 1.0416 7.51594 0.972552C7.51594 0.903502 7.50164 0.835199 7.47393 0.771949C7.44623 0.708699 7.40573 0.651874 7.35497 0.605052Z', - width: 8, - height: 6, - fill: '#A1A1AA' + path: 'M12.4733 4.80657C12.4114 4.74409 12.3376 4.69449 12.2564 4.66065C12.1752 4.6268 12.088 4.60938 12 4.60938C11.912 4.60938 11.8249 4.6268 11.7436 4.66065C11.6624 4.69449 11.5886 4.74409 11.5267 4.80657L6.56001 9.77991L4.47334 7.68657C4.40899 7.62441 4.33303 7.57554 4.2498 7.54274C4.16656 7.50993 4.07768 7.49385 3.98822 7.49539C3.89877 7.49694 3.8105 7.51609 3.72844 7.55176C3.64639 7.58742 3.57217 7.63889 3.51001 7.70324C3.44785 7.76759 3.39897 7.84355 3.36617 7.92679C3.33337 8.01002 3.31728 8.0989 3.31883 8.18836C3.32038 8.27781 3.33953 8.36609 3.37519 8.44814C3.41085 8.53019 3.46233 8.60441 3.52667 8.66657L6.08667 11.2266C6.14865 11.2891 6.22238 11.3387 6.30362 11.3725C6.38486 11.4063 6.472 11.4238 6.56001 11.4238C6.64802 11.4238 6.73515 11.4063 6.81639 11.3725C6.89763 11.3387 6.97137 11.2891 7.03334 11.2266L12.4733 5.78657C12.541 5.72415 12.595 5.64838 12.632 5.56404C12.6689 5.47971 12.688 5.38864 12.688 5.29657C12.688 5.20451 12.6689 5.11344 12.632 5.0291C12.595 4.94477 12.541 4.869 12.4733 4.80657Z', + width: 16, + height: 16, + fill: '#7879EB' } export const plusIcon = { diff --git a/src/types/common.ts b/src/types/common.ts index 0315014d..4bd3b31e 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -109,3 +109,21 @@ export interface TaskStatusListTypes { value: Status content: string } + +export type NotificationType = + | 'COMMENT' + | 'TASK_REQUESTED' + | 'STATUS_SWITCHED' + | 'PROCESSOR_ASSIGNED' + | 'PROCESSOR_CHANGED' + +export interface NotificationContent { + notificationId: number + taskId: number + notificationType: NotificationType + receiverId: number + taskTitle: string + message: string + isRead: boolean + createdAt: string +} diff --git a/src/utils/getNotification.ts b/src/utils/getNotification.ts new file mode 100644 index 00000000..e69de29b From 3472269c8ab50fa34a5ef07a64e222ec3ed551db Mon Sep 17 00:00:00 2001 From: seorang42 Date: Thu, 6 Feb 2025 11:12:15 +0900 Subject: [PATCH 02/10] =?UTF-8?q?:recycle:=20[refactor]=20:=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EB=A1=9C=EA=B7=B8=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EC=A0=90=EA=B2=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.ts | 24 ++-------- src/components/top-bar/ProfileModal.vue | 11 +++-- src/components/top-bar/SideBar.vue | 10 ++-- src/components/top-bar/TopBar.vue | 21 ++++----- src/stores/member.ts | 62 +++++++++++++------------ src/types/auth.ts | 15 ++++-- src/views/LoginView.vue | 10 ++-- 7 files changed, 73 insertions(+), 80 deletions(-) diff --git a/src/api/auth.ts b/src/api/auth.ts index 653a443f..d0a72aec 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -3,11 +3,8 @@ import Cookies from 'js-cookie' import type { loginDataTypes } from '@/types/auth' import { useMemberStore } from '@/stores/member' -export const postLogin = async (loginData: loginDataTypes, sessionId: string) => { - const memberStore = useMemberStore() - const response = await axiosInstance.post('/api/auths/login', loginData, { - headers: { sessionId: sessionId } - }) +export const postLogin = async (loginData: loginDataTypes) => { + const response = await axiosInstance.post('/api/auths/login', loginData, {}) Cookies.set('accessToken', response.data.accessToken, { path: '/', sameSite: 'strict' @@ -16,8 +13,6 @@ export const postLogin = async (loginData: loginDataTypes, sessionId: string) => path: '/', sameSite: 'strict' }) - - await memberStore.updateMemberInfoWithToken() return response.data } @@ -29,16 +24,7 @@ export const patchPassword = async (password: string) => { export const deleteLogout = async () => { const memberStore = useMemberStore() - const refreshToken = Cookies.get('refreshToken') - - const response = await axiosInstance.delete('/api/auths/logout', { - headers: { - Authorization: `Bearer ${import.meta.env.VITE_ACCESS_TOKEN}`, - refreshToken: refreshToken - } - }) - Cookies.remove('accessToken', { path: '/' }) - Cookies.remove('refreshToken', { path: '/' }) - await memberStore.updateMemberInfoWithToken() - return response + memberStore.$reset() + Cookies.remove('accessToken') + Cookies.remove('refreshToken') } diff --git a/src/components/top-bar/ProfileModal.vue b/src/components/top-bar/ProfileModal.vue index 3f0f7f11..0019037a 100644 --- a/src/components/top-bar/ProfileModal.vue +++ b/src/components/top-bar/ProfileModal.vue @@ -9,7 +9,7 @@ 프로필 이미지
info.value.imageUrl) -const name = computed(() => info.value.memberName) -const nickname = computed(() => info.value.nickname) +const imgUrl = computed(() => info.value.profileImageUrl) +const name = computed(() => info.value.name) +const nickname = computed(() => info.value.nicknanme) const router = useRouter() @@ -85,8 +85,9 @@ const closeLogoutModal = () => { router.push('/login') } -const handleLogout = () => { +const handleLogout = async () => { deleteLogout() openLogoutModal() + emit('close') } diff --git a/src/components/top-bar/SideBar.vue b/src/components/top-bar/SideBar.vue index 7ba44dde..fd6b711c 100644 --- a/src/components/top-bar/SideBar.vue +++ b/src/components/top-bar/SideBar.vue @@ -40,9 +40,9 @@
프로필 이미지
info.value.memberRole) -const name = computed(() => info.value.memberName) -const nickname = computed(() => info.value.nickname) +const role = computed(() => info.value.role) +const name = computed(() => info.value.name) +const nickname = computed(() => info.value.nicknanme) const filteredMenu = computed(() => { return role.value === 'ROLE_USER' diff --git a/src/components/top-bar/TopBar.vue b/src/components/top-bar/TopBar.vue index aab65a1f..0643fa14 100644 --- a/src/components/top-bar/TopBar.vue +++ b/src/components/top-bar/TopBar.vue @@ -4,14 +4,14 @@
프로필 이미지
{ await memberStore.updateMemberInfoWithToken() const originUrl = route.path.split('/')[1] - if (info.value.memberRole === 'ROLE_USER') { + if (info.value.role === 'ROLE_USER') { if (!PERMITTED_URL.ROLE_USER.includes(originUrl)) router.push('/my-request') - } else if (info.value.memberRole === 'ROLE_MANAGER') { + } else if (info.value.role === 'ROLE_MANAGER') { if (!PERMITTED_URL.ROLE_MANAGER.includes(originUrl)) router.push('/my-task') - } else if (info.value.memberRole === 'ROLE_ADMIN') { + } else if (info.value.role === 'ROLE_ADMIN') { if (!PERMITTED_URL.ROLE_ADMIN.includes(originUrl)) router.push('/member-management') - } else { - if (!PERMITTED_URL.UNKNOWN.includes(originUrl)) { - router.push('/login') - } } }) @@ -99,6 +95,7 @@ const isNotifiVisible = ref(false) const isProfileVisible = ref(false) const fetchNotificationCount = async () => { + if (!isLogined.value) return try { const data = await getNotifiCount() countNotifi.value = data.count @@ -122,7 +119,7 @@ const onCloseSide = () => { watch( () => info.value, async newInfo => { - if (newInfo.memberName) { + if (newInfo.name) { await fetchNotificationCount() } }, diff --git a/src/stores/member.ts b/src/stores/member.ts index a3b1ef72..ea6a7cad 100644 --- a/src/stores/member.ts +++ b/src/stores/member.ts @@ -3,55 +3,57 @@ import { axiosInstance } from '@/utils/axios' import { ref } from 'vue' import type { User } from '@/types/auth' import Cookies from 'js-cookie' +import { useRouter } from 'vue-router' export const useMemberStore = defineStore('memberInfo', () => { - const info = ref({ - memberName: '', - nickname: '', - imageUrl: '', - memberRole: '', - memberStatus: '' - }) + const INITIAL_INFO: User = { + profileImageUrl: '', + name: '', + nicknanme: '', + email: '', + isReviewer: false, + role: '', + departmentName: '', + departmentRole: '' + } + const info = ref(INITIAL_INFO) const refreshToken = ref(Cookies.get('refreshToken') || '') const isLogined = ref(!!refreshToken.value) + const router = useRouter() async function updateMemberInfoWithToken() { - const response = await axiosInstance.get('/api/members/info') - console.log('API Response:', response.data) - updateMemberInfo(response.data) - isLogined.value = true - } - - function updateMemberInfo(responseData: any) { - info.value = { - memberName: responseData.name || '', - nickname: responseData.nicknanme || '', - imageUrl: responseData.profileImageUrl || '', - memberRole: responseData.role || '', - memberStatus: '' + if (!Cookies.get('accessToken')) { + router.push('/login') + return + } + try { + const { data }: { data: User } = await axiosInstance.get('/api/members/info') + info.value = data + isLogined.value = true + return data.role + } catch { + router.push('/login') } - console.log('Updated member info:', info.value) } function logout() { - info.value = { - memberName: '', - nickname: '', - imageUrl: '', - memberRole: '', - memberStatus: '' - } + $reset() isLogined.value = false Cookies.remove('accessToken') Cookies.remove('refreshToken') } + function $reset() { + isLogined.value = false + info.value = INITIAL_INFO + } + return { info, isLogined, - updateMemberInfo, updateMemberInfoWithToken, - logout + logout, + $reset } }) diff --git a/src/types/auth.ts b/src/types/auth.ts index 87007613..e1cd5cbe 100644 --- a/src/types/auth.ts +++ b/src/types/auth.ts @@ -1,9 +1,14 @@ +import type { Role } from './common' + export interface User { - memberName: string - nickname: string - imageUrl: string - memberRole: string - memberStatus: string + profileImageUrl: string + name: string + nicknanme: string + email: string + isReviewer: boolean + role: Role | '' + departmentName: string + departmentRole: string } export interface loginDataTypes { diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index 1dd39baf..85edf3a1 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -48,11 +48,13 @@ import { ref } from 'vue' import { useRouter } from 'vue-router' import { postLogin } from '@/api/auth' +import { useMemberStore } from '@/stores/member' const router = useRouter() const nickname = ref('') const password = ref('') +const memberStore = useMemberStore() const handleLogin = async () => { try { @@ -60,11 +62,11 @@ const handleLogin = async () => { nickname: nickname.value, password: password.value } - const sessionId = '000' - const res = await postLogin(loginData, sessionId) + const res = await postLogin(loginData) + const role = await memberStore.updateMemberInfoWithToken() - if (res) { - switch (res.memberInfo.memberRole) { + if (res && role) { + switch (role) { case 'ROLE_ADMIN': router.push('/member-management') break From 94caeb22fab7103d4f17278d52e364cbfbb09e0a Mon Sep 17 00:00:00 2001 From: seorang42 Date: Thu, 6 Feb 2025 11:41:04 +0900 Subject: [PATCH 03/10] =?UTF-8?q?:bug:=20[fix]=20=EC=9E=AC=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=8B=9C=20ProfileModal=20=EC=97=B4?= =?UTF-8?q?=EB=A0=A4=20=EC=9E=88=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/top-bar/ProfileModal.vue | 2 +- src/stores/member.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/top-bar/ProfileModal.vue b/src/components/top-bar/ProfileModal.vue index 0019037a..db00f98a 100644 --- a/src/components/top-bar/ProfileModal.vue +++ b/src/components/top-bar/ProfileModal.vue @@ -81,7 +81,7 @@ const openLogoutModal = () => { } const closeLogoutModal = () => { isModalVisible.value = false - emit('close') + memberStore.isLogined = false router.push('/login') } diff --git a/src/stores/member.ts b/src/stores/member.ts index ea6a7cad..150e918a 100644 --- a/src/stores/member.ts +++ b/src/stores/member.ts @@ -45,7 +45,6 @@ export const useMemberStore = defineStore('memberInfo', () => { } function $reset() { - isLogined.value = false info.value = INITIAL_INFO } From 3ef4c4c27ac618cebe53250697e5c6b8eba68b35 Mon Sep 17 00:00:00 2001 From: seorang42 Date: Thu, 6 Feb 2025 13:29:04 +0900 Subject: [PATCH 04/10] =?UTF-8?q?:bug:=20[fix]=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=A7=8C=EB=A3=8C=20=EC=8B=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.ts | 2 +- src/components/top-bar/ProfileModal.vue | 3 +-- src/utils/axios.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/api/auth.ts b/src/api/auth.ts index 2ec0d57d..7ec7a9eb 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -4,7 +4,7 @@ import type { loginDataTypes } from '@/types/auth' import { useMemberStore } from '@/stores/member' export const postLogin = async (loginData: loginDataTypes) => { - const response = await axiosInstance.post('/api/auths/login', loginData, {}) + const response = await axiosInstance.post('/api/auths/login', loginData) Cookies.set('accessToken', response.data.accessToken, { path: '/', sameSite: 'strict' diff --git a/src/components/top-bar/ProfileModal.vue b/src/components/top-bar/ProfileModal.vue index b16cdec8..811c2c52 100644 --- a/src/components/top-bar/ProfileModal.vue +++ b/src/components/top-bar/ProfileModal.vue @@ -78,11 +78,10 @@ const handleEdit = () => { } const openLogoutModal = () => { isModalVisible.value = true - isLogined.value = false } const closeLogoutModal = () => { isModalVisible.value = false - memberStore.isLogined = false + isLogined.value = false router.push('/login') } diff --git a/src/utils/axios.ts b/src/utils/axios.ts index 9c12f4c6..de4651c4 100644 --- a/src/utils/axios.ts +++ b/src/utils/axios.ts @@ -26,7 +26,7 @@ const getNewAccessToken = async () => { console.error('토큰 발행 실패', e) Cookies.remove('accessToken') Cookies.remove('refreshToken') - window.location.reload() + window.location.href = '/login' } } const setInterceptors = (instance: AxiosInstance) => { From 07ef7da329716c5d725589f2dfba47b0edf9d89c Mon Sep 17 00:00:00 2001 From: seorang42 Date: Thu, 6 Feb 2025 15:49:37 +0900 Subject: [PATCH 05/10] =?UTF-8?q?:recycle:=20[refactor]=20:=20TaskDetail?= =?UTF-8?q?=20=EC=A0=90=EA=B2=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/PieChart.vue | 5 +++-- src/components/lists/NoContent.vue | 2 +- .../my-request/MyRequestListCard.vue | 5 +++-- src/components/my-task/MyTaskListCard.vue | 5 +++-- .../RequestHistoryListCard.vue | 5 +++-- .../requested/RequestedListCard.vue | 5 +++-- .../statistics/StatisticsCategoryCard.vue | 5 ++++- src/components/task-detail/TaskDetail.vue | 19 +++++++++++-------- .../task-detail/TaskDetailHistoryChat.vue | 16 ++++++++++------ .../task-detail/TaskDetailHistoryInput.vue | 3 +-- .../task-detail/TaskDetailLabelDropdown.vue | 9 +++++++-- .../task-detail/TaskDetailRight.vue | 2 +- .../task-detail/TaskDetailTopBar.vue | 2 +- src/components/top-bar/TopBar.vue | 10 +++++++++- src/stores/scrollLock.ts | 8 ++++++++ 15 files changed, 68 insertions(+), 33 deletions(-) create mode 100644 src/stores/scrollLock.ts diff --git a/src/components/PieChart.vue b/src/components/PieChart.vue index ec71e3fc..795f1382 100644 --- a/src/components/PieChart.vue +++ b/src/components/PieChart.vue @@ -5,7 +5,7 @@ :options="options" /> + :content="!content ? `집계된 ${periodText[periodType]} 데이터가 없습니다` : content" /> diff --git a/src/components/task-detail/TaskDetailRight.vue b/src/components/task-detail/TaskDetailRight.vue index 7332f94e..3fa2fe92 100644 --- a/src/components/task-detail/TaskDetailRight.vue +++ b/src/components/task-detail/TaskDetailRight.vue @@ -1,5 +1,5 @@ From aab5a62ed55212eba8b27565ac9da359ea637a0d Mon Sep 17 00:00:00 2001 From: seorang42 Date: Fri, 7 Feb 2025 00:03:02 +0900 Subject: [PATCH 10/10] =?UTF-8?q?:sparkles:=20[feat]=20:=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=EC=9D=B4=20=EC=97=B4=EB=A0=A4=EC=9E=88=EC=9D=84=20?= =?UTF-8?q?=EB=95=8C=20=EC=83=81=EC=9C=84=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/PieChart.vue | 6 ++++-- src/components/icons/NotificationIcon.vue | 2 +- src/components/lists/NoContent.vue | 2 +- src/components/login-logs/LoginLogsListCard.vue | 4 ++-- src/components/my-request/MyRequestListCard.vue | 2 ++ src/components/my-task/MyTaskListCard.vue | 2 ++ .../request-history/RequestHistoryListCard.vue | 2 ++ src/components/requested/RequestedListCard.vue | 6 +++++- src/components/task-board/TaskBoard.vue | 9 ++++----- .../task-detail/TaskDetailManagerDropdown.vue | 7 ++++++- src/components/team-board/CurrentTaskRatio.vue | 9 ++++++--- src/components/top-bar/TopBar.vue | 10 ++++------ src/stores/scrollLock.ts | 8 -------- src/utils/date.ts | 17 +++++++++++++++++ 14 files changed, 56 insertions(+), 30 deletions(-) delete mode 100644 src/stores/scrollLock.ts diff --git a/src/components/PieChart.vue b/src/components/PieChart.vue index 795f1382..50239597 100644 --- a/src/components/PieChart.vue +++ b/src/components/PieChart.vue @@ -5,7 +5,9 @@ :options="options" /> + :content=" + !content && periodType ? `집계된 ${periodText[periodType]} 데이터가 없습니다` : content + " /> diff --git a/src/components/login-logs/LoginLogsListCard.vue b/src/components/login-logs/LoginLogsListCard.vue index d8346563..9624fbec 100644 --- a/src/components/login-logs/LoginLogsListCard.vue +++ b/src/components/login-logs/LoginLogsListCard.vue @@ -16,7 +16,7 @@ import type { ListCardProps } from '@/types/common' import ListCardTab from '../lists/ListCardTab.vue' import type { LoginLogsListData } from '@/types/admin' -import { formatDate } from '@/utils/date' +import { formatFullDateTime } from '@/utils/date' const logStatus = { LOGIN: '로그인 시도', @@ -31,7 +31,7 @@ const myRequestTabList: ListCardProps[] = [ isTextXs: true, isTextBody: true }, - { content: formatDate(info.requestAt), width: 180, isTextXs: true }, + { content: formatFullDateTime(info.requestAt), width: 180, isTextXs: true }, { content: info.nickName, width: 80 }, { content: info.clientIp, width: 120, isTextXs: true }, { content: String(info.statusCode), width: 40, isTextXs: true, isStatusCode: true }, diff --git a/src/components/my-request/MyRequestListCard.vue b/src/components/my-request/MyRequestListCard.vue index 8b392d68..390a61a5 100644 --- a/src/components/my-request/MyRequestListCard.vue +++ b/src/components/my-request/MyRequestListCard.vue @@ -30,6 +30,8 @@ const { info } = defineProps<{ info: MyRequestListData }>() const selectedID = ref(null) const handleModal = (id: number | null) => { + if (id) document.body.style.overflow = 'hidden' + else document.body.style.overflow = '' selectedID.value = id } diff --git a/src/components/my-task/MyTaskListCard.vue b/src/components/my-task/MyTaskListCard.vue index 76c9f1e1..d9d24c9c 100644 --- a/src/components/my-task/MyTaskListCard.vue +++ b/src/components/my-task/MyTaskListCard.vue @@ -30,6 +30,8 @@ const { info } = defineProps<{ info: MyTaskListData }>() const selectedID = ref(null) const handleModal = (id: number | null) => { + if (id) document.body.style.overflow = 'hidden' + else document.body.style.overflow = '' selectedID.value = id } const myRequestTabList: ListCardProps[] = [ diff --git a/src/components/request-history/RequestHistoryListCard.vue b/src/components/request-history/RequestHistoryListCard.vue index f781d8e5..000b85c9 100644 --- a/src/components/request-history/RequestHistoryListCard.vue +++ b/src/components/request-history/RequestHistoryListCard.vue @@ -30,6 +30,8 @@ const { info } = defineProps<{ info: RequestHistoryListData }>() const selectedID = ref(null) const handleModal = (id: number | null) => { + if (id) document.body.style.overflow = 'hidden' + else document.body.style.overflow = '' selectedID.value = id } const myRequestTabList: ListCardProps[] = [ diff --git a/src/components/requested/RequestedListCard.vue b/src/components/requested/RequestedListCard.vue index 5c78fdb8..248e08e1 100644 --- a/src/components/requested/RequestedListCard.vue +++ b/src/components/requested/RequestedListCard.vue @@ -17,7 +17,7 @@ 승인 @@ -75,6 +75,8 @@ const requestedTabList: ListCardProps[] = [ const selectedID = ref(null) const handleModal = (id: number | null) => { + if (id) document.body.style.overflow = 'hidden' + else document.body.style.overflow = '' selectedID.value = id } @@ -89,11 +91,13 @@ const isModalVisible = ref({ const modalError = ref('') const rejectReason = ref('') const toggleModal = (key: keyof typeof isModalVisible.value) => { + document.body.style.overflow = 'hidden' isModalVisible.value = Object.fromEntries( Object.keys(isModalVisible.value).map(k => [k, k === key]) ) as typeof isModalVisible.value } const closeModal = () => { + document.body.style.overflow = '' const prevSuccess = isModalVisible.value.success isModalVisible.value = { reject: false, fail: false, success: false } if (prevSuccess) queryClient.invalidateQueries({ queryKey: ['requested'] }) diff --git a/src/components/task-board/TaskBoard.vue b/src/components/task-board/TaskBoard.vue index 07f51035..c7cd4823 100644 --- a/src/components/task-board/TaskBoard.vue +++ b/src/components/task-board/TaskBoard.vue @@ -8,7 +8,7 @@
- 검토 중 {{ data?.tasksInProgress.length }} + 검토 중 {{ data?.tasksInReviewing.length }}
@@ -47,7 +47,7 @@
{{ '상태를 변경할 작업을\n끌어 놓으세요' }} @@ -55,7 +55,7 @@
{ targetTaskId, nextTaskId } - console.log(prevTaskId, targetTaskId, nextTaskId) await axiosInstance.patch('/api/task-board', body, { params: { status } }) queryClient.invalidateQueries({ queryKey: ['taskBoard'] }) } @@ -172,6 +171,6 @@ const { data } = useQuery({ }) const tasksInProgress = computed(() => [...(data.value?.tasksInProgress || [])]) -const tasksPendingComplete = computed(() => [...(data.value?.tasksInReviewing || [])]) +const tasksInReviewing = computed(() => [...(data.value?.tasksInReviewing || [])]) const tasksCompleted = computed(() => [...(data.value?.tasksCompleted || [])]) diff --git a/src/components/task-detail/TaskDetailManagerDropdown.vue b/src/components/task-detail/TaskDetailManagerDropdown.vue index cc88e0ea..772ded8f 100644 --- a/src/components/task-detail/TaskDetailManagerDropdown.vue +++ b/src/components/task-detail/TaskDetailManagerDropdown.vue @@ -1,6 +1,8 @@ diff --git a/src/components/top-bar/TopBar.vue b/src/components/top-bar/TopBar.vue index b21b9c8a..714367d9 100644 --- a/src/components/top-bar/TopBar.vue +++ b/src/components/top-bar/TopBar.vue @@ -5,7 +5,7 @@ @@ -67,7 +67,6 @@ import { getNotifiCount } from '@/api/common' import { useRoute, useRouter } from 'vue-router' import { PERMITTED_URL } from '@/constants/common' import { useOutsideClick } from '../hooks/useOutsideClick' -import { useScrollLockStore } from '@/stores/scrollLock' const memberStore = useMemberStore() const { isLogined, info } = storeToRefs(memberStore) @@ -116,6 +115,7 @@ const toggleProfile = () => { const onCloseSide = () => { isSideOpen.value = false + document.body.style.overflow = '' } watch(isLogined, newValue => { @@ -137,10 +137,8 @@ watch( const { htmlRef: notifiRef } = useOutsideClick(() => isNotifiVisible.value && toggleNotifi()) const { htmlRef: profileRef } = useOutsideClick(() => isProfileVisible.value && toggleProfile()) -const store = useScrollLockStore() -const { scrollLock } = storeToRefs(store) -const toggleSidebar = () => { +const onOpenSide = () => { + document.body.style.overflow = 'hidden' isSideOpen.value = !isSideOpen.value - scrollLock.value = !scrollLock.value } diff --git a/src/stores/scrollLock.ts b/src/stores/scrollLock.ts deleted file mode 100644 index 7dd5cf09..00000000 --- a/src/stores/scrollLock.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineStore } from 'pinia' -import { ref } from 'vue' - -export const useScrollLockStore = defineStore('scrollLock', () => { - const scrollLock = ref(false) - - return { scrollLock } -}) diff --git a/src/utils/date.ts b/src/utils/date.ts index 7b7f2378..269f5ef1 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -62,3 +62,20 @@ export const formatTodayOrNot = (dateStr: string, timeStr: string) => { return `${inputDate.getMonth() + 1}월 ${inputDate.getDate()}일` } } + +export const formatFullDateTime = (dateString: string) => { + const date = new Date(dateString) + + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + + let hours = date.getHours() + const minutes = String(date.getMinutes()).padStart(2, '0') + const seconds = String(date.getSeconds()).padStart(2, '0') + + const period = hours < 12 ? '오전' : '오후' + hours = hours % 12 || 12 + + return `${year}.${month}.${day} ${period} ${hours}:${minutes}:${seconds}` +}