feat(stats): AI 코멘트 로딩 인디케이터 바 + 예상지출 '계산 중' 표시
Deploy / deploy (push) Failing after 12m6s

코멘트 생성 지연 동안 애니메이션 진행바와 예상지출 계산 중 상태 노출.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
sb
2026-07-05 15:34:23 +09:00
parent e9e397434f
commit 59a17f9087
+34 -5
View File
@@ -371,7 +371,10 @@ onMounted(async () => {
<!-- AI 재무 코멘트 + 절약 가이드: 이번 집계 해석 --> <!-- AI 재무 코멘트 + 절약 가이드: 이번 집계 해석 -->
<div v-if="aiLoading || aiBullets.length || aiTips.length" class="ai-comment"> <div v-if="aiLoading || aiBullets.length || aiTips.length" class="ai-comment">
<div class="ai-comment-head"> 이번 AI 코멘트</div> <div class="ai-comment-head"> 이번 AI 코멘트</div>
<p v-if="aiLoading" class="ai-comment-loading">집계를 분석하고 있어요</p> <div v-if="aiLoading" class="ai-loading">
<span class="ai-loading-text">집계를 분석하고 있어요</span>
<div class="ai-loading-bar"><span></span></div>
</div>
<template v-else> <template v-else>
<ul v-if="aiBullets.length" class="ai-comment-list"> <ul v-if="aiBullets.length" class="ai-comment-list">
<li v-for="(b, i) in aiBullets" :key="i">{{ b }}</li> <li v-for="(b, i) in aiBullets" :key="i">{{ b }}</li>
@@ -420,7 +423,11 @@ onMounted(async () => {
{{ expenseDelta.diff >= 0 ? '+' : '' }}{{ won(expenseDelta.diff) }}<template v-if="expenseDelta.pct !== null"> ({{ expenseDelta.pct >= 0 ? '+' : '' }}{{ expenseDelta.pct }}%)</template> {{ expenseDelta.diff >= 0 ? '+' : '' }}{{ won(expenseDelta.diff) }}<template v-if="expenseDelta.pct !== null"> ({{ expenseDelta.pct >= 0 ? '+' : '' }}{{ expenseDelta.pct }}%)</template>
</b> </b>
</div> </div>
<div v-if="aiForecast" class="ie-row forecast"> <div v-if="aiLoading && !aiForecast" class="ie-row forecast">
<span>예상 지출 <small>AI 계산 </small></span>
<b class="pending">···</b>
</div>
<div v-else-if="aiForecast" class="ie-row forecast">
<span>예상 지출 <small>월말 추정 · AI</small></span> <span>예상 지출 <small>월말 추정 · AI</small></span>
<b class="expense">{{ won(aiForecast) }}</b> <b class="expense">{{ won(aiForecast) }}</b>
</div> </div>
@@ -612,10 +619,32 @@ h2 {
color: hsla(160, 100%, 32%, 1); color: hsla(160, 100%, 32%, 1);
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.ai-comment-loading { .ai-loading-text {
font-size: 0.85rem; font-size: 0.85rem;
opacity: 0.6; opacity: 0.65;
margin: 0; }
.ai-loading-bar {
height: 4px;
margin-top: 0.45rem;
border-radius: 999px;
background: hsla(160, 100%, 37%, 0.15);
overflow: hidden;
}
.ai-loading-bar > span {
display: block;
width: 40%;
height: 100%;
border-radius: 999px;
background: hsla(160, 100%, 37%, 0.85);
animation: ai-indeterminate 1.1s ease-in-out infinite;
}
@keyframes ai-indeterminate {
0% { transform: translateX(-110%); }
100% { transform: translateX(360%); }
}
.ie-row .pending {
opacity: 0.4;
letter-spacing: 2px;
} }
.ai-comment-list { .ai-comment-list {
margin: 0; margin: 0;