在这里插入图片描述

目录

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

概述

本案例在 Kotlin Multiplatform (KMP) 工程中实现了一个 健康工具 - 体检数据分析工具

  • 输入:用户的体检数据(血红蛋白、白细胞、血小板、血糖、血压、胆固醇),使用空格分隔,例如:150 7.5 250 5.5 120 200
  • 输出:
    • 体检数据分析:各项指标的数值和单位
    • 指标评估:各项指标的健康等级评估
    • 健康风险评估:根据体检数据的健康风险分析
    • 健康建议:根据各项指标的个性化健康建议
    • 医学解释:各项指标的医学含义和重要性
  • 技术路径:Kotlin → Kotlin/JS → JavaScript 模块 → ArkTS 页面调用。

这个案例展示了 KMP 跨端开发在健康医疗领域的应用:

把体检数据分析逻辑写在 Kotlin 里,一次实现,多端复用;把分析界面写在 ArkTS 里,专注 UI 和体验。

Kotlin 侧负责解析体检数据、评估各项指标、计算健康风险和生成健康建议;ArkTS 侧只需要把输入字符串传给 Kotlin 函数,并把返回结果原样展示出来即可。借助 KMP 的 Kotlin/JS 能力,这个体检数据分析工具可以在 Node.js、Web 前端以及 OpenHarmony 中复用相同的代码逻辑。


功能设计

输入数据格式

体检数据分析工具采用简单直观的输入格式:

  • 使用 空格分隔 各个参数。
  • 第一个参数是血红蛋白(整数或浮点数,单位:g/dL)。
  • 第二个参数是白细胞(浮点数,单位:10^9/L)。
  • 第三个参数是血小板(整数或浮点数,单位:10^9/L)。
  • 第四个参数是血糖(浮点数,单位:mmol/L)。
  • 第五个参数是收缩压(整数,单位:mmHg)。
  • 第六个参数是胆固醇(整数或浮点数,单位:mg/dL)。
  • 输入示例:
150 7.5 250 5.5 120 200

这可以理解为:

  • 血红蛋白:150 g/dL
  • 白细胞:7.5 10^9/L
  • 血小板:250 10^9/L
  • 血糖:5.5 mmol/L
  • 收缩压:120 mmHg
  • 胆固醇:200 mg/dL

工具会基于这些数据计算出:

  • 各项指标的健康等级:正常/偏低/偏高/异常
  • 健康风险指数:0-100 的综合风险评分
  • 需要关注的指标:哪些指标需要重点关注
  • 个性化建议:根据各项指标的具体建议

输出信息结构

为了便于在 ArkTS 页面以及终端中直接展示,Kotlin 函数返回的是一段结构化的多行文本,划分为几个分区:

  1. 标题区:例如"🏥 体检数据分析",一眼看出工具用途。
  2. 体检数据:各项指标的数值和单位。
  3. 指标评估:各项指标的健康等级。
  4. 健康风险:综合健康风险评估。
  5. 健康建议:根据各项指标的建议。
  6. 医学解释:各项指标的医学含义。

这样的输出结构使得:

  • 在 ArkTS 中可以直接把整段文本绑定到 Text 组件,配合 monospace 字体,阅读体验类似终端报告。
  • 如果将来想把结果保存到日志或者后端,直接保存字符串即可。
  • 需要更精细的 UI 时,也可以在前端根据分隔符进行拆分,再按块展示。

Kotlin 实现代码(KMP)

核心代码在 src/jsMain/kotlin/App.kt 中,通过 @JsExport 导出。以下是完整的 Kotlin 实现:

