欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。


在医疗健康领域的跨端应用开发中,慢性病管理类应用对数据准确性、功能完整性和跨平台兼容性均有极高要求。本文将深度拆解基于React Native开发的慢性病管理应用代码,从领域数据模型设计、状态管理逻辑、UI组件适配到鸿蒙系统跨端兼容的核心技术要点,全方位剖析医疗级跨端应用的开发范式与最佳实践。

应用架构设计

这款慢性病管理应用聚焦于糖尿病、高血压等慢性疾病的全周期管理,涵盖用户健康档案、个性化饮食/运动/用药方案管理、健康报告自动推送等核心功能。从架构层面来看,整个应用严格遵循React Native的组件化设计思想,以TypeScript为开发语言构建强类型的业务逻辑层,这不仅保证了医疗数据的准确性,更是实现鸿蒙系统兼容的核心基础。

从跨端适配的底层逻辑分析,代码中未引入任何平台专属API(如iOS的HealthKit、Android的ContentProvider或鸿蒙的Health Ability),所有核心功能均基于React Native的通用核心组件(SafeAreaView、View、Text、TextInput、Modal等)和基础API(Dimensions、Alert、TouchableOpacity)构建。这种设计完全契合React Native的跨端理念——通过JS桥接层将统一的组件抽象映射为不同平台的原生控件,在鸿蒙系统中,这些组件会被React Native for HarmonyOS框架转换为ArkUI原生组件,从而保证UI渲染和交互逻辑在鸿蒙设备上的一致性,避免了因平台差异导致的代码碎片化问题,同时满足医疗应用对跨端稳定性的严苛要求。

强类型领域模型

慢性病管理应用对数据的精准性和规范性要求极高,代码中通过多层级的TypeScript类型定义构建了完整的医疗领域数据模型,这不仅规避了前端开发中的类型错误,更在跨端编译阶段提前拦截了因平台数据格式差异导致的潜在问题。

// 核心用户健康档案模型
type User = {
  id: string;
  name: string;
  condition: string; // 慢性病类型
  age: number;
  gender: string;
};

// 饮食方案关联模型(包含嵌套的餐食子模型)
type DietPlan = {
  id: string;
  userId: string;
  title: string;
  description: string;
  meals: Meal[];
};
type Meal = {
  id: string;
  name: string;
  calories: number;
  ingredients: string[];
};

// 运动/用药/健康报告模型体系
type ExercisePlan = { /* 包含嵌套Exercise子模型 */ };
type MedicationPlan = { /* 包含嵌套Medication子模型 */ };
type HealthReport = { /* 健康评估报告模型 */ };

这些类型定义构建了完整的慢性病管理数据体系,从用户基础信息到饮食/运动/用药方案的嵌套结构,所有状态数据均严格遵循对应的类型约束。在鸿蒙系统中,React Native的TypeScript编译器会对JS层与鸿蒙原生层之间的数据交互进行类型校验,避免了因鸿蒙ArkTS的静态类型系统与JavaScript动态类型特性不兼容导致的运行时错误。值得注意的是,所有字段均采用标准的string/number基础类型或基础类型数组,未使用任何平台专属的复杂数据类型,这是保证跨端数据序列化/反序列化一致性的关键设计,确保热量、用药剂量、运动时长等核心医疗数据在鸿蒙设备上的精准传递与展示。


应用的核心业务逻辑基于React Hooks(useState、useEffect)实现,这种轻量级的状态管理方式完美适配React Native的跨端生命周期模型,同时与鸿蒙系统的组件生命周期形成深度映射,尤其适配了慢性病管理应用中定时推送健康报告这类周期性任务的需求。

状态设计

// 基础医疗数据状态
const [users] = useState<User[]>([/* 初始化用户健康档案 */]);
const [dietPlans, setDietPlans] = useState<DietPlan[]>([/* 初始化饮食方案 */]);
const [exercisePlans, setExercisePlans] = useState<ExercisePlan[]>([/* 初始化运动方案 */]);
const [medicationPlans, setMedicationPlans] = useState<MedicationPlan[]>([/* 初始化用药方案 */]);
const [healthReports, setHealthReports] = useState<HealthReport[]>([/* 初始化健康报告 */]);

// 交互状态与表单状态
const [selectedUser, setSelectedUser] = useState<string | null>(null);
const [newDietPlan, setNewDietPlan] = useState({/* 饮食方案表单初始值 */});
const [isModalVisible, setIsModalVisible] = useState(false);

useState负责管理组件内部的状态数据,其不可变的状态更新机制(如setDietPlans([...dietPlans, newPlan]))保证了医疗数据的一致性,状态更新会触发React Native的虚拟DOM重渲染,最终映射为鸿蒙系统的ArkUI组件更新。而useEffect则承担了跨端生命周期管理的核心职责,代码中通过useEffect实现的健康报告自动推送逻辑:

useEffect(() => {
  const interval = setInterval(() => {
    const randomUser = users[Math.floor(Math.random() * users.length)];
    const newReport: HealthReport = {
      id: (healthReports.length + 1).toString(),
      userId: randomUser.id,
      date: new Date().toISOString().split('T')[0],
      content: '您的健康状况稳定,请继续遵循医嘱。'
    };
    setHealthReports(prevReports => [...prevReports, newReport]);
  }, 30000);

  return () => clearInterval(interval);
}, [users, healthReports]);

