在这里插入图片描述

目录

  1. 概述
  2. 工具功能
  3. 核心实现
  4. Kotlin 源代码
  5. JavaScript 编译代码
  6. ArkTS 调用代码
  7. 实战案例
  8. 最佳实践

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个功能完整的营养热量计算器系统。营养热量分析是现代健康管理和健身应用中的核心需求,广泛应用于减肥管理、健身计划、营养咨询、医疗诊断等领域。这个工具提供了对食物热量和营养成分的全面分析支持,包括热量计算、宏量营养素分析(蛋白质、脂肪、碳水化合物)、微量营养素追踪、每日摄入量评估等功能。

在实际应用中,营养热量计算器广泛应用于以下场景:个人健康管理应用、健身房管理系统、营养咨询平台、医疗诊断系统、食品标签分析、膳食计划制定等。通过 KMP 框架的跨端能力,我们可以在不同平台上使用相同的营养分析逻辑,确保热量计算的准确性和一致性。

工具的特点

  • 全面的营养分析:支持热量、蛋白质、脂肪、碳水化合物等多维度营养分析
  • 食物数据库:包含常见食物的营养信息
  • 每日摄入追踪:记录和分析每日营养摄入
  • 个性化建议:根据用户目标提供营养建议
  • 营养平衡评估:评估营养摄入是否均衡
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. 食物热量计算

热量是衡量食物能量含量的重要指标。不同的食物含有不同的热量,准确计算食物热量对于健康管理和减肥计划至关重要。热量计算需要考虑食物的类型、重量和烹饪方式。在营养应用中,热量计算是用户最关注的信息之一。

  • 基础热量查询:查询常见食物的热量含量
  • 重量调整:根据实际食用量调整热量
  • 烹饪方式影响:考虑不同烹饪方式对热量的影响
  • 食物组合分析:计算多种食物组合的总热量

2. 宏量营养素分析

宏量营养素(蛋白质、脂肪、碳水化合物)是人体所需的主要营养物质。不同的宏量营养素对人体有不同的作用。宏量营养素分析需要考虑各种营养素的比例和总摄入量。

  • 蛋白质分析:计算蛋白质含量和摄入比例
  • 脂肪分析:区分饱和脂肪、不饱和脂肪等
  • 碳水化合物分析:区分简单碳水和复杂碳水
  • 营养素比例:计算各营养素的摄入比例

3. 微量营养素追踪

微量营养素(维生素、矿物质等)虽然需要量少,但对人体健康至关重要。微量营养素追踪需要监测维生素、矿物质、纤维素等的摄入。

  • 维生素追踪:追踪各种维生素的摄入
  • 矿物质监测:监测钙、铁、锌等矿物质
  • 纤维素计算:计算膳食纤维的摄入量
  • 缺乏风险评估:评估营养素缺乏的风险

4. 每日摄入评估

每日摄入评估是将用户的营养摄入与推荐摄入量进行比较。这需要考虑用户的年龄、性别、活动水平等因素。每日摄入评估帮助用户了解自己的营养摄入是否符合健康标准。

  • 推荐摄入量:根据用户信息计算推荐摄入量
  • 摄入对比:将实际摄入与推荐摄入进行比较
  • 超标警告:警告营养摄入过量
  • 不足提醒:提醒营养摄入不足

5. 营养平衡评估

营养平衡评估是综合考虑各种营养素摄入的评估。营养平衡对于健康和疾病预防很重要。营养平衡评估需要考虑营养素之间的相互作用。

  • 平衡指数:计算营养摄入的平衡指数
  • 营养评级:根据平衡指数给出评级
  • 改善建议:提供改善营养平衡的建议
  • 风险评估:评估营养不平衡带来的健康风险

6. 膳食计划建议

根据用户的目标和当前营养摄入,提供个性化的膳食计划建议。膳食计划建议需要考虑用户的饮食偏好和健康目标。

  • 减肥计划:为减肥用户提供低热量膳食建议
  • 增肌计划:为健身用户提供高蛋白膳食建议
  • 健康维持:为普通用户提供均衡膳食建议
  • 特殊饮食:支持素食、无麸质等特殊饮食

7. 食物替代建议

根据用户的营养目标,提供食物替代建议。食物替代建议帮助用户在保持营养的同时改变饮食习惯。

  • 热量相近食物:推荐热量相近的替代食物
  • 营养相近食物:推荐营养成分相近的替代食物
  • 更健康选择:推荐更健康的食物替代
  • 口味偏好:考虑用户的口味偏好

核心实现

1. 食物热量计算

data class Food(
    val name: String,
    val caloriesPer100g: Double,
    val protein: Double,
    val fat: Double,
    val carbs: Double,
    val fiber: Double
)

fun calculateFoodCalories(food: Food, weight: Double): Double {
    return (food.caloriesPer100g / 100) * weight
}