@OptIn(ExperimentalJsExport::class)
@JsExport
fun healthCheckAnalyzer(inputData: String = "150 7.5 250 5.5 120 200"): String {
    // 输入格式: 血红蛋白(g/dL) 白细胞(10^9/L) 血小板(10^9/L) 血糖(mmol/L) 收缩压(mmHg) 胆固醇(mg/dL)
    val parts = inputData.trim().split(" ").filter { it.isNotEmpty() }

    if (parts.size < 6) {
        return "❌ 错误: 请输入完整的信息,格式: 血红蛋白 白细胞 血小板 血糖 收缩压 胆固醇\n例如: 150 7.5 250 5.5 120 200"
    }

    val hemoglobin = parts[0].toDoubleOrNull() ?: return "❌ 错误: 血红蛋白必须是数字"
    val whiteBlood = parts[1].toDoubleOrNull() ?: return "❌ 错误: 白细胞必须是数字"
    val platelet = parts[2].toDoubleOrNull() ?: return "❌ 错误: 血小板必须是数字"
    val bloodSugar = parts[3].toDoubleOrNull() ?: return "❌ 错误: 血糖必须是数字"
    val systolicPressure = parts[4].toIntOrNull() ?: return "❌ 错误: 收缩压必须是整数"
    val cholesterol = parts[5].toDoubleOrNull() ?: return "❌ 错误: 胆固醇必须是数字"

    if (hemoglobin < 50 || hemoglobin > 200) {
        return "❌ 错误: 血红蛋白必须在 50-200 g/dL 之间"
    }

    if (whiteBlood < 1 || whiteBlood > 30) {
        return "❌ 错误: 白细胞必须在 1-30 10^9/L 之间"
    }

    if (platelet < 20 || platelet > 500) {
        return "❌ 错误: 血小板必须在 20-500 10^9/L 之间"
    }

    if (bloodSugar < 2 || bloodSugar > 30) {
        return "❌ 错误: 血糖必须在 2-30 mmol/L 之间"
    }

    if (systolicPressure < 60 || systolicPressure > 250) {
        return "❌ 错误: 收缩压必须在 60-250 mmHg 之间"
    }

    if (cholesterol < 50 || cholesterol > 500) {
        return "❌ 错误: 胆固醇必须在 50-500 mg/dL 之间"
    }

    // 评估血红蛋白
    val hemoglobinLevel = when {
        hemoglobin >= 120 && hemoglobin <= 160 -> "✅ 正常"
        hemoglobin < 120 -> "⚠️ 偏低(贫血风险)"
        else -> "⚠️ 偏高"
    }

    // 评估白细胞
    val whiteBloodLevel = when {
        whiteBlood >= 4.5 && whiteBlood <= 11 -> "✅ 正常"
        whiteBlood < 4.5 -> "⚠️ 偏低(免疫力下降)"
        else -> "⚠️ 偏高(感染风险)"
    }

    // 评估血小板
    val plateletLevel = when {
        platelet >= 150 && platelet <= 400 -> "✅ 正常"
        platelet < 150 -> "⚠️ 偏低(出血风险)"
        else -> "⚠️ 偏高"
    }

    // 评估血糖
    val bloodSugarLevel = when {
        bloodSugar >= 3.9 && bloodSugar <= 6.1 -> "✅ 正常"
        bloodSugar < 3.9 -> "⚠️ 偏低(低血糖风险)"
        bloodSugar <= 7 -> "⚠️ 空腹血糖受损"
        else -> "🔴 异常(糖尿病风险)"
    }

    // 评估血压
    val pressureLevel = when {
        systolicPressure < 120 -> "✅ 正常"
        systolicPressure < 130 -> "👍 升高"
        systolicPressure < 140 -> "⚠️ 高血压第一阶段"
        else -> "🔴 高血压第二阶段"
    }

    // 评估胆固醇
    val cholesterolLevel = when {
        cholesterol < 200 -> "✅ 正常"
        cholesterol < 240 -> "⚠️ 边界升高"
        else -> "🔴 升高(心脏病风险)"
    }

    // 计算健康风险指数
    var riskScore = 0
    if (hemoglobin < 120) riskScore += 15
    if (whiteBlood < 4.5 || whiteBlood > 11) riskScore += 10
    if (platelet < 150) riskScore += 15
    if (bloodSugar > 7) riskScore += 25
    if (systolicPressure >= 140) riskScore += 20
    if (cholesterol >= 240) riskScore += 15

    // 判断健康风险等级
    val riskLevel = when {
        riskScore == 0 -> "✅ 低风险"
        riskScore <= 20 -> "👍 中低风险"
        riskScore <= 40 -> "⚠️ 中等风险"
        riskScore <= 60 -> "🔴 中高风险"
        else -> "🆘 高风险"
    }

    // 生成健康建议
    val healthAdvice = StringBuilder()
    if (hemoglobin < 120) {
        healthAdvice.append("• 血红蛋白偏低,建议增加铁质摄入,多吃红肉、蛋类、豆类\n")
    }
    if (whiteBlood < 4.5) {
        healthAdvice.append("• 白细胞偏低,免疫力下降,建议增加营养,避免过度疲劳\n")
    }
    if (whiteBlood > 11) {
        healthAdvice.append("• 白细胞偏高,可能有感染,建议就医检查\n")
    }
    if (platelet < 150) {
        healthAdvice.append("• 血小板偏低,出血风险增加,建议避免剧烈运动\n")
    }
    if (bloodSugar > 7) {
        healthAdvice.append("• 血糖升高,糖尿病风险增加,建议减少糖分摄入,增加运动\n")
    }
    if (systolicPressure >= 140) {
        healthAdvice.append("• 血压升高,高血压风险,建议减少盐分摄入,增加有氧运动\n")
    }
    if (cholesterol >= 240) {
        healthAdvice.append("• 胆固醇升高,心脏病风险增加,建议减少油腻食物摄入\n")
    }
    if (healthAdvice.isEmpty()) {
        healthAdvice.append("• 所有指标正常,继续保持良好的生活习惯\n")
    }

    // 医学解释
    val medicalExplanation = """
    📚 医学解释:
    
    血红蛋白:携带氧气的蛋白质,低于正常值表示贫血,可能导致疲劳、头晕
    白细胞:免疫系统的重要组成部分,过低表示免疫力下降,过高表示可能有感染
    血小板:血液凝固的关键,过低可能导致出血不止,过高可能导致血栓
    血糖:能量代谢的指标,过高表示糖尿病风险,过低可能导致低血糖
    血压:心脏泵血的力量,过高增加心脏病和中风风险
    胆固醇:脂质代谢的指标,过高增加心脏病和动脉硬化风险
    """.trimIndent()

    // 构建输出文本
    val result = StringBuilder()
    result.append("🏥 体检数据分析\n")
    result.append("═".repeat(60)).append("\n\n")
    
    result.append("📋 体检数据\n")
    result.append("─".repeat(60)).append("\n")
    result.append("血红蛋白: ${String.format("%.1f", hemoglobin)} g/dL\n")
    result.append("白细胞: ${String.format("%.1f", whiteBlood)} 10^9/L\n")
    result.append("血小板: ${String.format("%.1f", platelet)} 10^9/L\n")
    result.append("血糖: ${String.format("%.1f", bloodSugar)} mmol/L\n")
    result.append("收缩压: ${systolicPressure} mmHg\n")
    result.append("胆固醇: ${String.format("%.1f", cholesterol)} mg/dL\n\n")

    result.append("⭐ 指标评估\n")
    result.append("─".repeat(60)).append("\n")
    result.append("血红蛋白: ${hemoglobinLevel}\n")
    result.append("白细胞: ${whiteBloodLevel}\n")
    result.append("血小板: ${plateletLevel}\n")
    result.append("血糖: ${bloodSugarLevel}\n")
    result.append("血压: ${pressureLevel}\n")
    result.append("胆固醇: ${cholesterolLevel}\n\n")

    result.append("⚠️ 健康风险评估\n")
    result.append("─".repeat(60)).append("\n")
    result.append("风险评分: ${riskScore}/100\n")
    result.append("风险等级: ${riskLevel}\n\n")

    result.append("💡 健康建议\n")
    result.append("─".repeat(60)).append("\n")
    result.append(healthAdvice.toString()).append("\n")

    result.append("${medicalExplanation}\n\n")

    result.append("🎯 建议行动\n")
    result.append("─".repeat(60)).append("\n")
    result.append("1. 定期体检,建议每年至少一次\n")
    result.append("2. 根据指标异常情况,及时就医咨询\n")
    result.append("3. 保持健康的生活方式:合理饮食、适度运动、充足睡眠\n")
    result.append("4. 控制压力,避免过度疲劳\n")
    result.append("5. 戒烟限酒,减少不良习惯\n")
    result.append("6. 定期监测血糖和血压\n")
    result.append("7. 增加有氧运动,每周至少150分钟\n")
    result.append("8. 保持健康体重,BMI在18.5-24.9之间\n")
    result.append("9. 多吃蔬菜水果,减少油腻食物\n")
    result.append("10. 定期复查,跟踪指标变化\n\n")

    result.append("📊 正常参考范围\n")
    result.append("─".repeat(60)).append("\n")
    result.append("• 血红蛋白: 120-160 g/dL\n")
    result.append("• 白细胞: 4.5-11 10^9/L\n")
    result.append("• 血小板: 150-400 10^9/L\n")
    result.append("• 血糖(空腹): 3.9-6.1 mmol/L\n")
    result.append("• 血压: <120 mmHg\n")
    result.append("• 胆固醇: <200 mg/dL\n\n")

    result.append("⚕️ 重要提示\n")
    result.append("─".repeat(60)).append("\n")
    result.append("本工具仅供参考,不能替代医生诊断。\n")
    result.append("如有异常指标,请立即咨询医生。\n")
    result.append("定期体检是预防疾病的最好方式。\n")

    return result.toString()
}

