From 1b53af525e0788ea2e62817beec78ebf5a2b784d Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Thu, 2 Jul 2026 00:31:50 +0900 Subject: [PATCH] =?UTF-8?q?feat(account):=20=EB=8C=80=EC=B6=9C=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=EA=B8=88=EC=95=A1=20=ED=95=84=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20+=20=EC=83=81=ED=99=98=EB=B0=A9=EC=8B=9D=EB=B3=84?= =?UTF-8?q?=20=EC=9E=90=EB=8F=99=EA=B3=84=EC=82=B0=20=EB=B6=84=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - loan_amount(대출 실행 금액) 컬럼 추가(DB/도메인/DTO/mapper) - 계좌 폼: 대출 실행 금액 입력 / 기록 시작 시 잔액(기존 openingBalance) 레이블 분리 - 계좌 카드: 실행금액·금리·상환방식 표시 - 상환 자동계산 3방식 분기: - 원리금균등: 납입금액 입력 → 이자(잔액×월이율) / 원금(납입-이자) 분리 - 원금균등: 실행금액÷기간=월원금, 잔액×월이율=이자 자동계산 - 만기일시: 잔액×월이율=이자만 자동계산, 원금 0 - 자동계산 후 이자·원금 수동 조정 가능 Co-Authored-By: Claude Sonnet 4.6 --- src/views/account/AccountView.vue | 78 +++++++++++++++++++------ src/views/account/AccountWalletView.vue | 15 ++++- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/views/account/AccountView.vue b/src/views/account/AccountView.vue index b1f4e5e..7f4b69f 100644 --- a/src/views/account/AccountView.vue +++ b/src/views/account/AccountView.vue @@ -132,23 +132,46 @@ 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 monthlyInterestOf(loan) { + return Math.round(Math.abs(loan.balance || 0) * (Number(loan.loanRate) / 100 / 12)) +} + +// 상환방식별 자동계산: 원금균등·만기일시는 납입금액 입력 불필요 +const loanAutoResult = computed(() => { + const loan = repayTargetLoanWallet.value + if (!loan) return null + const interest = monthlyInterestOf(loan) + if (loan.loanMethod === 'BULLET') { + return { interest, principal: 0, total: interest, needsInput: false } + } + if (loan.loanMethod === 'EQUAL_PRINCIPAL' && loan.loanAmount && loan.loanMonths) { + const principal = Math.round(Number(loan.loanAmount) / loan.loanMonths) + return { interest, principal, total: principal + interest, needsInput: false } + } + return { interest: null, principal: null, total: null, needsInput: true } +}) + +watch(loanAutoResult, (r) => { + if (r && !r.needsInput) { + form.interest = r.interest + form.principal = r.principal + loanPaymentAmount.value = r.total + } +}) + 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) - } + const interest = monthlyInterestOf(loan) + form.interest = Math.min(interest, payment) + form.principal = Math.max(0, payment - form.interest) } -watch(loanPaymentAmount, (val) => { if (val) calcLoanRepayment(Number(val)) }) +watch(loanPaymentAmount, (val) => { + if (loanAutoResult.value?.needsInput && val) calcLoanRepayment(Number(val)) +}) watch(() => form.toWalletId, () => { loanPaymentAmount.value = null form.principal = null @@ -1162,15 +1185,26 @@ onMounted(async () => { - + -