Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
9c24ec0
:recycle: [refactor] : 승인 대기 중 요청 세부사항 조회 이벤트 연결
Minkyu0424 Feb 5, 2025
8629508
:lipstick: [design] : 전역 검정 설정
Minkyu0424 Feb 5, 2025
e9f6fb0
:recycle: [refactor] : 히스토리 및 상세정보 ui 피드백 반영
Minkyu0424 Feb 5, 2025
f7d2c1c
:recycle: [refactor] : 날짜변환 유틸 함수 + 요청자의 댓글 작성, 조회 반영
Minkyu0424 Feb 5, 2025
85e040c
:recycle: [refactor] : 작성자 유형에 따른 히스토리 ui 타입 분별과 시간표시 중첩시 하나만 표현
Minkyu0424 Feb 5, 2025
e98680f
:recycle: [refactor] : 조합글자의 api 요청이 두 번 가는 이슈 방지
Minkyu0424 Feb 5, 2025
e5dca4b
:sparkles: [feat] : 파일 전송
Minkyu0424 Feb 5, 2025
fe9be6f
:sparkles: [feat] : 파일 전송 후 역할별 뷰
Minkyu0424 Feb 5, 2025
315843f
:recycle: [refactor] : api 등록 및 메뉴 점 아이콘 등록
Minkyu0424 Feb 5, 2025
51b209f
Merge branch 'develop' of https://github.com/TaskFlow-CLAP/TaskFlow-F…
Minkyu0424 Feb 5, 2025
0f6a9b1
:sparkles: [feat] : 삭제 api 연결 comment ID 받아야함
Minkyu0424 Feb 5, 2025
96a4d3d
:recycle: [refactor] : 작업 상태 종료로 변경시 알람
Minkyu0424 Feb 6, 2025
ac169ca
:recycle: [refactor] : 일반 유저의 경우 다른 api로 상세 정보 호출
Minkyu0424 Feb 6, 2025
850ace3
:sparkles: [feat] : 특정 경로 이동시 상세정보 모달이 뜨도록 함
Minkyu0424 Feb 6, 2025
f333e68
:sparkles: [feat] : 파일 삭제를 위한 메뉴 아이콘 생성
Minkyu0424 Feb 6, 2025
c0c3ea3
Merge branch 'develop' of https://github.com/TaskFlow-CLAP/TaskFlow-F…
Minkyu0424 Feb 6, 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
20 changes: 20 additions & 0 deletions src/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,23 @@ export const getHistory = async (taskID: number) => {
const response = await axiosInstance.get(`/api/tasks/${taskID}/histories`)
return response.data
}

export const postComment = async (taskID: number, content: string) => {
const response = await axiosInstance.post(`/api/comment/${taskID}`, { content })
return response.data
}

export const postCommentAttachment = async (taskID: number, formdata: FormData) => {
const response = await formDataAxiosInstance.post(`/api/comment/attachment/${taskID}`, formdata)
return response.data
}

export const patchComment = async (commentId: number, content: string) => {
const response = await axiosInstance.patch(`/api/comment/${commentId}`, { content })
return response.data
}

export const deleteComment = async (commentId: number) => {
const response = await axiosInstance.delete(`/api/comment/${commentId}`)
return response.data
}
1 change: 1 addition & 0 deletions src/assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

body {
font-family: 'SUIT-Variable', sans-serif;
color: #18181B;
}