代码说明

这段 Kotlin 代码实现了完整的体检数据分析和健康风险评估功能。让我详细解释关键部分:

数据验证:首先验证输入的各项指标是否有效,确保数据在合理范围内。

指标评估:根据医学标准对各项指标进行评估,判断是否正常、偏低或偏高。

风险计算:根据异常指标的严重程度计算综合风险评分,帮助用户了解整体健康状况。

健康建议生成:根据各项异常指标生成个性化的健康建议。

医学解释:提供各项指标的医学含义和重要性说明。


JavaScript 调用示例

编译后的 JavaScript 代码可以在 Node.js 或浏览器中直接调用。以下是 JavaScript 的使用示例:

// 导入编译后的 Kotlin/JS 模块
const { healthCheckAnalyzer } = require('./hellokjs.js');

// 示例 1:健康体检数据
const result1 = healthCheckAnalyzer("150 7.5 250 5.5 120 200");
console.log("示例 1 - 健康体检数据:");
console.log(result1);
console.log("\n");

// 示例 2:血糖升高
const result2 = healthCheckAnalyzer("145 7.2 280 8.5 125 210");
console.log("示例 2 - 血糖升高:");
console.log(result2);
console.log("\n");

// 示例 3:血压升高
const result3 = healthCheckAnalyzer("155 7.8 260 6.2 145 220");
console.log("示例 3 - 血压升高:");
console.log(result3);
console.log("\n");

