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


在医疗信息化建设中,医院系统对接是实现医疗数据共享和便捷访问的关键环节。今天我们来深入分析一个基于 React Native 开发的医院系统对接应用,该应用集成了检查报告管理、医生管理和医学影像查看等功能,为患者提供了便捷的医疗报告查看和解读平台。

通过类型定义确保数据结构的一致性和代码的可维护性

该应用采用了 React Native 现代开发技术栈,主要包括:

  • React Hooks:使用 useState 管理应用状态,包括检查报告数据、医生信息、选中状态和模态框控制等
  • TypeScript:通过类型定义确保数据结构的一致性和代码的可维护性
  • 跨平台组件:使用 SafeAreaViewTouchableOpacityScrollViewModal 等实现跨平台兼容的用户界面
  • 响应式布局:利用 Dimensions API 获取屏幕尺寸,确保在不同设备上的良好显示效果
  • 基础组件:使用 ViewTextTextInput 等构建用户界面

表示检查报告,包含 ID、患者 ID、检查名称、日期、结果、状态和图像链接

应用通过 TypeScript 定义了两个核心数据类型,构建了完整的医院系统对接数据模型:

  • TestReport:表示检查报告,包含 ID、患者 ID、检查名称、日期、结果、状态和图像链接
  • Doctor:表示医生信息,包含 ID、姓名、专业、经验、评分和可用性

这种强类型定义不仅提高了代码的可读性和可维护性,也为鸿蒙跨端适配提供了清晰的数据结构映射基础。

通过初始化的 useState 直接存储

应用采用了基于 useState 的轻量级状态管理方案,为不同功能模块分别管理状态:

  • 检查报告:通过 useState 管理,支持更新报告状态
  • 医生信息:通过初始化的 useState 直接存储
  • 交互状态:选中的报告、选中的医生、解读内容、模态框可见性等通过独立的 useState 管理

这种模式在中小型应用中非常高效,既避免了过度设计,又保证了状态管理的清晰性。


检查报告管理是应用的核心功能,主要包括:

  • 展示检查报告列表,包括检查名称、日期、结果和状态
  • 查看报告详细信息,包括图像链接
  • 下载检查报告
  • 更新报告状态(如从"待解读"变为"解读中")