.shadow-custom {
Expand Down
2 changes: 1 addition & 1 deletion src/components/my-request/MyRequestList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ import { useRequestParamsStore } from '@/stores/params'
import type { MyRequestResponse } from '@/types/user'
import { axiosInstance } from '@/utils/axios'
import { useQuery } from '@tanstack/vue-query'
import { computed } from 'vue'
import { useParseParams } from '../hooks/useParseParams'
import ListContainer from '../lists/ListContainer.vue'
import ListPagination from '../lists/ListPagination.vue'
import NoContent from '../lists/NoContent.vue'
import MyRequestListBar from './MyRequestListBar.vue'
import MyRequestListCard from './MyRequestListCard.vue'
import { computed } from 'vue'

const { params } = useRequestParamsStore()
const onPageChange = (value: number) => {
Expand Down
1 change: 0 additions & 1 deletion src/components/request-task/RequestTask.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ const handleSubmit = async () => {
const formData = new FormData()
const taskInfo = {
categoryId: category2.value.id,

title: title.value,
description: description.value
}
Expand Down
18 changes: 13 additions & 5 deletions src/components/requested/RequestedListCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<div class="list-card">
<ListCardTab
v-for="tab in requestedTabList"
@click="handleModal(info.taskId)"
:key="tab.content"
:content="tab.content"
:width="tab.width"
Expand All @@ -19,13 +20,13 @@
class="button-medium-default">
거부
</button>
<button
@click="toggleModal('reject')"
class="button-medium-default">
거부
</button>
</div>
</div>
<TaskDetail
v-if="selectedID"
:is-approved="true"
:selected-id="selectedID"
:close-task-detail="() => handleModal(null)" />

<ModalView
:is-open="isModalVisible.reject"
Expand Down Expand Up @@ -59,6 +60,7 @@ import { ref } from 'vue'
import { useRouter } from 'vue-router'
import ListCardTab from '../lists/ListCardTab.vue'
import ModalView from '../ModalView.vue'
import TaskDetail from '../task-detail/TaskDetail.vue'

const { info } = defineProps<{ info: RequestedListData }>()
const requestedTabList: ListCardProps[] = [
Expand All @@ -69,6 +71,12 @@ const requestedTabList: ListCardProps[] = [
{ 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 Down
24 changes: 15 additions & 9 deletions src/components/task-detail/TaskDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
<div
class="flex flex-col overflow-y-auto rounded-lg w-full max-w-[1200px] min-w-[1024px] bg-white p-6">
<TaskDetailTopBar
:is-approved="isApproved"
:is-approved="data?.taskStatus !== 'REQUESTED'"
:close-task-detail="closeTaskDetail"
:id="data?.taskId || 0"
:isProcessor="data?.processorNickName === info.nickname" />
:isProcessor="data?.processorNickName === info.nickname || info.memberRole === 'ROLE_'"
:isRequestor="data?.requesterNickName === info.nickname" />
<div
class="w-full flex gap-6"
v-if="data">
<div class="w-full h-[718px] flex flex-col gap-y-8 overflow-y-auto scrollbar-hide">
<TaskDetailLeft :data="data" />
<div class="w-full border-[0.5px] border-border-1"></div>
<div class="w-full h-[1px] bg-border-1 shrink-0"></div>
<TaskDetailHistory
:historyData="historyData?.histories || []"
:is-approved="isApproved" />
:task-id="selectedId"
:requestor-name="data.requesterNickName" />
</div>
<div class="w-[1px] bg-border-1"></div>
<TaskDetailRight
Expand All @@ -27,27 +29,31 @@
</template>

<script setup lang="ts">
import { getHistory, getTaskDetailManager } from '@/api/user'
import { getHistory, getTaskDetailManager, getTaskDetailUser } from '@/api/user'
import { useMemberStore } from '@/stores/member'
import type { TaskDetailDatas, TaskDetailHistoryProps, TaskDetailProps } from '@/types/user'
import type { TaskDetailDatas, TaskDetailHistoryData, TaskDetailProps } from '@/types/user'
import { useQuery } from '@tanstack/vue-query'
import { storeToRefs } from 'pinia'
import TaskDetailHistory from './TaskDetailHistory.vue'
import TaskDetailLeft from './TaskDetailLeft.vue'
import TaskDetailRight from './TaskDetailRight.vue'
import TaskDetailTopBar from './TaskDetailTopBar.vue'

const { isApproved, closeTaskDetail, selectedId } = defineProps<TaskDetailProps>()
const { closeTaskDetail, selectedId } = defineProps<TaskDetailProps>()

const memberStore = useMemberStore()
const { info } = storeToRefs(memberStore)
console.log(info, '인포')

const { data } = useQuery<TaskDetailDatas>({
queryKey: ['taskDetailUser', selectedId],
queryFn: () => getTaskDetailManager(selectedId)
queryFn:
info.value.memberRole === 'ROLE_USER'
? () => getTaskDetailUser(selectedId)
: () => getTaskDetailManager(selectedId)
})

const { data: historyData } = useQuery<TaskDetailHistoryProps>({
const { data: historyData } = useQuery<TaskDetailHistoryData>({
queryKey: ['historyData', selectedId],
queryFn: () => getHistory(selectedId)
})
Expand Down
42 changes: 36 additions & 6 deletions src/components/task-detail/TaskDetailHistory.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<template>
<div>
<p class="task-detail">히스토리</p>
<TaskDetailHistoryInput :history="historyData" />
<TaskDetailHistoryInput
:history="historyData"
:taskId="taskId"
:requestor-name="requestorName" />
<div class="flex flex-col w-full items-center gap-6 mt-8">
<div
class="flex w-full flex-col items-center gap-6"
v-for="item in historyData"
v-for="(item, i) in historyData"
:key="item.historyId">
<div
v-if="shouldDisplayDate(i)"
class="flex px-4 h-7 items-center justify-center bg-primary1 rounded-full text-white text-xs font-bold">
{{ formatDateWithDay(item.date) }}
</div>
Expand All @@ -26,7 +30,16 @@
class="text-primary1">
{{ item.details.taskDetails?.value }}
</p>
<TaskDetailHistoryChat v-else-if="item.taskHistoryType === 'COMMENT'" />
<TaskDetailHistoryChat
v-else-if="item.taskHistoryType === 'COMMENT'"
:history="item"
:requestor-name="requestorName"
:task-id="taskId" />
<TaskDetailHistoryFile
v-else-if="item.taskHistoryType === 'COMMENT_FILE'"
:history="item"
:requestor-name="requestorName"
:task-id="taskId" />
<p>{{ HistoryMessageAfter[item.taskHistoryType] }}</p>
</div>
</div>
Expand All @@ -36,11 +49,28 @@

<script setup lang="ts">
import { HistoryMessageAfter, HistoryMessageBefore } from '@/constants/user'
import type { TaskHistory } from '@/types/user'
import type { TaskDetailHistoryProps } from '@/types/common'
import { formatDateWithDay } from '@/utils/date'
import { watch } from 'vue'
import TaskDetailHistoryChat from './TaskDetailHistoryChat.vue'
import TaskDetailHistoryFile from './TaskDetailHistoryFile.vue'
import TaskDetailHistoryInput from './TaskDetailHistoryInput.vue'

const { historyData } = defineProps<{ historyData: TaskHistory[] }>()
console.log(historyData, '가져온 히스토리')
const { historyData, taskId, requestorName } = defineProps<TaskDetailHistoryProps>()

let displayedDates = new Set<string>()

const shouldDisplayDate = (index: number) => {
const date = formatDateWithDay(historyData[index].date)
if (displayedDates.has(date)) return false
else displayedDates.add(date)
return true
}

watch(
() => historyData,
() => {
displayedDates = new Set<string>()
}
)
</script>
78 changes: 71 additions & 7 deletions src/components/task-detail/TaskDetailHistoryChat.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,79 @@
<template>
<div class="flex w-full justify-start">
<div class="w-10 h-10 rounded-full pt-1.5">
<div :class="['flex w-full', isProcessor ? 'justify-end' : 'justify-start']">
<div :class="['w-10 h-10 rounded-full pt-1.5', isProcessor ? 'order-3' : 'order-1']">
<img
src="/images/mockProfile.jpg"
:src="history.details.commentDetails?.profileImageUrl || '/images/mockProfile.jpg'"
class="rounded-full" />
</div>
<div class="flex max-w-[400px] flex-wrap px-6 py-4 bg-background-2 ml-4 text-black rounded-lg">
네네... 부탁드릴게요 가능하시다면 오늘 오후 6시까지 되었으면 좋겠습니다! 감사합니다.
<div
:class="[
'flex flex-col gap-2 order-2',
isProcessor ? 'items-end pr-4 pl-1' : 'items-start pl-4 pr-1'
]">
<p>{{ history.details.commentDetails?.nickName }}</p>
<p
:class="[
'flex max-w-[400px] flex-wrap px-6 py-4 text-black rounded-lg',
isProcessor ? 'bg-primary2' : 'bg-background-2'
]">
{{ history.details.commentDetails?.comment }}
</p>
</div>
<div
:class="[
'flex flex-col h-full justify-end text-xs font-bold text-body gap-1 relative',
isProcessor ? 'order-1 items-end' : 'order-3 items-start'
]">
<div
v-if="history.details.commentDetails?.nickName === info.nickname"
class="relative cursor-pointer">
<CommonIcons
:name="menuDotIcon"
@click="clickMenuDot" />
<div
v-if="isClicked"
@click="deleteCommentText"
:class="[
'absolute shadow-custom bottom-0 w-20 h-7 flex items-center justify-center text-xs text-red-1 bg-white hover:bg-background-1',
isProcessor ? 'right-6' : 'left-6'
]">
삭제
</div>
</div>
<div class="flex flex-col gap-1">
{{ history.details.commentDetails?.isModified ? '(수정됨)' : '' }}
{{ formatTodayOrNot(history.date, history.time) }}
</div>
</div>
<div class="flex h-full items-end text-xs font-bold text-body ml-2">오후 2:18</div>
</div>
</template>

<script setup lang="ts"></script>
<script setup lang="ts">
import { deleteComment } from '@/api/user'
import { menuDotIcon } from '@/constants/iconPath'
import { useMemberStore } from '@/stores/member'
import type { TaskDetailHistoryChatProps } from '@/types/common'
import { formatTodayOrNot } from '@/utils/date'
import { useQueryClient } from '@tanstack/vue-query'
import { storeToRefs } from 'pinia'
import { computed, defineProps, ref } from 'vue'
import CommonIcons from '../common/CommonIcons.vue'

const memberStore = useMemberStore()
const { info } = storeToRefs(memberStore)
const isClicked = ref(false)
const isProcessor = computed(() => history.details.commentDetails?.nickName !== requestorName)
const queryClient = useQueryClient()

const { taskId, history, requestorName } = defineProps<TaskDetailHistoryChatProps>()

const clickMenuDot = async () => {
isClicked.value = !isClicked.value
}

const deleteCommentText = async () => {
isClicked.value = !isClicked.value
await deleteComment(history.historyId)
queryClient.invalidateQueries({ queryKey: ['historyData', taskId] })
}
</script>
Loading
Loading