// 示例 4:贫血风险
const result4 = healthCheckAnalyzer("110 6.5 240 5.8 115 190");
console.log("示例 4 - 贫血风险:");
console.log(result4);
console.log("\n");

// 示例 5:多项指标异常
const result5 = healthCheckAnalyzer("100 3.8 120 9.5 155 280");
console.log("示例 5 - 多项指标异常:");
console.log(result5);
console.log("\n");

// 示例 6:使用默认参数
const result6 = healthCheckAnalyzer();
console.log("示例 6 - 使用默认参数:");
console.log(result6);

// 实际应用场景:从用户输入获取数据
function analyzeHealthCheck(userInput) {
    try {
        const result = healthCheckAnalyzer(userInput);
        return {
            success: true,
            data: result
        };
    } catch (error) {
        return {
            success: false,
            error: error.message
        };
    }
}

// 测试实际应用
const userInput = "140 7.2 270 6.8 130 210";
const analysis = analyzeHealthCheck(userInput);
if (analysis.success) {
    console.log("体检数据分析结果:");
    console.log(analysis.data);
} else {
    console.log("分析失败:", analysis.error);
}

// 多次体检对比
function compareHealthChecks(checks) {
    console.log("\n多次体检对比:");
    console.log("═".repeat(60));
    
    const results = checks.map((check, index) => {
        const analysis = healthCheckAnalyzer(check);
        return {
            number: index + 1,
            check,
            analysis
        };
    });

    results.forEach(result => {
        console.log(`\n第 ${result.number} 次体检 (${result.check}):`);
        console.log(result.analysis);
    });

    return results;
}

// 测试多次体检对比
const checks = [
    "150 7.5 250 5.5 120 200",
    "145 7.2 280 6.2 125 210",
    "140 7.0 270 6.8 130 220",
    "135 6.8 260 7.2 135 230"
];

compareHealthChecks(checks);

