Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
55c6a10
:bug: [fix] : 요청 상세조회에서 반려시에도 모달 같게 뜨도록
Minkyu0424 Feb 15, 2025
3a20bf6
:bug: [fix] : 승인 대기중 요청 반려 미입력시 다시 띄워주기
Minkyu0424 Feb 15, 2025
5217df2
:bug: [fix] : 요청 실패시 로딩 모달 멈추기
Minkyu0424 Feb 15, 2025
5c2a83a
:bug: [fix] : 요청 수정에서 실패시 로딩 모달 멈추기
Minkyu0424 Feb 15, 2025
d381fab
:bug: [fix] : 수정시 내 요청에서 최신화, 재요청 오류 해결
Minkyu0424 Feb 16, 2025
21fb9de
:bug: [fix] : 내 요청, 수정에서 무한 로딩 오류 해결
Minkyu0424 Feb 16, 2025
6b94449
:bug: [fix] : 2차 카테고리 존재하는 1차 카테고리만 보여주기
Minkyu0424 Feb 16, 2025
8c74e71
:bug: [fix] : 요청 승인 및 수정에서도 서브 카테고리 존재에 따른 1차 카테고리 렌더링
Minkyu0424 Feb 16, 2025
2f93412
:bug: [fix] : 수정 시에 파일 크기에 대한 표시 정상화
Minkyu0424 Feb 16, 2025
de1745f
:bug: [fix] : 중복된 파일에 대한 경고
Minkyu0424 Feb 16, 2025
4beaa9f
:bug: [fix] : 히스토리 입력 시 줄바꿈과 \n 처리
Minkyu0424 Feb 16, 2025
c12498d
:bug: [fix] : 요청 수정 시 템플릿 변경 반영
Minkyu0424 Feb 16, 2025
4d15b6b
:bug: [fix] : 포맷
Minkyu0424 Feb 16, 2025
d554a95
:twisted_rightwards_arrows: [fix] : conflict resolved
Minkyu0424 Feb 16, 2025
3cf09fb
:recycle: [refactor] : conflict resolved
Minkyu0424 Feb 16, 2025
0686f72
:recycle: [refactor] : 히스토리 댓글, 파일 글씨크기 감소
Minkyu0424 Feb 16, 2025
2d9ba78
:recycle: [refactor] : 담당자 미선택시 드롭다운 placeholder
Minkyu0424 Feb 16, 2025
dca43aa
:recycle: [refactor] : 히스토리 v-if 에서 벗어난 빈 div 제거
Minkyu0424 Feb 16, 2025
2f77c18
:recycle: [refactor] : 중첩되는 v-if문 통일
Minkyu0424 Feb 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion src/components/my-request/MyRequestList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<template #listCards>
<MyRequestListCard
v-for="info in data?.content"
:key="info.taskStatus + info.processorName + info.taskId"
:key="info.taskStatus + info.processorName + info.taskId + info.title + info.categoryName"
:info="info" />
<NoContent v-if="data?.content.length === 0" />
</template>
Expand Down
8 changes: 7 additions & 1 deletion src/components/request-approve/RequestApprove.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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<Category | null>(null)
Expand Down Expand Up @@ -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
Expand Down
53 changes: 40 additions & 13 deletions src/components/request-task/ReRequestTask.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
:limit-length="200" />
<RequestTaskFileInput
v-model="file"
:initFileArr="initFileArr"
:isEdit="true" />
<FormButtonContainer
:handleCancel="handleCancel"
Expand All @@ -46,14 +47,26 @@
<template #header>작업{{ statusText }}을 실패했습니다</template>
<template #body>잠시후 시도해주세요</template>
</ModalView>
<ModalView
:isOpen="isModalVisible === 'loading'"
type="loadingType">
<template #header>작업을 요청 중입니다...</template>
<template #body>잠시만 기다려주세요</template>
</ModalView>
</div>
</template>