fun calculateNutrients(food: Food, weight: Double): Map<String, Double> {
    val multiplier = weight / 100
    return mapOf(
        "calories" to food.caloriesPer100g * multiplier,
        "protein" to food.protein * multiplier,
        "fat" to food.fat * multiplier,
        "carbs" to food.carbs * multiplier,
        "fiber" to food.fiber * multiplier
    )
}

代码说明: 食物热量计算使用食物的基础营养数据和实际食用量进行计算。通过定义 Food 数据类,可以方便地存储和管理食物信息。计算时使用比例法,根据实际重量调整营养值。

2. 每日摄入评估

data class UserProfile(
    val age: Int,
    val gender: String,
    val weight: Double,
    val height: Double,
    val activityLevel: String
)

fun calculateDailyCalorieNeeds(user: UserProfile): Double {
    // 使用 Mifflin-St Jeor 公式计算基础代谢率
    val bmr = if (user.gender.lowercase() == "male") {
        (10 * user.weight) + (6.25 * user.height) - (5 * user.age) + 5
    } else {
        (10 * user.weight) + (6.25 * user.height) - (5 * user.age) - 161
    }
    
    // 根据活动水平调整
    val activityMultiplier = when (user.activityLevel.lowercase()) {
        "sedentary" -> 1.2
        "light" -> 1.375
        "moderate" -> 1.55
        "active" -> 1.725
        "veryactive" -> 1.9
        else -> 1.5
    }
    
    return bmr * activityMultiplier
}

fun calculateMacroNeeds(dailyCalories: Double, goal: String): Map<String, Double> {
    return when (goal.lowercase()) {
        "weight_loss" -> mapOf(
            "protein" to dailyCalories * 0.30 / 4,  // 30% from protein
            "fat" to dailyCalories * 0.25 / 9,       // 25% from fat
            "carbs" to dailyCalories * 0.45 / 4      // 45% from carbs
        )
        "muscle_gain" -> mapOf(
            "protein" to dailyCalories * 0.35 / 4,
            "fat" to dailyCalories * 0.25 / 9,
            "carbs" to dailyCalories * 0.40 / 4
        )
        else -> mapOf(
            "protein" to dailyCalories * 0.25 / 4,
            "fat" to dailyCalories * 0.30 / 9,
            "carbs" to dailyCalories * 0.45 / 4
        )
    }
}

代码说明: 每日摄入评估使用科学的公式计算用户的热量需求。Mifflin-St Jeor 公式是目前最准确的基础代谢率计算方法。根据用户的活动水平调整,可以得到更准确的每日热量需求。

3. 营养平衡评估

fun assessNutritionBalance(dailyIntake: Map<String, Double>, dailyNeeds: Map<String, Double>): Map<String, Any> {
    var balanceScore = 100
    val issues = mutableListOf<String>()
    
    for ((nutrient, intake) in dailyIntake) {
        val need = dailyNeeds[nutrient] ?: continue
        val percentage = (intake / need) * 100
        
        when {
            percentage < 80 -> {
                balanceScore -= 10
                issues.add("$nutrient 摄入不足 (${percentage.toInt()}%)")
            }
            percentage > 120 -> {
                balanceScore -= 5
                issues.add("$nutrient 摄入过量 (${percentage.toInt()}%)")
            }
        }
    }
    
    balanceScore = balanceScore.coerceIn(0, 100)
    
    val rating = when {
        balanceScore >= 80 -> "优秀"
        balanceScore >= 60 -> "良好"
        balanceScore >= 40 -> "一般"
        else -> "需要改善"
    }
    
    return mapOf(
        "score" to balanceScore,
        "rating" to rating,
        "issues" to issues
    )
}

代码说明: 营养平衡评估通过比较实际摄入与推荐摄入来计算平衡指数。通过识别摄入不足或过量的营养素,可以提供具体的改善建议。

4. 膳食计划建议

fun generateDietPlan(user: UserProfile, goal: String, preferences: List<String>): List<String> {
    val dailyCalories = calculateDailyCalorieNeeds(user)
    val macroNeeds = calculateMacroNeeds(dailyCalories, goal)
    
    val recommendations = mutableListOf<String>()
    
    when (goal.lowercase()) {
        "weight_loss" -> {
            recommendations.add("每日热量摄入: ${dailyCalories.toInt()} 卡路里")
            recommendations.add("蛋白质: ${(macroNeeds["protein"] ?: 0).toInt()} 克 (帮助保持肌肉)")
            recommendations.add("多吃低热量、高纤维的食物")
            recommendations.add("避免高糖、高脂肪的食物")
            recommendations.add("每天喝足够的水")
        }
        "muscle_gain" -> {
            recommendations.add("每日热量摄入: ${(dailyCalories * 1.1).toInt()} 卡路里")
            recommendations.add("蛋白质: ${(macroNeeds["protein"] ?: 0).toInt()} 克 (每公斤体重1.6-2.2克)")
            recommendations.add("增加复杂碳水化合物的摄入")
            recommendations.add("选择优质蛋白质来源")
            recommendations.add("配合力量训练")
        }
        else -> {
            recommendations.add("每日热量摄入: ${dailyCalories.toInt()} 卡路里")
            recommendations.add("保持营养均衡")
            recommendations.add("多吃蔬菜和水果")
            recommendations.add("选择全谷物食品")
            recommendations.add("限制盐和糖的摄入")
        }
    }
    
    return recommendations
}