// 健康指标趋势分析
function analyzeHealthTrend(checks) {
    const data = checks.map(check => {
        const parts = check.split(' ').map(Number);
        return {
            hemoglobin: parts[0],
            whiteBlood: parts[1],
            platelet: parts[2],
            bloodSugar: parts[3],
            pressure: parts[4],
            cholesterol: parts[5]
        };
    });

    console.log("\n健康指标趋势分析:");
    console.log(`血糖趋势: ${data[0].bloodSugar}${data[data.length - 1].bloodSugar} mmol/L`);
    console.log(`血压趋势: ${data[0].pressure}${data[data.length - 1].pressure} mmHg`);
    console.log(`胆固醇趋势: ${data[0].cholesterol}${data[data.length - 1].cholesterol} mg/dL`);
}

analyzeHealthTrend(checks);

JavaScript 代码说明

这段 JavaScript 代码展示了如何在 Node.js 环境中调用编译后的 Kotlin 函数。关键点包括:

模块导入:使用 require 导入编译后的 JavaScript 模块,获取导出的 healthCheckAnalyzer 函数。

多个示例:展示了不同体检数据的调用方式,包括健康、异常等情况。

错误处理:在实际应用中,使用 try-catch 块来处理可能的错误。

多次体检对比compareHealthChecks 函数展示了如何对比多次体检数据。

趋势分析analyzeHealthTrend 函数演示了如何进行健康指标的趋势分析。


ArkTS 页面集成与调用

在 OpenHarmony 的 ArkTS 页面中集成这个体检数据分析工具。以下是完整的 ArkTS 实现代码:

import { healthCheckAnalyzer } from './hellokjs';

@Entry
@Component
struct HealthCheckAnalyzerPage {
  @State hemoglobin: string = "150";
  @State whiteBlood: string = "7.5";
  @State platelet: string = "250";
  @State bloodSugar: string = "5.5";
  @State pressure: string = "120";
  @State cholesterol: string = "200";
  @State analysisResult: string = "";
  @State isLoading: boolean = false;

