Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
29a529b
:recycle: [fix] : 히스토리 길이제한 + 전송시에도 방지
Minkyu0424 Feb 13, 2025
2be62e0
:recycle: [fix] : 파일이름 길이 축약해서 전송
Minkyu0424 Feb 14, 2025
3410d06
:recycle: [fix] : 회원 수정 시 최신화
Minkyu0424 Feb 14, 2025
88cc04b
:recycle: [fix] : 카테고리 1차 삭제시 경고
Minkyu0424 Feb 14, 2025
d06d9df
:recycle: [fix] : 상세조회에서 담당자 선택후 담당자 정보 새로 불러오기
Minkyu0424 Feb 14, 2025
e09aa9d
:recycle: [fix] : 구분 수정 취소시 되돌리기, 글자제한 10글자
Minkyu0424 Feb 14, 2025
004b14b
:recycle: [fix] : 구분 수정 시에도 길이 측정 및 제한된 길이 내에서 전달 제한
Minkyu0424 Feb 14, 2025
762657e
:recycle: [fix] : 부가 정보 -> 부가 설명으로 변경
Minkyu0424 Feb 14, 2025
4ae5908
:bug: [fix] : 길이제한 표시 위치 변경
Minkyu0424 Feb 14, 2025
dcdce2f
:bug: [fix] : 에러핸들링 함수 생성
Minkyu0424 Feb 14, 2025
c321696
:bug: [fix] : csv파일로 회원추가시 에러 핸들링
Minkyu0424 Feb 14, 2025
92aa417
:bug: [fix] : 내 정보 수정에서 길이 제한사항 우측 아래푯
Minkyu0424 Feb 14, 2025
aa1c761
:bug: [fix] : csv관련 오류 잘못된 닉네임 형식 오류 추가
Minkyu0424 Feb 14, 2025
709dd5e
:bug: [fix] : 요청 승인 한번만 되도록 제한
Minkyu0424 Feb 14, 2025
dd8e6b2
:bug: [fix] : 새회원 추가 시 담당자 권한여부 표시 + 역할 제한
Minkyu0424 Feb 14, 2025
7d3b54b
:bug: [fix] : 담당자 수정 시 권한여부 표시 + 역할 제한
Minkyu0424 Feb 14, 2025
d16548e
:bug: [fix] : 회원정보 수정 시 잔여작업 있을 시 막기
Minkyu0424 Feb 14, 2025
4f92c89
:bug: [fix] : 회원삭제 시 잔여작업 존재 알리고 삭제 마긱
Minkyu0424 Feb 14, 2025
425b830
:bug: [fix] : 종료사유 미 입력시 닫히지 않고 포커싱 및 텍스트 붉게
Minkyu0424 Feb 14, 2025
8911faa
:bug: [fix] : 다시 입력안하고 그냥 닫으면 포커싱 초기화
Minkyu0424 Feb 14, 2025
ae1ba2e
:twisted_rightwards_arrows: [fix] : conflict resolved
Minkyu0424 Feb 14, 2025
18d2dd6
:bug: [fix] : 닫기로 안닫히는 이슈 해결
Minkyu0424 Feb 14, 2025
aa953ed
:bug: [fix] : 회원추가 수정 시 길이제한 반영
Minkyu0424 Feb 14, 2025
bf91bf8
:bug: [fix] : 공통 인풋 길이제한 입력 받도록 수정
Minkyu0424 Feb 14, 2025
568f90f
:bug: [fix] : 히스토리 작성란 200자 제한
Minkyu0424 Feb 14, 2025
84b8d31
:bug: [fix] : 커밋삭제
Minkyu0424 Feb 14, 2025
09c913d
:bug: [fix] : 히스토리 외부 클릭 시에도 삭제버튼 닫히기
Minkyu0424 Feb 14, 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
4 changes: 2 additions & 2 deletions src/components/common/EditInformation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@ const validateName = () => {
const regex = /[!@#$%^&*(),.?":{}|<>\p{Emoji}]/gu
isInvalid.value = regex.test(name.value)
if (isInvalid.value == true) {
nameError.value = '이름에는 특수문자가 포함될 수 없습니다.'
nameError.value = '이름에는 특수문자가 포함될 수 없습니다'
}
if (name.value.length > 10 || name.value.length < 1) {
isFull.value = true
nameError.value = '이름은 1글자 이상, 10글자이하만 가능합니다.'
nameError.value = '이름은 1글자 이상, 10글자이하만 가능합니다'
} else {
isFull.value = false
}
Expand Down
5 changes: 3 additions & 2 deletions src/components/common/ModalView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@
<slot name="body"></slot>
</div>
</div>

<textarea
v-if="type == 'inputType' || type === 'terminate'"
v-model="textValue"
:placeholder="
type === 'terminate' ? '종료 사유를 입력해주세요' : '반려 사유를 입력해주세요'
"
:class="{ 'border border-red-1 placeholder-red-500': isEmpty }"
class="flex border w-full border-border-1 px-4 py-3 focus:outline-none resize-none h-[120px]" />
</div>

Expand Down Expand Up @@ -86,10 +86,11 @@ import { onUnmounted, ref, watch } from 'vue'
import CommonIcons from './CommonIcons.vue'
import LoadingIcon from './LoadingIcon.vue'

const { isOpen, type, modelValue } = defineProps<{
const { isOpen, type, modelValue, isEmpty } = defineProps<{
isOpen: boolean
type?: string
modelValue?: string
isEmpty?: boolean
}>()

const emit = defineEmits<{
Expand Down
46 changes: 34 additions & 12 deletions src/components/member-management/MemberManagementAddByCsv.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
type="file"
id="file"
accept=".csv"
ref="fileInput"
@change="handleFileUpload" />
<label
for="file"
Expand All @@ -15,40 +16,61 @@
파일로 일괄 추가
</label>
<ModalView
:isOpen="isModalVisible"
:isOpen="isModalVisible === 'success'"
:type="'successType'"
@close="handleCancel">
<template #header>회원이 추가되었습니다</template>
</ModalView>
<ModalView
:isOpen="isModalVisible === 'error'"
:type="'failType'"
@close="handleCancel">
<template #header>회원 추가를 실패했습니다</template>
<template #body>{{ errorText }}</template>
</ModalView>
</div>
</template>

<script setup lang="ts">
import { addMemberAdminByCsv } from '@/api/admin'
import { plusIcon } from '@/constants/iconPath'
import { useMemberManagementParamsStore } from '@/stores/params'
import { getErrorCSV } from '@/utils/getErorr'
import { useQueryClient } from '@tanstack/vue-query'
import { ref } from 'vue'
import CommonIcons from '../common/CommonIcons.vue'
import ModalView from '../common/ModalView.vue'

const queryClient = useQueryClient()
const isModalVisible = ref(false)
const isModalVisible = ref('')
const { params } = useMemberManagementParamsStore()
const errorText = ref('')
const fileInput = ref<HTMLInputElement | null>(null)

const handleFileUpload = async (event: Event) => {
const target = event.target as HTMLInputElement
const file = target.files?.[0]
if (!file) return
const formData = new FormData()
formData.append('file', file)
await addMemberAdminByCsv(formData)
queryClient.invalidateQueries({ queryKey: ['member', { ...params }] })
isModalVisible.value = true
target.value = ''
try {
const target = event.target as HTMLInputElement
const file = target.files?.[0]
if (!file) return

const formData = new FormData()
formData.append('file', file)
await addMemberAdminByCsv(formData)

queryClient.invalidateQueries({ queryKey: ['member', { ...params }] })
isModalVisible.value = 'success'
} catch (error) {
errorText.value = getErrorCSV(error)
isModalVisible.value = 'error'
} finally {
if (fileInput.value) {
fileInput.value.value = ''
}
}
}

const handleCancel = () => {
isModalVisible.value = false
isModalVisible.value = ''
errorText.value = ''
}
</script>
8 changes: 5 additions & 3 deletions src/components/member-management/MemberManagementList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
<template #listCards>
<MemberManagementListCard
v-for="info in data?.content"
:key="info.memberId"
:key="
info.memberId + info.name + info.departmentName + info.departmentRole + info.isReviewer
"
:info="info" />
<NoContent v-if="data?.content.length === 0" />
</template>
Expand All @@ -22,18 +24,18 @@
</template>

<script setup lang="ts">
import { useMemberStore } from '@/stores/member'
import { useMemberManagementParamsStore } from '@/stores/params'
import type { MemberManagementResponse } from '@/types/admin'
import { axiosInstance } from '@/utils/axios'
import { useQuery } from '@tanstack/vue-query'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
import ListContainer from '../lists/ListContainer.vue'
import ListPagination from '../lists/ListPagination.vue'
import NoContent from '../lists/NoContent.vue'
import MemberManagementListBar from './MemberManagementListBar.vue'
import MemberManagementListCard from './MemberManagementListCard.vue'
import { useMemberStore } from '@/stores/member'
import { storeToRefs } from 'pinia'

const { params } = useMemberManagementParamsStore()
const onPageChange = (value: number) => {
Expand Down
22 changes: 14 additions & 8 deletions src/components/member-management/MemberManagementListCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,19 @@
</template>

<script setup lang="ts">
import { useErrorStore } from '@/stores/error'
import { useMemberStore } from '@/stores/member'
import type { MemberManagementListData } from '@/types/admin'
import type { ListCardProps, Role } from '@/types/common'
import { axiosInstance } from '@/utils/axios'
import { formatDate } from '@/utils/date'
import { useQueryClient } from '@tanstack/vue-query'
import { storeToRefs } from 'pinia'
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import ModalView from '../common/ModalView.vue'
import ResultModal from '../common/ResultModal.vue'
import ListCardTab from '../lists/ListCardTab.vue'
import ModalView from '../common/ModalView.vue'
import { useMemberStore } from '@/stores/member'
import { storeToRefs } from 'pinia'
import { useErrorStore } from '@/stores/error'

const roleContent = (role: Role) => {
return role === 'ROLE_USER' ? '사용자' : role === 'ROLE_MANAGER' ? '담당자' : '관리자'
Expand Down Expand Up @@ -108,10 +108,16 @@ const closeModal = () => {
}

const onMemberDelete = async (memberId: number) => {
await axiosInstance.delete(`/api/managements/members`, { data: { memberId } })
resultModalType.value = 'successType'
message.value = '회원을 삭제했습니다'
toggleModal('result')
try {
await axiosInstance.delete(`/api/managements/members`, { data: { memberId } })
resultModalType.value = 'successType'
message.value = '회원을 삭제했습니다'
toggleModal('result')
} catch {
resultModalType.value = 'failType'
message.value = '회원의 잔여작업이 존재합니다'
toggleModal('result')
}
}

const onMemberInvite = async (memberId: number) => {
Expand Down
4 changes: 4 additions & 0 deletions src/components/request-approve/RequestApprove.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const subCategoryArr = ref<SubCategory[]>([])
const afterSubCategoryArr = ref<SubCategory[]>([])
const approveData = ref(INITIAL_REQUEST_APPROVE_DATA)
const isInvalidate = ref('')
const isApproving = ref(false)
const isFirst = ref(true)

const router = useRouter()
Expand Down Expand Up @@ -143,6 +144,7 @@ const handleCancel = () => {
}

const handleSubmit = async () => {
if (isApproving.value || isModalVisible.value) return
if (!category1.value) {
isInvalidate.value = 'category1'
return
Expand All @@ -163,6 +165,7 @@ const handleSubmit = async () => {
isInvalidate.value = ''
return
}
isApproving.value = true

const requestData = {
categoryId: category2.value.subCategoryId,
Expand All @@ -172,6 +175,7 @@ const handleSubmit = async () => {
: null,
labelId: approveData.value.label?.labelId || null
}

await postTaskApprove(requestId, requestData)
isModalVisible.value = true
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/request-task/ReRequestTask.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<RequestTaskTextArea
v-model="description"
:is-invalidate="isInvalidate"
:placeholderText="'부가 정보를 입력해주세요'"
:placeholderText="'부가 설명을 입력해주세요'"
:limit-length="200" />
<RequestTaskFileInput
v-model="file"
Expand Down
2 changes: 1 addition & 1 deletion src/components/request-task/RequestTask.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<RequestTaskTextArea
v-model="description"
:is-invalidate="isInvalidate"
:placeholderText="'부가 정보를 입력해주세요'"
:placeholderText="'부가 설명을 입력해주세요'"
:limit-length="200" />
<RequestTaskFileInput
v-model="file"
Expand Down
4 changes: 2 additions & 2 deletions src/components/request-task/RequestTaskDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</div>
<div
v-if="dropdownOpen"
class="absolute w-full h-40 overflow-y-auto scrollbar-hide top-[52px] flex flex-col gap-2 p-2 bg-white rounded z-10 shadow border-t border-t-border-2">
class="absolute w-full max-h-40 overflow-y-auto scrollbar-hide top-[52px] flex flex-col gap-2 p-2 bg-white rounded z-10 shadow border-t border-t-border-2">
<div
v-for="option in options"
:key="option"
Expand All @@ -36,10 +36,10 @@

<script lang="ts" setup>
import { dropdownIcon } from '@/constants/iconPath'
import { useOutsideClick } from '@/hooks/useOutsideClick'
import type { RequestTaskDropdownProps } from '@/types/user'
import { ref } from 'vue'
import CommonIcons from '../common/CommonIcons.vue'
import { useOutsideClick } from '@/hooks/useOutsideClick'

const { placeholderText, options, labelName, modelValue, isLabel, disabled, isInvalidate } =
defineProps<RequestTaskDropdownProps>()
Expand Down
14 changes: 6 additions & 8 deletions src/components/request-task/RequestTaskFileInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,14 @@ const handleModal = () => {
isModalVisible.value = !isModalVisible.value
}

const truncateFilename = (name: string, maxLength: number) => {
return [...name].slice(0, maxLength).join('')
}

const handleFileUpload = (event: Event) => {
const target = event.target as HTMLInputElement
if (target.files && target.files.length > 0) {
const newFiles = Array.from(target.files)
.map(file => {
const truncatedName = truncateFilename(file.name, 35)
const newFile = new File([file], truncatedName, { type: file.type })
const normalizedFileName = file.name.normalize('NFC')
const newFileName = normalizedFileName.slice(0, 18)
const newFile = new File([file], newFileName, { type: file.type })
return newFile.size <= 5 * 1024 * 1024 ? newFile : null
})
.filter(file => file !== null) as File[]
Expand All @@ -98,8 +95,9 @@ const handleDrop = (event: DragEvent) => {
if (files && files.length > 0) {
const newFiles = Array.from(files)
.map(file => {
const truncatedName = truncateFilename(file.name, 35)
const newFile = new File([file], truncatedName, { type: file.type })
const normalizedFileName = file.name.normalize('NFC')
const newFileName = normalizedFileName.slice(0, 18)
const newFile = new File([file], newFileName, { type: file.type })
return newFile.size <= 5 * 1024 * 1024 ? newFile : null
})
.filter(file => file !== null) as File[]
Expand Down
6 changes: 3 additions & 3 deletions src/components/request-task/RequestTaskInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
:disabled="isEdit"
@input="updateValue(($event.target as HTMLInputElement).value)"
:placeholder="placeholderText"
:class="`${isEdit ? 'text-gray-500' : ''} ${isInvalidate ? 'border-red-1' : 'border-border-1'}`"
:maxlength="labelName === '제목' ? 30 : undefined" />
:class="`${isEdit ? 'text-gray-1' : ''} ${isInvalidate ? 'border-red-1' : 'border-border-1'}`"
:maxlength="limitLength" />
<p
v-if="limitLength"
class="absolute text-xs top-[calc(100%+4px)] w-full flex justify-end text-body">
({{ inputLength }}/{{ limitLength }})
{{ inputLength }} / {{ limitLength }}
</p>
</div>
</template>
Expand Down
7 changes: 7 additions & 0 deletions src/components/task-detail/TaskDetailHistoryChat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
isRequestor ? 'order-3 items-start' : 'order-1 items-end'
]">
<div
ref="btnRef"
v-if="history.details.commentDetails?.nickName === info.nickname"
class="relative cursor-pointer h-full">
<CommonIcons
Expand Down Expand Up @@ -63,6 +64,7 @@
<script setup lang="ts">
import { deleteComment } from '@/api/user'
import { menuDotIcon } from '@/constants/iconPath'
import { useOutsideClick } from '@/hooks/useOutsideClick'
import { useMemberStore } from '@/stores/member'
import type { TaskDetailHistoryChatProps } from '@/types/common'
import { formatTimeShort } from '@/utils/date'
Expand Down Expand Up @@ -95,6 +97,9 @@ const closeModal = () => {
isClicked.value = !isClicked.value
isModalOpen.value = false
}
const closeMenuDot = () => {
isClicked.value = false
}

const deleteCommentText = async () => {
isClicked.value = !isClicked.value
Expand All @@ -104,4 +109,6 @@ const deleteCommentText = async () => {
}
queryClient.invalidateQueries({ queryKey: ['historyData', taskId] })
}

const { htmlRef: btnRef } = useOutsideClick(() => closeMenuDot())
</script>
Loading