在这里插入图片描述

目录

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

概述

本案例在 Kotlin Multiplatform (KMP) 工程中实现了一个成绩排行榜生成与分析工具

  • 输入:一串“姓名 分数”的列表,例如:张三 95, 李四 88, 王五 76
  • 输出:
    • 排名列表(第 N 名、分数、相对平均分)
    • 基础统计(人数、最高分、最低分、平均分)
    • 分数段统计(优秀/良好/及格/不及格人数及占比)
    • 综合评语
  • 技术路径:Kotlin → Kotlin/JS → JavaScript 模块 → ArkTS 页面调用

这是继 BMI 体质指数计算器贷款等额本息还款计算器 之后的第三个完整链路案例,继续体现“算法在 Kotlin,界面在 ArkTS”的模式。


功能设计

输入格式:

张三 95, 李四 88, 王五 76

设计要点:

  • 使用逗号分隔多位同学,空格分隔姓名与成绩
  • 兼容一定程度的空格与格式误差(trim 处理)
  • 对解析失败或格式不正确给出友好错误提示

分析内容:

  1. 排行榜:按分数从高到低排序,给出名次、分数以及相对平均分的差值
  2. 基础统计:总人数、最高分、最低分、平均分
  3. 分段统计
    • 优秀:>= 90
    • 良好:80 - 89
    • 及格:60 - 79
    • 不及格:< 60
  4. 综合评语:根据平均分给出整体表现评价

Kotlin 实现代码(KMP)

src/jsMain/kotlin/App.kt 中新增 scoreRankingAnalyzer 方法,并通过 @JsExport 导出:

@OptIn(ExperimentalJsExport::class)
@JsExport
fun scoreRankingAnalyzer(inputText: String = "张三 95, 李四 88, 王五 76"): String {
    // 输入格式: "姓名 分数, 姓名 分数, ..."
    if (inputText.trim().isEmpty()) {
        return "❌ 错误: 输入不能为空\n请输入类似 '张三 95, 李四 88' 的内容"
    }

    // 解析为 (姓名, 分数)
    val entries = inputText.split(",")
        .map { it.trim() }
        .filter { it.isNotEmpty() }
        .mapNotNull { part ->
            val pieces = part.split(" ").filter { it.isNotEmpty() }
            if (pieces.size < 2) return@mapNotNull null
            val name = pieces[0]
            val score = pieces[1].toDoubleOrNull() ?: return@mapNotNull null
            name to score
        }

    if (entries.isEmpty()) {
        return "❌ 错误: 没有解析到有效的姓名和分数\n示例: 张三 95, 李四 88, 王五 76"
    }

    // 排序
    val sorted = entries.sortedByDescending { it.second }

    // 基础统计
    val scores = sorted.map { it.second }
    val count = scores.size
    val max = scores.maxOrNull() ?: 0.0
    val min = scores.minOrNull() ?: 0.0
    val avg = if (count > 0) scores.sum() / count else 0.0

    // 分段统计
    val excellent = scores.count { it >= 90 }
    val good = scores.count { it in 80.0..89.999 }
    val pass = scores.count { it in 60.0..79.999 }
    val fail = scores.count { it < 60.0 }

    // 排行榜文本
    val rankingLines = sorted.mapIndexed { index, (name, score) ->
        val rank = index + 1
        val diffToAvg = ((score - avg) * 10).toInt() / 10.0
        "  第${rank}名: $name - ${score} 分 (相对平均: ${diffToAvg} 分)"
    }

    // 简单评语
    val comment = when {
        avg >= 90 -> "整体水平非常优秀,保持当前学习节奏。"
        avg >= 75 -> "整体水平良好,可以针对薄弱同学进行辅导。"
        avg >= 60 -> "整体刚好及格,建议加强基础知识训练。"
        else -> "整体水平偏低,需要系统性复习与训练。"
    }

    fun percent(part: Int): Double = if (count > 0) (part * 1000 / count) / 10.0 else 0.0

    return "📊 成绩排行榜生成与分析\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "原始输入: $inputText\n\n" +
           "1️⃣ 排行榜:\n" +
           rankingLines.joinToString("\n") + "\n\n" +
           "2️⃣ 基础统计:\n" +
           "  人数: $count\n" +
           "  最高分: $max\n" +
           "  最低分: $min\n" +
           "  平均分: ${((avg * 10).toInt() / 10.0)}\n\n" +
           "3️⃣ 分数段统计:\n" +
           "  优秀(>=90): $excellent 人 (${percent(excellent)}%)\n" +
           "  良好(80-89): $good 人 (${percent(good)}%)\n" +
           "  及格(60-79): $pass 人 (${percent(pass)}%)\n" +
           "  不及格(<60): $fail 人 (${percent(fail)}%)\n\n" +
           "4️⃣ 综合评语:\n" +
           "  $comment\n\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "✅ 分析完成!"
}