代码说明: 膳食计划建议根据用户的目标和需求提供个性化的建议。通过考虑用户的目标(减肥、增肌或维持),可以提供针对性的营养建议。


Kotlin 源代码

// NutritionCalculator.kt
data class Food(
    val name: String,
    val caloriesPer100g: Double,
    val protein: Double,
    val fat: Double,
    val carbs: Double,
    val fiber: Double
)

data class UserProfile(
    val age: Int,
    val gender: String,
    val weight: Double,
    val height: Double,
    val activityLevel: String
)

class NutritionCalculator {
    
    private val foodDatabase = mapOf(
        "鸡胸肉" to Food("鸡胸肉", 165.0, 31.0, 3.6, 0.0, 0.0),
        "鸡蛋" to Food("鸡蛋", 155.0, 13.0, 11.0, 1.1, 0.0),
        "牛奶" to Food("牛奶", 61.0, 3.2, 3.3, 4.8, 0.0),
        "米饭" to Food("米饭", 130.0, 2.7, 0.3, 28.0, 0.4),
        "面包" to Food("面包", 265.0, 9.0, 3.3, 49.0, 2.7),
        "苹果" to Food("苹果", 52.0, 0.3, 0.2, 14.0, 2.4),
        "香蕉" to Food("香蕉", 89.0, 1.1, 0.3, 23.0, 2.6),
        "西兰花" to Food("西兰花", 34.0, 2.8, 0.4, 7.0, 2.4),
        "胡萝卜" to Food("胡萝卜", 41.0, 0.9, 0.2, 10.0, 2.8),
        "三文鱼" to Food("三文鱼", 208.0, 20.0, 13.0, 0.0, 0.0)
    )
    
    fun getFood(name: String): Food? = foodDatabase[name]
    
    fun calculateFoodCalories(food: Food, weight: Double): Double {
        return (food.caloriesPer100g / 100) * weight
    }
    
    fun calculateNutrients(food: Food, weight: Double): Map<String, Double> {
        val multiplier = weight / 100
        return mapOf(
            "calories" to food.caloriesPer100g * multiplier,
            "protein" to food.protein * multiplier,
            "fat" to food.fat * multiplier,
            "carbs" to food.carbs * multiplier,
            "fiber" to food.fiber * multiplier
        )
    }
    
    fun calculateDailyCalorieNeeds(user: UserProfile): Double {
        val bmr = if (user.gender.lowercase() == "male") {
            (10 * user.weight) + (6.25 * user.height) - (5 * user.age) + 5
        } else {
            (10 * user.weight) + (6.25 * user.height) - (5 * user.age) - 161
        }
        
        val activityMultiplier = when (user.activityLevel.lowercase()) {
            "sedentary" -> 1.2
            "light" -> 1.375
            "moderate" -> 1.55
            "active" -> 1.725
            "veryactive" -> 1.9
            else -> 1.5
        }
        
        return bmr * activityMultiplier
    }
    
    fun calculateMacroNeeds(dailyCalories: Double, goal: String): Map<String, Double> {
        return when (goal.lowercase()) {
            "weight_loss" -> mapOf(
                "protein" to dailyCalories * 0.30 / 4,
                "fat" to dailyCalories * 0.25 / 9,
                "carbs" to dailyCalories * 0.45 / 4
            )
            "muscle_gain" -> mapOf(
                "protein" to dailyCalories * 0.35 / 4,
                "fat" to dailyCalories * 0.25 / 9,
                "carbs" to dailyCalories * 0.40 / 4
            )
            else -> mapOf(
                "protein" to dailyCalories * 0.25 / 4,
                "fat" to dailyCalories * 0.30 / 9,
                "carbs" to dailyCalories * 0.45 / 4
            )
        }
    }
    
    fun assessNutritionBalance(dailyIntake: Map<String, Double>, dailyNeeds: Map<String, Double>): Map<String, Any> {
        var balanceScore = 100
        val issues = mutableListOf<String>()
        
        for ((nutrient, intake) in dailyIntake) {
            val need = dailyNeeds[nutrient] ?: continue
            val percentage = (intake / need) * 100
            
            when {
                percentage < 80 -> {
                    balanceScore -= 10
                    issues.add("$nutrient 摄入不足 (${percentage.toInt()}%)")
                }
                percentage > 120 -> {
                    balanceScore -= 5
                    issues.add("$nutrient 摄入过量 (${percentage.toInt()}%)")
                }
            }
        }
        
        balanceScore = balanceScore.coerceIn(0, 100)
        
        val rating = when {
            balanceScore >= 80 -> "优秀"
            balanceScore >= 60 -> "良好"
            balanceScore >= 40 -> "一般"
            else -> "需要改善"
        }
        
        return mapOf(
            "score" to balanceScore,
            "rating" to rating,
            "issues" to issues
        )
    }
    