这段代码在鸿蒙系统中能够稳定运行的核心原因在于:setInterval/clearInterval是React Native封装的通用定时器API,已适配鸿蒙的任务调度机制;useEffect的返回清理函数则对应鸿蒙组件的onDestroy生命周期,确保定时器在组件卸载时被正确销毁,避免鸿蒙系统中的内存泄漏问题,这对需要长期运行的慢性病管理应用尤为重要。


应用的UI层完全基于React Native的核心组件构建,样式通过StyleSheet.create统一管理,这种设计既保证了UI在鸿蒙系统中的无缝适配,又兼顾了医疗应用对界面清晰性、操作便捷性的特殊要求。

样式系统

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f0f9ff', // 医疗级浅蓝主题色,适配鸿蒙视觉规范
  },
  section: {
    backgroundColor: '#ffffff',
    marginHorizontal: 16,
    marginBottom: 12,
    borderRadius: 12,
    padding: 16,
    // 阴影效果的跨端适配:elevation适配鸿蒙/Android,shadow系列适配iOS
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  input: {
    flex: 1,
    backgroundColor: '#f0f9ff',
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingVertical: 8,
    fontSize: 14,
    color: '#0c4a6e',
    marginRight: 8,
  },
  // 按钮、卡片、弹窗等组件样式定义
});

StyleSheet将CSS样式抽象为跨平台的样式对象,在鸿蒙系统中,flex布局、padding/margin、borderRadius等核心样式属性会被精准转换为ArkUI的布局属性(如flexDirection、paddingLeft、borderRadius);针对热量、时长等数值型输入,TextInput组件设置keyboardType="numeric"属性,在鸿蒙设备上会自动唤起数字键盘,提升医疗数据录入的准确性和便捷性。代码中通过Dimensions.get('window')获取屏幕尺寸:

const { width, height } = Dimensions.get('window');

该API在鸿蒙系统中能够准确获取设备的屏幕像素尺寸,避免了直接使用鸿蒙原生API(如getWindowSize)导致的代码碎片化,保证了不同屏幕尺寸鸿蒙设备(手机、平板、智慧屏)上的布局一致性,尤其适配了老年用户常用的大屏设备显示需求。

交互组件

核心交互逻辑基于TouchableOpacity组件实现,该组件在鸿蒙系统中会被渲染为具备点击反馈的原生按钮组件,保证了跨端交互体验的统一,同时其清晰的视觉样式(如选中态的边框高亮)符合医疗应用的操作指引要求:

<TouchableOpacity 
  style={[styles.card, selectedUser === user.id && styles.selectedCard]}
  onPress={() => handleSelectUser(user.id)}
>
  {/* 用户健康档案展示 */}
</TouchableOpacity>

Modal组件通过animationType="slide"实现滑动弹窗效果,在鸿蒙系统中适配为原生的滑动模态框,用于展示饮食方案、用药详情等核心医疗信息,既保证了信息展示的完整性,又符合鸿蒙系统的交互规范。Alert.alert作为跨端通用弹窗API,在鸿蒙设备上调用原生弹窗组件,用于操作结果提示和错误提醒,确保医疗操作的反馈及时且清晰。


当前代码已具备基础的鸿蒙兼容能力,在生产环境中可针对鸿蒙系统的特性和医疗应用的特殊需求进行以下优化,进一步提升慢性病管理应用的体验:

  1. 高性能列表渲染:当前饮食方案、健康报告等采用ScrollView + map的方式渲染,在鸿蒙系统中面对大量历史医疗数据时可能出现卡顿。可替换为React Native的FlatList组件,该组件在鸿蒙系统中会适配ArkUI的List组件,实现按需渲染和组件复用,大幅提升列表滚动性能,尤其适合展示用户长期的饮食/运动/用药记录数据。

  2. 原生医疗能力扩展:若需调用鸿蒙的医疗相关原生能力(如健康数据读写、系统级用药提醒、生物识别验证),可通过React Native的Native Module机制封装鸿蒙原生API,构建JS与ArkTS的通信桥梁,在保留跨端代码架构的同时,充分利用鸿蒙系统的原生医疗能力,例如将用药提醒同步到鸿蒙系统日历、健康应用中。

  3. 无障碍适配优化:慢性病管理应用的核心用户包含老年群体,可基于鸿蒙系统的无障碍能力,通过React Native的Accessibility相关属性(如accessibilityLabel、accessibilityHint)优化组件的无障碍描述,适配鸿蒙的屏幕朗读功能,提升老年用户的使用体验。

