Merge branch 'dev'
This commit is contained in:
@@ -37,10 +37,47 @@ const form = reactive({
|
||||
const submitting = ref(false)
|
||||
const formError = ref(null)
|
||||
|
||||
// 드롭다운(계좌별 내역)
|
||||
// 드롭다운(계좌별 내역) — 월별로 표시
|
||||
const expandedId = ref(null)
|
||||
const entriesByWallet = reactive({})
|
||||
const loadingEntries = ref(false)
|
||||
const entryMonth = reactive({}) // 계좌별 선택 월(YYYY-MM)
|
||||
|
||||
function currentYm() {
|
||||
const d = new Date()
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
|
||||
}
|
||||
function ymLabel(ym) {
|
||||
return ym ? ym.replace('-', '.') : ''
|
||||
}
|
||||
// 데이터가 있는 월 목록(오름차순)
|
||||
function monthList(w) {
|
||||
const set = new Set((entriesByWallet[w.id] || []).map((e) => (e.entryDate || '').slice(0, 7)).filter(Boolean))
|
||||
return [...set].sort()
|
||||
}
|
||||
function monthEntries(w) {
|
||||
const ym = entryMonth[w.id]
|
||||
return (entriesByWallet[w.id] || []).filter((e) => (e.entryDate || '').slice(0, 7) === ym)
|
||||
}
|
||||
function monthSum(w) {
|
||||
return monthEntries(w).reduce((s, e) => s + effectAmount(e, w.id), 0)
|
||||
}
|
||||
function canPrev(w) {
|
||||
return monthList(w).indexOf(entryMonth[w.id]) > 0
|
||||
}
|
||||
function canNext(w) {
|
||||
const ms = monthList(w)
|
||||
const i = ms.indexOf(entryMonth[w.id])
|
||||
return i >= 0 && i < ms.length - 1
|
||||
}
|
||||
// 데이터가 있는 월 사이로만 이동(빈 달 건너뜀)
|
||||
function shiftMonth(w, delta) {
|
||||
const ms = monthList(w)
|
||||
if (!ms.length) return
|
||||
const i = ms.indexOf(entryMonth[w.id])
|
||||
const j = Math.min(ms.length - 1, Math.max(0, (i === -1 ? ms.length - 1 : i) + delta))
|
||||
entryMonth[w.id] = ms[j]
|
||||
}
|
||||
|
||||
const isLiability = (t) => t === 'CARD' || t === 'LOAN'
|
||||
|
||||
@@ -109,6 +146,9 @@ async function toggleExpand(w) {
|
||||
loadingEntries.value = true
|
||||
try {
|
||||
entriesByWallet[w.id] = await accountApi.walletEntries(w.id)
|
||||
// 기본 선택 월 = 내역이 있는 가장 최근 월(없으면 이번 달)
|
||||
const ms = monthList(w)
|
||||
entryMonth[w.id] = ms.length ? ms[ms.length - 1] : currentYm()
|
||||
} catch {
|
||||
entriesByWallet[w.id] = []
|
||||
} finally {
|
||||
@@ -366,15 +406,27 @@ onBeforeUnmount(() => sortable?.destroy())
|
||||
<InvestPortfolio v-else-if="w.type === 'INVEST'" :wallet-id="w.id" @changed="load" />
|
||||
<template v-else>
|
||||
<p v-if="loadingEntries" class="drop-msg">불러오는 중...</p>
|
||||
<ul v-else-if="(entriesByWallet[w.id] || []).length" class="drop-list">
|
||||
<li v-for="e in entriesByWallet[w.id]" :key="e.id" class="drop-row">
|
||||
<span class="d-date">{{ entryDate(e.entryDate) }}</span>
|
||||
<span class="d-desc">{{ entryDesc(e, w) }}</span>
|
||||
<span class="d-amount" :class="effectAmount(e, w.id) < 0 ? 'neg' : 'pos'">
|
||||
{{ effectAmount(e, w.id) >= 0 ? '+' : '' }}{{ won(effectAmount(e, w.id)) }}
|
||||
<template v-else-if="(entriesByWallet[w.id] || []).length">
|
||||
<!-- 월 네비게이션 + 그 달 합계 -->
|
||||
<div class="month-nav">
|
||||
<button type="button" class="mn-btn" :disabled="!canPrev(w)" aria-label="이전 달" @click="shiftMonth(w, -1)">◀</button>
|
||||
<span class="mn-label">{{ ymLabel(entryMonth[w.id]) }}</span>
|
||||
<button type="button" class="mn-btn" :disabled="!canNext(w)" aria-label="다음 달" @click="shiftMonth(w, 1)">▶</button>
|
||||
<span class="mn-sum" :class="monthSum(w) < 0 ? 'neg' : 'pos'">
|
||||
합계 {{ monthSum(w) >= 0 ? '+' : '' }}{{ won(monthSum(w)) }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul v-if="monthEntries(w).length" class="drop-list">
|
||||
<li v-for="e in monthEntries(w)" :key="e.id" class="drop-row">
|
||||
<span class="d-date">{{ entryDate(e.entryDate) }}</span>
|
||||
<span class="d-desc">{{ entryDesc(e, w) }}</span>
|
||||
<span class="d-amount" :class="effectAmount(e, w.id) < 0 ? 'neg' : 'pos'">
|
||||
{{ effectAmount(e, w.id) >= 0 ? '+' : '' }}{{ won(effectAmount(e, w.id)) }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else class="drop-msg">이 달 내역이 없습니다.</p>
|
||||
</template>
|
||||
<p v-else class="drop-msg">연관 내역이 없습니다.</p>
|
||||
</template>
|
||||
</div>
|
||||
@@ -576,6 +628,45 @@ button.primary {
|
||||
font-size: 0.78rem;
|
||||
margin: 0;
|
||||
}
|
||||
.month-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.3rem 0 0.4rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.mn-btn {
|
||||
width: 1.8rem;
|
||||
height: 1.8rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
background: var(--color-background-soft);
|
||||
color: var(--color-text);
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
}
|
||||
.mn-btn:disabled {
|
||||
opacity: 0.35;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.mn-label {
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
min-width: 4.2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.mn-sum {
|
||||
margin-left: auto;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.mn-sum.pos {
|
||||
color: #2e7d32;
|
||||
}
|
||||
.mn-sum.neg {
|
||||
color: #c0392b;
|
||||
}
|
||||
.drop-list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user