Bladeren bron

增加贷款利率反推工具

zxlie 6 jaren geleden
bovenliggende
commit
528b9607df

+ 1 - 1
apps/manifest.json

@@ -1,6 +1,6 @@
 {
   "name": "WEB前端助手(FeHelper)-Dev",
-  "version": "2019.05.2919",
+  "version": "2019.05.3115",
   "manifest_version": 2,
   "default_locale": "zh_CN",
   "description": "FE助手:JSON格式化、JSON比对、二维码生成与解码、信息编解码、代码压缩&美化、页面取色、Markdown、网页截屏、编码设置、正则、Crontab、时间转换、网页性能检测、密码生成器、便签笔记、chrome插件下载等",

BIN
apps/static/screenshot/crx/WEB前端助手(FeHelper)_v2019.05.3115.crx


+ 19 - 2
apps/toolkit/payback/index.css

@@ -1,9 +1,8 @@
 .mod-radios {
     font-size: 14px;
 }
-.mod-value label{
+.mod-value label {
     margin-right: 0;
-    font-size: 16px;
 }
 .mod-value .x-input {
     display: inline-block;
@@ -70,4 +69,22 @@ select.x-select {
 }
 #containerPayback .x-btn {
     margin-left: 20px;
+}
+#containerPayback .x-exchange {
+    float: right;
+    font-size: 12px;
+    color: #48b;
+    text-decoration: underline;
+}
+#containerPayback .x-exchange:hover {
+    cursor: pointer;
+    color: #f00;
+}
+.x-calc-title {
+    border-bottom: 1px solid #ccc;
+    padding-bottom: 5px;
+    margin-bottom: 15px;
+}
+.x-revrate {
+    color: #f00;
 }

File diff suppressed because it is too large
+ 0 - 0
apps/toolkit/payback/index.html


+ 138 - 13
apps/toolkit/payback/index.js