这款基于React Native开发的慢性病管理应用,通过TypeScript强类型约束、React Hooks状态管理、通用UI组件与样式设计,构建了具备完整鸿蒙跨端兼容能力的医疗级应用架构。核心技术要点可总结为:

  • 采用通用API+组件构建核心医疗业务逻辑,规避平台专属代码,是实现鸿蒙兼容的基础,同时保证了医疗应用的跨端稳定性;
  • TypeScript类型系统不仅提升医疗数据的准确性,更在跨端编译阶段拦截数据类型错误,适配鸿蒙ArkTS的静态类型特性;
  • React Hooks的状态管理与鸿蒙组件生命周期深度适配,尤其满足了慢性病管理应用中定时推送健康报告等周期性任务的跨端运行需求;
  • 统一的StyleSheet样式系统实现了UI在鸿蒙设备上的一致性渲染,兼顾医疗应用的视觉清晰性和操作便捷性。

基于该架构,只需少量针对鸿蒙原生医疗能力的扩展和无障碍优化,即可打造出体验优良的鸿蒙版慢性病管理应用,为跨端医疗健康类应用开发提供了可复用的技术范式。


在慢性病管理领域,数字化工具正逐渐成为改善患者生活质量和疾病控制效果的重要手段。本文将深入剖析一个基于 React Native 构建的慢性病管理应用,探讨其技术实现细节及鸿蒙跨端能力的应用。

架构设计

该应用采用了现代 React Native 函数式组件架构,通过 TypeScript 类型系统和 React Hooks 实现了一个功能完整的慢性病管理系统。核心技术栈包括:

  • React Native:作为跨端开发框架,提供了统一的组件 API,确保应用在 iOS、Android 及鸿蒙平台上的一致性体验
  • TypeScript:通过严格的类型定义增强代码可维护性,明确了数据结构和组件接口
  • React Hooks:使用 useState 管理应用状态,useEffect 处理副作用逻辑,实现了声明式的状态管理
  • Base64 图标:采用 Base64 编码的图标资源,避免了不同平台资源格式的差异,提高了跨端兼容性
  • 响应式布局:使用 Dimensions API 获取屏幕尺寸,实现适配不同设备的响应式界面

数据模型设计

应用通过 TypeScript 接口定义了七个核心数据类型,构建了完整的慢性病管理数据模型体系:

// 用户类型
type User = {
  id: string;
  name: string;
  condition: string;
  age: number;
  gender: string;
};

// 饮食方案类型
type DietPlan = {
  id: string;
  userId: string;
  title: string;
  description: string;
  meals: Meal[];
};

// 餐食类型
type Meal = {
  id: string;
  name: string;
  calories: number;
  ingredients: string[];
};

// 运动方案类型
type ExercisePlan = {
  id: string;
  userId: string;
  title: string;
  description: string;
  exercises: Exercise[];
};

// 运动类型
type Exercise = {
  id: string;
  name: string;
  duration: number;
  intensity: string;
};

// 用药方案类型
type MedicationPlan = {
  id: string;
  userId: string;
  medications: Medication[];
};

// 药物类型
type Medication = {
  id: string;
  name: string;
  dosage: string;
  frequency: string;
  time: string;
};

// 健康报告类型
type HealthReport = {
  id: string;
  userId: string;
  date: string;
  content: string;
};

这种强类型设计不仅提高了代码可读性,也为鸿蒙跨端适配提供了清晰的数据契约,确保不同平台间数据传递的一致性。数据模型的设计充分考虑了慢性病管理的核心要素,包含了用户基本信息、疾病状况、饮食方案、运动方案、用药方案和健康报告等。

状态管理

应用使用 useState Hook 管理多个复杂状态,包括用户列表、饮食方案、运动方案、用药方案、健康报告等:

const [users] = useState<User[]>([
  {
    id: '1',
    name: '李先生',
    condition: '糖尿病',
    age: 45,
    gender: '男'
  },
  {
    id: '2',
    name: '王女士',
    condition: '高血压',
    age: 52,
    gender: '女'
  }
]);

// 其他状态定义...

特别值得注意的是,应用通过 useEffect 实现了健康报告的自动推送机制:

// 自动推送健康报告
useEffect(() => {
  const interval = setInterval(() => {
    const randomUser = users[Math.floor(Math.random() * users.length)];
    const newReport: HealthReport = {
      id: (healthReports.length + 1).toString(),
      userId: randomUser.id,
      date: new Date().toISOString().split('T')[0],
      content: '您的健康状况稳定,请继续遵循医嘱。'
    };
    setHealthReports(prevReports => [...prevReports, newReport]);
  }, 30000);

  return () => clearInterval(interval);
}, [users, healthReports]);

这种基于时间间隔的自动推送机制,模拟了真实场景中医生定期评估患者健康状况的过程,为患者提供了持续的健康管理支持。同时,通过 useEffect 的清理函数,确保了定时器在组件卸载时被正确清除,避免了内存泄漏。

在 React Native 鸿蒙跨端开发中,该应用体现了以下关键技术点:

  1. 组件兼容性:使用 React Native 核心组件(如 SafeAreaView、View、Text、TouchableOpacity、ScrollView、Modal 等),确保在鸿蒙系统上的兼容性
  2. 资源管理:通过 Base64 编码的图标资源,避免了不同平台资源格式的差异,提高了跨端部署的一致性
  3. 尺寸适配:使用 Dimensions API 获取屏幕尺寸,实现响应式布局,适应不同设备屏幕
  4. 状态管理:采用 React Hooks 进行状态管理,保持跨平台代码一致性
  5. 类型安全:TypeScript 类型定义确保了数据结构在不同平台间的一致性
  6. API 调用:使用 React Native 统一的 API 调用方式,如 Alert 组件,确保在鸿蒙平台上的正确显示

