Skip to content

Commit 943fa50

Browse files
authored
Merge pull request #34 from TaskFlow-CLAP/CLAP-134
CLAP-134 팀 작업 현황 페이지 UI 제작
2 parents eaf28bf + 2964a51 commit 943fa50

File tree

16 files changed

+527
-4
lines changed

16 files changed

+527
-4
lines changed

package-lock.json

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
},
1515
"dependencies": {
1616
"axios": "^1.7.9",
17+
"chart.js": "^4.4.7",
1718
"js-cookie": "^3.0.5",
1819
"pinia": "^2.3.0",
1920
"vue": "^3.5.13",
21+
"vue-chartjs": "^5.3.2",
2022
"vue-router": "^4.5.0",
2123
"vuedraggable": "^4.1.0"
2224
},

src/components/PieChart.vue

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<template>
2+
<Pie
3+
:data="teamData"
4+
:options="options" />
5+
</template>
6+
7+
<script setup lang="ts">
8+
import { Pie } from 'vue-chartjs'
9+
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, Colors } from 'chart.js'
10+
ChartJS.register(Title, Tooltip, Legend, ArcElement, Colors)
11+
12+
const { labels, series } = defineProps<{ labels: string[]; series: number[] }>()
13+
14+
const teamData = {
15+
labels,
16+
datasets: [
17+
{
18+
data: series
19+
}
20+
]
21+
}
22+
23+
const options = {
24+
responsive: true,
25+
maintainAspectRatio: false
26+
}
27+
</script>

