Skip to content

Commit

Permalink
loan change list can export to excel & optimize text & docs
Browse files Browse the repository at this point in the history
  • Loading branch information
DropFan committed Jan 13, 2025
1 parent 39d41aa commit b0564f2
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 36 deletions.
26 changes: 18 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
Changelog
===

[0.6] - 2025-01-13
---

* [New]还款过程变更记录也支持一起导出到 Excel 中。
* [New]还款过程变更记录新增字段。
* 部分文案优化。
* 文档优化

[0.5] - 2025-01-13
---

增加还款过程变更列表展示
优化页面布局和样式。
重构部分代码。
* [New]新增还款过程变更记录展示
* 优化页面布局和样式。
* 重构部分代码。

[0.4] - 2025-01-12
---

添加网站 logo/icon,添加 PWA 应用设置,可以将 Web App 添加到桌面。
* [New]添加网站 logo/icon
* [New]添加 PWA 应用设置,可以将 Web App 添加到手机/电脑桌面直接使用。

[0.3] - 2025-01-12
---

完善说明,部署到 GitHub Pages,绑定域名。
* [New]完善说明文档
* [New]部署到 GitHub Pages,绑定域名。

[0.2] - 2025-01-11
---

添加 导出到 Excel 功能。
* [New]新增导出到 Excel 功能。

[0.1] - 2025-01-11
---

完成初版。
支持贷款计算、利率变更、提前还款
* [New]完成初版。
* [New]支持贷款计算、利率变更、提前还款
35 changes: 26 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
## 项目概述

本项目是一个贷款计算器的 Web 应用,支持用户根据贷款金额、期限、利率和还款方式,计算并显示月还款金额、剩余贷款金额和未来还款计划。
此外,不同于网上其他房贷计算器,我专门针对存量房贷开发了还贷模拟的特殊功能:可以多次调整利率或提前还款,模拟用户真实还款情况。这也是我写这个程序的初衷,以前一直用表格来处理这个需求,但不方便给别人用。之前有人找我要表格还得传文件,干脆以后写个程序部署到网上,也方便大家使用,正好最近我闲来有心情于是就有了这个。

经过测试,按照时间先后多次操作调整利率和提前还款的计算结果与我之前用 numbers/excel 的数据一致。但每次变动时由于银行按天计算产生的利息差不在本应用考虑范围,此误差仅影响变动当月的结果,不影响后续月供金额的结果。
此外,不同于网上其他房贷计算器,我专门针对存量房贷开发了还贷模拟的特殊功能:可以多次调整利率或提前还款,模拟用户真实还款情况,并支持将数据导出到 Excel。

这也是我写这个程序的初衷,以前一直用表格来处理这个需求,但不方便给别人用。之前有人找我要表格还得传文件,干脆以后写个程序部署到网上,也方便大家使用,正好最近我闲来有心情于是就有了这个。

经过测试,按照时间先后多次操作调整利率和提前还款的计算结果与我之前用 numbers/excel 的数据一致。但每次变动时由于银行按天计算产生的利息差不在本应用考虑范围,此误差仅影响变动当月利息与真实情况有差异,不影响后续其他计算。

纯原生 HTML/Javascript/CSS 代码,直接浏览器运行,不依赖任何框架,仅 excel 导出功能引用了一个第三方类库。
**未添加任何参数验证和错误处理,大家不用测试异常数据了~**

## 更新记录