1. 用户管理

应用实现了用户选择和管理功能,用户可以根据疾病类型和个人信息进行分类管理:

const handleSelectUser = (userId: string) => {
  setSelectedUser(userId);
  Alert.alert('选择用户', '您已选择该用户进行健康管理');
};

2. 饮食方案

应用提供了饮食方案的添加功能,用户可以创建包含多个餐食的个性化饮食方案:

const handleAddDietPlan = () => {
  if (newDietPlan.title && newDietPlan.description && newDietPlan.mealName && newDietPlan.mealCalories && newDietPlan.mealIngredients && selectedUser) {
    const newMeal: Meal = {
      id: (dietPlans.flatMap(p => p.meals).length + 1).toString(),
      name: newDietPlan.mealName,
      calories: parseInt(newDietPlan.mealCalories),
      ingredients: newDietPlan.mealIngredients.split(',')
    };
    const newPlan: DietPlan = {
      id: (dietPlans.length + 1).toString(),
      userId: selectedUser,
      title: newDietPlan.title,
      description: newDietPlan.description,
      meals: [newMeal]
    };
    setDietPlans([...dietPlans, newPlan]);
    setNewDietPlan({ title: '', description: '', mealName: '', mealCalories: '', mealIngredients: '' });
    Alert.alert('添加成功', '新的饮食方案已添加');
  } else {
    Alert.alert('提示', '请选择用户并填写完整的饮食方案信息');
  }
};

应用实现了运动方案的添加功能,用户可以创建包含多个运动项目的个性化运动方案,根据慢性病类型和个人体能状况进行调整。

应用提供了用药方案的管理功能,用户可以记录药物名称、剂量、服用频率和时间,确保按时服药。

应用实现了健康报告的自动生成和管理功能,定期推送健康状况评估,为患者提供持续的健康管理支持。


应用的 UI 设计遵循了现代移动应用的设计原则,使用了以下组件和交互模式:

  • 安全区域:通过 SafeAreaView 确保内容显示在安全区域内,适应不同设备的屏幕刘海和底部指示条
  • 滚动视图:通过 ScrollView 实现内容的垂直滚动,适应不同长度的方案列表和健康报告
  • 卡片布局:使用 TouchableOpacity 和 View 组合实现卡片式列表项,提供清晰的视觉层次和交互反馈
  • 模态框:通过 Modal 组件展示详细信息,如方案详情、健康报告等
  • 交互反馈:使用 Alert 组件提供操作反馈和提示信息
  • 响应式设计:根据屏幕尺寸动态调整布局,确保在不同设备上的良好显示效果

  1. 跨端架构:基于 React Native 构建,实现了一次编码多平台运行的目标,特别关注了鸿蒙平台的适配
  2. 类型安全:全面使用 TypeScript 类型定义,提高代码质量和可维护性,确保健康数据的准确性
  3. 多维度健康管理:同时管理饮食、运动、用药等多个维度的健康数据,提供全面的慢性病管理视角
  4. 个性化方案:根据用户的疾病类型和个人信息,提供个性化的健康管理方案
  5. 自动健康报告:通过定期自动生成健康报告,为用户提供持续的健康管理支持
  6. 实时数据反馈:通过即时的 Alert 反馈,增强用户操作体验
  7. 模块化设计:通过清晰的类型定义和函数划分,实现了代码的模块化,提高了可维护性
  8. 数据结构设计:通过嵌套的数据结构,如饮食方案包含餐食,运动方案包含运动项目,实现了复杂健康数据的有效组织

在实际应用中,还可以考虑以下性能优化策略:

  1. 状态管理优化:对于大型应用,可以考虑使用 Redux 或 Context API 进行全局状态管理,提高状态更新的效率
  2. 组件拆分:将大型组件拆分为更小的可复用组件,提高渲染性能和代码可维护性
  3. 数据缓存:对用户数据和方案信息进行本地缓存,减少重复计算和网络请求
  4. 动画性能:使用 React Native 的 Animated API 实现流畅的过渡动画,提升用户体验
  5. 内存管理:确保及时清理不再使用的状态和事件监听器,避免内存泄漏
  6. 网络优化:对于实际应用中的远程数据同步,实现合理的网络请求策略,如批量上传、增量同步等
  7. 计算优化:对于卡路里计算、运动强度评估等频繁操作,可以考虑使用 memoization 技术缓存计算结果
  8. 列表优化:对于长列表,使用 FlatList 组件替代 ScrollView,提高渲染性能