src/components/TaskCard.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
<div class="flex flex-col gap-1">
77
<div class="flex justify-between items-center gap-4">
88
<span class="text-black">{{ data.title }}</span>
9-
<CommonIcons :name="bentoIcon" />
9+
<CommonIcons
10+
v-if="draggable"
11+
:name="bentoIcon" />
1012
</div>
1113
<span class="text-xs text-body">{{ data.mainCategoryName }} - {{ data.categoryName }}</span>
1214
</div>
@@ -33,7 +35,7 @@ import type { TaskCardProps } from '@/types/manager'
3335
import CommonIcons from './common/CommonIcons.vue'
3436
import { statusAsColor } from '@/utils/statusAsColor'
3537
36-
const { data } = defineProps<{ data: TaskCardProps }>()
38+
const { data } = defineProps<{ data: TaskCardProps; draggable?: boolean }>()
3739
3840
const borderLeft = computed(() => {
3941
return `border-${statusAsColor(data.taskStatus as Status)}-1`
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useTeamBoardParamsStore } from '@/stores/params'
2+
3+
export const useTeamBoardParamsChange = () => {
4+
const { params } = useTeamBoardParamsStore()
5+
6+
const onArrayChange = <Value extends number | string>(array: Value[], value: Value) => {
7+
return array.includes(value) ? array.filter(el => el !== value) : [...array, value]
8+
}
9+
10+
const onOrderChange = (value: string) => {
11+
params.order = value
12+
}
13+
const onTitleChange = (value: string) => {
14+
params.title = value
15+
}
16+
const onMainChange = (value: number) => {
17+
params.mainCategoryId = onArrayChange(params.mainCategoryId, value)
18+
}
19+
const onSubChange = (value: number) => {
20+
params.categoryId = onArrayChange(params.categoryId, value)
21+
}
22+
23+
return {
24+
onOrderChange,
25+
onTitleChange,
26+
onMainChange,
27+
onSubChange
28+
}
29+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<template>
2+
<div class="flex flex-col gap-3">
3+
<span class="text-xl font-bold text-black">현재 작업 비율</span>
4+
<div class="flex flex-col gap-4">
5+
<div class="flex justify-between items-center">
6+
<div class="flex items-center gap-3">
7+
<span class="text-xs font-bold text-body">진행 중 {{ teamSummary.inProgress }}건</span>
8+
<div class="w-[1px] h-[10px] bg-body" />
9+
<span class="text-xs font-bold text-body"
10+
>완료 대기 {{ teamSummary.pendingCompletion }}건</span
11+
>
12+
</div>
13+
<span class="text-xs font-bold text-primary1">총 {{ teamSummary.totalTasks }}건</span>
14+
</div>
15+
<div
16+
class="w-full h-[360px] rounded-lg bg-primary2 shadow-custom overflow-y-scroll items-center p-6 gap-4">
17+
<PieChart
18+
:labels="chartLabels"
19+
:series="chartSeries" />
20+
</div>
21+
</div>
22+
</div>
23+
</template>
24+
25+
<script setup lang="ts">
26+
import PieChart from '../PieChart.vue'
27+
28+
const { teamSummary, teamData } = defineProps<{
29+
teamSummary: {
30+
inProgress: number
31+
pendingCompletion: number
32+
totalTasks: number
33+
}
34+
teamData: { name: string; tasks: number }[]
35+
}>()
36+
37+
const chartSeries = teamData.map(member => member.tasks)
38+
const chartLabels = teamData.map(member => member.name)
39+
</script>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<div class="grow overflow-y-scroll p-6">
3+
<div class="grid grid-cols-3 gap-12">
4+
<CurrentTaskRatio
5+
:team-summary="teamSummary"
6+
:team-data="teamData" />
7+
<TeamBoardCard
8+
v-for="member in DUMMY_TEAM_MEMBERS_LIST"
9+
:key="member.name"
10+
:name="member.name"
11+
:department="member.department"
12+
:task-status-summary="member.taskStatusSummary"
13+
:tasks="member.tasks" />
14+
</div>
15+
</div>
16+
</template>
17+
18+
<script setup lang="ts">
19+
import { DUMMY_TEAM_MEMBERS_LIST } from '@/datas/dummy'
20+
import TeamBoardCard from './TeamBoardCard.vue'
21+
import CurrentTaskRatio from './CurrentTaskRatio.vue'
22+
23+
const getSummaryCount = (key: 'inProgress' | 'pendingCompletion' | 'totalTasks') => {
24+
let count = 0
25+
DUMMY_TEAM_MEMBERS_LIST.forEach(el => (count += el.taskStatusSummary[key]))
26+
return count
27+
}
28+
const teamSummary = {
29+
inProgress: getSummaryCount('inProgress'),
30+
pendingCompletion: getSummaryCount('pendingCompletion'),
31+
totalTasks: getSummaryCount('totalTasks')
32+
}
33+
34+
const teamData = DUMMY_TEAM_MEMBERS_LIST.map(el => ({
35+
name: el.name,
36+
tasks: el.taskStatusSummary.totalTasks
37+
}))
38+
</script>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<template>
2+
<div class="flex flex-col gap-4">
3+
<div class="flex justify-between items-center">
4+
<div class="flex items-center gap-2">
5+
<div class="w-6 h-6 rounded-full overflow-hidden">
6+
<img src="https://picsum.photos/24" />
7+
</div>
8+
<span class="text-black">{{ name }}</span>
9+
</div>
10+
<span class="text-xs font-bold text-body">{{ department }}</span>
11+
</div>
12+
<div class="flex justify-between items-center">
13+
<div class="flex items-center gap-3">
14+
<span class="text-xs font-bold text-body"
15+
>진행 중 {{ taskStatusSummary.inProgress }}건</span
16+
>
17+
<div class="w-[1px] h-[10px] bg-body" />
18+
<span class="text-xs font-bold text-body"
19+
>완료 대기 {{ taskStatusSummary.pendingCompletion }}건</span
20+
>
21+
</div>
22+
<span class="text-xs font-bold text-primary1">총 {{ taskStatusSummary.totalTasks }}건</span>
23+
</div>
24+
<div
25+
class="w-full h-[360px] rounded-lg bg-primary2 shadow-custom overflow-y-scroll flex flex-col items-center p-6 gap-4">
26+
<TaskCard
27+
v-for="task in tasks"
28+
:key="task.taskId"
29+
:data="task" />
30+
</div>
31+
</div>
32+
</template>
33+
34+
<script setup lang="ts">
35+
import type { TeamBoardCardProps } from '@/types/manager'
36+
import TaskCard from '../TaskCard.vue'
37+
38+
const { name, department, taskStatusSummary, tasks } = defineProps<TeamBoardCardProps>()
39+
</script>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<template>
2+
<div class="flex gap-4">
3+
<FilterDropdown
4+
title="정렬"
5+
:option-list="[
6+
{ value: 'CONTRIBUTION', content: '기여도순' },
7+
{ value: 'NAME', content: '이름순' }
8+
]"
9+
:value="params.order"
10+
@update:value="onParamsChange.onOrderChange" />
11+
<FilterInput
12+
title="제목"
13+
:value="''"
14+
@update:value="onParamsChange.onTitleChange" />
15+
<FilterCategory
16+
:category-list="DUMMY_CATEGORY_LIST"
17+
:main="params.mainCategoryId"
18+
:sub="params.categoryId"
19+
@update:main="onParamsChange.onMainChange"
20+
@update:sub="onParamsChange.onSubChange" />
21+
</div>
22+
</template>
23+
24+
<script setup lang="ts">
25+
import { DUMMY_CATEGORY_LIST } from '@/datas/dummy'
26+
import FilterCategory from '../filters/FilterCategory.vue'
27+
import FilterDropdown from '../filters/FilterDropdown.vue'
28+
import FilterInput from '../filters/FilterInput.vue'
29+
import { useTeamBoardParamsStore } from '@/stores/params'
30+
import { useTeamBoardParamsChange } from '../hooks/useTeamBoardParamsChange'
31+
32+
const { params } = useTeamBoardParamsStore()
33+
34+
const onParamsChange = useTeamBoardParamsChange()
35+
</script>

0 commit comments

Comments
 (0)