    fun generateDietPlan(user: UserProfile, goal: String): List<String> {
        val dailyCalories = calculateDailyCalorieNeeds(user)
        val macroNeeds = calculateMacroNeeds(dailyCalories, goal)
        
        val recommendations = mutableListOf<String>()
        
        when (goal.lowercase()) {
            "weight_loss" -> {
                recommendations.add("每日热量摄入: ${dailyCalories.toInt()} 卡路里")
                recommendations.add("蛋白质: ${(macroNeeds["protein"] ?: 0).toInt()} 克")
                recommendations.add("多吃低热量、高纤维的食物")
                recommendations.add("避免高糖、高脂肪的食物")
                recommendations.add("每天喝足够的水")
            }
            "muscle_gain" -> {
                recommendations.add("每日热量摄入: ${(dailyCalories * 1.1).toInt()} 卡路里")
                recommendations.add("蛋白质: ${(macroNeeds["protein"] ?: 0).toInt()} 克")
                recommendations.add("增加复杂碳水化合物的摄入")
                recommendations.add("选择优质蛋白质来源")
                recommendations.add("配合力量训练")
            }
            else -> {
                recommendations.add("每日热量摄入: ${dailyCalories.toInt()} 卡路里")
                recommendations.add("保持营养均衡")
                recommendations.add("多吃蔬菜和水果")
                recommendations.add("选择全谷物食品")
                recommendations.add("限制盐和糖的摄入")
            }
        }
        
        return recommendations
    }
    
    fun analyzeMeal(foods: List<Pair<String, Double>>): Map<String, Any> {
        var totalCalories = 0.0
        var totalProtein = 0.0
        var totalFat = 0.0
        var totalCarbs = 0.0
        var totalFiber = 0.0
        
        for ((foodName, weight) in foods) {
            val food = getFood(foodName) ?: continue
            val nutrients = calculateNutrients(food, weight)
            
            totalCalories += nutrients["calories"] ?: 0.0
            totalProtein += nutrients["protein"] ?: 0.0
            totalFat += nutrients["fat"] ?: 0.0
            totalCarbs += nutrients["carbs"] ?: 0.0
            totalFiber += nutrients["fiber"] ?: 0.0
        }
        
        return mapOf(
            "calories" to String.format("%.1f", totalCalories),
            "protein" to String.format("%.1f", totalProtein),
            "fat" to String.format("%.1f", totalFat),
            "carbs" to String.format("%.1f", totalCarbs),
            "fiber" to String.format("%.1f", totalFiber)
        )
    }
}

fun main() {
    val calculator = NutritionCalculator()
    val user = UserProfile(age = 30, gender = "male", weight = 75.0, height = 180.0, activityLevel = "moderate")
    
    println("=== 营养热量计算器演示 ===\n")
    
    // 计算每日热量需求
    val dailyCalories = calculator.calculateDailyCalorieNeeds(user)
    println("每日热量需求: ${dailyCalories.toInt()} 卡路里\n")
    
    // 分析一餐
    val meal = listOf(
        "鸡胸肉" to 150.0,
        "米饭" to 150.0,
        "西兰花" to 100.0
    )
    val mealAnalysis = calculator.analyzeMeal(meal)
    println("一餐营养分析: $mealAnalysis\n")
    
    // 生成膳食计划
    val dietPlan = calculator.generateDietPlan(user, "weight_loss")
    println("减肥膳食计划:")
    dietPlan.forEach { println("• $it") }
}

Kotlin 代码说明: 这个实现提供了完整的营养计算功能。NutritionCalculator 类包含了食物数据库、热量计算、营养分析等多个方法。通过使用数据类存储食物和用户信息,代码更加清晰易维护。食物数据库可以根据需要扩展。


JavaScript 编译代码

// NutritionCalculator.js
class Food {
    constructor(name, caloriesPer100g, protein, fat, carbs, fiber) {
        this.name = name;
        this.caloriesPer100g = caloriesPer100g;
        this.protein = protein;
        this.fat = fat;
        this.carbs = carbs;
        this.fiber = fiber;
    }
}

class UserProfile {
    constructor(age, gender, weight, height, activityLevel) {
        this.age = age;
        this.gender = gender;
        this.weight = weight;
        this.height = height;
        this.activityLevel = activityLevel;
    }
}