在开发过程中,可能面临的技术挑战及解决方案:

  1. 鸿蒙平台适配:通过使用 React Native 核心组件和统一的 API 调用方式,确保应用在鸿蒙平台上的兼容性
  2. 数据同步:实现本地数据与云端数据的实时同步,确保多设备数据一致性,特别是医疗健康数据的安全性和隐私保护
  3. 用户隐私保护:实现健康数据的加密存储和传输,保护用户隐私,符合医疗数据安全法规
  4. 离线功能:实现基本的离线操作能力,确保在网络不稳定情况下的正常使用
  5. 性能优化:针对不同设备性能差异,实现自适应的性能优化策略,确保在中低端设备上的流畅运行
  6. 用户体验一致性:确保在不同平台上的用户体验一致,特别是交互方式和视觉效果
  7. 数据准确性:确保健康数据的准确性和可靠性,避免因数据错误导致的健康风险

通过对这个慢性病管理应用的技术解读,我们可以看到 React Native 在跨端开发中的强大能力。该应用不仅实现了完整的慢性病管理功能,还展示了如何通过 TypeScript、React Hooks 等现代前端技术构建高质量的跨端应用。


真实演示案例代码:






// App.tsx
import React, { useState, useEffect } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert, TextInput, Modal } from 'react-native';