@@ -1,5 +1,6 @@
 /**
- * FeHelper 进制转换工具
+ * FeHelper 贷款计算器工具
+ * @author zhaoxianlie
  */
 new Vue({
     el: '#containerPayback',
@@ -12,7 +13,17 @@ new Vue({
         formula: {
             "1": '等额本息:月供=贷款本金×[年化利率÷12×(1+年化利率÷12) ^ 还款月数]÷{[(1+年化利率÷12) ^ 还款月数]-1}',
             "2": '等额本金:月供=贷款本金÷还款月数x(1+年化利率÷12x剩余还款期数)'
-        }
+        },
+
+        calcMode: 'rate',
+        calcModeText: {
+            'rate': '实际年化反推',
+            'loan': '月供账单计算'
+        },
+
+        revRate: 0,
+        revAllAmount: 11347.20,
+        revAllInterest: 0
     },
 
     mounted: function () {
@@ -30,11 +41,16 @@ new Vue({
                     return;
                 }
 
-                if (parseInt(this.paybackMode) === 1) {
-                    this.avgCapitalPlusInterest();
+                if (this.calcMode === 'rate') {
+                    if (parseInt(this.paybackMode) === 1) {
+                        this.avgCapitalPlusInterest();
+                    } else {
+                        this.avgCapitalOnly();
+                    }
                 } else {
-                    this.avgCapitalOnly();
+                    this.revCalcYearRate();
                 }
+
             });
         },
 
@@ -42,7 +58,7 @@ new Vue({
          * 数据合法性校验
          */
         dataCheck: function () {
-            if (!this.money || /\D/.test(this.money) || parseInt(this.money) <= 0) {
+            if (!this.money || !/\d|\./.test(this.money) || parseInt(this.money) <= 0) {
                 alert('请输入正确的贷款金额!');
                 return false;
             }
@@ -54,10 +70,23 @@ new Vue({
                 alert('在哪儿能贷30年?');
                 return false;
             }
-            if (!this.yearRate || !/\d|\./.test(this.yearRate) || parseFloat(this.yearRate) <= 0) {
-                alert('请输入正确的贷款年化利率!');
-                return false;
+
+            if (this.calcMode === 'rate') {
+                if (!this.yearRate || !/\d|\./.test(this.yearRate) || parseFloat(this.yearRate) <= 0) {
+                    alert('请输入正确的贷款年化利率!');
+                    return false;
+                }
+            } else {
+                if (!this.revAllAmount || !/\d|\./.test(this.revAllAmount) || parseInt(this.revAllAmount) <= 0) {
+                    alert('请输入正确的总还款额!');
+                    return false;
+                }
+                if(parseInt(this.revAllAmount) < parseInt(this.money)) {
+                    alert('还款总额比贷款本金还低,这种情况就不用算了吧。。。');
+                    return false;
+                }
             }
+
             return true;
         },
 
@@ -95,7 +124,7 @@ new Vue({
                 amount: Number(this.money).toFixed(2),
                 interest: (Math.round(allInterest * 100) / 100).toFixed(2),
                 bill: (Math.round(allBillsAmount * 100) / 100).toFixed(2),
-                totalAmount:'-',
+                totalAmount: '-',
                 totalInterest: '-',
                 leftOver: (Math.round(leftOver * 100) / 100).toFixed(2),
                 leftInterest: (Math.round(allInterest * 100) / 100).toFixed(2)
@@ -125,7 +154,7 @@ new Vue({
                     amount: (Math.round(amount * 100) / 100).toFixed(2),
                     interest: (Math.round(interest * 100) / 100).toFixed(2),
                     bill: (Math.round(bill * 100) / 100).toFixed(2),
-                    totalAmount:(Math.round((this.money - leftOver) * 100) / 100).toFixed(2),
+                    totalAmount: (Math.round((this.money - leftOver) * 100) / 100).toFixed(2),
                     totalInterest: (Math.round((allInterest - leftInterest) * 100) / 100).toFixed(2),
                     leftOver: (Math.round(leftOver * 100) / 100).toFixed(2),
                     leftInterest: (Math.round(leftInterest * 100) / 100).toFixed(2)
@@ -161,7 +190,7 @@ new Vue({
                 amount: Number(this.money).toFixed(2),
                 interest: (Math.round(allInterest * 100) / 100).toFixed(2),
                 bill: (Math.round(allBillsAmount * 100) / 100).toFixed(2),
-                totalAmount:'-',
+                totalAmount: '-',
                 totalInterest: '-',
                 leftOver: (Math.round(leftOver * 100) / 100).toFixed(2),
                 leftInterest: (Math.round(allInterest * 100) / 100).toFixed(2)
@@ -183,12 +212,108 @@ new Vue({
                     amount: (Math.round(amount * 100) / 100).toFixed(2),
                     interest: (Math.round(interest * 100) / 100).toFixed(2),
                     bill: (Math.round((amount + interest) * 100) / 100).toFixed(2),
-                    totalAmount:(Math.round((this.money - leftOver) * 100) / 100).toFixed(2),
+                    totalAmount: (Math.round((this.money - leftOver) * 100) / 100).toFixed(2),
                     totalInterest: (Math.round((allInterest - leftInterest) * 100) / 100).toFixed(2),
                     leftOver: (Math.round(leftOver * 100) / 100).toFixed(2),
                     leftInterest: (Math.round(leftInterest * 100) / 100).toFixed(2)
                 });
             }
+        },
+
+        /**
+         * 计算模式切换
+         */
+        exchange: function () {
+            this.calcMode = this.calcMode === 'rate' ? 'loan' : 'rate';
+            this.$nextTick(() => {
+                if (this.calcMode === 'rate') {
+                    this.paybackConvert();
+                } else {
+                    this.revCalcYearRate();
+                }
+            });
+        },
+
+        /**
+         * 通过给定的贷款本金、期限、总利息,进行真实年后利率反推
+         */
+        revCalcYearRate: function () {
+
+            let retryArr = [];
+
+            // 近似二分法定利率
+            let getRate = (cur, curMore) => {
+                // 找到上一次迭代时候的结果
+                let rt = retryArr[retryArr.length - 2];
+
+                if (curMore) {
+                    if (rt[1]) { // 上次大,这次还大,直接找到最后一次「小」的值做二分,否则-2处理
+                        for (let i = retryArr.length - 3; i >= 0; i--) {
+                            if (!retryArr[i][1]) {
+                                return (cur + retryArr[i][0]) / 2;
+                            }
+                        }
+                        return cur - 2;
+                    } else { // 上次小,这次大,直接两次结果做二分
+                        return (cur + rt[0]) / 2;
+                    }
+                } else {
+                    if (rt[1]) { // 上次小,这次还大,直接两次结果做二分
+                        return (cur + rt[0]) / 2;
+                    } else { // 上次小,这次还小,直接找到最后一次「大」的值做二分,否则+2处理
+                        for (let i = retryArr.length - 3; i >= 0; i--) {
+                            if (retryArr[i][1]) {
+                                return (cur + retryArr[i][0]) / 2;
+                            }
+                        }
+                        return cur + 2;
+                    }
+                }
+            };
+
+            // 利率近似值计算
+            let calcTotal = (money, month, year, target, method) => {
+                let rate = year / 12 / 100;
+
+                let total = 0;
+                if (method === 1) { // 等额本息
+                    let mRate = Math.pow(rate + 1, month);
+                    total = month * Math.round(money * rate * mRate / (mRate - 1) * 100) / 100;
+                } else { // 等额本金
+                    total = (money / month + money * rate + money / month * (1 + rate)) / 2 * month;
+                }
+
+                let delta = Math.abs(total - target);
+                return delta >= 0 && delta <= ((target - money) / money * month / 12 / 0.1374) ? [year] : (total > target ? [year, 1] : [year, 0]);
+            };
+
+
+            // 迭代推演
+            let guessRate = (money, month, total, method) => {
+                retryArr = [[0, 0], [0, 0]];
+
+                let cur = (total - money) / money / month * 12 * 100;
+                let arr = calcTotal(money, month, cur, total, method);
+
+                let rt, time = 0, result = 'unknown';
+                while (time < 1000) {
+                    time++;
+                    if (arr.length === 1) {
+                        result = Math.round(arr[0] * 10) / 10 + '%';
+                        break;
+                    }
+                    else {
+                        retryArr.push(arr);
+                        cur = getRate(arr[0], arr[1]);
+                        arr = calcTotal(money, month, cur, total, method);
+                    }
+                }
+
+                return result;
+            };
+
+            this.revAllInterest = Math.round((this.revAllAmount - this.money) * 100) / 100;
+            this.revRate = guessRate(this.money, this.months, this.revAllAmount, parseInt(this.paybackMode));
         }
     }
 });

Some files were not shown because too many files changed in this diff