feat: 홈 대시보드 + 영수증 OCR + 카드 할부 + 소수점 매수 등 UI 개선
CI / build (push) Failing after 13m56s

- 홈: 로그인 시 요약(이번달 수입/지출, 순자산, 예산대비지출 바)+바로가기, 비로그인 랜딩
- 영수증 OCR(온디바이스 Tesseract.js): 금액·날짜·상호 추출해 내역 폼 자동입력
- 내역 카드 할부(2~24개월) 입력/표시
- 투자 소수점 수량 입력(step=any)
- 계좌 관리 등록버튼 탭 라인 우측 이동, 정기거래 3단 레이아웃
- 목록 좌측 여백 제거(분류/예산/태그/계좌), 대시보드 일/주 버튼 제거, 도넛/파이 차트 잘림 수정

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-03 16:42:07 +09:00
parent 483cf755ed
commit efbe298a1f
12 changed files with 834 additions and 49 deletions
+8 -4
View File
@@ -30,6 +30,10 @@ const tradesByHolding = reactive({})
function won(n) {
return (n ?? 0).toLocaleString('ko-KR')
}
// 수량(소수점 매매 지원): 최대 6자리, 불필요한 0 제거
function shares(n) {
return Number(n ?? 0).toLocaleString('ko-KR', { maximumFractionDigits: 6 })
}
function todayStr() {
const d = new Date()
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
@@ -186,7 +190,7 @@ onMounted(load)
<div>
<div class="h-name">{{ h.name }}<span v-if="h.ticker" class="h-ticker">{{ h.ticker }}</span></div>
<div class="h-sub">
{{ won(h.quantity) }} · 평단 {{ won(h.avgPrice) }}
{{ shares(h.quantity) }} · 평단 {{ won(h.avgPrice) }}
<template v-if="h.currentPrice != null"> · 현재가 {{ won(h.currentPrice) }}</template>
<span v-else class="noprice"> · 현재가 미입력</span>
</div>
@@ -213,7 +217,7 @@ onMounted(load)
<li v-for="t in tradesByHolding[h.id]" :key="t.id" class="trade-row">
<span class="t-date">{{ tDate(t.tradeDate) }}</span>
<span class="t-type" :class="t.tradeType === 'SELL' ? 'sell' : 'buy'">{{ t.tradeType === 'SELL' ? '매도' : '매수' }}</span>
<span class="t-qty">{{ won(t.quantity) }} × {{ won(t.price) }}</span>
<span class="t-qty">{{ shares(t.quantity) }} × {{ won(t.price) }}</span>
<span class="t-fee" v-if="t.fee">수수료 {{ won(t.fee) }}</span>
<span class="t-amt">{{ won(t.amount) }}</span>
<IconBtn class="t-del" icon="trash" title="매매 삭제" variant="danger" size="sm" @click="removeTrade(t, h.id)" />
@@ -261,10 +265,10 @@ onMounted(load)
</select>
</label>
<label>거래일<input v-model="tForm.tradeDate" type="date" :disabled="tSubmitting" /></label>
<label>수량()<input v-model.number="tForm.quantity" type="number" min="1" :disabled="tSubmitting" /></label>
<label>수량()<input v-model.number="tForm.quantity" type="number" min="0" step="any" inputmode="decimal" placeholder="예: 0.5 / 1.25 (소수점 가능)" :disabled="tSubmitting" /></label>
<label>단가()<input v-model.number="tForm.price" type="number" min="0" :disabled="tSubmitting" /></label>
<label>수수료/세금<input v-model.number="tForm.fee" type="number" min="0" placeholder="(선택)" :disabled="tSubmitting" /></label>
<p v-if="tForm.tradeType === 'SELL'" class="pf-hint">보유 {{ won(tradeHolding?.quantity) }} · 평단 {{ won(tradeHolding?.avgPrice) }}</p>
<p v-if="tForm.tradeType === 'SELL'" class="pf-hint">보유 {{ shares(tradeHolding?.quantity) }} · 평단 {{ won(tradeHolding?.avgPrice) }}</p>
<p v-if="tError" class="pf-msg err">{{ tError }}</p>
<div class="pf-buttons">
<IconBtn icon="close" title="취소" @click="tradeModal = false" />