在这里插入图片描述

目录

  1. 概述
  2. 等额本息算法原理
  3. Kotlin 实现代码(KMP)
  4. JavaScript 编译输出与类型定义
  5. ArkTS 页面集成与调用
  6. 交互示例
  7. 编译与自动复制流程
  8. 总结

概述

本案例在 Kotlin Multiplatform (KMP) 工程中实现了一个贷款等额本息还款计算器

  • 输入:贷款金额(元)、年利率(%)、期数(月)
  • 输出:
    • 每月等额本息还款额
    • 总利息、还款总金额
    • 前若干期(最多 6 期)还款计划(本金/利息/剩余本金)
  • 技术路径:Kotlin → Kotlin/JS → JavaScript 模块 → ArkTS 页面调用

这与前一个 BMI 案例类似,也是“算法在 Kotlin,界面在 ArkTS”的完整链路示例。


等额本息算法原理

等额本息(常见房贷、车贷方式)的每月还款额公式:

每月还款额 = 本金 × 月利率 × (1 + 月利率)^n / ((1 + 月利率)^n - 1)

其中:
- 本金:Loan Principal
- 月利率:年利率 / 12
- n:还款总期数(单位:月)

每一期:

  • 当期利息 = 剩余本金 × 月利率
  • 当期本金 = 每月还款额 - 当期利息
  • 剩余本金 = 上期剩余本金 - 当期本金

通过循环即可得到一份“还款计划表”。


Kotlin 实现代码(KMP)

src/jsMain/kotlin/App.kt 中新增 loanRepaymentCalculator 方法并使用 @JsExport 导出:

import kotlin.math.pow

@OptIn(ExperimentalJsExport::class)
@JsExport
fun loanRepaymentCalculator(inputText: String = "100000 3.85 12"): String {
    // 输入格式: "贷款总额(元) 年利率(%) 期数(月)", 例如 "100000 3.85 12"
    val parts = inputText.trim().split(" ").filter { it.isNotEmpty() }

    if (parts.size < 3) {
        return "❌ 错误: 请按 '金额 年利率 月数' 的格式输入,例如: 100000 3.85 12"
    }

    val principal = parts[0].toDoubleOrNull()
    val annualRate = parts[1].toDoubleOrNull()
    val months = parts[2].toIntOrNull()

    if (principal == null || annualRate == null || months == null || principal <= 0 || annualRate <= 0 || months <= 0) {
        return "❌ 错误: 金额 / 利率 / 月数 无效\n请输入正确的正数,例如: 100000 3.85 12"
    }

    // 1. 计算月利率
    val monthlyRate = annualRate / 100.0 / 12.0

    // 2. 等额本息每月还款额公式
    val factor = (1 + monthlyRate).pow(months.toDouble())
    val monthlyPayment = principal * monthlyRate * factor / (factor - 1)

    // 保留两位小数
    fun round2(v: Double): Double = (v * 100).toInt() / 100.0
    val monthlyPaymentRounded = round2(monthlyPayment)

    // 3. 生成前若干期还款计划(最多前 6 期)
    var remaining = principal
    var totalInterest = 0.0
    val schedule = mutableListOf<String>()
    val showMonths = if (months < 6) months else 6

    for (m in 1..months) {
        val interest = remaining * monthlyRate
        val principalPart = monthlyPayment - interest
        remaining -= principalPart
        totalInterest += interest

        if (m <= showMonths) {
            schedule.add(
                "  第${m}期: 本金 ${round2(principalPart)} 元, 利息 ${round2(interest)} 元, 剩余本金 ${round2(remaining.coerceAtLeast(0.0))} 元"
            )
        }
    }

    val totalPayment = principal + totalInterest

    return "💰 贷款等额本息还款计算器\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "输入: 金额 ${principal} 元, 年利率 ${annualRate}%, 期数 ${months} 个月\n\n" +
           "1️⃣ 每月还款额:\n" +
           "  每月需还: ${monthlyPaymentRounded} 元\n\n" +
           "2️⃣ 总体统计:\n" +
           "  支付总利息: ${round2(totalInterest)} 元\n" +
           "  还款总金额: ${round2(totalPayment)} 元\n\n" +
           "3️⃣ 前 ${showMonths} 期还款计划:\n" +
           schedule.joinToString("\n") + "\n\n" +
           "4️⃣ 说明:\n" +
           "  • 本工具使用等额本息公式,仅供学习演示使用\n" +
           "  • 实际贷款可能存在手续费、浮动利率等因素\n\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "✅ 计算完成!"
}

这是贷款等额本息还款计算器的核心实现函数,展示了完整的贷款计算算法。函数使用 @OptIn(ExperimentalJsExport::class)@JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。函数首先进行输入解析,使用 split(" ") 分割输入字符串,使用 filter { it.isNotEmpty() } 过滤空字符串。然后验证输入格式,检查是否包含三个部分。使用 toDoubleOrNull()toIntOrNull() 安全转换数字,避免非法输入导致崩溃。计算月利率,将年利率转换为月利率。使用等额本息公式计算每月还款额:monthlyPayment = principal * monthlyRate * factor / (factor - 1),其中 factor = (1 + monthlyRate)^n。定义 round2() 内部函数用于保留两位小数。生成还款计划,循环计算每一期的利息、本金和剩余本金,最多显示前 6 期。计算总利息和总还款金额。最后使用字符串模板和 joinToString() 格式化输出完整的计算报告。这个函数展示了如何将复杂的金融计算转换为用户友好的输出。

说明:

  • 输入统一通过 String 传入(方便 ArkTS 侧直接拼接)
  • 函数返回多行中文说明文本,便于 ArkTS 直接展示
  • 使用 kotlin.math.pow 处理幂运算,兼容 Kotlin/JS