<script lang="ts" setup>
import { getMainCategory, getSubCategory } from '@/api/common'
import { getTaskDetailUser, patchTaskRequest, postTaskRequest } from '@/api/user'
import {
getSubCategoryDetail,
getTaskDetailUser,
patchTaskRequest,
postTaskRequest
} from '@/api/user'
import type { Category, SubCategory } from '@/types/common'
import type { AttachmentResponse } from '@/types/user'
import getPossibleCategory from '@/utils/possibleCategory'
import { computed, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import FormButtonContainer from '../common/FormButtonContainer.vue'
Expand Down Expand Up @@ -91,7 +104,12 @@ const handleCancel = () => {
}

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()
const data = await getTaskDetailUser(Number(id))
Expand All @@ -103,6 +121,7 @@ onMounted(async () => {
)
title.value = data.title
description.value = data.description

file.value = data.attachmentResponses.map((attachment: AttachmentResponse) => {
return new File([attachment.fileUrl], attachment.fileName, { type: 'application/pdf' })
})
Expand All @@ -120,6 +139,13 @@ watch(category1, async newValue => {
)
})

watch(category2, async newVal => {
if (newVal) {
const res = await getSubCategoryDetail(newVal.subCategoryId)
description.value = res.descriptionExample
}
})

const handleSubmit = async () => {
if (isSubmitting.value || isModalVisible.value) return

Expand All @@ -140,11 +166,9 @@ const handleSubmit = async () => {
return
}

isSubmitting.value = true

const formData = new FormData()

isSubmitting.value = true
isModalVisible.value = 'loading'

const attachmentsToDelete = initFileArr.value
.filter(initFile => !file.value?.some(f => f.name === initFile.fileName))
Expand All @@ -161,7 +185,7 @@ const handleSubmit = async () => {
attachmentsToDelete: attachmentsToDelete
}

const jsonTaskInfo = JSON.stringify(taskInfoEdit)
const jsonTaskInfo = JSON.stringify(reqType === 'edit' ? taskInfoEdit : taskInfo)
const newBlob = new Blob([jsonTaskInfo], { type: 'application/json' })
formData.append('taskInfo', newBlob)

Expand All @@ -177,13 +201,16 @@ const handleSubmit = async () => {
formData.append('attachment', f)
})
}

if (reqType === 're') {
await postTaskRequest(formData)
} else {
await patchTaskRequest(id, formData)
try {
if (reqType === 're') {
await postTaskRequest(formData)
} else {
await patchTaskRequest(id, formData)
}
isModalVisible.value = 'success'
} finally {
isSubmitting.value = false
if (isModalVisible.value !== 'success') isModalVisible.value = ''
}
isModalVisible.value = 'success'
isSubmitting.value = false
}
</script>
21 changes: 16 additions & 5 deletions src/components/request-task/RequestTask.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -79,7 +80,12 @@ const subCategoryArr = ref<SubCategory[]>([])
const afterSubCategoryArr = ref<SubCategory[]>([])

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()
})
Expand Down Expand Up @@ -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
}
}
</script>
46 changes: 35 additions & 11 deletions src/components/request-task/RequestTaskFileInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
<RequestTaskFileInputAfter
:files="modelValue"
:isEdit
:removeFile="removeFile" />
:removeFile="removeFile"
:initFileArr="initFileArr" />
</label>
<div
v-else
Expand All @@ -33,34 +34,42 @@
</label>
</div>
<ModalView
:is-open="isModalVisible"
:is-open="isModalVisible === 'invalidate'"
type="failType"
@close="handleModal">
@close="closeModal">
<template #header>파일추가를 실패했습니다</template>
<template #body>최대 5개, 각 5mb까지 가능합니다</template>
</ModalView>
<ModalView
:is-open="isModalVisible === 'duplicated'"
type="failType"
@close="closeModal">
<template #header>중복된 파일입니다</template>
</ModalView>
</div>
</template>

<script lang="ts" setup>
import CommonIcons from '@/components/common/CommonIcons.vue'
import { uploadIcon } from '@/constants/iconPath'
import type { AttachmentResponse } from '@/types/user'
import { computed, ref } from 'vue'
import ModalView from '../common/ModalView.vue'
import RequestTaskFileInputAfter from './RequestTaskFileInputAfter.vue'