class NutritionCalculator {
    constructor() {
        this.foodDatabase = {
            "鸡胸肉": new Food("鸡胸肉", 165, 31, 3.6, 0, 0),
            "鸡蛋": new Food("鸡蛋", 155, 13, 11, 1.1, 0),
            "牛奶": new Food("牛奶", 61, 3.2, 3.3, 4.8, 0),
            "米饭": new Food("米饭", 130, 2.7, 0.3, 28, 0.4),
            "面包": new Food("面包", 265, 9, 3.3, 49, 2.7),
            "苹果": new Food("苹果", 52, 0.3, 0.2, 14, 2.4),
            "香蕉": new Food("香蕉", 89, 1.1, 0.3, 23, 2.6),
            "西兰花": new Food("西兰花", 34, 2.8, 0.4, 7, 2.4),
            "胡萝卜": new Food("胡萝卜", 41, 0.9, 0.2, 10, 2.8),
            "三文鱼": new Food("三文鱼", 208, 20, 13, 0, 0)
        };
    }
    
    getFood(name) {
        return this.foodDatabase[name] || null;
    }
    
    calculateFoodCalories(food, weight) {
        return (food.caloriesPer100g / 100) * weight;
    }
    
    calculateNutrients(food, weight) {
        const multiplier = weight / 100;
        return {
            calories: food.caloriesPer100g * multiplier,
            protein: food.protein * multiplier,
            fat: food.fat * multiplier,
            carbs: food.carbs * multiplier,
            fiber: food.fiber * multiplier
        };
    }
    
    calculateDailyCalorieNeeds(user) {
        let bmr;
        if (user.gender.toLowerCase() === "male") {
            bmr = (10 * user.weight) + (6.25 * user.height) - (5 * user.age) + 5;
        } else {
            bmr = (10 * user.weight) + (6.25 * user.height) - (5 * user.age) - 161;
        }
        
        let activityMultiplier;
        switch (user.activityLevel.toLowerCase()) {
            case "sedentary": activityMultiplier = 1.2; break;
            case "light": activityMultiplier = 1.375; break;
            case "moderate": activityMultiplier = 1.55; break;
            case "active": activityMultiplier = 1.725; break;
            case "veryactive": activityMultiplier = 1.9; break;
            default: activityMultiplier = 1.5;
        }
        
        return bmr * activityMultiplier;
    }
    
    calculateMacroNeeds(dailyCalories, goal) {
        switch (goal.toLowerCase()) {
            case "weight_loss":
                return {
                    protein: (dailyCalories * 0.30) / 4,
                    fat: (dailyCalories * 0.25) / 9,
                    carbs: (dailyCalories * 0.45) / 4
                };
            case "muscle_gain":
                return {
                    protein: (dailyCalories * 0.35) / 4,
                    fat: (dailyCalories * 0.25) / 9,
                    carbs: (dailyCalories * 0.40) / 4
                };
            default:
                return {
                    protein: (dailyCalories * 0.25) / 4,
                    fat: (dailyCalories * 0.30) / 9,
                    carbs: (dailyCalories * 0.45) / 4
                };
        }
    }
    
    assessNutritionBalance(dailyIntake, dailyNeeds) {
        let balanceScore = 100;
        const issues = [];
        
        for (const nutrient in dailyIntake) {
            const intake = dailyIntake[nutrient];
            const need = dailyNeeds[nutrient];
            if (!need) continue;
            
            const percentage = (intake / need) * 100;
            
            if (percentage < 80) {
                balanceScore -= 10;
                issues.push(`${nutrient} 摄入不足 (${Math.floor(percentage)}%)`);
            } else if (percentage > 120) {
                balanceScore -= 5;
                issues.push(`${nutrient} 摄入过量 (${Math.floor(percentage)}%)`);
            }
        }
        
        balanceScore = Math.max(0, Math.min(100, balanceScore));
        
        let rating;
        if (balanceScore >= 80) rating = "优秀";
        else if (balanceScore >= 60) rating = "良好";
        else if (balanceScore >= 40) rating = "一般";
        else rating = "需要改善";
        
        return {
            score: balanceScore,
            rating: rating,
            issues: issues
        };
    }
    