  build() {
    Column() {
      // 顶部栏
      Row() {
        Text("🏥 体检数据分析")
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
      }
      .width("100%")
      .height(60)
      .backgroundColor("#1976D2")
      .justifyContent(FlexAlign.Center)
      .padding({ top: 10, bottom: 10 })

      // 主容器
      Scroll() {
        Column() {
          // 血红蛋白输入
          Text("血红蛋白 (g/dL)")
            .fontSize(14)
            .fontColor("#333333")
            .margin({ top: 20, left: 15 })

          TextInput({
            placeholder: "例如: 150",
            text: this.hemoglobin
          })
            .width("90%")
            .height(45)
            .margin({ top: 8, bottom: 15, left: 15, right: 15 })
            .padding({ left: 10, right: 10 })
            .backgroundColor("#BBDEFB")
            .border({ width: 1, color: "#1976D2" })
            .onChange((value: string) => {
              this.hemoglobin = value;
            })

          // 白细胞输入
          Text("白细胞 (10^9/L)")
            .fontSize(14)
            .fontColor("#333333")
            .margin({ left: 15 })

          TextInput({
            placeholder: "例如: 7.5",
            text: this.whiteBlood
          })
            .width("90%")
            .height(45)
            .margin({ top: 8, bottom: 15, left: 15, right: 15 })
            .padding({ left: 10, right: 10 })
            .backgroundColor("#BBDEFB")
            .border({ width: 1, color: "#1976D2" })
            .onChange((value: string) => {
              this.whiteBlood = value;
            })

          // 血小板输入
          Text("血小板 (10^9/L)")
            .fontSize(14)
            .fontColor("#333333")
            .margin({ left: 15 })

          TextInput({
            placeholder: "例如: 250",
            text: this.platelet
          })
            .width("90%")
            .height(45)
            .margin({ top: 8, bottom: 15, left: 15, right: 15 })
            .padding({ left: 10, right: 10 })
            .backgroundColor("#BBDEFB")
            .border({ width: 1, color: "#1976D2" })
            .onChange((value: string) => {
              this.platelet = value;
            })

          // 血糖输入
          Text("血糖 (mmol/L)")
            .fontSize(14)
            .fontColor("#333333")
            .margin({ left: 15 })

          TextInput({
            placeholder: "例如: 5.5",
            text: this.bloodSugar
          })
            .width("90%")
            .height(45)
            .margin({ top: 8, bottom: 15, left: 15, right: 15 })
            .padding({ left: 10, right: 10 })
            .backgroundColor("#BBDEFB")
            .border({ width: 1, color: "#1976D2" })
            .onChange((value: string) => {
              this.bloodSugar = value;
            })

          // 血压输入
          Text("收缩压 (mmHg)")
            .fontSize(14)
            .fontColor("#333333")
            .margin({ left: 15 })

          TextInput({
            placeholder: "例如: 120",
            text: this.pressure
          })
            .width("90%")
            .height(45)
            .margin({ top: 8, bottom: 15, left: 15, right: 15 })
            .padding({ left: 10, right: 10 })
            .backgroundColor("#BBDEFB")
            .border({ width: 1, color: "#1976D2" })
            .onChange((value: string) => {
              this.pressure = value;
            })

          // 胆固醇输入
          Text("胆固醇 (mg/dL)")
            .fontSize(14)
            .fontColor("#333333")
            .margin({ left: 15 })

          TextInput({
            placeholder: "例如: 200",
            text: this.cholesterol
          })
            .width("90%")
            .height(45)
            .margin({ top: 8, bottom: 15, left: 15, right: 15 })
            .padding({ left: 10, right: 10 })
            .backgroundColor("#BBDEFB")
            .border({ width: 1, color: "#1976D2" })
            .onChange((value: string) => {
              this.cholesterol = value;
            })

          // 按钮区域
          Row() {
            Button("🔍 分析数据")
              .width("45%")
              .height(45)
              .backgroundColor("#1976D2")
              .fontColor(Color.White)
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .onClick(() => {
                this.isLoading = true;
                setTimeout(() => {
                  const input = `${this.hemoglobin} ${this.whiteBlood} ${this.platelet} ${this.bloodSugar} ${this.pressure} ${this.cholesterol}`;
                  this.analysisResult = healthCheckAnalyzer(input);
                  this.isLoading = false;
                }, 300);
              })

            Blank()

            Button("🔄 重置")
              .width("45%")
              .height(45)
              .backgroundColor("#2196F3")
              .fontColor(Color.White)
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .onClick(() => {
                this.hemoglobin = "150";
                this.whiteBlood = "7.5";
                this.platelet = "250";
                this.bloodSugar = "5.5";
                this.pressure = "120";
                this.cholesterol = "200";
                this.analysisResult = "";
                this.isLoading = false;
              })
          }
          .width("90%")
          .margin({ top: 10, bottom: 20, left: 15, right: 15 })
          .justifyContent(FlexAlign.SpaceBetween)

          // 加载指示器
          if (this.isLoading) {
            Row() {
              LoadingProgress()
                .width(40)
                .height(40)
                .color("#1976D2")
              Text("  正在分析中...")
                .fontSize(14)
                .fontColor("#666666")
            }
            .width("90%")
            .height(50)
            .margin({ bottom: 15, left: 15, right: 15 })
            .justifyContent(FlexAlign.Center)
            .backgroundColor("#BBDEFB")
            .borderRadius(8)
          }

          // 结果显示区域
          if (this.analysisResult.length > 0) {
            Column() {
              Text("📋 分析结果")
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .fontColor("#1976D2")
                .margin({ bottom: 10 })

              Text(this.analysisResult)
                .width("100%")
                .fontSize(12)
                .fontFamily("monospace")
                .fontColor("#333333")
                .lineHeight(1.6)
                .padding(10)
                .backgroundColor("#FAFAFA")
                .border({ width: 1, color: "#E0E0E0" })
                .borderRadius(8)
            }
            .width("90%")
            .margin({ top: 20, bottom: 30, left: 15, right: 15 })
            .padding(15)
            .backgroundColor("#BBDEFB")
            .borderRadius(8)
            .border({ width: 1, color: "#1976D2" })
          }
        }
        .width("100%")
      }
      .layoutWeight(1)
      .backgroundColor("#FFFFFF")
    }
    .width("100%")
    .height("100%")
    .backgroundColor("#F5F5F5")
  }
}

ArkTS 代码说明

这段 ArkTS 代码实现了完整的用户界面和交互逻辑。关键点包括:

导入函数:从编译后的 JavaScript 模块中导入 healthCheckAnalyzer 函数。

状态管理:使用 @State 装饰器管理八个状态:六个体检指标、分析结果和加载状态。

UI 布局:包含顶部栏、六个输入框、分析和重置按钮、加载指示器和结果显示区域。

