feat: 업무 상세 해야 할 일을 카테고리 탭 구조로 변경

그룹 나열 → 필수/관리/보안/부가 탭으로 전환(생성 화면·보고 모달과 동일한 탭 UI 재사용).
검토 모달은 기존 그룹 구조 유지.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 15:39:54 +09:00
parent 98a2308c4e
commit 814dd7bb8b
+77 -53
View File
@@ -64,13 +64,22 @@ const checklistPct = computed(() => {
// 수정 요청(changes) 상태 — 미완료 항목을 '보완 필요(X)'로 표기
const isChangesReview = computed(() => task.value?.status === 'changes')
// 카테고리별 그룹(항목 있는 카테고리만, 필수/관리/보안/부가 고정 순서)
// 카테고리별 그룹(항목 있는 카테고리만, 필수/관리/보안/부가 고정 순서) — 검토 모달에서 사용
const checklistGroups = computed(() =>
CHECKLIST_CATEGORIES.map((cat) => ({
category: cat,
items: task.value?.checklist.filter((c) => c.category === cat) ?? [],
})).filter((g) => g.items.length > 0),
)
// 상세 체크리스트 — 카테고리 탭 구조
const checklistTab = ref<ChecklistCategory>('필수')
const checklistTabItems = computed(
() => task.value?.checklist.filter((c) => c.category === checklistTab.value) ?? [],
)
function checklistCatCount(cat: ChecklistCategory): number {
return task.value?.checklist.filter((c) => c.category === cat).length ?? 0
}
// 카테고리 → 색상 클래스(필수=sec-1 …)
function categoryClass(cat: ChecklistCategory): string {
const map: Record<ChecklistCategory, string> = {
@@ -642,71 +651,78 @@ function badgeFor(name: string | undefined): { label: string; cls: string } {
완료 처리는 승인 워크플로우(승인 완료 일괄 완료)로만 이루어진다.
-->
<div class="checklist">
<!-- 카테고리 -->
<div
v-for="group in checklistGroups"
:key="group.category"
class="cat-group"
class="cat-tabs ck-tabs"
role="tablist"
>
<div
class="cat-group-head"
:class="categoryClass(group.category)"
<button
v-for="tab in CHECKLIST_CATEGORIES"
:key="tab"
type="button"
class="cat-tab"
:class="[categoryClass(tab), { active: checklistTab === tab }]"
role="tab"
:aria-selected="checklistTab === tab"
@click="checklistTab = tab"
>
<span class="cat-dot" />
<span class="cat-name">{{ group.category }}</span>
<span class="cat-count">{{ group.items.length }}</span>
</div>
{{ tab }}
<span class="cat-count">{{ checklistCatCount(tab) }}</span>
</button>
</div>
<!-- 활성 항목 -->
<div
v-for="(item, i) in checklistTabItems"
:key="item.id ?? i"
class="citem-wrap"
>
<div
v-for="(item, i) in group.items"
:key="item.id ?? i"
class="citem-wrap"
class="citem"
:class="{ done: item.done, todo: !item.done && isChangesReview }"
>
<div
class="citem"
<span
class="cbox"
:class="{ done: item.done, todo: !item.done && isChangesReview }"
>
<span
class="cbox"
:class="{ done: item.done, todo: !item.done && isChangesReview }"
>
<svg
v-if="item.done"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="3.5"
stroke-linecap="round"
stroke-linejoin="round"
><path d="M20 6 9 17l-5-5" /></svg>
<svg
v-else-if="isChangesReview"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="3.5"
stroke-linecap="round"
stroke-linejoin="round"
><path d="M18 6 6 18M6 6l12 12" /></svg>
</span>
<span class="ctext">{{ item.text }}</span>
<span
v-if="!item.done && isChangesReview"
class="citem-tag"
>보완 필요</span>
</div>
<!-- 항목별 보완 내용(수정 요청 입력된 경우) -->
<div
v-if="!item.done && isChangesReview && item.reviewNote"
class="citem-note"
>
{{ item.reviewNote }}
</div>
<svg
v-if="item.done"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="3.5"
stroke-linecap="round"
stroke-linejoin="round"
><path d="M20 6 9 17l-5-5" /></svg>
<svg
v-else-if="isChangesReview"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="3.5"
stroke-linecap="round"
stroke-linejoin="round"
><path d="M18 6 6 18M6 6l12 12" /></svg>
</span>
<span class="ctext">{{ item.text }}</span>
<span
v-if="!item.done && isChangesReview"
class="citem-tag"
>보완 필요</span>
</div>
<!-- 항목별 보완 내용(수정 요청 입력된 경우) -->
<div
v-if="!item.done && isChangesReview && item.reviewNote"
class="citem-note"
>
{{ item.reviewNote }}
</div>
</div>
<div
v-if="checklistGroups.length === 0"
v-if="checklistTabItems.length === 0"
class="check-empty"
>
등록된 없습니다.
'{{ checklistTab }}' 항목 없습니다.
</div>
</div>
</div>
@@ -3512,6 +3528,14 @@ a.file-info {
gap: 0.25rem;
padding: 0.75rem 1.25rem 0;
}
/* 체크리스트 카드용 탭 — 모달과 달리 좌우 패딩 없이, 항목과 구분선 */
.ck-tabs {
flex-wrap: wrap;
padding: 0;
margin-bottom: 0.75rem;
border-bottom: 1px solid var(--border);
padding-bottom: 0.5rem;
}
.cat-tab {
display: inline-flex;
align-items: center;