    generateDietPlan(user, goal) {
        const dailyCalories = this.calculateDailyCalorieNeeds(user);
        const macroNeeds = this.calculateMacroNeeds(dailyCalories, goal);
        
        const recommendations = [];
        
        switch (goal.toLowerCase()) {
            case "weight_loss":
                recommendations.push(`每日热量摄入: ${Math.floor(dailyCalories)} 卡路里`);
                recommendations.push(`蛋白质: ${Math.floor(macroNeeds.protein)}`);
                recommendations.push("多吃低热量、高纤维的食物");
                recommendations.push("避免高糖、高脂肪的食物");
                recommendations.push("每天喝足够的水");
                break;
            case "muscle_gain":
                recommendations.push(`每日热量摄入: ${Math.floor(dailyCalories * 1.1)} 卡路里`);
                recommendations.push(`蛋白质: ${Math.floor(macroNeeds.protein)}`);
                recommendations.push("增加复杂碳水化合物的摄入");
                recommendations.push("选择优质蛋白质来源");
                recommendations.push("配合力量训练");
                break;
            default:
                recommendations.push(`每日热量摄入: ${Math.floor(dailyCalories)} 卡路里`);
                recommendations.push("保持营养均衡");
                recommendations.push("多吃蔬菜和水果");
                recommendations.push("选择全谷物食品");
                recommendations.push("限制盐和糖的摄入");
        }
        
        return recommendations;
    }
    
    analyzeMeal(foods) {
        let totalCalories = 0;
        let totalProtein = 0;
        let totalFat = 0;
        let totalCarbs = 0;
        let totalFiber = 0;
        
        for (const [foodName, weight] of foods) {
            const food = this.getFood(foodName);
            if (!food) continue;
            
            const nutrients = this.calculateNutrients(food, weight);
            totalCalories += nutrients.calories;
            totalProtein += nutrients.protein;
            totalFat += nutrients.fat;
            totalCarbs += nutrients.carbs;
            totalFiber += nutrients.fiber;
        }
        
        return {
            calories: totalCalories.toFixed(1),
            protein: totalProtein.toFixed(1),
            fat: totalFat.toFixed(1),
            carbs: totalCarbs.toFixed(1),
            fiber: totalFiber.toFixed(1)
        };
    }
}

// 使用示例
const calculator = new NutritionCalculator();
const user = new UserProfile(30, "male", 75, 180, "moderate");

console.log("=== 营养热量计算器演示 ===\n");

const dailyCalories = calculator.calculateDailyCalorieNeeds(user);
console.log(`每日热量需求: ${Math.floor(dailyCalories)} 卡路里\n`);

const meal = [
    ["鸡胸肉", 150],
    ["米饭", 150],
    ["西兰花", 100]
];
const mealAnalysis = calculator.analyzeMeal(meal);
console.log("一餐营养分析:", mealAnalysis);

const dietPlan = calculator.generateDietPlan(user, "weight_loss");
console.log("\n减肥膳食计划:");
dietPlan.forEach(item => console.log("• " + item));

JavaScript 代码说明: JavaScript 版本是 Kotlin 代码的直接转译。由于 JavaScript 和 Kotlin 在语法上有差异,我们使用 class 定义数据类,使用 switch 语句替代 when 表达式。整体逻辑和算法与 Kotlin 版本保持一致,确保跨平台的一致性。


ArkTS 调用代码

// NutritionCalculatorPage.ets
import { NutritionCalculator } from './NutritionCalculator';

@Entry
@Component
struct NutritionCalculatorPage {
    @State selectedFoods: Array<{ name: string, weight: number }> = [];
    @State mealAnalysis: string = '';
    @State userAge: number = 30;
    @State userGender: string = 'male';
    @State userWeight: number = 75;
    @State userHeight: number = 180;
    @State userActivity: string = 'moderate';
    @State goal: string = 'weight_loss';
    @State showResult: boolean = false;
    @State isLoading: boolean = false;
    
    private calculator: NutritionCalculator = new NutritionCalculator();
    
    private foodList = [
        '鸡胸肉', '鸡蛋', '牛奶', '米饭', '面包',
        '苹果', '香蕉', '西兰花', '胡萝卜', '三文鱼'
    ];
    
    private genderOptions = [
        { label: '男性', value: 'male' },
        { label: '女性', value: 'female' }
    ];
    
    private activityOptions = [
        { label: '久坐', value: 'sedentary' },
        { label: '轻度活动', value: 'light' },
        { label: '中度活动', value: 'moderate' },
        { label: '活跃', value: 'active' },
        { label: '非常活跃', value: 'veryactive' }
    ];
    
    private goalOptions = [
        { label: '减肥', value: 'weight_loss' },
        { label: '增肌', value: 'muscle_gain' },
        { label: '维持', value: 'maintain' }
    ];
    
    performAnalysis() {
        this.isLoading = true;
        try {
            const user = {
                age: this.userAge,
                gender: this.userGender,
                weight: this.userWeight,
                height: this.userHeight,
                activityLevel: this.userActivity
            };
            
            const dailyCalories = this.calculator.calculateDailyCalorieNeeds(user);
            const dietPlan = this.calculator.generateDietPlan(user, this.goal);
            
            let resultText = "🥗 营养分析结果\n";
            resultText += "━━━━━━━━━━━━━━━━━━━━━\n";
            resultText += `每日热量需求: ${Math.floor(dailyCalories)} 卡路里\n`;
            resultText += `目标: ${this.goal === 'weight_loss' ? '减肥' : this.goal === 'muscle_gain' ? '增肌' : '维持'}\n\n`;
            resultText += "📋 膳食建议:\n";
            dietPlan.forEach((item: string) => {
                resultText += `${item}\n`;
            });
            
            this.mealAnalysis = resultText;
            this.showResult = true;
        } catch (error) {
            this.mealAnalysis = '分析失败: ' + (error instanceof Error ? error.message : String(error));
            this.showResult = true;
        } finally {
            this.isLoading = false;
        }
    }
    
