선형 계산(expenseForecast) 제거, AI 코멘트의 forecast/근거 표시. 경과일·총일수 전달. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,8 @@ const categoryList = ref([]) // 분류 목록(대/소분류 매핑용)
|
||||
const trendData = ref([]) // [{month, netWorth}]
|
||||
const aiBullets = ref([]) // AI 재무 코멘트(현황 관찰)
|
||||
const aiTips = ref([]) // AI 절약 가이드(실행 제안)
|
||||
const aiForecast = ref(null) // AI 월말 예상 지출(일회성 큰 지출 제외 추정)
|
||||
const aiForecastNote = ref('') // 예상 지출 근거 문장
|
||||
const aiLoading = ref(false)
|
||||
|
||||
const periodLabel = computed(() => `${year.value}년 ${String(month.value).padStart(2, '0')}월`)
|
||||
@@ -65,16 +67,8 @@ const expenseDelta = computed(() => {
|
||||
return { prev, diff, pct }
|
||||
})
|
||||
|
||||
/* ===== 이번달 예상 지출 (실제 지출 추세로 월말 추정, run-rate) =====
|
||||
경과일까지 실제 지출을 일평균으로 환산해 그 달 총일수로 추정. 이번 달에만 표시. */
|
||||
const expenseForecast = computed(() => {
|
||||
const isCurrent = year.value === now.getFullYear() && month.value === now.getMonth() + 1
|
||||
if (!isCurrent) return null // 지난/미래 달은 추정 불필요(이미 확정 또는 데이터 없음)
|
||||
const totalDays = daysInMonth(year.value, month.value)
|
||||
const elapsed = now.getDate()
|
||||
const projected = elapsed > 0 ? Math.round((monthExpense.value / elapsed) * totalDays) : monthExpense.value
|
||||
return { projected, elapsed, totalDays }
|
||||
})
|
||||
/* 월말 예상 지출은 단순 선형(run-rate) 대신 AI가 추정한다(aiForecast).
|
||||
일회성 큰 지출(노트북 등)을 일평균에서 제외해 현실적인 값을 준다. loadAiComment 참고. */
|
||||
|
||||
/* ===== 막대 차트 (기간별 예산 대비 지출) ===== */
|
||||
const bars = computed(() => {
|
||||
@@ -280,7 +274,10 @@ async function loadAiComment() {
|
||||
aiLoading.value = true
|
||||
aiBullets.value = []
|
||||
aiTips.value = []
|
||||
aiForecast.value = null
|
||||
aiForecastNote.value = ''
|
||||
try {
|
||||
const isCurrent = year.value === now.getFullYear() && month.value === now.getMonth() + 1
|
||||
const res = await accountApi.aiComment({
|
||||
year: year.value,
|
||||
month: month.value,
|
||||
@@ -289,13 +286,19 @@ async function loadAiComment() {
|
||||
prevExpense: prevMonthExpense.value,
|
||||
budget: budgetTotal.value,
|
||||
spent: spentTotal.value,
|
||||
elapsedDays: isCurrent ? now.getDate() : 0,
|
||||
totalDays: daysInMonth(year.value, month.value),
|
||||
categories: (catData.value || []).slice(0, 8).map((c) => ({ category: c.category, total: c.total })),
|
||||
})
|
||||
aiBullets.value = res?.bullets || []
|
||||
aiTips.value = res?.tips || []
|
||||
aiForecast.value = res?.forecast || null
|
||||
aiForecastNote.value = res?.forecastNote || ''
|
||||
} catch {
|
||||
aiBullets.value = []
|
||||
aiTips.value = []
|
||||
aiForecast.value = null
|
||||
aiForecastNote.value = ''
|
||||
} finally {
|
||||
aiLoading.value = false
|
||||
}
|
||||
@@ -417,17 +420,15 @@ onMounted(async () => {
|
||||
{{ expenseDelta.diff >= 0 ? '+' : '' }}{{ won(expenseDelta.diff) }}<template v-if="expenseDelta.pct !== null"> ({{ expenseDelta.pct >= 0 ? '+' : '' }}{{ expenseDelta.pct }}%)</template>
|
||||
</b>
|
||||
</div>
|
||||
<div v-if="expenseForecast" class="ie-row forecast">
|
||||
<span>예상 지출 <small>월말 추정</small></span>
|
||||
<b class="expense">{{ won(expenseForecast.projected) }}</b>
|
||||
<div v-if="aiForecast" class="ie-row forecast">
|
||||
<span>예상 지출 <small>월말 추정 · AI</small></span>
|
||||
<b class="expense">{{ won(aiForecast) }}</b>
|
||||
</div>
|
||||
<div class="ie-bar">
|
||||
<div class="ie-fill income" :style="{ width: incomePct + '%' }"></div>
|
||||
</div>
|
||||
<div class="ie-row net"><span>수지</span><b :class="monthIncome - monthExpense < 0 ? 'expense' : 'income'">{{ won(monthIncome - monthExpense) }}</b></div>
|
||||
<p v-if="expenseForecast" class="forecast-note">
|
||||
최근 추세 기준({{ expenseForecast.elapsed }}/{{ expenseForecast.totalDays }}일 · 현재 {{ won(monthExpense) }})<template v-if="budgetTotal > 0">, 예산 대비 {{ Math.round((expenseForecast.projected / budgetTotal) * 100) }}%</template>
|
||||
</p>
|
||||
<p v-if="aiForecastNote" class="forecast-note">{{ aiForecastNote }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user