// Base64 图标库
const ICONS_BASE64 = {
  diet: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  exercise: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  medication: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  report: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

const { width, height } = Dimensions.get('window');

// 用户类型
type User = {
  id: string;
  name: string;
  condition: string;
  age: number;
  gender: string;
};

// 饮食方案类型
type DietPlan = {
  id: string;
  userId: string;
  title: string;
  description: string;
  meals: Meal[];
};

// 餐食类型
type Meal = {
  id: string;
  name: string;
  calories: number;
  ingredients: string[];
};

// 运动方案类型
type ExercisePlan = {
  id: string;
  userId: string;
  title: string;
  description: string;
  exercises: Exercise[];
};

// 运动类型
type Exercise = {
  id: string;
  name: string;
  duration: number;
  intensity: string;
};

// 用药方案类型
type MedicationPlan = {
  id: string;
  userId: string;
  medications: Medication[];
};

// 药物类型
type Medication = {
  id: string;
  name: string;
  dosage: string;
  frequency: string;
  time: string;
};

// 健康报告类型
type HealthReport = {
  id: string;
  userId: string;
  date: string;
  content: string;
};

// 慢性病管理应用组件
const ChronicDiseaseManagementApp: React.FC = () => {
  const [users] = useState<User[]>([
    {
      id: '1',
      name: '李先生',
      condition: '糖尿病',
      age: 45,
      gender: '男'
    },
    {
      id: '2',
      name: '王女士',
      condition: '高血压',
      age: 52,
      gender: '女'
    }
  ]);

  const [dietPlans, setDietPlans] = useState<DietPlan[]>([
    {
      id: '1',
      userId: '1',
      title: '糖尿病饮食方案',
      description: '低糖、低脂、高纤维饮食',
      meals: [
        {
          id: '1',
          name: '早餐',
          calories: 300,
          ingredients: ['燕麦粥', '鸡蛋', '牛奶']
        },
        {
          id: '2',
          name: '午餐',
          calories: 400,
          ingredients: ['糙米饭', '蒸鱼', '青菜']
        }
      ]
    }
  ]);

  const [exercisePlans, setExercisePlans] = useState<ExercisePlan[]>([
    {
      id: '1',
      userId: '1',
      title: '糖尿病运动方案',
      description: '有氧运动为主,每周至少150分钟',
      exercises: [
        {
          id: '1',
          name: '快走',
          duration: 30,
          intensity: '中等'
        },
        {
          id: '2',
          name: '游泳',
          duration: 45,
          intensity: '中等'
        }
      ]
    }
  ]);

  const [medicationPlans, setMedicationPlans] = useState<MedicationPlan[]>([
    {
      id: '1',
      userId: '1',
      medications: [
        {
          id: '1',
          name: '二甲双胍',
          dosage: '500mg',
          frequency: '每日两次',
          time: '早晚各一次'
        }
      ]
    }
  ]);

  const [healthReports, setHealthReports] = useState<HealthReport[]>([
    {
      id: '1',
      userId: '1',
      date: '2023-12-01',
      content: '血糖控制良好,建议继续保持当前饮食和运动习惯。'
    }
  ]);

  const [selectedUser, setSelectedUser] = useState<string | null>(null);
  const [newDietPlan, setNewDietPlan] = useState({
    title: '',
    description: '',
    mealName: '',
    mealCalories: '',
    mealIngredients: ''
  });
  const [newExercisePlan, setNewExercisePlan] = useState({
    title: '',
    description: '',
    exerciseName: '',
    exerciseDuration: '',
    exerciseIntensity: ''
  });
  const [newMedication, setNewMedication] = useState({
    name: '',
    dosage: '',
    frequency: '',
    time: ''
  });
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [modalContent, setModalContent] = useState('');

  // 自动推送健康报告
  useEffect(() => {
    const interval = setInterval(() => {
      const randomUser = users[Math.floor(Math.random() * users.length)];
      const newReport: HealthReport = {
        id: (healthReports.length + 1).toString(),
        userId: randomUser.id,
        date: new Date().toISOString().split('T')[0],
        content: '您的健康状况稳定,请继续遵循医嘱。'
      };
      setHealthReports(prevReports => [...prevReports, newReport]);
    }, 30000);

    return () => clearInterval(interval);
  }, [users, healthReports]);

  const handleSelectUser = (userId: string) => {
    setSelectedUser(userId);
    Alert.alert('选择用户', '您已选择该用户进行健康管理');
  };

  const handleAddDietPlan = () => {
    if (newDietPlan.title && newDietPlan.description && newDietPlan.mealName && newDietPlan.mealCalories && newDietPlan.mealIngredients && selectedUser) {
      const newMeal: Meal = {
        id: (dietPlans.flatMap(p => p.meals).length + 1).toString(),
        name: newDietPlan.mealName,
        calories: parseInt(newDietPlan.mealCalories),
        ingredients: newDietPlan.mealIngredients.split(',')
      };
      const newPlan: DietPlan = {
        id: (dietPlans.length + 1).toString(),
        userId: selectedUser,
        title: newDietPlan.title,
        description: newDietPlan.description,
        meals: [newMeal]
      };
      setDietPlans([...dietPlans, newPlan]);
      setNewDietPlan({ title: '', description: '', mealName: '', mealCalories: '', mealIngredients: '' });
      Alert.alert('添加成功', '新的饮食方案已添加');
    } else {
      Alert.alert('提示', '请选择用户并填写完整的饮食方案信息');
    }
  };

  const handleAddExercisePlan = () => {
    if (newExercisePlan.title && newExercisePlan.description && newExercisePlan.exerciseName && newExercisePlan.exerciseDuration && newExercisePlan.exerciseIntensity && selectedUser) {
      const newExercise: Exercise = {
        id: (exercisePlans.flatMap(p => p.exercises).length + 1).toString(),
        name: newExercisePlan.exerciseName,
        duration: parseInt(newExercisePlan.exerciseDuration),
        intensity: newExercisePlan.exerciseIntensity
      };
      const newPlan: ExercisePlan = {
        id: (exercisePlans.length + 1).toString(),
        userId: selectedUser,
        title: newExercisePlan.title,
        description: newExercisePlan.description,
        exercises: [newExercise]
      };
      setExercisePlans([...exercisePlans, newPlan]);
      setNewExercisePlan({ title: '', description: '', exerciseName: '', exerciseDuration: '', exerciseIntensity: '' });
      Alert.alert('添加成功', '新的运动方案已添加');
    } else {
      Alert.alert('提示', '请选择用户并填写完整的运动方案信息');
    }
  };

  const handleAddMedication = () => {
    if (newMedication.name && newMedication.dosage && newMedication.frequency && newMedication.time && selectedUser) {
      const newMed: Medication = {
        id: (medicationPlans.flatMap(p => p.medications).length + 1).toString(),
        name: newMedication.name,
        dosage: newMedication.dosage,
        frequency: newMedication.frequency,
        time: newMedication.time
      };
      setMedicationPlans(prevPlans => 
        prevPlans.map(plan => 
          plan.userId === selectedUser 
            ? { ...plan, medications: [...plan.medications, newMed] } 
            : plan
        )
      );
      setNewMedication({ name: '', dosage: '', frequency: '', time: '' });
      Alert.alert('添加成功', '新的药物已添加到用药方案中');
    } else {
      Alert.alert('提示', '请选择用户并填写完整的药物信息');
    }
  };

  const handleViewDietPlan = (planId: string) => {
    const plan = dietPlans.find(p => p.id === planId);
    if (plan) {
      const meals = plan.meals.map(meal => `${meal.name}: ${meal.calories} kcal (${meal.ingredients.join(', ')})`).join('\n');
      setModalContent(`方案名称: ${plan.title}\n描述: ${plan.description}\n餐食:\n${meals}`);
      setIsModalVisible(true);
    }
  };

  const handleViewExercisePlan = (planId: string) => {
    const plan = exercisePlans.find(p => p.id === planId);
    if (plan) {
      const exercises = plan.exercises.map(ex => `${ex.name}: ${ex.duration}分钟 (${ex.intensity})`).join('\n');
      setModalContent(`方案名称: ${plan.title}\n描述: ${plan.description}\n运动:\n${exercises}`);
      setIsModalVisible(true);
    }
  };

  const handleViewMedicationPlan = (planId: string) => {
    const plan = medicationPlans.find(p => p.id === planId);
    if (plan) {
      const meds = plan.medications.map(med => `${med.name}: ${med.dosage}, ${med.frequency}, ${med.time}`).join('\n');
      setModalContent(`用药方案:\n${meds}`);
      setIsModalVisible(true);
    }
  };

  const handleViewHealthReport = (reportId: string) => {
    const report = healthReports.find(r => r.id === reportId);
    if (report) {
      const user = users.find(u => u.id === report.userId);
      setModalContent(`用户: ${user?.name}\n日期: ${report.date}\n内容: ${report.content}`);
      setIsModalVisible(true);
    }
  };

  const openModal = (content: string) => {
    setModalContent(content);
    setIsModalVisible(true);
  };

  const closeModal = () => {
    setIsModalVisible(false);
  };

  return (
    <SafeAreaView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <Text style={styles.title}>慢性病管理</Text>
        <Text style={styles.subtitle}>针对糖尿病、高血压等慢性病,提供饮食、运动、用药方案,定期推送健康报告</Text>
      </View>

      <ScrollView style={styles.content}>
        {/* 用户列表 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>用户列表</Text>
          {users.map(user => (
            <TouchableOpacity 
              key={user.id}
              style={[
                styles.card,
                selectedUser === user.id && styles.selectedCard
              ]}
              onPress={() => handleSelectUser(user.id)}
            >
              <Text style={styles.icon}>👤</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{user.name}</Text>
                <Text style={styles.cardDescription}>病情: {user.condition}</Text>
                <Text style={styles.cardDescription}>年龄: {user.age}</Text>
                <Text style={styles.cardDescription}>性别: {user.gender}</Text>
              </View>
            </TouchableOpacity>
          ))}
        </View>

        {/* 饮食方案 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>饮食方案</Text>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="方案名称"
              value={newDietPlan.title}
              onChangeText={(text) => setNewDietPlan({ ...newDietPlan, title: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="方案描述"
              value={newDietPlan.description}
              onChangeText={(text) => setNewDietPlan({ ...newDietPlan, description: text })}
            />
          </View>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="餐食名称"
              value={newDietPlan.mealName}
              onChangeText={(text) => setNewDietPlan({ ...newDietPlan, mealName: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="热量 (kcal)"
              value={newDietPlan.mealCalories}
              onChangeText={(text) => setNewDietPlan({ ...newDietPlan, mealCalories: text })}
              keyboardType="numeric"
            />
          </View>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="食材 (逗号分隔)"
              value={newDietPlan.mealIngredients}
              onChangeText={(text) => setNewDietPlan({ ...newDietPlan, mealIngredients: text })}
            />
          </View>
          <TouchableOpacity 
            style={styles.addButton}
            onPress={handleAddDietPlan}
          >
            <Text style={styles.addText}>添加饮食方案</Text>
          </TouchableOpacity>
          {dietPlans.map(plan => (
            <TouchableOpacity 
              key={plan.id}
              style={styles.planCard}
              onPress={() => handleViewDietPlan(plan.id)}
            >
              <Text style={styles.icon}>🍎</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{plan.title}</Text>
                <Text style={styles.cardDescription}>{plan.description}</Text>
              </View>
            </TouchableOpacity>
          ))}
        </View>

        {/* 运动方案 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>运动方案</Text>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="方案名称"
              value={newExercisePlan.title}
              onChangeText={(text) => setNewExercisePlan({ ...newExercisePlan, title: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="方案描述"
              value={newExercisePlan.description}
              onChangeText={(text) => setNewExercisePlan({ ...newExercisePlan, description: text })}
            />
          </View>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="运动名称"
              value={newExercisePlan.exerciseName}
              onChangeText={(text) => setNewExercisePlan({ ...newExercisePlan, exerciseName: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="时长 (分钟)"
              value={newExercisePlan.exerciseDuration}
              onChangeText={(text) => setNewExercisePlan({ ...newExercisePlan, exerciseDuration: text })}
              keyboardType="numeric"
            />
          </View>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="强度"
              value={newExercisePlan.exerciseIntensity}
              onChangeText={(text) => setNewExercisePlan({ ...newExercisePlan, exerciseIntensity: text })}
            />
          </View>
          <TouchableOpacity 
            style={styles.addButton}
            onPress={handleAddExercisePlan}
          >
            <Text style={styles.addText}>添加运动方案</Text>
          </TouchableOpacity>
          {exercisePlans.map(plan => (
            <TouchableOpacity 
              key={plan.id}
              style={styles.planCard}
              onPress={() => handleViewExercisePlan(plan.id)}
            >
              <Text style={styles.icon}>🏃</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{plan.title}</Text>
                <Text style={styles.cardDescription}>{plan.description}</Text>
              </View>
            </TouchableOpacity>
          ))}
        </View>

        {/* 用药方案 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>用药方案</Text>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="药物名称"
              value={newMedication.name}
              onChangeText={(text) => setNewMedication({ ...newMedication, name: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="剂量"
              value={newMedication.dosage}
              onChangeText={(text) => setNewMedication({ ...newMedication, dosage: text })}
            />
          </View>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="频率"
              value={newMedication.frequency}
              onChangeText={(text) => setNewMedication({ ...newMedication, frequency: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="时间"
              value={newMedication.time}
              onChangeText={(text) => setNewMedication({ ...newMedication, time: text })}
            />
          </View>
          <TouchableOpacity 
            style={styles.addButton}
            onPress={handleAddMedication}
          >
            <Text style={styles.addText}>添加药物</Text>
          </TouchableOpacity>
          {medicationPlans.map(plan => (
            <TouchableOpacity 
              key={plan.id}
              style={styles.planCard}
              onPress={() => handleViewMedicationPlan(plan.id)}
            >
              <Text style={styles.icon}>💊</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>用药方案</Text>
                <Text style={styles.cardDescription}>药物数量: {plan.medications.length}</Text>
              </View>
            </TouchableOpacity>
          ))}
        </View>

        {/* 健康报告 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>健康报告</Text>
          {healthReports.map(report => (
            <TouchableOpacity 
              key={report.id}
              style={styles.reportCard}
              onPress={() => handleViewHealthReport(report.id)}
            >
              <Text style={styles.icon}>📊</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>报告ID: {report.id}</Text>
                <Text style={styles.cardDescription}>日期: {report.date}</Text>
                <Text style={styles.cardDescription}>内容: {report.content}</Text>
              </View>
            </TouchableOpacity>
          ))}
        </View>

        {/* 使用说明 */}
        <View style={styles.infoCard}>
          <Text style={styles.sectionTitle}>📘 使用说明</Text>
          <Text style={styles.infoText}>• 选择用户进行慢性病管理</Text>
          <Text style={styles.infoText}>• 添加个性化的饮食、运动、用药方案</Text>
          <Text style={styles.infoText}>• 定期查看健康报告,了解身体状况</Text>
          <Text style={styles.infoText}>• 遵循医嘱,保持健康生活方式</Text>
        </View>

        {/* 弹框内容 */}
        <Modal
          animationType="slide"
          transparent={true}
          visible={isModalVisible}
          onRequestClose={closeModal}
        >
          <View style={styles.modalContainer}>
            <View style={styles.modalContent}>
              <Text style={styles.modalTitle}>详细信息</Text>
              <Text style={styles.modalText}>{modalContent}</Text>
              <TouchableOpacity
                style={styles.closeButton}
                onPress={closeModal}
              >
                <Text style={styles.closeButtonText}>关闭</Text>
              </TouchableOpacity>
            </View>
          </View>
        </Modal>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f0f9ff',
  },
  header: {
    flexDirection: 'column',
    padding: 16,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#bae6fd',
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#0c4a6e',
    marginBottom: 4,
  },
  subtitle: {
    fontSize: 14,
    color: '#0284c7',
  },
  content: {
    flex: 1,
    marginTop: 12,
  },
  section: {
    backgroundColor: '#ffffff',
    marginHorizontal: 16,
    marginBottom: 12,
    borderRadius: 12,
    padding: 16,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  sectionTitle: {
    fontSize: 16,
    fontWeight: '600',
    color: '#0c4a6e',
    marginBottom: 12,
  },
  card: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f0f9ff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
  },
  selectedCard: {
    borderWidth: 2,
    borderColor: '#0284c7',
  },
  planCard: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f0f9ff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
  },
  reportCard: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f0f9ff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
  },
  icon: {
    fontSize: 28,
    marginRight: 12,
  },
  cardInfo: {
    flex: 1,
  },
  cardTitle: {
    fontSize: 16,
    fontWeight: '500',
    color: '#0c4a6e',
    marginBottom: 4,
  },
  cardDescription: {
    fontSize: 14,
    color: '#0284c7',
    marginBottom: 2,
  },
  inputRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 12,
  },
  input: {
    flex: 1,
    backgroundColor: '#f0f9ff',
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingVertical: 8,
    fontSize: 14,
    color: '#0c4a6e',
    marginRight: 8,
  },
  addButton: {
    backgroundColor: '#0284c7',
    padding: 12,
    borderRadius: 8,
    alignItems: 'center',
  },
  addText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '500',
  },
  infoCard: {
    backgroundColor: '#ffffff',
    marginHorizontal: 16,
    marginBottom: 80,
    borderRadius: 12,
    padding: 16,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  infoText: {
    fontSize: 14,
    color: '#64748b',
    lineHeight: 20,
    marginBottom: 4,
  },
  modalContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
  modalContent: {
    width: '80%',
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 20,
    elevation: 5,
  },
  modalTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#0c4a6e',
    marginBottom: 12,
    textAlign: 'center',
  },
  modalText: {
    fontSize: 14,
    color: '#0c4a6e',
    lineHeight: 20,
    marginBottom: 20,
  },
  closeButton: {
    backgroundColor: '#0284c7',
    padding: 10,
    borderRadius: 8,
    alignItems: 'center',
  },
  closeButtonText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '500',
  },
});

export default ChronicDiseaseManagementApp;

请添加图片描述


打包

接下来通过打包命令npn run harmony将reactNative的代码打包成为bundle,这样可以进行在开源鸿蒙OpenHarmony中进行使用。

在这里插入图片描述

打包之后再将打包后的鸿蒙OpenHarmony文件拷贝到鸿蒙的DevEco-Studio工程目录去:

在这里插入图片描述

最后运行效果图如下显示:

请添加图片描述
本文深入解析了基于React Native开发的慢性病管理应用架构与实现细节。该应用采用TypeScript构建强类型医疗数据模型,确保跨平台数据一致性;通过React Hooks管理状态,实现与鸿蒙系统的生命周期映射;UI层完全使用React Native核心组件和StyleSheet样式系统,确保在鸿蒙设备上的无缝适配。文章重点剖析了医疗领域数据建模、跨端状态管理、UI适配等关键技术,展示了如何在不使用平台专属API的情况下,开发满足医疗级要求的跨平台应用。这种架构设计既保证了功能完整性,又实现了iOS/Android/鸿蒙多端兼容,为医疗健康类应用的跨平台开发提供了实践范例。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