应用支持 CT 扫描和 MRI 检查等多种医学影像的查看,使用了示例图像链接(https://example.com/ct-scan-image 和 https://example.com/mri-scan-image)来模拟医学影像的展示。

应用内置了医生信息列表,包含医生的姓名、专业、经验、评分和可用性状态。用户可以点击选择医生进行报告解读,为患者提供专业的医疗解读服务。

报告解读请求功能为患者提供了专业的医学解读服务:

  • 选择需要解读的检查报告
  • 选择合适的医生进行解读
  • 填写解读请求内容
  • 提交解读请求并更新报告状态

应用通过卡片式布局展示检查报告和医生信息,使用 TouchableOpacity 组件实现交互功能,点击卡片后可以查看详细信息或执行相关操作。此外,应用使用 Modal 组件展示详细信息,提升了用户体验。


组件映射

在鸿蒙 OS 适配过程中,需要注意以下组件映射:

  • SafeAreaView:在鸿蒙上需要使用 SafeArea 组件或自定义适配
  • TouchableOpacity:对应鸿蒙的 ButtonText 组件配合点击事件
  • ScrollView:对应鸿蒙的 ListContainerScroll 组件
  • Modal:对应鸿蒙的 Dialog 组件
  • Alert:对应鸿蒙的 ToastDialogAlertDialog 组件
  • TextInput:对应鸿蒙的 TextField 组件

鸿蒙 OS 对 Flexbox 布局的支持与 React Native 基本一致,但在细节上仍需注意:

  • 确保样式命名符合鸿蒙规范
  • 调整间距和尺寸以适应鸿蒙设备的显示特性
  • 注意字体大小和行高的适配
  • 对于表单输入控件,需要适配鸿蒙的输入框样式和交互方式

在鸿蒙跨端开发中,性能优化是一个重要考虑因素:

  • 使用 memo 优化组件渲染,特别是对于报告列表、医生列表等重复渲染的场景
  • 合理使用 useCallbackuseMemo 减少不必要的计算
  • 优化图片资源,考虑使用鸿蒙的资源加载机制
  • 对于医学影像的处理,需要特别注意性能优化,确保图像的流畅加载和显示
  • 对于列表数据的渲染,考虑使用虚拟化技术减少内存占用

应用集成了 CT 扫描和 MRI 检查等医学影像的查看功能,为患者提供了直观的检查结果展示。通过图像链接的方式,患者可以方便地查看自己的医学影像,了解检查结果。

报告状态管理

应用实现了完整的报告状态管理流程:

  • 待解读:报告已生成但尚未得到专业解读
  • 解读中:医生正在解读报告
  • 已完成:报告已完成解读

这种状态管理机制确保了报告解读的及时性和可追踪性。

专家解读请求

应用为患者提供了便捷的专家解读请求功能,患者可以选择合适的医生进行报告解读,获得专业的医疗建议。这一功能弥合了患者与专业医疗知识之间的差距。

应用采用了清晰的模块化设计:

  • 功能按模块划分(报告管理、医生管理、解读请求)
  • 组件职责单一,便于维护和扩展
  • 状态管理逻辑与 UI 渲染分离

Base64 图标库

应用使用 Base64 编码的图标,这种方式有几个优点:

  • 减少网络请求,提高加载速度
  • 避免图标资源的跨平台适配问题
  • 减小应用包体积

虽然示例中使用的是占位 Base64 编码,但实际应用中可以使用真实的图标编码。


文件结构

示例代码集中在 App.tsx 文件中,适合小型应用。对于大型应用,建议按功能模块拆分文件:

  • /components:存放可复用组件,如报告卡片、医生卡片等

  • /types:存放类型定义,如 TestReport、Doctor 等

  • /hooks:存放自定义 hooks,如报告管理逻辑、解读请求逻辑等

  • /services:存放 API 调用和业务逻辑,如数据存储、影像加载服务等

  • /utils:存放工具函数,如日期处理、数据格式化等

  • 命名规范:变量和函数命名清晰,符合语义化要求

  • 类型安全:使用 TypeScript 确保类型安全

  • 错误处理:通过条件判断处理可能的异常情况,如表单验证

  • 注释:代码结构清晰,关键部分有适当注释

  • 性能考虑:合理使用 React Hooks,避免不必要的渲染和计算

应用架构具有良好的扩展性:

  • 可以轻松添加新的检查类型和报告格式
  • 可以集成真实的医院系统 API,实现数据的实时同步
  • 可以扩展支持更多的医学影像类型,如超声、X光等
  • 可以集成视频会诊功能,实现医生与患者的实时沟通
  • 可以添加数据可视化功能,如检查结果趋势图表等

这个医院系统对接应用展示了如何使用 React Native 构建功能完备的医疗报告管理工具,特别是在医学影像集成和专家解读请求方面的实践具有重要参考价值。通过跨端开发技术,可以在不同平台为患者提供一致的服务体验。

随着医疗信息化的不断发展,这类应用的需求将不断增长。未来可以考虑:

  • 与更多医院系统对接,实现医疗数据的互联互通
  • 利用 AI 技术对医学影像进行初步分析,辅助医生进行诊断
  • 支持更多的检查类型和报告格式,满足不同科室的需求
  • 开发配套的医生端应用,实现更高效的报告解读流程
  • 集成电子病历功能,为患者提供完整的医疗记录管理

React Native 鸿蒙跨端开发代表了移动应用开发的未来趋势,通过一套代码库覆盖多个平台,不仅可以降低开发成本,还可以确保用户体验的一致性。在医疗应用领域,这种开发模式尤为重要,因为它可以让开发者更专注于核心功能的实现,而不是平台差异的处理。

通过对这个医院系统对接应用的技术分析,我们可以看到 React Native 在构建跨平台医疗应用方面的强大能力。从技术架构到功能实现,从用户体验到跨端适配,这个应用都展示了现代移动应用开发的最佳实践。


医院系统对接是智慧医疗在影像诊断场景的核心落地形态,聚焦“检查报告管理-医生资源匹配-在线解读请求-报告下载查看”全流程的影像诊断服务逻辑,既要保证CT/MRI等检查报告数据的准确性与状态同步性,又需兼顾医生资源匹配的合理性与解读请求提交的完整性,同时实现多端服务体验的一致性。本文基于这套 React Native 医院系统对接应用代码,从架构设计、核心业务逻辑、鸿蒙跨端适配三个维度,系统解读影像诊断场景的跨端开发逻辑与技术要点,重点剖析 React Native 与鸿蒙系统的适配底层逻辑和落地实践方案,尤其针对检查报告状态更新、医生资源筛选、解读请求提交等核心交互的跨端实现进行深度拆解。

一、检查报告管理、医生资源匹配、解读请求

该医院系统对接应用基于 React Native 函数式组件 + TypeScript 强类型架构构建,核心依赖 React Native 原生基础组件(SafeAreaView、ScrollView、TouchableOpacity、TextInput、Modal 等)与 useState 核心 Hook,未引入第三方 UI 框架或复杂状态管理库。这种极简架构是医院系统对接这类“强数据同步、轻实时交互”场景实现鸿蒙跨端的核心优势——轻量意味着适配成本更低,且能最大程度保证多端影像诊断服务流程逻辑的一致性,尤其适合检查报告管理、医生资源匹配、解读请求提交等核心逻辑的跨端复用。

从跨端技术底层逻辑来看,React Native 以“JS 桥接层(JS Bridge)”为核心实现跨端能力:前端编写的 JSX 组件与医院系统对接业务逻辑,通过桥接层映射为不同平台的原生组件,iOS 端映射为 UIKit 体系、Android 端映射为 View 体系,而鸿蒙(HarmonyOS)端则通过 React Native for HarmonyOS 适配层,完成 React Native 组件/API 与鸿蒙 ArkUI 组件/API 的双向映射。该应用的代码结构完全遵循跨端开发规范:无平台专属硬编码、状态管理基于 React 原生 Hooks、样式采用跨端通用的 Flex 布局,从根源上消除了鸿蒙适配的技术壁垒,同时保证检查报告状态更新、医生资源匹配、解读请求提交等核心影像诊断管理流程逻辑在多端的一致性。

值得注意的是,应用核心的解读请求提交(handleRequestInterpretation)、报告状态更新(testReports.map)、医生在线状态展示(doctor.available 条件渲染)逻辑均为纯 JS 状态操作与数组关联查询实现,无任何平台相关依赖,这是跨端复用的关键——鸿蒙端可通过 JS 引擎直接执行该逻辑,无需适配任何原生能力,保证影像诊断管理规则在多端的完全一致,避免因平台差异导致的解读请求提交失败、报告状态更新异常等核心问题。


1. 医生资源信息展示的跨端一致性

应用通过 TypeScript 接口定义了 TestReport(检查报告)、Doctor(医生)两类核心数据类型,字段设计精准匹配影像诊断全流程数据需求,且所有字段均为 JS 基础数据类型(string/number/boolean),为跨端适配奠定基础:

  • TestReport 作为核心业务数据模型,涵盖报告ID、患者ID、检查项目、日期、结果、状态、影像链接等字段,状态(status: string)采用标准化枚举式字符串(已完成/待解读/解读中),在鸿蒙端适配层可直接映射为 ArkTS 的 string 类型,避免多端数据类型解析差异导致的报告状态展示错误,尤其在“CT扫描 2023-12-01 正常 已完成”这类核心报告信息的传递上,保证了跨端的数据准确性;影像链接(imageUrl: string)为标准化 URL 字符串,鸿蒙端适配层可直接解析,为后续影像预览功能的跨端扩展预留基础;
  • Doctor 模型新增在线状态字段(available: boolean),布尔值为 JS/ArkTS 通用基础类型,医生在线状态的展示逻辑跨端统一,评分(rating: number)为数值类型,专科(specialty)、经验(experience)为标准化字符串,保证医生资源信息展示的跨端一致性。

这种强类型+场景化的数据模型设计,在跨端场景下保证了数据结构的一致性——鸿蒙端适配层可直接解析 TypeScript 类型定义,与 ArkTS 中的数据模型形成精准映射,避免多端数据格式不一致导致的报告信息展示异常、医生在线状态错误等核心问题,是医院系统对接场景跨端落地的基础保障。

2. 医生列表的展示逻辑跨端统一

应用采用 useState 实现多维度状态管理,核心状态均具备跨端复用的特性,且针对医院系统对接场景做了适配性设计:

  • 核心业务数据状态(testReports/doctors)中,doctors 为只读设计,适配层自动映射为鸿蒙的 @State 响应式状态,医生列表的展示逻辑跨端统一;testReports 支持状态更新操作(setTestReports),数组映射更新(testReports.map(r => r.id === selectedReport ? { ...r, status: '解读中' } : r))为 ES6+ 标准语法,鸿蒙端直接执行,报告状态更新的规则跨端一致,保证多端报告状态的同步性;
  • 交互状态(selectedReport/selectedDoctor/interpretation)维护选中报告、选中医生与解读内容,selectedReport/selectedDoctor 为字符串/空值赋值,interpretation 为字符串状态,其更新逻辑为基础赋值操作,鸿蒙端直接执行,报告选择、医生选择、解读内容输入的交互逻辑跨端统一;
  • 弹窗状态(isModalVisible/modalContent)维护弹窗显隐与内容,其更新逻辑为基础状态操作,鸿蒙端适配层会将 Modal 的显示状态映射为 ArkUI 弹窗的显隐状态,报告详情展示的逻辑跨端统一。

1. Flex 布局的跨端统一

应用在基础样式之上新增检查报告卡片、医生卡片、解读请求输入区域专属样式,核心样式设计既遵循跨端兼容原则,又针对影像诊断场景的操作习惯做了特殊优化,适配鸿蒙系统无明显改造成本:

  • Flex 布局的跨端统一:从检查报告卡片的“图标+信息+查看/下载按钮”、医生卡片的“图标+信息+在线状态”,到解读请求输入区域的“多行输入框+提交按钮”布局,全量采用 Flex 布局体系——检查报告卡片使用 flexDirection: 'row' + alignItems: 'center' 横向布局,“查看详情”“下载”按钮独立排布,保证报告操作的便捷性;医生卡片使用 flexDirection: 'row' + alignItems: 'center' 横向布局,在线状态标识独立排布,方便快速识别医生可用性。Flex 作为 W3C 标准布局方案,在鸿蒙端可被适配层直接解析为 ArkUI 的 Flex 布局,无需重构任何布局逻辑,仅需保证样式属性命名与 React Native 规范一致,尤其在检查报告操作、医生资源筛选、解读请求提交等核心影像诊断交互区域的布局上,Flex 布局的跨端一致性表现突出;
  • 医院系统对接专属样式的跨端适配
    • 选中报告/医生卡片样式(selectedCardborderWidth: 2 + borderColor: '#0284c7')为通用样式属性,鸿蒙端适配层会将边框属性转换为 ArkUI 的 border 相关属性,选中项的高亮边框视觉效果跨端统一,帮助用户快速识别选择状态;
    • 查看/下载按钮样式(viewButton/downloadButton)分别采用蓝/绿背景色区分功能,为通用样式属性,鸿蒙端适配层直接解析,按钮的视觉辨识度与点击区域跨端统一,方便用户操作报告;
    • 解读请求输入框样式(interpretationInput)设置 minHeight: 80 + textAlignVertical: 'top',为通用样式属性,鸿蒙端适配层直接解析,多行输入的排版逻辑跨端统一,符合用户输入解读需求的操作习惯;
    • 医生在线状态样式(availability)采用 emoji 图标+文字组合,为纯文本展示逻辑,鸿蒙端直接渲染,在线/离线状态的视觉区分跨端统一;
  • 屏幕适配与层级兼容Dimensions.get('window') 获取设备宽高的 API 在鸿蒙端已完成原生映射,为不同尺寸鸿蒙设备(手机、平板)的自适应布局预留基础,尤其适配平板设备的报告大屏查看场景;shadow + elevation 的双层阴影设计,鸿蒙系统对 elevation 属性的支持与 Android 端完全兼容,保证各类卡片、信息卡片的视觉层级跨端统一,同时阴影透明度(0.1)的低饱和度设计,避免视觉干扰,符合医疗场景专业、清晰的视觉需求;
  • 安全区域适配SafeAreaView 组件在鸿蒙端已适配为 ArkUI 的 SafeArea 组件,保证头部医院系统对接标题区域在不同鸿蒙设备上的展示完整性,避免标题被刘海屏、全面屏遮挡,尤其适配医护人员/患者的视觉聚焦习惯。

(1)报告选择逻辑(handleSelectReport)包含状态更新(setSelectedReport)与弹窗反馈(Alert.alert

检查报告管理是医院系统对接的基础功能,核心适配逻辑如下:

  • 报告列表渲染采用 map 方法遍历 testReports 数组,该逻辑为纯 JS 数组操作,鸿蒙端通过 JS 引擎直接执行,列表渲染的顺序与报告信息展示的完整性跨端一致,保证报告信息的准确展示;
  • 报告选择逻辑(handleSelectReport)包含状态更新(setSelectedReport)与弹窗反馈(Alert.alert),状态更新为基础字符串赋值,弹窗反馈转换为鸿蒙 AlertDialog 组件,选择操作的反馈逻辑跨端一致;
  • 报告详情查看逻辑(handleViewReport)包含数据查找(testReports.find)、弹窗内容拼接、弹窗显隐控制,数据查找为 JS 原生数组方法,弹窗内容拼接为纯 JS 模板字符串操作,弹窗显隐控制为基础状态赋值,鸿蒙端直接执行,详情展示的逻辑跨端统一;
  • 报告下载逻辑(handleDownloadReport)包含数据查找与弹窗反馈,数据查找为 JS 原生数组方法,弹窗反馈转换为鸿蒙 AlertDialog 组件,下载操作的反馈逻辑跨端一致。
(2)医生资源匹配组件

医生资源匹配是医院系统对接的核心资源管理功能,核心适配逻辑如下:

  • 医生列表渲染采用 map 方法遍历 doctors 数组,在线状态展示(doctor.available ? '🟢 在线' : '🔴 离线')为纯 JS 条件渲染,鸿蒙端直接执行,在线状态的展示规则跨端一致;
  • 医生选择逻辑(handleSelectDoctor)包含状态更新(setSelectedDoctor)与弹窗反馈,状态更新为基础字符串赋值,弹窗反馈转换为鸿蒙 AlertDialog 组件,选择操作的反馈逻辑跨端一致。
(3)解读请求提交组件

解读请求提交是医院系统对接的核心交互功能,核心适配逻辑如下:

  • 解读内容输入采用 TextInput 组件(multiline: true)实现,onChangeText/placeholder/textAlignVertical 属性在鸿蒙端已适配,多行输入的交互逻辑跨端统一;
  • 解读请求提交逻辑(handleRequestInterpretation)包含表单校验(selectedReport && selectedDoctor && interpretation.trim())、报告状态更新(setTestReports)、状态重置(setInterpretation)、弹窗反馈,表单校验为纯 JS 布尔运算,报告状态更新使用数组映射方法,状态重置为基础字符串赋值,弹窗反馈转换为鸿蒙 AlertDialog 组件,提交操作的逻辑跨端一致。

1. 解读请求提交全流程逻辑

handleRequestInterpretation 是医院系统对接的核心服务机制,实现了“表单校验-数据查找-状态更新-反馈提示”的全流程解读请求处理,核心适配逻辑如下:

  • 表单校验逻辑(selectedReport && selectedDoctor && interpretation.trim())为纯 JS 布尔运算,鸿蒙端直接执行,校验规则跨端一致,保证解读请求提交的完整性;
  • 数据查找逻辑(testReports.find/doctors.find)为 JS 原生数组方法,无任何平台依赖,鸿蒙端直接执行,报告/医生信息查找的规则跨端一致;
  • 报告状态更新逻辑(testReports.map(r => r.id === selectedReport ? { ...r, status: '解读中' } : r))为 JS 原生数组方法,鸿蒙端直接执行,报告状态更新的规则跨端一致,保证多端报告状态的同步性;
  • 状态重置逻辑(setInterpretation(''))为基础字符串赋值,鸿蒙端直接执行,输入框重置的规则跨端一致;
  • 反馈提示逻辑(Alert.alert)转换为鸿蒙 AlertDialog 组件,提示文案为纯 JS 字符串,鸿蒙端直接执行,提示展示的逻辑跨端一致。

2. 跨端 API 兼容处理

应用使用的核心 API 均为 React Native 跨端兼容 API,在鸿蒙端可无缝适配,且针对医院系统对接场景做了适配性验证:

  • 数组 API:map/find/扩展运算符等数组方法为 JS 原生 API,鸿蒙端通过 JS 引擎直接执行,无需适配,保证检查报告/医生列表的渲染、查找、状态更新等核心逻辑的跨端一致性;
  • 字符串 API:字符串 trim、拼接、模板字符串等操作为 JS 原生 API,鸿蒙端直接执行,保证解读内容校验、弹窗内容拼接等核心逻辑的跨端一致性;
  • 交互 API:TouchableOpacityonPress 回调、TextInputmultiline/textAlignVertical/onChangeText 属性、Alert.alert 弹窗、Modal 组件的核心属性,在鸿蒙端均已完成适配,点击交互、输入交互、弹窗反馈、模态框展示的逻辑跨端一致,符合医护人员/患者的操作习惯;
  • 样式 API:StyleSheet.create 封装的样式规则,适配层转换为 ArkUI 的样式对象,尤其选中报告/医生卡片的条件样式绑定逻辑,鸿蒙端可直接解析,保证选择状态的视觉适配跨端统一。

该医院系统对接应用作为智慧医疗影像诊断场景核心模块,适配鸿蒙系统的成本极低,核心适配思路与技术要点如下:

应用核心的解读请求提交、报告状态更新、医生选择、报告下载等逻辑均为纯 JS 实现,无任何平台相关依赖,这是跨端复用的最大优势——鸿蒙端可通过 JS 引擎直接执行该逻辑,无需适配任何原生能力。在生产环境中扩展影像预览、报告在线打印、医生实时沟通等逻辑时,新增规则仍为纯 JS 逻辑(影像预览可通过原生模块封装鸿蒙图片预览 API,核心业务逻辑复用),鸿蒙端可直接复用,仅需保证规则逻辑的通用性,无需考虑平台差异,这也是医院系统对接场景跨端开发的核心优势。

该应用当前的列表渲染采用基础 map 方法,在生产环境中若检查报告/医生数据量较大(如超过50份报告、20位医生),可替换为 React Native 的 FlatList 高性能列表组件——FlatList 在鸿蒙端已完成深度适配,支持虚拟化列表渲染,其核心属性(data/renderItem/keyExtractor)与 React Native 端完全一致,且 FlatListrenderItem 中可直接复用现有卡片样式与选中条件样式绑定逻辑,仅需少量调整即可适配鸿蒙端的性能优化策略,保证列表的滚动性能,尤其适合多报告、多医生的影像诊断场景。

鸿蒙系统有自身的医疗影像诊断场景友好型设计规范,在适配时可通过条件编译实现差异化样式,既保证遵循鸿蒙设计规范,又能保留现有代码的完整性与场景友好特性:

// 鸿蒙端医院系统对接样式差异化适配示例
import { Platform } from 'react-native';
const isHarmonyOS = Platform.OS === 'harmony';

const adaptiveStyles = {
  card: {
    ...styles.card,
    backgroundColor: isHarmonyOS ? '#e0f7fa' : '#f0f9ff',
    borderRadius: isHarmonyOS ? 14 : 12,
    padding: isHarmonyOS ? 20 : 16, // 鸿蒙端增大内边距,更适合查看医疗报告
  },
  selectedCard: {
    ...styles.selectedCard,
    borderWidth: isHarmonyOS ? 3 : 2, // 鸿蒙端增大选中边框宽度
    borderColor: isHarmonyOS ? '#0369a1' : '#0284c7',
  },
  interpretationInput: {
    ...styles.interpretationInput,
    fontSize: isHarmonyOS ? 16 : 14, // 鸿蒙端增大输入框字体
    padding: isHarmonyOS ? 16 : 12,
    minHeight: isHarmonyOS ? 100 : 80, // 鸿蒙端增大输入框高度
  },
  requestButton: {
    ...styles.requestButton,
    padding: isHarmonyOS ? 14 : 12, // 鸿蒙端增大提交按钮点击区域
    borderRadius: isHarmonyOS ? 10 : 8,
  }
};

这种轻量级的差异化适配,既能保证符合鸿蒙的医疗影像诊断场景友好设计规范,又能保留现有代码的完整性,尤其在检查报告卡片、解读请求输入框、提交按钮等核心影像诊断交互组件的样式适配中,效果显著,同时维持了医院系统对接场景专业、清晰的视觉调性。

该 React Native 医院系统对接应用实现了检查报告管理、医生资源匹配、在线解读请求、报告下载查看等核心智慧医疗服务功能,代码结构符合跨端开发规范,可低成本适配鸿蒙系统。针对生产环境落地,可做以下优化:

  1. 影像预览功能对接:通过 React Native 原生模块封装鸿蒙的图片预览 API,实现 CT/MRI 影像的在线预览,核心报告查看逻辑可完全复用现有代码,仅需对接鸿蒙的图片预览原生 API,提升影像诊断的可视化能力;
  2. 医生在线状态实时同步:通过 React Native 原生模块封装鸿蒙的 WebSocket API,实现医生在线状态的实时更新,核心医生列表渲染逻辑可复用,仅需扩展实时状态同步能力,提升医生资源匹配的准确性;
  3. 解读请求状态跟踪:新增解读请求状态数据模型与状态管理,区分“待处理/处理中/已完成”,该逻辑为纯 JS 字符串状态判断,鸿蒙端直接执行,无需适配原生能力,提升解读请求管理的精细化程度;
  4. 医院系统数据对接:对接医院 HIS/PACS 系统接口,实现检查报告的自动同步,数据同步逻辑为纯 JS 数组操作,鸿蒙端直接执行,保证报告数据的实时性与准确性;
  5. 电子签名与报告确认:通过 React Native 原生模块封装鸿蒙的电子签名 API,实现医生解读报告后的电子签名确认,核心解读请求提交逻辑可复用,仅需扩展电子签名能力,提升报告解读的合法性与规范性。

真实演示案例代码:








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

// Base64 图标库
const ICONS_BASE64 = {
  report: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  doctor: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  ct: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  mri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

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

// 检查报告类型
type TestReport = {
  id: string;
  patientId: string;
  testName: string;
  date: string;
  result: string;
  status: string;
  imageUrl: string;
};

// 医生类型
type Doctor = {
  id: string;
  name: string;
  specialty: string;
  experience: string;
  rating: number;
  available: boolean;
};

// 医院系统对接应用组件
const HospitalSystemIntegrationApp: React.FC = () => {
  const [testReports, setTestReports] = useState<TestReport[]>([
    {
      id: '1',
      patientId: '1',
      testName: 'CT扫描',
      date: '2023-12-01',
      result: '正常',
      status: '已完成',
      imageUrl: 'https://example.com/ct-scan-image'
    },
    {
      id: '2',
      patientId: '1',
      testName: 'MRI检查',
      date: '2023-12-02',
      result: '发现异常',
      status: '待解读',
      imageUrl: 'https://example.com/mri-scan-image'
    }
  ]);

  const [doctors] = useState<Doctor[]>([
    {
      id: '1',
      name: '张医生',
      specialty: '放射科',
      experience: '10年经验',
      rating: 4.8,
      available: true
    },
    {
      id: '2',
      name: '李医生',
      specialty: '神经内科',
      experience: '12年经验',
      rating: 4.9,
      available: false
    }
  ]);

  const [selectedReport, setSelectedReport] = useState<string | null>(null);
  const [selectedDoctor, setSelectedDoctor] = useState<string | null>(null);
  const [interpretation, setInterpretation] = useState('');
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [modalContent, setModalContent] = useState('');

  const handleSelectReport = (reportId: string) => {
    setSelectedReport(reportId);
    Alert.alert('选择报告', '您已选择该报告进行查看');
  };

  const handleSelectDoctor = (doctorId: string) => {
    setSelectedDoctor(doctorId);
    Alert.alert('选择医生', '您已选择该医生进行解读');
  };

  const handleRequestInterpretation = () => {
    if (selectedReport && selectedDoctor && interpretation.trim()) {
      const report = testReports.find(r => r.id === selectedReport);
      const doctor = doctors.find(d => d.id === selectedDoctor);
      if (report && doctor) {
        setTestReports(testReports.map(r => 
          r.id === selectedReport ? { ...r, status: '解读中' } : r
        ));
        setInterpretation('');
        Alert.alert('请求提交', `已向${doctor.name}医生提交解读请求`);
      }
    } else {
      Alert.alert('提示', '请选择报告和医生,并填写解读内容');
    }
  };

  const handleViewReport = (reportId: string) => {
    const report = testReports.find(r => r.id === reportId);
    if (report) {
      setModalContent(`检查项目: ${report.testName}\n日期: ${report.date}\n结果: ${report.result}\n状态: ${report.status}\n图像链接: ${report.imageUrl}`);
      setIsModalVisible(true);
    }
  };

  const handleDownloadReport = (reportId: string) => {
    const report = testReports.find(r => r.id === reportId);
    if (report) {
      Alert.alert('下载报告', `正在下载${report.testName}报告`);
    }
  };

  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}>用户可实时查看CTMRI等报告,支持医生在线解读</Text>
      </View>

      <ScrollView style={styles.content}>
        {/* 检查报告列表 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>检查报告</Text>
          {testReports.map(report => (
            <TouchableOpacity 
              key={report.id}
              style={[
                styles.card,
                selectedReport === report.id && styles.selectedCard
              ]}
              onPress={() => handleSelectReport(report.id)}
            >
              <Text style={styles.icon}>📋</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{report.testName}</Text>
                <Text style={styles.cardDescription}>日期: {report.date}</Text>
                <Text style={styles.cardDescription}>结果: {report.result}</Text>
                <Text style={styles.cardDescription}>状态: {report.status}</Text>
              </View>
              <TouchableOpacity 
                style={styles.viewButton}
                onPress={() => handleViewReport(report.id)}
              >
                <Text style={styles.viewText}>查看详情</Text>
              </TouchableOpacity>
              <TouchableOpacity 
                style={styles.downloadButton}
                onPress={() => handleDownloadReport(report.id)}
              >
                <Text style={styles.downloadText}>下载</Text>
              </TouchableOpacity>
            </TouchableOpacity>
          ))}
        </View>

        {/* 医生列表 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>医生列表</Text>
          {doctors.map(doctor => (
            <TouchableOpacity 
              key={doctor.id}
              style={[
                styles.card,
                selectedDoctor === doctor.id && styles.selectedCard
              ]}
              onPress={() => handleSelectDoctor(doctor.id)}
            >
              <Text style={styles.icon}>👨‍⚕️</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{doctor.name}</Text>
                <Text style={styles.cardDescription}>专科: {doctor.specialty}</Text>
                <Text style={styles.cardDescription}>经验: {doctor.experience}</Text>
                <Text style={styles.cardDescription}>评分: {doctor.rating}</Text>
              </View>
              <Text style={styles.availability}>
                {doctor.available ? '🟢 在线' : '🔴 离线'}
              </Text>
            </TouchableOpacity>
          ))}
        </View>

        {/* 解读请求 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>医生解读</Text>
          <TextInput
            style={styles.interpretationInput}
            placeholder="请输入需要医生解读的内容..."
            multiline
            value={interpretation}
            onChangeText={setInterpretation}
          />
          <TouchableOpacity 
            style={styles.requestButton}
            onPress={handleRequestInterpretation}
          >
            <Text style={styles.requestText}>请求解读</Text>
          </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',
  },
  icon: {
    fontSize: 28,
    marginRight: 12,
  },
  cardInfo: {
    flex: 1,
  },
  cardTitle: {
    fontSize: 16,
    fontWeight: '500',
    color: '#0c4a6e',
    marginBottom: 4,
  },
  cardDescription: {
    fontSize: 14,
    color: '#0284c7',
    marginBottom: 2,
  },
  availability: {
    fontSize: 14,
    color: '#0c4a6e',
    fontWeight: '500',
  },
  viewButton: {
    backgroundColor: '#0284c7',
    paddingHorizontal: 12,
    paddingVertical: 6,
    borderRadius: 8,
    marginRight: 8,
  },
  viewText: {
    color: '#ffffff',
    fontSize: 12,
    fontWeight: '500',
  },
  downloadButton: {
    backgroundColor: '#10b981',
    paddingHorizontal: 12,
    paddingVertical: 6,
    borderRadius: 8,
  },
  downloadText: {
    color: '#ffffff',
    fontSize: 12,
    fontWeight: '500',
  },
  interpretationInput: {
    backgroundColor: '#f0f9ff',
    borderRadius: 12,
    padding: 12,
    fontSize: 14,
    color: '#0c4a6e',
    minHeight: 80,
    textAlignVertical: 'top',
    marginBottom: 12,
  },
  requestButton: {
    backgroundColor: '#0284c7',
    padding: 12,
    borderRadius: 8,
    alignItems: 'center',
  },
  requestText: {
    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 HospitalSystemIntegrationApp;

请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述
本文介绍了一个基于React Native开发的医院系统对接应用,该应用集成了检查报告管理、医生管理和医学影像查看等功能。采用React Hooks、TypeScript等技术栈,通过类型定义确保数据结构一致性和代码可维护性。核心功能包括检查报告状态管理、医生资源匹配和解读请求提交,使用卡片式布局和Modal组件提升用户体验。文章重点分析了React Native与鸿蒙系统的跨端适配方案,包括组件映射、性能优化等技术要点。该应用展示了React Native在构建跨平台医疗应用方面的能力,为医疗信息化建设提供了参考价值。

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

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