const { modelValue } = defineProps<{
const { modelValue, isEdit, initFileArr } = defineProps<{
modelValue: File[] | null
isEdit?: boolean
initFileArr?: AttachmentResponse[]
}>()
const emit = defineEmits(['update:modelValue'])

const hasFiles = computed(() => modelValue && modelValue.length > 0)
const isDragging = ref(false)
const isModalVisible = ref(false)
const isModalVisible = ref('')

const handleModal = () => {
isModalVisible.value = !isModalVisible.value
const closeModal = () => {
isModalVisible.value = ''
}

const handleFileUpload = (event: Event) => {
Expand All @@ -76,12 +85,19 @@ const handleFileUpload = (event: Event) => {
.filter(file => file !== null) as File[]

if (newFiles.length !== target.files.length) {
handleModal()
isModalVisible.value = 'invalidate'
return
}

const existingFileNames = modelValue ? modelValue.map(file => file.name) : []
if (newFiles.some(file => existingFileNames.includes(file.name))) {
isModalVisible.value = 'duplicated'
return
}

const updatedFiles = modelValue ? [...modelValue, ...newFiles] : newFiles
if (updatedFiles.length > 5) {
handleModal()
isModalVisible.value = 'invalidate'
return
}
emit('update:modelValue', updatedFiles.length === 1 ? [updatedFiles[0]] : updatedFiles)
Expand All @@ -101,13 +117,21 @@ const handleDrop = (event: DragEvent) => {
return newFile.size <= 5 * 1024 * 1024 ? newFile : null
})
.filter(file => file !== null) as File[]

if (newFiles.length !== files.length) {
handleModal()
isModalVisible.value = 'invalidate'
return
}

const existingFileNames = modelValue ? modelValue.map(file => file.name) : []
if (newFiles.some(file => existingFileNames.includes(file.name))) {
isModalVisible.value = 'duplicated'
return
}

const updatedFiles = modelValue ? [...modelValue, ...newFiles] : newFiles
if (updatedFiles.length > 5) {
handleModal()
isModalVisible.value = 'invalidate'
return
}
emit('update:modelValue', updatedFiles.length === 1 ? [updatedFiles[0]] : updatedFiles)
Expand Down
11 changes: 9 additions & 2 deletions src/components/request-task/RequestTaskFileInputAfter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
class="flex w-full justify-between items-center h-8 text-xs border-b border-b-border-2 px-4 shrink-0">
<p class="flex truncate mr-3">{{ file.name }}</p>
<div class="flex gap-6">
<p class="w-[60px]">{{ isEdit ? file.size : formatFileSize(file.size) }}</p>
<p class="w-[60px]">
{{ isEdit ? getFileSizeByName(file.name, file.size) : formatFileSize(file.size) }}
</p>
<p class="w-36">{{ new Date().toLocaleString() }}</p>
<div class="w-10 flex items-center justify-center cursor-pointer">
<CommonIcons
Expand Down Expand Up @@ -47,5 +49,10 @@ import type { RequestTaskFileInputProps } from '@/types/user'
import { formatFileSize } from '@/utils/unit'
import CommonIcons from '../common/CommonIcons.vue'

const { files, removeFile, isEdit } = defineProps<RequestTaskFileInputProps>()
const { files, removeFile, isEdit, initFileArr } = defineProps<RequestTaskFileInputProps>()

const getFileSizeByName = (fileName: string, size: number): string | number => {
const file = initFileArr?.find(file => file.fileName === fileName)
return file ? file.fileSize : formatFileSize(size)
}
</script>
25 changes: 16 additions & 9 deletions src/components/requested/RequestedListCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@
:is-open="isModalVisible.reject"
@update:model-value="value => (rejectReason = value || '')"
type="inputType"
@close="closeModal"
@close="closeAllModal"
@click="rejectRequest">
<template #header>반려 사유를 입력해주세요</template>
</ModalView>
<ModalView
:is-open="isModalVisible.success"
type="successType"
@close="closeModal">
@close="closeAllModal">
<template #header>반려가 완료되었습니다</template>
</ModalView>
<ModalView
Expand Down Expand Up @@ -75,13 +75,6 @@ const requestedTabList: ListCardProps[] = [
{ content: info.title },
{ content: info.requesterName, width: 120, profileImg: info.requesterImg }
]

const selectedID = ref<number | null>(null)

const handleModal = (id: number | null) => {
selectedID.value = id
}

const router = useRouter()
const queryClient = useQueryClient()

Expand All @@ -90,24 +83,38 @@ const isModalVisible = ref({
fail: false,
success: false
})
const backModal = ref(false)
const modalError = ref('')
const rejectReason = ref('')
const selectedID = ref<number | null>(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)
})
Expand Down
Loading