代码说明:

这是成绩排行榜生成与分析工具的核心 Kotlin 函数。函数接收一个包含"姓名 分数"对的字符串,用逗号分隔。首先验证输入不为空。使用 split(",") 按逗号分隔多个学生,再用空格分隔姓名和分数,使用 mapNotNull 过滤无效数据。按分数从高到低排序。计算基础统计:人数、最高分、最低分、平均分。按分数段统计:优秀(≥90)、良好(80-89)、及格(60-79)、不及格(<60)。使用 mapIndexed 生成排行榜文本,计算每个学生相对平均分的差值。根据平均分生成综合评语。定义 percent 函数计算百分比。最后将所有数据格式化为多部分输出字符串。

说明:

  • 使用 split(",") 切分多个同学,再用空格切分姓名与成绩
  • 对解析失败的数据直接过滤掉,并在整体为空时返回错误提示
  • 所有输出通过字符串拼接完成,方便 ArkTS 直接展示

JavaScript 编译输出与类型定义

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

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

类型定义中会包含:

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

代码说明:

这是 Kotlin 函数编译到 TypeScript 后生成的类型定义。声明了 scoreRankingAnalyzer 函数的签名:接收一个可选的字符串参数 inputText,返回字符串。这个类型定义允许 ArkTS/TypeScript 在导入 hellokjs 模块时获得完整的类型检查和智能代码提示,提高开发效率和代码安全性。

这样在 ArkTS/TypeScript 中导入 hellokjs 模块时可获得类型检查和智能提示。


ArkTS 页面集成与调用

首页 Index.ets 已改为“成绩排行榜生成与分析”页面,核心结构如下:

import { scoreRankingAnalyzer } from './hellokjs';

@Entry
@Component
struct Index {
  @State message: string = '请输入姓名和分数组成的列表';
  @State inputText: string = '张三 95, 李四 88, 王五 76';
  @State resultText: string = '';

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

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

  build() {
    Column() {
      // 标题、输入框、结果显示、默认示例&清空按钮等
    }
  }
}

代码说明:

这是 OpenHarmony ArkTS 页面的核心实现。首先导入 Kotlin 编译生成的 scoreRankingAnalyzer 函数。定义三个状态变量:message 显示操作状态,inputText 存储用户输入的学生成绩列表,resultText 存储分析结果。aboutToAppear() 生命周期钩子在页面加载时自动调用 calculateRanking() 进行初始计算。calculateRanking() 方法获取输入文本,调用 Kotlin 函数进行排行榜分析,更新结果和状态信息,使用 try-catch 捕获异常。build() 方法定义 UI 布局,包括标题、输入框、结果显示区域等。

说明:

  • ArkTS 通过 inputText 收集原始字符串,并直接传给 Kotlin 函数
  • 返回的多行文本结果通过 resultText 在 UI 中滚动展示

交互示例

示例 1:基础示例

输入:

张三 95, 李四 88, 王五 76

输出片段示例:

1️⃣ 排行榜:
  第1名: 张三 - 95.0 分 (相对平均: 11.0 分)
  第2名: 李四 - 88.0 分 (相对平均: 4.0 分)
  第3名: 王五 - 76.0 分 (相对平均: -8.0 分)

2️⃣ 基础统计:
  人数: 3
  最高分: 95.0
  最低分: 76.0
  平均分: 84.0

3️⃣ 分数段统计:
  优秀(>=90): 1 人 (...
Logo

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

更多推荐