    build() {
        Column() {
            // 标题
            Text('营养热量计算器')
                .fontSize(28)
                .fontWeight(FontWeight.Bold)
                .margin({ top: 20, bottom: 20 })
                .textAlign(TextAlign.Center)
                .width('100%')
            
            // 用户信息输入
            Scroll() {
                Column() {
                    // 年龄
                    Column() {
                        Text(`年龄: ${this.userAge}`)
                            .fontSize(14)
                            .fontColor('#666666')
                            .margin({ bottom: 10 })
                        
                        Slider({ value: this.userAge, min: 18, max: 80, step: 1 })
                            .onChange((value: number) => {
                                this.userAge = value;
                            })
                            .width('100%')
                    }
                    .width('100%')
                    .padding(12)
                    .backgroundColor('#f5f5f5')
                    .borderRadius(8)
                    .margin({ bottom: 15 })
                    
                    // 性别
                    Column() {
                        Text('性别')
                            .fontSize(14)
                            .fontColor('#666666')
                            .margin({ bottom: 10 })
                        
                        Select(this.genderOptions)
                            .value(this.userGender)
                            .onSelect((index: number, value?: string) => {
                                this.userGender = value || 'male';
                            })
                            .width('100%')
                            .height(40)
                    }
                    .width('100%')
                    .padding(12)
                    .backgroundColor('#f5f5f5')
                    .borderRadius(8)
                    .margin({ bottom: 15 })
                    
                    // 体重
                    Column() {
                        Text(`体重: ${this.userWeight}kg`)
                            .fontSize(14)
                            .fontColor('#666666')
                            .margin({ bottom: 10 })
                        
                        Slider({ value: this.userWeight, min: 40, max: 150, step: 1 })
                            .onChange((value: number) => {
                                this.userWeight = value;
                            })
                            .width('100%')
                    }
                    .width('100%')
                    .padding(12)
                    .backgroundColor('#f5f5f5')
                    .borderRadius(8)
                    .margin({ bottom: 15 })
                    
                    // 身高
                    Column() {
                        Text(`身高: ${this.userHeight}cm`)
                            .fontSize(14)
                            .fontColor('#666666')
                            .margin({ bottom: 10 })
                        
                        Slider({ value: this.userHeight, min: 140, max: 220, step: 1 })
                            .onChange((value: number) => {
                                this.userHeight = value;
                            })
                            .width('100%')
                    }
                    .width('100%')
                    .padding(12)
                    .backgroundColor('#f5f5f5')
                    .borderRadius(8)
                    .margin({ bottom: 15 })
                    
                    // 活动水平
                    Column() {
                        Text('活动水平')
                            .fontSize(14)
                            .fontColor('#666666')
                            .margin({ bottom: 10 })
                        
                        Select(this.activityOptions)
                            .value(this.userActivity)
                            .onSelect((index: number, value?: string) => {
                                this.userActivity = value || 'moderate';
                            })
                            .width('100%')
                            .height(40)
                    }
                    .width('100%')
                    .padding(12)
                    .backgroundColor('#f5f5f5')
                    .borderRadius(8)
                    .margin({ bottom: 15 })
                    
                    // 目标
                    Column() {
                        Text('目标')
                            .fontSize(14)
                            .fontColor('#666666')
                            .margin({ bottom: 10 })
                        
                        Select(this.goalOptions)
                            .value(this.goal)
                            .onSelect((index: number, value?: string) => {
                                this.goal = value || 'weight_loss';
                            })
                            .width('100%')
                            .height(40)
                    }
                    .width('100%')
                    .padding(12)
                    .backgroundColor('#f5f5f5')
                    .borderRadius(8)
                }
                .width('100%')
                .padding(15)
                .backgroundColor('#ffffff')
                .borderRadius(10)
                .border({ width: 1, color: '#eeeeee' })
            }
            .height('50%')
            .margin({ bottom: 20 })
            
            // 分析按钮
            Button('分析营养')
                .width('100%')
                .height(45)
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .backgroundColor('#1B7837')
                .fontColor('#ffffff')
                .onClick(() => {
                    this.performAnalysis();
                })
                .margin({ bottom: 20 })
            
            // 结果显示
            if (this.showResult) {
                Column() {
                    Scroll() {
                        Text(this.mealAnalysis)
                            .fontSize(12)
                            .fontColor('#333333')
                            .width('100%')
                            .padding(12)
                            .fontFamily('monospace')
                            .textAlign(TextAlign.Start)
                    }
                    .width('100%')
                    .height('100%')
                }
                .width('100%')
                .height('45%')
                .padding(15)
                .backgroundColor('#ffffff')
                .borderRadius(10)
                .border({ width: 1, color: '#eeeeee' })
            }
            
            Blank()
        }
        .width('100%')
        .height('100%')
        .padding(15)
        .backgroundColor('#f5f5f5')
    }
}