JavaScript 编译输出与类型定义

执行构建脚本后,会在 build/js/packages/hellokjs/kotlin/ 下生成:

hellokjs.mjs   // ESModule 格式的 JS
hellokjs.d.ts  // TypeScript 类型定义

.d.ts 中会有类似声明:

export declare function loanRepaymentCalculator(inputText?: string): string;

这段 TypeScript 类型声明定义了 loanRepaymentCalculator 函数的签名。export declare function 表示这是一个导出的函数声明。inputText?: string 表示函数接受一个可选的字符串参数,如果不提供则使用默认值。返回类型为 string,表示函数返回一个字符串。这个类型声明由 Kotlin 编译器自动生成,为 ArkTS/TypeScript 提供类型提示和代码补全。

这样在 ArkTS/TypeScript 中导入 hellokjs 模块时会有良好的类型提示。


ArkTS 页面集成与调用

首页 Index.ets 已改为“贷款等额本息还款计算器”页面,核心结构如下(简化版):

import { loanRepaymentCalculator } from './hellokjs';

@Entry
@Component
struct Index {
  @State message: string = '请输入贷款金额、年利率和期数';
  @State amount: string = '100000';
  @State annualRate: string = '3.85';
  @State months: string = '12';
  @State resultText: string = '';

  aboutToAppear(): void {
    this.calculateLoan();
  }

  calculateLoan(): void {
    try {
      const input: string = `${this.amount} ${this.annualRate} ${this.months}`;
      const result: string = loanRepaymentCalculator(input);
      this.resultText = result;
      this.message = '✓ 计算完成';
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.message = `✗ 错误: ${errorMessage}`;
    }
  }

  build() {
    Column() {
      // 顶部标题栏、输入区域、结果区域、默认示例&清空按钮等
    }
  }
}

这段 ArkTS 代码是鸿蒙应用的用户界面实现,展示了如何在 ArkTS 中导入和调用编译后的 Kotlin 函数。首先使用 import 语句从编译后的 JavaScript 模块中导入 loanRepaymentCalculator 函数。使用 @State 装饰器定义五个响应式状态变量:message 用于显示状态信息,amount 存储贷款金额,annualRate 存储年利率,months 存储还款期数,resultText 存储计算结果。aboutToAppear() 生命周期函数在组件加载时自动调用 calculateLoan() 进行初始计算。calculateLoan() 方法将三个输入值拼接成一个字符串,调用 Kotlin 编译的 JavaScript 函数 loanRepaymentCalculator(),获取计算结果,然后更新 resultTextmessage。使用 try-catch 块捕获异常。build() 方法构建整个 UI 布局。这个结构实现了清晰的前后端职责划分:ArkTS 只负责收集输入和展示结果,所有贷款计算逻辑都集中在 Kotlin 中。

说明:

  • ArkTS 只负责输入收集和 UI 展示
  • 实际的利息计算、还款计划生成逻辑全部在 Kotlin 中实现

交互示例

示例 1:10 万元,年利率 3.85%,12 期

输入:

金额: 100000 元
年利率: 3.85 %
期数: 12 月

输出片段示例(部分):

1️⃣ 每月还款额:
  每月需还: 8565.35 元

2️⃣ 总体统计:
  支付总利息: xxxx.xx 元
  还款总金额: xxxxxx.xx 元

3️⃣ 前 6 期还款计划:
  第1期: 本金 xxxx.xx 元, 利息 xxx.xx 元, 剩余本金 xxxxx.xx 元
  第2期: 本金 xxxx.xx 元, 利息 xxx.xx 元, 剩余本金 xxxxx.xx 元
  ...

示例 2:较长期限(如 36 期)

  • showMonths 只展示前 6 期详情,避免输出过长
  • 总利息、总还款金额会明显增加,可用于对比不同期数的成本

示例 3:错误输入

例如:

输入: abc 3.85 12

会返回:

❌ 错误: 金额 / 利率 / 月数 无效
请输入正确的正数,例如: 100000 3.85 12

编译与自动复制流程

与 BMI 案例相同,使用脚本自动完成 编译 + 复制 + 重命名

# 在项目根目录执行
build-and-copy.bat

这段代码展示了如何执行自动化构建脚本。在项目根目录运行 build-and-copy.bat 脚本,该脚本会自动完成编译和文件复制的全部流程。

脚本会:

  1. 调用 gradlew build 编译 Kotlin/JS
  2. 检查 hellokjs.mjshellokjs.d.ts 是否生成
  3. 将它们复制到 ArkTS pages 目录,并将 .mjs 重命名为 .js

目标路径:

d:\flutter_Obj\kmp_openharmony\kmp_ceshiapp\entry\src\main\ets\pages\hellokjs.js
d:\flutter_Obj\kmp_openharmony\kmp_ceshiapp\entry\src\main\ets\pages\hellokjs.d.ts

总结

通过 贷款等额本息还款计算器 这个案例,你已经拥有两条完整的 KMP → ArkTS 链路示例:

  • BMI 体质指数计算器
  • 贷款等额本息还款计算器

共同特点:

  1. 算法集中在 Kotlin:方便后续复用到 Web、桌面等平台
  2. ArkTS 专注 UI 交互:收集输入、展示结果
  3. 通过 Kotlin/JS 打通鸿蒙端:一份 Kotlin 代码,多端共享逻辑

你可以继续用这种模式扩展更多实用工具,比如:

  • 提前还款模拟器
  • 投资收益计算器(定投/单次投资)
  • 收支记账统计分析工具

只需重复这套流程:

  1. App.kt 中新增 @JsExport 函数
  2. 执行构建脚本编译并复制 JS
  3. 在 ArkTS 页面中导入并调用
  4. 写一篇对应的技术文章记录实现过程
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