diff --git a/src/api/user.ts b/src/api/user.ts index 9624dab..8509d0e 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -88,3 +88,8 @@ export const getSubCategoryDetail = async (categoryId: number) => { const response = await axiosInstance.get(`/api/sub-categories/${categoryId}`) return response.data } + +export const terminateTaskUser = async (taskId: number, reason: string) => { + const response = await axiosInstance.patch(`/api/tasks/${taskId}/terminate`, { reason }) + return response.data +} diff --git a/src/components/my-request/MyRequestList.vue b/src/components/my-request/MyRequestList.vue index e8b4f0e..a15365a 100644 --- a/src/components/my-request/MyRequestList.vue +++ b/src/components/my-request/MyRequestList.vue @@ -7,7 +7,7 @@ diff --git a/src/components/request-approve/RequestApprove.vue b/src/components/request-approve/RequestApprove.vue index 89fd9b4..392fd09 100644 --- a/src/components/request-approve/RequestApprove.vue +++ b/src/components/request-approve/RequestApprove.vue @@ -75,6 +75,7 @@ import CategoryDropDown from '../request-task/CategoryDropDown.vue' import DueDateInput from './DueDateInput.vue' import LabelDropdown from './LabelDropdown.vue' import ManagerDropdown from './ManagerDropdown.vue' +import getPossibleCategory from '@/utils/possibleCategory' const isModalVisible = ref(false) const category1 = ref(null) @@ -119,7 +120,12 @@ onMounted(async () => { setError('존재하지 않는 요청입니다', '', () => redirectToLogin('/requested')) return } - mainCategoryArr.value = await getMainCategory() + const mainCategory = await getMainCategory() + const mainIds = await getPossibleCategory() + const filteredMainCategory = mainCategory.filter((category: Category) => + mainIds.includes(category.mainCategoryId) + ) + mainCategoryArr.value = filteredMainCategory subCategoryArr.value = await getSubCategory() const data = await getTaskDetailUser(requestId) const selected = mainCategoryArr.value.find(ct => ct.name === data.mainCategoryName) || null diff --git a/src/components/request-task/ReRequestTask.vue b/src/components/request-task/ReRequestTask.vue index 2cc9252..16cd168 100644 --- a/src/components/request-task/ReRequestTask.vue +++ b/src/components/request-task/ReRequestTask.vue @@ -27,6 +27,7 @@ :limit-length="200" /> 작업{{ statusText }}을 실패했습니다 + + + + diff --git a/src/components/request-task/RequestTask.vue b/src/components/request-task/RequestTask.vue index 19d483f..7091923 100644 --- a/src/components/request-task/RequestTask.vue +++ b/src/components/request-task/RequestTask.vue @@ -52,6 +52,7 @@ import { getMainCategory, getSubCategory } from '@/api/common' import { getSubCategoryDetail, postTaskRequest } from '@/api/user' import type { Category, SubCategory } from '@/types/common' +import getPossibleCategory from '@/utils/possibleCategory' import { onMounted, ref, watch } from 'vue' import { useRouter } from 'vue-router' import FormButtonContainer from '../common/FormButtonContainer.vue' @@ -79,7 +80,12 @@ const subCategoryArr = ref([]) const afterSubCategoryArr = ref([]) onMounted(async () => { - mainCategoryArr.value = await getMainCategory() + const mainCategory = await getMainCategory() + const mainIds = await getPossibleCategory() + const filteredMainCategory = mainCategory.filter((category: Category) => + mainIds.includes(category.mainCategoryId) + ) + mainCategoryArr.value = filteredMainCategory subCategoryArr.value = await getSubCategory() afterSubCategoryArr.value = await getSubCategory() }) @@ -147,9 +153,14 @@ const handleSubmit = async () => { if (file.value && file.value.length > 0) { file.value.forEach(f => formData.append('attachment', f)) } - await postTaskRequest(formData) - isModalVisible.value = 'success' - isSubmitting.value = false - isUploading.value = false + + try { + await postTaskRequest(formData) + isModalVisible.value = 'success' + } finally { + if (isModalVisible.value !== 'success') isModalVisible.value = '' + isSubmitting.value = false + isUploading.value = false + } } diff --git a/src/components/request-task/RequestTaskFileInput.vue b/src/components/request-task/RequestTaskFileInput.vue index e4d8ac5..81ba9a8 100644 --- a/src/components/request-task/RequestTaskFileInput.vue +++ b/src/components/request-task/RequestTaskFileInput.vue @@ -11,7 +11,8 @@ + :removeFile="removeFile" + :initFileArr="initFileArr" />
+ @close="closeModal"> + + + diff --git a/src/components/requested/RequestedListCard.vue b/src/components/requested/RequestedListCard.vue index 3d0e710..9aa6c48 100644 --- a/src/components/requested/RequestedListCard.vue +++ b/src/components/requested/RequestedListCard.vue @@ -35,14 +35,14 @@ :is-open="isModalVisible.reject" @update:model-value="value => (rejectReason = value || '')" type="inputType" - @close="closeModal" + @close="closeAllModal" @click="rejectRequest"> + @close="closeAllModal"> (null) - -const handleModal = (id: number | null) => { - selectedID.value = id -} - const router = useRouter() const queryClient = useQueryClient() @@ -90,24 +83,38 @@ const isModalVisible = ref({ fail: false, success: false }) +const backModal = ref(false) const modalError = ref('') const rejectReason = ref('') +const selectedID = ref(null) + +const handleModal = (id: number | null) => { + selectedID.value = id +} + const toggleModal = (key: keyof typeof isModalVisible.value) => { isModalVisible.value = Object.fromEntries( Object.keys(isModalVisible.value).map(k => [k, k === key]) ) as typeof isModalVisible.value } const closeModal = () => { + isModalVisible.value = { reject: backModal.value ? true : false, fail: false, success: false } +} + +const closeAllModal = () => { const prevSuccess = isModalVisible.value.success isModalVisible.value = { reject: false, fail: false, success: false } if (prevSuccess) queryClient.invalidateQueries({ queryKey: ['requested'] }) } + const rejectRequest = async () => { if (rejectReason.value.length === 0) { toggleModal('fail') modalError.value = '반려 사유를 입력해주세요' + backModal.value = true return } + backModal.value = false await axiosInstance.patch(`/api/tasks/${info.taskId}/terminate`, { reason: DOMPurify.sanitize(rejectReason.value) }) diff --git a/src/components/task-detail/TaskDetailHistory.vue b/src/components/task-detail/TaskDetailHistory.vue index 85e18f8..9b31707 100644 --- a/src/components/task-detail/TaskDetailHistory.vue +++ b/src/components/task-detail/TaskDetailHistory.vue @@ -5,10 +5,9 @@ :history="historyData" :taskId="taskId" :requestor-name="requestorName" /> - -
+
{{ formatTimeShort(item.time) }}
-
+

{{ HistoryMessageBefore[item.taskHistoryType] }}

-

- {{ item.details.taskDetails?.value }} -

-

+

{{ item.details.taskDetails?.value }}

{{ HistoryMessageAfter[item.taskHistoryType] }}

diff --git a/src/components/task-detail/TaskDetailHistoryChat.vue b/src/components/task-detail/TaskDetailHistoryChat.vue index d822386..8497cdb 100644 --- a/src/components/task-detail/TaskDetailHistoryChat.vue +++ b/src/components/task-detail/TaskDetailHistoryChat.vue @@ -18,7 +18,7 @@

{{ history.details.commentDetails?.comment || history.details.taskDetails?.value }} diff --git a/src/components/task-detail/TaskDetailHistoryFile.vue b/src/components/task-detail/TaskDetailHistoryFile.vue index 0186509..0aa0275 100644 --- a/src/components/task-detail/TaskDetailHistoryFile.vue +++ b/src/components/task-detail/TaskDetailHistoryFile.vue @@ -13,7 +13,7 @@

{{ history.details.commentFileDetails?.nickName }}

-
-

+

+

{{ history.details.commentFileDetails?.fileName }}

diff --git a/src/components/task-detail/TaskDetailHistoryInput.vue b/src/components/task-detail/TaskDetailHistoryInput.vue index 415d02e..134f5d5 100644 --- a/src/components/task-detail/TaskDetailHistoryInput.vue +++ b/src/components/task-detail/TaskDetailHistoryInput.vue @@ -103,8 +103,10 @@ const handleModal = () => { isModalVisible.value = !isModalVisible.value } -const handleEnterKey = () => { - if (!isComposing.value) { +const handleEnterKey = (event: KeyboardEvent) => { + if (event.shiftKey) { + messageText.value += '\n' + } else if (!isComposing.value) { sendMessage() } } diff --git a/src/components/task-detail/TaskDetailManagerDropdown.vue b/src/components/task-detail/TaskDetailManagerDropdown.vue index 5778f17..3af5154 100644 --- a/src/components/task-detail/TaskDetailManagerDropdown.vue +++ b/src/components/task-detail/TaskDetailManagerDropdown.vue @@ -9,8 +9,8 @@ -

- {{ modelValue?.nickname }} +

+ {{ modelValue?.nickname || '담당자를 선택해주세요' }}

-
+
@@ -50,6 +50,7 @@ import ImageContainer from '../common/ImageContainer.vue' const { modelValue } = defineProps<{ modelValue: ManagerTypes; taskId: number }>() const emit = defineEmits(['update:modelValue']) +console.log(modelValue,'현재 담당자' ) const dropdownOpen = ref(false) const managerArr = ref([]) diff --git a/src/components/task-detail/TaskDetailTopBar.vue b/src/components/task-detail/TaskDetailTopBar.vue index 73fa368..6738523 100644 --- a/src/components/task-detail/TaskDetailTopBar.vue +++ b/src/components/task-detail/TaskDetailTopBar.vue @@ -15,6 +15,13 @@

요청 수정

+
+ +

요청 취소

+
요청 승인

- -

요청 취소

+ +

요청 반려

diff --git a/src/components/user-manage/UserUpdate.vue b/src/components/user-manage/UserUpdate.vue index 667709e..6c0fed4 100644 --- a/src/components/user-manage/UserUpdate.vue +++ b/src/components/user-manage/UserUpdate.vue @@ -8,30 +8,16 @@ :limit-length="10" :labelName="'이름'" />
- +
- - + + :value="userRegistrationForm.email" />
{ isInvalidate.value = 'nameEmpty' return } - if (!userRegistrationForm.value.nickname) { - isInvalidate.value = 'nicknameEmpty' - return - } - if (!usernameRegex.test(userRegistrationForm.value.nickname)) { - isInvalidate.value = 'wrongNickname' - return - } - if (!emailRegex.test(userRegistrationForm.value.email)) { - isInvalidate.value = 'wrongEmail' - return - } if (!userRegistrationForm.value.department?.departmentId) { isInvalidate.value = 'departmentEmpty' return @@ -191,7 +163,6 @@ const handleSubmit = async () => { departmentId: userRegistrationForm.value.department.departmentId, departmentRole: userRegistrationForm.value.departmentRole } - await updateMemberAdmin(userId.value, formData) isModalVisible.value = 'success' } diff --git a/src/types/user.ts b/src/types/user.ts index ff25da4..d5c8bd3 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -39,6 +39,7 @@ export interface RequestTaskFileInputProps { files: File[] | null removeFile: (index: number) => void isEdit?: boolean + initFileArr?: AttachmentResponse[] } export interface RequestTaskTextAreaProps { diff --git a/src/utils/possibleCategory.ts b/src/utils/possibleCategory.ts new file mode 100644 index 0000000..1c9d72a --- /dev/null +++ b/src/utils/possibleCategory.ts @@ -0,0 +1,17 @@ +import { getCategory } from '@/api/common' +import type { Category } from '@/types/common' +import { ref } from 'vue' + +const getPossibleCategory = async (): Promise => { + const categories = ref([]) + const possibleCategory = await getCategory() + categories.value = possibleCategory + + const mainCategoryIds = categories.value + .filter(category => category.subCategory && category.subCategory.length > 0) + .map(category => category.mainCategoryId) + + return mainCategoryIds +} + +export default getPossibleCategory