diff --git a/src/views/account/AccountView.vue b/src/views/account/AccountView.vue index 1fd61f5..b1f4e5e 100644 --- a/src/views/account/AccountView.vue +++ b/src/views/account/AccountView.vue @@ -127,6 +127,33 @@ const repayTargetIsCard = computed(() => { const w = wallets.value.find((x) => x.id === form.toWalletId) return !!w && w.type === 'CARD' }) +// 금리가 설정된 대출 계좌를 선택한 경우 자동계산 활성 +const repayTargetLoanWallet = computed(() => { + const w = wallets.value.find((x) => x.id === form.toWalletId) + return w?.type === 'LOAN' && w.loanRate ? w : null +}) +// 납입총액 입력 → 원금/이자 자동분리 +const loanPaymentAmount = ref(null) +function calcLoanRepayment(payment) { + const loan = repayTargetLoanWallet.value + if (!loan || !payment || payment <= 0) return + const monthlyRate = Number(loan.loanRate) / 100 / 12 + const remainingDebt = Math.abs(loan.balance || 0) + const monthlyInterest = Math.round(remainingDebt * monthlyRate) + if (loan.loanMethod === 'BULLET') { + form.interest = payment + form.principal = 0 + } else { + form.interest = Math.min(monthlyInterest, payment) + form.principal = Math.max(0, payment - form.interest) + } +} +watch(loanPaymentAmount, (val) => { if (val) calcLoanRepayment(Number(val)) }) +watch(() => form.toWalletId, () => { + loanPaymentAmount.value = null + form.principal = null + form.interest = null +}) // 카드 지출일 때만 할부 입력 노출 (2~24개월, 일시불은 빈값) const showInstallment = computed(() => form.type === 'EXPENSE' && form.walletKind === 'CARD') const installmentMonthly = computed(() => { @@ -1135,8 +1162,23 @@ onMounted(async () => { - - + + + @@ -1973,6 +2015,18 @@ button.primary { .acc-chip.add-chip.sub-add { flex: 0 0 auto; } +.loan-breakdown { + display: flex; + gap: 1rem; + padding: 0.45rem 0.6rem; + border-radius: 6px; + background: var(--color-background-soft); + font-size: 0.85rem; + color: var(--color-text); +} +.loan-breakdown b { + color: hsla(160, 100%, 37%, 1); +} .tag-field { display: flex; flex-direction: column; diff --git a/src/views/account/AccountWalletView.vue b/src/views/account/AccountWalletView.vue index 87ae50b..bbb113c 100644 --- a/src/views/account/AccountWalletView.vue +++ b/src/views/account/AccountWalletView.vue @@ -33,6 +33,11 @@ const form = reactive({ openingBalance: 0, openingDate: '', currentValue: null, + // 대출(LOAN) 전용 + loanRate: null, + loanMethod: '', + loanMonths: null, + loanStart: '', }) const submitting = ref(false) const formError = ref(null) @@ -229,6 +234,10 @@ function openCreate() { openingBalance: 0, openingDate: '', currentValue: null, + loanRate: null, + loanMethod: '', + loanMonths: null, + loanStart: '', }) formError.value = null formOpen.value = true @@ -245,6 +254,10 @@ function openEdit(w) { openingBalance: isLiability(w.type) ? -(w.openingBalance || 0) : w.openingBalance || 0, openingDate: w.openingDate || '', currentValue: w.currentValue ?? null, + loanRate: w.loanRate ?? null, + loanMethod: w.loanMethod || '', + loanMonths: w.loanMonths ?? null, + loanStart: w.loanStart || '', }) formError.value = null formOpen.value = true @@ -258,6 +271,7 @@ async function submit() { } submitting.value = true const magnitude = Number(form.openingBalance) || 0 + const isLoan = form.type === 'LOAN' const payload = { type: form.type, name: form.name.trim(), @@ -271,6 +285,10 @@ async function submit() { form.type === 'INVEST' && form.currentValue !== '' && form.currentValue != null ? Number(form.currentValue) : null, + loanRate: isLoan && form.loanRate !== null && form.loanRate !== '' ? Number(form.loanRate) : null, + loanMethod: isLoan && form.loanMethod ? form.loanMethod : null, + loanMonths: isLoan && form.loanMonths ? Number(form.loanMonths) : null, + loanStart: isLoan && form.loanStart ? form.loanStart : null, } try { if (editId.value) await accountApi.updateWallet(editId.value, payload) @@ -297,6 +315,9 @@ async function remove(w) { function cardTypeLabel(v) { return v === 'CHECK' ? '체크' : v === 'CREDIT' ? '신용' : '' } +function loanMethodLabel(v) { + return v === 'EQUAL_PAYMENT' ? '원리금균등' : v === 'EQUAL_PRINCIPAL' ? '원금균등' : v === 'BULLET' ? '만기일시' : '' +} onMounted(async () => { await load() @@ -362,6 +383,9 @@ onBeforeUnmount(() => sortable?.destroy()) >{{ revealedAccts.has(w.id) ? '🙈' : '👁' }} +
@@ -458,6 +482,29 @@ onBeforeUnmount(() => sortable?.destroy()) + + +

{{ formError }}