交互逻辑:用户输入体检数据后,点击分析按钮。应用会调用 Kotlin 函数进行分析,显示加载动画,最后展示详细的分析结果。

样式设计:使用蓝色主题,与医疗和健康相关的主题相符。所有输入框、按钮和结果显示区域都有相应的样式设置。


数据输入与交互体验

输入数据格式规范

为了确保工具能够正确处理用户输入,用户应该遵循以下规范:

  1. 血红蛋白:整数或浮点数,单位 g/dL,范围 50-200。
  2. 白细胞:浮点数,单位 10^9/L,范围 1-30。
  3. 血小板:整数或浮点数,单位 10^9/L,范围 20-500。
  4. 血糖:浮点数,单位 mmol/L,范围 2-30。
  5. 收缩压:整数,单位 mmHg,范围 60-250。
  6. 胆固醇:整数或浮点数,单位 mg/dL,范围 50-500。
  7. 分隔符:使用空格分隔各个参数。

示例输入

  • 健康体检数据150 7.5 250 5.5 120 200
  • 血糖升高145 7.2 280 8.5 125 210
  • 血压升高155 7.8 260 6.2 145 220
  • 贫血风险110 6.5 240 5.8 115 190
  • 多项指标异常100 3.8 120 9.5 155 280

交互流程

  1. 用户打开应用,看到输入框和默认数据
  2. 用户输入六项体检指标
  3. 点击"分析数据"按钮,应用调用 Kotlin 函数进行分析
  4. 应用显示加载动画,表示正在处理
  5. 分析完成后,显示详细的分析结果,包括指标评估、健康风险、建议等
  6. 用户可以点击"重置"按钮清空数据,重新开始

编译与自动复制流程

编译步骤

  1. 编译 Kotlin 代码

    ./gradlew build
    
  2. 生成 JavaScript 文件
    编译过程会自动生成 hellokjs.d.tshellokjs.js 文件。

  3. 复制到 ArkTS 项目
    使用提供的脚本自动复制生成的文件到 ArkTS 项目的 pages 目录:

    ./build-and-copy.bat
    

文件结构

编译完成后,项目结构如下:

kmp_openharmony/
├── src/
│   └── jsMain/
│       └── kotlin/
│           └── App.kt (包含 healthCheckAnalyzer 函数)
├── build/
│   └── js/
│       └── packages/
│           └── hellokjs/
│               ├── hellokjs.d.ts
│               └── hellokjs.js
└── kmp_ceshiapp/
    └── entry/
        └── src/
            └── main/
                └── ets/
                    └── pages/
                        ├── hellokjs.d.ts (复制后)
                        ├── hellokjs.js (复制后)
                        └── Index.ets (ArkTS 页面)

总结

这个案例展示了如何使用 Kotlin Multiplatform 技术实现一个跨端的健康工具 - 体检数据分析工具。通过将核心逻辑写在 Kotlin 中,然后编译为 JavaScript,最后在 ArkTS 中调用,我们实现了代码的一次编写、多端复用。

核心优势

  1. 代码复用:Kotlin 代码可以在 JVM、JavaScript 和其他平台上运行,避免重复开发。
  2. 类型安全:Kotlin 的类型系统确保了代码的安全性和可维护性。
  3. 性能优化:Kotlin 编译为 JavaScript 后,性能与手写 JavaScript 相当。
  4. 易于维护:集中管理业务逻辑,使得维护和更新变得更加容易。
  5. 用户体验:通过 ArkTS 提供的丰富 UI 组件,可以创建美观、易用的用户界面。

扩展方向

  1. 数据持久化:将用户的体检记录保存到本地存储或云端。
  2. 数据可视化:使用图表库展示体检指标的变化趋势。
  3. 多次对比:支持多次体检数据的对比分析。
  4. AI 诊断:使用机器学习进行更精准的健康诊断。
  5. 医生咨询:集成在线医生咨询功能。
  6. 健康建议:根据体检结果提供个性化的健康计划。
  7. 数据导出:支持体检报告的导出和分享。
  8. 集成医院系统:连接医院的体检系统获取数据。

通过这个案例,开发者可以学到如何在 KMP 项目中实现复杂的健康数据分析逻辑,以及如何在 OpenHarmony 平台上构建高效的跨端应用。这个体检数据分析工具可以作为健康管理应用、医疗平台或个人健康档案的核心模块。

Logo

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

更多推荐