点击查看[更新记录](https://github.com/DropFan/loan-calculator/blob/main/CHANGELOG.md)

## 使用方法

1. 打开浏览器,~~访问项目的根目录下的`index.html`文件。如果需要在手机上访问,在项目根目录执行`npm run dev` 启动本地 http server,就可以访问了~~ 直接访问[这个地址](https://loan.v2dl.net/)就行。
Expand All @@ -19,11 +26,14 @@

## 注意事项

- 生成还贷计划后,按照时间顺序依次操作利率变更和提前还款,如可能导致数据异常的情况,比如一个月内多次变更利率/提前还款,由于现实里不存在这种情况,本程序暂不做兼容支持
- 生成还贷计划后,可按照时间先后顺序多次操作利率变更和提前还款
- 本计算器按月计算,确保月份填写正确。
- 日期中的天数不重要,但请尽量选择合理的日期以保证计算准确性。
- 每次变动时由于银行按天计算产生的利息差不在本应用考虑范围,此误差仅影响变动当月的结果,不影响后续月供金额的结果。
- 每次操作(如调整利率或提前还款)会刷新指定日期之后的所有数据。
- 每次变更操作(如调整利率或提前还款)会刷新指定日期之后的所有数据。
- 变更操作当月生效,如当月数据与银行不一致,因变更当月银行是按天计算利息,属于正常误差,仅影响当月利息,不影响其他计算。
- 如可能导致数据异常的情况,比如一个月内多次变更利率/提前还款,由于现实里不存在这种情况,本程序暂不做兼容支持。
- 如发现与实际不一致或因日期选错导致数据异常,可在上方重新生成还款计划表再次操作。
- **所有代码在浏览器本地运行,不用担心数据泄露,请放心使用。**
- **未添加任何参数验证和错误处理,大家不用测试异常数据了~**

## 功能描述
Expand All @@ -38,7 +48,7 @@
- **还贷方式**:选择“等额本息”或“等额本金”。
- **贷款开始日期**:选择贷款开始的具体日期,次月开始还月供。

点击“计算”按钮后,页面会显示每月还款金额和剩余贷款本金,并生成详细的还款计划表。
点击“计算”按钮后,页面会显示每月还款金额和剩余贷款详情,并生成详细的还款计划表。

### 2. 还款计划表

Expand All @@ -52,7 +62,8 @@
- 剩余本金
- 剩余期数
- 年利率
- 备注
- 还款方式
- 备注说明

每次变更时会刷新指定日期之后的所有数据。全表可导出为 Excel 文件。

Expand All @@ -74,7 +85,11 @@

### 5. 导出为 Excel

用户点击导出按钮即可将还款计划表导出为 Excel 文件,方便保存和打印。
还贷计划表和变更操作记录可以导出为 Excel 文件,方便保存和打印。
用户点击导出按钮即可下载 Excel 文件到本地,

---
本文部分内容是 AI 生成的,开发者指南这部分感觉说了跟没说一样。。。

## 开发者指南

Expand All @@ -96,5 +111,7 @@

## 版权声明

本项目由 [Tiger](https://github.com/DropFan) 开发,仅供学习和参考使用。
本项目由 [@Tiger](https://github.com/DropFan) 开发,仅供学习和参考使用。
未经许可,不得用于商业用途。

如果有任何疑问或建议,请随时联系作者本人,或提交反馈到[本项目 ISSUES](https://github.com/DropFan/loan-schedule/issues)
6 changes: 4 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,10 @@ <h2>贷款计算</h2>
<div id="additional-functions">
<h2>变更操作</h2>
<div class="description">
<p>生成还贷计划后,可按照时间先后顺序多次操作利率变更和提前还款,如可能导致数据异常的情况,比如一个月内多次变更利率/提前还款,由于现实里不存在这种情况,本程序暂不做兼容支持。</p>
<p>如因日期选错导致数据异常,可在上方重新生成还款计划表再次操作。</p>
<p>生成还贷计划后,可按照时间先后顺序多次操作利率变更和提前还款。</p>
<p>变更操作当月生效,如当月数据与银行不一致,因变更当月银行是按天计算利息,属于正常误差,仅影响当月利息,不影响其他计算。</p>
<p>如可能导致数据异常的情况,比如一个月内多次变更利率/提前还款,由于现实里不存在这种情况,本程序暂不做兼容支持。</p>
<p>如发现与实际不一致或因日期选错导致数据异常,可在上方重新生成还款计划表再次操作。</p>
</div>
<div class="form-group">
<div class="form">
Expand Down
56 changes: 39 additions & 17 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,17 @@ function getRemainingSchedule(startDate) {
function refreshLoanChangeList(changeDetail) {
const changeDate = new Date(changeDetail.date);
const {
loanAmount, monthlyPayment,
annualInterestRate, loanMethod,
comment
loanAmount,
remainingTerm,
monthlyPayment,
annualInterestRate,
loanMethod,
comment,
} = changeDetail;
_loanChangeList.push({
date: changeDate,
loanAmount,
remainingTerm,
monthlyPayment,
annualInterestRate,
loanMethod,
Expand All @@ -251,6 +255,7 @@ function refreshLoanChangeList(changeDetail) {
${changeDate.toISOString().split("T")[0]}</span> <span class="loan-change-comment">${comment}</span></p>
<p class="loan-change-detail">每月还款金额: <span class="monthly-payment">${monthlyPayment.toFixed(2)}</span> 元 &nbsp;
剩余贷款本金: <span class="remaining-loan">${loanAmount.toFixed(2)}</span> 元 &nbsp;
剩余期数: <span class="remaining-term">${remainingTerm}</span> 月 &nbsp;
还款方式:<span class="loan-method">${LoanMethodName[loanMethod]}</span> &nbsp;
利率:<span class="interest-rate">${annualInterestRate}%</span></p>
`;
Expand All @@ -259,11 +264,9 @@ function refreshLoanChangeList(changeDetail) {
function refreshPaymentSchedule(schedule) {
const tbody = document.querySelector("#schedule-table tbody");
tbody.innerHTML = ""; // 清空之前的表格数据

rows = [];
schedule.forEach((item) => {
const row = document.createElement("tr");
row.innerHTML = `
<td>${item.period}</td>
rows.push(`<tr><td>${item.period}</td>
<td>${item.paymentDate}</td>
<td>${item.monthlyPayment.toFixed(2)}</td>
<td>${item.principal.toFixed(2)}</td>
Expand All @@ -272,10 +275,9 @@ function refreshPaymentSchedule(schedule) {
<td>${item.remainingTerm}</td>
<td>${item.annualInterestRate}%</td>
<td>${item.loanMethod}</td>
<td>${item.comment}</td>
`;
tbody.appendChild(row);
<td>${item.comment}</td></tr>`);
});
tbody.innerHTML = rows.join("");
}

function calculateLoan(loanAmount, loanTerm, interestRate, startDate, loanMethod) {
Expand Down Expand Up @@ -334,6 +336,7 @@ document
monthlyPayment: result.monthlyPayment,
annualInterestRate: annualInterestRate,
loanMethod: loanMethod,
remainingTerm: loanTerm,
});

refreshPaymentSchedule(result.schedule);
Expand Down Expand Up @@ -408,6 +411,7 @@ document
monthlyPayment: monthlyPayment,
annualInterestRate: annualInterestRate,
loanMethod: loanMethod,
remainingTerm: remainingTerm - 1,
});
refreshPaymentSchedule(_loanSchedule);
});
Expand Down Expand Up @@ -435,10 +439,7 @@ document.getElementById("prepay-loan").addEventListener("click", function () {
_loanSchedule[remainingSchedule.paidPeriods - 1].principal += prepayAmount;
_loanSchedule[remainingSchedule.paidPeriods - 1].remainingLoan -=
prepayAmount;
_loanSchedule[remainingSchedule.paidPeriods - 1].comment =
" " +
prepayDate.toISOString().split("T")[0] +
"提前还款" + prepayAmount;

remainingLoan = _loanSchedule[remainingSchedule.paidPeriods - 1].remainingLoan;

// startDate = prepayDate.setMonth(prepayDate.getMonth() - 1); // 计算时日期前移一个月
Expand Down Expand Up @@ -474,6 +475,9 @@ document.getElementById("prepay-loan").addEventListener("click", function () {
comment += ",月供不变";
}

_loanSchedule[remainingSchedule.paidPeriods - 1].comment =
" " + prepayDate.toISOString().split("T")[0] + comment;

// 将更新后的计划追加到原计划后面
_loanSchedule = _loanSchedule
.slice(0, remainingSchedule.paidPeriods)
Expand All @@ -486,16 +490,17 @@ document.getElementById("prepay-loan").addEventListener("click", function () {
monthlyPayment: monthlyPayment,
annualInterestRate: annualInterestRate,
loanMethod: loanMethod,
remainingTerm: remainingTerm,
});

refreshPaymentSchedule(_loanSchedule);
});

// 导出 Excel 文件
function exportToExcel(filename, rows) {
function exportToExcel(filename, rows = _loanSchedule, changeList = _loanChangeList) {
const worksheetData = [
[ "期数", "还款日期", "月还款金额", "本金", "利息", "剩余本金", "剩余期数",
"利率", "说明", "由微信公众号 Hacking4fun 生成",],
["期数", "还款日期", "月还款金额", "本金", "利息", "剩余本金", "剩余期数",
"利率", "还款方式", "说明"],
...rows.map((row) => [
row.period,
row.paymentDate,
Expand All @@ -511,6 +516,23 @@ function exportToExcel(filename, rows) {
]),
];

worksheetData.push(
["", "", "", "", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", "", "", "", ""],
["", "", "变更列表", "", "", "", "", "", "", "", ""],
["", "", "", "", "", "", "", "", "", "", ""],
["变更日期", "月还款金额", "剩余本金", "剩余期数","利率", "还款方式", "说明"],
...changeList.map((row) => [
row.date.toISOString().split("T")[0],
row.monthlyPayment.toFixed(2),
row.loanAmount.toFixed(2),
row.remainingTerm,
row.annualInterestRate + "%",
LoanMethodName[row.loanMethod],
row.comment,
])
);

rightContent = [
[
"", "", "", "", "",
Expand Down

0 comments on commit b0564f2

Please sign in to comment.