From ef1d718fb850dc4122926f0502c64f15e02c93fa Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Sat, 27 Jun 2026 21:38:07 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=86=B5=EA=B3=84=20=EB=B6=84=EB=A5=98?= =?UTF-8?q?=EB=B3=84=20=EC=A7=91=EA=B3=84=EB=A5=BC=20=EB=8C=80=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20(=EC=86=8C?= =?UTF-8?q?=EB=B6=84=EB=A5=98=20=ED=8E=BC=EC=B9=A8=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=EB=A1=9C=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EB=8B=A8=EC=B6=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - catByMajor: 소분류를 부모 대분류로 합산해 파이/범례 표기 - 중복되던 '대분류 합계' 섹션 제거 Co-Authored-By: Claude Opus 4.8 --- src/views/account/AccountDashboardView.vue | 55 +++++++++------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/views/account/AccountDashboardView.vue b/src/views/account/AccountDashboardView.vue index eb5057e..760cde1 100644 --- a/src/views/account/AccountDashboardView.vue +++ b/src/views/account/AccountDashboardView.vue @@ -114,12 +114,32 @@ function hideTip() { const PIE_R = 46 // viewBox 120 기준, 선두께 20(hover 24) 포함해도 잘리지 않도록 (46+12=58 ≤ 60) const PIE_C = 2 * Math.PI * PIE_R const PIE_COLORS = ['#3b82a6', '#e67e22', '#2e7d32', '#9b59b6', '#c0392b', '#16a085', '#f39c12', '#8e44ad', '#27ae60', '#d35400', '#2980b9', '#7f8c8d'] -const catTotal = computed(() => catData.value.reduce((s, d) => s + d.total, 0)) +// 분류별 집계를 대분류 기준으로 묶는다 (소분류까지 펼치면 항목이 너무 많아 스크롤이 길어짐). +// 소분류는 부모(대분류)명으로 합산, 매핑이 없으면 자기 자신을 대분류로 본다. +const catByMajor = computed(() => { + const list = categoryList.value.filter((c) => c.type === catType.value) + const byId = {} + list.forEach((c) => (byId[c.id] = c)) + const toMajor = (name) => { + const c = list.find((x) => x.name === name) + if (c && c.parentId != null && byId[c.parentId]) return byId[c.parentId].name + return name + } + const map = {} + for (const d of catData.value) { + const major = toMajor(d.category) + map[major] = (map[major] || 0) + d.total + } + return Object.entries(map) + .map(([category, total]) => ({ category, total })) + .sort((a, b) => b.total - a.total) +}) +const catTotal = computed(() => catByMajor.value.reduce((s, d) => s + d.total, 0)) const pieSegments = computed(() => { const total = catTotal.value if (total <= 0) return [] let acc = 0 - return catData.value.map((d, i) => { + return catByMajor.value.map((d, i) => { const len = (d.total / total) * PIE_C const seg = { category: d.category, @@ -196,26 +216,6 @@ async function loadCategoryList() { categoryList.value = [] } } -// 소분류명 → 대분류명 매핑(현재 구분). 소분류가 아니면 자기 자신. -const majorRollup = computed(() => { - const list = categoryList.value.filter((c) => c.type === catType.value) - const byId = {} - list.forEach((c) => (byId[c.id] = c)) - const toMajor = (name) => { - const c = list.find((x) => x.name === name) - if (c && c.parentId != null && byId[c.parentId]) return byId[c.parentId].name - return name - } - const map = {} - for (const d of catData.value) { - const major = toMajor(d.category) - map[major] = (map[major] || 0) + d.total - } - const rows = Object.entries(map).map(([category, total]) => ({ category, total })).sort((a, b) => b.total - a.total) - // 실제로 묶인 게 있을 때만(소분류 존재) 노출 - const hasSub = list.some((c) => c.parentId != null) && rows.length < catData.value.length - return hasSub ? rows : [] -}) function setCatType(t) { catType.value = t loadCat() @@ -422,16 +422,7 @@ onMounted(async () => { -
-
대분류 합계
-
    -
  • - {{ m.category }} - {{ won(m.total) }} -
  • -
-
-

{{ catType === 'EXPENSE' ? '지출' : '수입' }} 내역이 없습니다.

+

{{ catType === 'EXPENSE' ? '지출' : '수입' }} 내역이 없습니다.