ArkTS 代码说明: ArkTS 调用代码展示了如何在 OpenHarmony 应用中使用营养计算器。页面包含用户信息输入(年龄、性别、体重、身高、活动水平、目标)、分析按钮和结果显示区域。通过 @State 装饰器管理状态,实现了完整的用户交互流程。用户可以输入个人信息,选择健身目标,然后点击分析按钮获得个性化的营养建议。


实战案例

案例1:健身房管理系统

在健身房管理系统中,需要为会员提供个性化的营养计划。

fun createMemberNutritionPlan(memberId: String, goal: String, preferences: List<String>): Map<String, Any> {
    val calculator = NutritionCalculator()
    val member = getMemberProfile(memberId)
    
    val dailyCalories = calculator.calculateDailyCalorieNeeds(member)
    val macroNeeds = calculator.calculateMacroNeeds(dailyCalories, goal)
    val dietPlan = calculator.generateDietPlan(member, goal)
    
    return mapOf(
        "memberId" to memberId,
        "dailyCalories" to dailyCalories,
        "macroNeeds" to macroNeeds,
        "dietPlan" to dietPlan,
        "createdDate" to System.currentTimeMillis()
    )
}

案例2:营养咨询应用

在营养咨询应用中,需要分析用户的膳食并提供改善建议。

fun analyzeDailyDiet(meals: List<List<Pair<String, Double>>>): Map<String, Any> {
    val calculator = NutritionCalculator()
    var totalCalories = 0.0
    var totalProtein = 0.0
    var totalFat = 0.0
    var totalCarbs = 0.0
    
    for (meal in meals) {
        val analysis = calculator.analyzeMeal(meal)
        totalCalories += (analysis["calories"] as? String)?.toDoubleOrNull() ?: 0.0
        totalProtein += (analysis["protein"] as? String)?.toDoubleOrNull() ?: 0.0
        totalFat += (analysis["fat"] as? String)?.toDoubleOrNull() ?: 0.0
        totalCarbs += (analysis["carbs"] as? String)?.toDoubleOrNull() ?: 0.0
    }
    
    return mapOf(
        "totalCalories" to totalCalories,
        "totalProtein" to totalProtein,
        "totalFat" to totalFat,
        "totalCarbs" to totalCarbs
    )
}

案例3:医疗诊断系统

在医疗诊断系统中,需要根据患者的营养摄入评估健康状况。

fun assessPatientNutrition(patientId: String, dailyIntake: Map<String, Double>): String {
    val calculator = NutritionCalculator()
    val patient = getPatientProfile(patientId)
    val dailyCalories = calculator.calculateDailyCalorieNeeds(patient)
    val dailyNeeds = calculator.calculateMacroNeeds(dailyCalories, "maintain")
    
    val assessment = calculator.assessNutritionBalance(dailyIntake, dailyNeeds)
    
    return when (assessment["rating"]) {
        "优秀" -> "营养摄入均衡,继续保持"
        "良好" -> "营养摄入基本均衡,可适当调整"
        "一般" -> "营养摄入不够均衡,建议改善"
        else -> "营养摄入严重不均衡,需要专业指导"
    }
}

最佳实践

1. 数据准确性

使用准确的食物营养数据。建议从官方营养数据库获取数据,而不是使用估计值。

2. 个性化计算

根据用户的个人信息(年龄、性别、体重、身高、活动水平)进行计算,确保结果的准确性。

3. 定期更新

定期更新食物数据库和营养建议,确保信息的最新性。

4. 用户教育

提供清晰的解释和教育内容,帮助用户理解营养信息。

5. 隐私保护

妥善处理用户的个人健康信息,确保隐私安全。

6. 专业指导

对于特殊情况(如医学饮食、过敏症等),建议用户咨询专业营养师。


总结

营养热量计算器是现代健康管理应用中的重要组件。通过 KMP 框架,我们可以创建一个跨端的营养分析系统,在 Kotlin、JavaScript 和 ArkTS 中使用相同的计算逻辑。这不仅提高了代码的可维护性,还确保了不同平台上计算结果的一致性。

在实际应用中,合理使用营养热量计算器可以帮助用户更好地管理健康。无论是减肥、增肌还是维持健康,营养计算器都能提供科学的指导。通过提供个性化的营养建议和详细的营养分析,我们可以帮助用户制定更加科学的膳食计划,实现健康目标。

Logo

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

更多推荐