Skip to content

Commit 72d65e7

Browse files
authored
Merge pull request #35 from TaskFlow-CLAP/CLAP-141
Clap-141 요청 승인 UI제작
2 parents 943fa50 + 96b1d13 commit 72d65e7

File tree

14 files changed

+236
-21
lines changed

14 files changed

+236
-21
lines changed

src/assets/styles.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,13 @@ body {
104104
.task-detail {
105105
@apply text-xs text-body font-bold mb-2;
106106
}
107+
108+
.request-task-dropdown {
109+
@apply flex w-full h-11 items-center rounded p-4 bg-white border border-border-1 cursor-pointer;
110+
}
111+
.request-task-dropdown-option-list {
112+
@apply absolute w-full h-40 overflow-y-auto top-[52px] flex flex-col gap-2 p-2 bg-white rounded z-10 shadow border-t border-t-border-2;
113+
}
114+
.request-task-dropdown-option {
115+
@apply w-full flex items-center h-11 p-2 rounded hover:bg-background-2 cursor-pointer;
116+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<input
3+
:type="inputType"
4+
:v-model="modelValue"
5+
class="w-full border border-gray-300 rounded px-3 py-2 cursor-pointer focus:outline-none text-center"
6+
@focus="e => (e.target as HTMLInputElement).showPicker()" />
7+
</template>
8+
9+
<script lang="ts" setup>
10+
import type { DueDateInputProps } from '@/types/common'
11+
import { defineProps } from 'vue'
12+
13+
const { modelValue, inputType } = defineProps<DueDateInputProps>()
14+
</script>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<template>
2+
<div>
3+
<div class="flex text-xs gap-x-1 mb-2">
4+
<p class="text-body font-bold">{{ labelName }}</p>
5+
<p class="text-red-1">*</p>
6+
</div>
7+
<div class="relative flex text-base">
8+
<div
9+
class="request-task-dropdown"
10+
@click="toggleDropdown">
11+
<p :class="{ 'text-body': modelValue === placeholderText }">
12+
{{ modelValue || placeholderText }}
13+
</p>
14+
<CommonIcons
15+
:name="dropdownIcon"
16+
:class="['ml-auto', { 'rotate-180': dropdownOpen }]" />
17+
</div>
18+
<div
19+
v-if="dropdownOpen"
20+
class="request-task-dropdown-option-list">
21+
<div
22+
v-for="option in options"
23+
:key="option"
24+
class="request-task-dropdown-option justify-between"
25+
@click="selectOption(option)">
26+
<div class="flex gap-2">
27+
<div class="w-6 h-6 rounded-full overflow-hidden">
28+
<img
29+
src="/images/mockProfile.jpg"
30+
alt="userProfile" />
31+
</div>
32+
<p>
33+
{{ option }}
34+
</p>
35+
</div>
36+
<p class="text-primary1 text-xs">잔여 작업 : {{ 3 }}</p>
37+
</div>
38+
</div>
39+
</div>
40+
</div>
41+
</template>
42+
43+
<script lang="ts" setup>
44+
import { dropdownIcon } from '@/constants/iconPath'
45+
import type { RequestTaskDropdownProps } from '@/types/user'
46+
import { ref } from 'vue'
47+
import CommonIcons from '../common/CommonIcons.vue'
48+
49+
const { placeholderText, options, labelName, modelValue } = defineProps<RequestTaskDropdownProps>()
50+
const emit = defineEmits(['update:modelValue'])
51+
const dropdownOpen = ref(false)
52+
53+
const toggleDropdown = () => {
54+
dropdownOpen.value = !dropdownOpen.value
55+
}
56+
57+
const selectOption = (option: string) => {
58+
emit('update:modelValue', option)
59+
dropdownOpen.value = false
60+
}
61+
</script>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<template>
2+
<div class="w-[552px] flex flex-col gap-y-6">
3+
<ModalView
4+
:isOpen="isModalVisible"
5+
:type="'successType'"
6+
@close="handleCancel">
7+
<template #header> 요청이 승인되었습니다 </template>
8+
</ModalView>
9+
<RequestTaskDropdown
10+
v-model="approveForm.category1"
11+
:options="DUMMY_REQUEST_TASK_CATEGORIES"
12+
:label-name="'1차 카테고리'"
13+
:placeholderText="'1차 카테고리를 선택해주세요'" />
14+
<RequestTaskDropdown
15+
v-model="approveForm.category2"
16+
:options="DUMMY_REQUEST_TASK_CATEGORIES"
17+
:label-name="'2차 카테고리'"
18+
:placeholderText="'2차 카테고리를 선택해주세요'" />
19+
<ProcessorDropdown
20+
v-model="approveForm.processor"
21+
:options="DUMMY_REQUEST_PROCESSORS"
22+
:label-name="'담당자'"
23+
:placeholderText="'담당자를 선택해주세요'" />
24+
<div class="flex flex-col gap-2">
25+
<p class="text-body text-xs font-bold">마감기한</p>
26+
<div class="flex w-full justify-center gap-6">
27+
<DueDateInput
28+
v-model="approveForm.dueDate"
29+
inputType="date" />
30+
<DueDateInput
31+
v-model="approveForm.dueTime"
32+
inputType="time" />
33+
</div>
34+
</div>
35+
<RequestTaskDropdown
36+
v-model="approveForm.labeling"
37+
:options="DUMMY_REQUEST_TASK_LABELS"
38+
:label-name="'구분'"
39+
:is-label="true"
40+
:placeholderText="'구분을 선택해주세요'" />
41+
<div class="w-full mt-4 flex justify-center">
42+
<div class="w-[400px] flex gap-6">
43+
<button
44+
class="button-large-default"
45+
@click="handleCancel">
46+
취소
47+
</button>
48+
<button
49+
class="button-large-primary"
50+
@click="handleSubmit">
51+
승인
52+
</button>
53+
</div>
54+
</div>
55+
</div>
56+
</template>
57+
58+
<script lang="ts" setup>
59+
import { INITIAL_REQUEST_APPROVE_FORM } from '@/constants/manager'
60+
import {
61+
DUMMY_REQUEST_PROCESSORS,
62+
DUMMY_REQUEST_TASK_CATEGORIES,
63+
DUMMY_REQUEST_TASK_LABELS
64+
} from '@/datas/taskdetail'
65+
import { ref } from 'vue'
66+
import ModalView from '../ModalView.vue'
67+
import RequestTaskDropdown from '../request-task/RequestTaskDropdown.vue'
68+
import DueDateInput from './DueDateInput.vue'
69+
import ProcessorDropdown from './ProcessorDropdown.vue'
70+
71+
const isModalVisible = ref(false)
72+
const approveForm = ref(INITIAL_REQUEST_APPROVE_FORM)
73+
74+
const handleCancel = () => {
75+
approveForm.value = { ...INITIAL_REQUEST_APPROVE_FORM }
76+
isModalVisible.value = false
77+
}
78+
79+
const handleSubmit = () => {
80+
const formData = new FormData()
81+
formData.append('approveForm', JSON.stringify(approveForm.value))
82+
console.log(JSON.parse(formData.get('approveForm') as string))
83+
isModalVisible.value = true
84+
}
85+
</script>

src/components/request-task/RequestTask.vue

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
<div class="w-[552px] flex flex-col gap-y-6">
33
<RequestTaskDropdown
44
v-model="category1"
5-
:options="REQUEST_TASK_CATEGORIES"
5+
:options="DUMMY_REQUEST_TASK_CATEGORIES"
66
:label-name="'1차 카테고리'"
77
:placeholderText="'1차 카테고리를 선택해주세요'" />
88
<RequestTaskDropdown
99
v-model="category2"
10-
:options="REQUEST_TASK_CATEGORIES"
10+
:options="DUMMY_REQUEST_TASK_CATEGORIES"
1111
:label-name="'2차 카테고리'"
1212
:placeholderText="'2차 카테고리를 선택해주세요'" />
1313
<RequestTaskInput
@@ -18,23 +18,23 @@
1818
:placeholderText="EXPLANATION_PLACEHOLDER" />
1919
<RequestTaskFileInput v-model="file" />
2020
<div class="w-full justify-center flex gap-6 mt-4">
21-
<button
22-
class="w-[188px] h-[52px] rounded text-white bg-primary1 flex items-center justify-center"
23-
@click="handleSubmit">
24-
요청
25-
</button>
2621
<button
2722
class="w-[188px] h-[52px] border border-disabled rounded text-disabled bg-white flex items-center justify-center"
2823
@click="handleCancel">
2924
취소
3025
</button>
26+
<button
27+
class="w-[188px] h-[52px] rounded text-white bg-primary1 flex items-center justify-center"
28+
@click="handleSubmit">
29+
요청
30+
</button>
3131
</div>
3232
</div>
3333
</template>
3434

3535
<script lang="ts" setup>
3636
import { EXPLANATION_PLACEHOLDER, TITLE_PLACEHOLDER } from '@/constants/user'
37-
import { REQUEST_TASK_CATEGORIES } from '@/datas/taskdetail'
37+
import { DUMMY_REQUEST_TASK_CATEGORIES } from '@/datas/taskdetail'
3838
import { ref } from 'vue'
3939
import RequestTaskDropdown from './RequestTaskDropdown.vue'
4040
import RequestTaskFileInput from './RequestTaskFileInput.vue'

src/components/request-task/RequestTaskDropdown.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
<div>
33
<div class="flex text-xs gap-x-1 mb-2">
44
<p class="text-body font-bold">{{ labelName }}</p>
5-
<p class="text-red-1">*</p>
5+
<p
6+
v-if="!isLabel"
7+
class="text-red-1">
8+
*
9+
</p>
610
</div>
711
<div class="relative flex text-base">
812
<div
@@ -36,7 +40,8 @@ import type { RequestTaskDropdownProps } from '@/types/user'
3640
import { ref } from 'vue'
3741
import CommonIcons from '../common/CommonIcons.vue'
3842
39-
const { placeholderText, options, labelName, modelValue } = defineProps<RequestTaskDropdownProps>()
43+
const { placeholderText, options, labelName, modelValue, isLabel } =
44+
defineProps<RequestTaskDropdownProps>()
4045
const emit = defineEmits(['update:modelValue'])
4146
const dropdownOpen = ref(false)
4247

src/constants/manager.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ListBarTabProps } from '@/types/common'
2+
import type { RequestApproveFormData } from '@/types/manager'
23

34
export const REQUESTED_LIST_BAR_TAB: ListBarTabProps[] = [
45
{ content: '요청일', width: 80, sortBy: 'REQUESTED' },
@@ -31,3 +32,12 @@ export const MY_TASK_LIST_BAR_TAB: ListBarTabProps[] = [
3132
{ content: '상태', width: 64 },
3233
{ content: '종료일', width: 80, sortBy: 'FINISHED' }
3334
]
35+
36+
export const INITIAL_REQUEST_APPROVE_FORM: RequestApproveFormData = {
37+
category1: '1차 카테고리를 선택해주세요',
38+
category2: '2차 카테고리를 선택해주세요',
39+
processor: '담당자를 선택해주세요',
40+
labeling: '구분을 선택해주세요',
41+
dueDate: '',
42+
dueTime: ''
43+
}

src/datas/taskdetail.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type {
44
TaskDetailRightProps
55
} from '@/types/user'
66

7-
export const REQUEST_TASK_CATEGORIES: string[] = [
7+
export const DUMMY_REQUEST_TASK_CATEGORIES: string[] = [
88
'Categroy 1',
99
'Categroy 2',
1010
'Categroy 3',
@@ -103,3 +103,7 @@ export const DUMMY_TASK_DETAIL_HISTORY: TaskDetailHistoryProps[] = [
103103
}
104104
}
105105
]
106+
107+
export const DUMMY_REQUEST_PROCESSORS: string[] = ['Tony', 'Chloe', 'Moya', 'MoyaMoya']
108+
109+
export const DUMMY_REQUEST_TASK_LABELS: string[] = ['긴급', '정기', '오류', '점검']

src/router/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const router = createRouter({
3434
},
3535
{
3636
path: '/task-request',
37-
name: 'task-request',
37+
name: 'TaskRequest',
3838
component: () => import('../views/TaskRequestView.vue')
3939
},
4040
{
@@ -72,6 +72,11 @@ const router = createRouter({
7272
path: '/team-board',
7373
name: 'TeamBoard',
7474
component: () => import('../views/TeamBoardView.vue')
75+
},
76+
{
77+
path: '/request-approve',
78+
name: 'RequestApprove',
79+
component: () => import('../views/RequestApproveView.vue')
7580
}
7681
]
7782
})

src/types/common.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ export type Status = '요청' | '진행 중' | '검토 중' | '완료' | '종료
4747
export type SortDirection = 'DESC' | 'ASC'
4848

4949
export type Role = 'USER' | 'MANAGER' | 'ADMIN'
50+
51+
export interface DueDateInputProps {
52+
modelValue: string
53+
inputType: string
54+
}

0 commit comments

Comments
 (0)