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


手术直播是医疗领域的创新应用,它通过技术手段让患者家属能够实时了解手术过程,同时为医学教育和远程会诊提供了新的途径。今天我们来深入分析一个基于 React Native 开发的手术直播应用,该应用集成了患者管理、家属管理、医生管理和直播控制等功能,为手术过程提供了透明化的观看平台。

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

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

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

表示家属信息,包含 ID、姓名、关系、联系方式和授权状态

应用通过 TypeScript 定义了三个核心数据类型,构建了完整的手术直播数据模型:

  • Patient:表示患者信息,包含 ID、姓名、手术类型和手术日期
  • FamilyMember:表示家属信息,包含 ID、姓名、关系、联系方式和授权状态
  • Doctor:表示医生信息,包含 ID、姓名、专业、经验和评分

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

状态管理

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

  • 静态数据(患者列表、医生列表)通过初始化的 useState 直接存储
  • 动态数据(家属列表、评论列表)通过 useState 管理,并支持添加和更新
  • 交互状态(选中的患者、选中的医生、直播状态、模态框可见性)通过独立的 useState 管理

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


应用支持患者信息的展示和选择,通过列表展示患者的基本信息,包括姓名、手术类型和手术日期。用户可以点击选择患者进行手术直播,为直播提供明确的目标对象。

家属管理是应用的重要功能,主要包括:

  • 展示家属信息,包括姓名、关系、联系方式和授权状态
  • 授权家属观看手术直播的权限
  • 查看家属详细信息

家属需要获得授权才能观看手术直播,这一设计确保了患者隐私和手术过程的安全性。

应用内置了医生信息列表,包含医生的姓名、专业、经验和评分。用户可以点击选择医生进行手术直播,为直播提供专业的医疗指导。

直播控制是应用的核心功能,主要包括:

  • 开始手术直播
  • 结束手术直播
  • 实时评论互动

当用户选择了患者和医生后,可以开始手术直播。直播过程中,观看者可以通过评论功能进行互动,医生可以实时讲解手术关键步骤。

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


组件映射

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

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

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

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

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

  • 使用 memo 优化组件渲染,特别是对于患者列表、家属列表等重复渲染的场景
  • 合理使用 useCallbackuseMemo 减少不必要的计算
  • 优化图片资源,考虑使用鸿蒙的资源加载机制
  • 对于直播功能,需要特别注意性能优化,确保视频流的流畅传输
  • 对于评论功能,考虑使用虚拟化技术减少内存占用

应用实现了家属授权机制,确保只有获得授权的家属才能观看手术直播。这一设计不仅保护了患者的隐私,也符合医疗伦理和法律要求。

应用考虑了患者、家属和医生三个角色的协同管理:

  • 患者:作为手术的主体,其信息是直播的核心
  • 家属:作为关心手术进展的一方,需要获得授权才能观看
  • 医生:作为手术的执行者,需要在直播中提供专业指导

应用支持直播过程中的实时评论互动,让观看者可以随时提问,医生可以实时解答,增强了直播的互动性和教育价值。

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

  • 功能按模块划分(患者管理、家属管理、医生管理、直播控制)
  • 组件职责单一,便于维护和扩展
  • 状态管理逻辑与 UI 渲染分离

Base64 图标库

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

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

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


文件结构

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

  • /components:存放可复用组件,如患者卡片、家属卡片、医生卡片等

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

  • /hooks:存放自定义 hooks,如直播控制逻辑、授权管理逻辑等

  • /services:存放 API 调用和业务逻辑,如数据存储、直播服务等

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

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

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

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

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

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

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

  • 可以轻松添加新的患者、家属和医生信息
  • 可以集成真实的直播服务,实现真正的手术直播功能
  • 可以扩展支持更多的直播管理功能,如直播录制、回放等
  • 可以集成视频会议功能,实现远程会诊
  • 可以添加数据可视化功能,如手术进度跟踪等

这个手术直播应用展示了如何使用 React Native 构建功能完备的医疗直播管理工具,特别是在家属授权机制和多角色协同管理方面的实践具有重要参考价值。通过跨端开发技术,可以在不同平台为医疗专业人士和患者家属提供一致的服务体验。

随着医疗技术的不断发展,手术直播在医学教育、远程会诊和患者家属沟通等方面的应用将越来越广泛。未来可以考虑:

  • 集成专业的医疗直播设备,实现高清、稳定的手术直播
  • 与医院的信息系统对接,实现患者信息的自动同步
  • 利用 AI 技术对手术过程进行实时分析和指导
  • 支持多平台直播,包括 Web 端、移动端等
  • 开发配套的医学教育平台,让手术直播成为医学教学的重要资源

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


手术直播是智慧医疗在外科手术场景的创新落地形态,聚焦“患者信息管理-医生对接-家属授权-直播控制-实时评论”全流程的手术直播服务逻辑,既要保证手术类型、直播状态等核心医疗数据的准确性,又需兼顾家属授权的安全性与直播控制的实时性,同时实现多端服务体验的一致性。本文基于这套 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 布局,从根源上消除了鸿蒙适配的技术壁垒,同时保证家属授权、直播启停、实时评论等核心手术直播管理流程逻辑在多端的一致性。

值得注意的是,应用核心的家属授权(handleAuthorizeFamily)、直播启停(handleStartLiveStream/handleStopLiveStream)、实时评论(handleAddComment)逻辑均为纯 JS 状态操作与数组关联查询实现,无任何平台相关依赖,这是跨端复用的关键——鸿蒙端可通过 JS 引擎直接执行该逻辑,无需适配任何原生能力,保证手术直播管理规则在多端的完全一致,避免因平台差异导致的家属授权失败、直播启停异常等核心问题。


1. 手术直播

应用通过 TypeScript 接口定义了 Patient(患者)、FamilyMember(家属)、Doctor(医生)三类核心数据类型,字段设计精准匹配手术直播全流程数据需求,且所有字段均为 JS 基础数据类型(string/number/boolean),为跨端适配奠定基础:

  • Patient 涵盖患者ID、姓名、手术类型、手术日期,手术类型(surgeryType)与手术日期(surgeryDate)为标准化字符串类型,在鸿蒙端适配层可直接映射为 ArkTS 的 string 类型,避免多端数据类型解析差异导致的患者信息展示错误,尤其在“李先生 膝关节置换 2023-12-10”这类核心患者信息的传递上,保证了跨端的数据准确性;
  • FamilyMember 新增授权状态字段(authorized: boolean),布尔值为 JS/ArkTS 通用基础类型,家属授权状态的展示与更新逻辑跨端统一,同时联系方式(contact)为标准化字符串,保证家属信息传递的跨端一致性;
  • Doctor 包含评分字段(rating: number),数值类型为 JS/ArkTS 通用基础类型,医生评分的展示规则无平台差异,专科(specialty)、经验(experience)为标准化字符串,保证医生信息展示的跨端一致性。

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

2. 应用采用 useState 实现多维度状态管理

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

  • 核心基础数据状态(patients/doctors)为只读设计,适配层自动映射为鸿蒙的 @State 响应式状态,患者列表、医生列表的展示逻辑跨端统一,保证基础医疗服务信息的一致性;
  • 动态业务数据状态(familyMembers/comments)支持新增/更新操作(setFamilyMembers/setComments),数组映射更新(familyMembers.map(member => member.id === familyId ? { ...member, authorized: true } : member))、数组扩展运算符([...comments, newComment])均为 ES6+ 标准语法,鸿蒙端直接执行,数据新增/状态更新的规则跨端一致,且关联查询逻辑绑定在状态更新之后,保证多端数据关联的准确性;
  • 交互状态(selectedPatient/selectedDoctor/liveStreamActive/newComment)维护选中医患、直播状态与新增评论信息,liveStreamActive 为布尔值状态,newComment 为字符串状态,其更新逻辑为基础赋值操作,鸿蒙端直接执行,医患选择、直播控制、评论输入的交互逻辑跨端统一;
  • 弹窗状态(isModalVisible/modalContent)维护弹窗显隐与内容,其更新逻辑为基础状态操作,鸿蒙端适配层会将 Modal 的显示状态映射为 ArkUI 弹窗的显隐状态,弹窗展示家属详情的逻辑跨端统一。

1. 医生卡片、家属卡片、直播控制按钮

应用在基础样式之上新增患者卡片、医生卡片、家属卡片、直播控制按钮、评论输入区域专属样式,核心样式设计既遵循跨端兼容原则,又针对手术直播场景的操作习惯做了特殊优化,适配鸿蒙系统无明显改造成本:

  • Flex 布局的跨端统一:从医患卡片的“图标+信息”、家属卡片的“图标+信息+授权按钮”,到评论输入区域的“输入框+发送按钮”、弹窗的“垂直居中+内容区”布局,全量采用 Flex 布局体系——家属卡片使用 flexDirection: 'row' + alignItems: 'center' 横向布局,“授权”按钮独立排布,保证家属授权操作的便捷性;评论输入区域使用 flexDirection: 'row' + alignItems: 'center' 横向布局,输入框与发送按钮的比例通过 flex: 1 控制,保证评论输入的交互流畅性。Flex 作为 W3C 标准布局方案,在鸿蒙端可被适配层直接解析为 ArkUI 的 Flex 布局,无需重构任何布局逻辑,仅需保证样式属性命名与 React Native 规范一致,尤其在家属授权、直播控制、实时评论等核心手术直播交互区域的布局上,Flex 布局的跨端一致性表现突出;
  • 手术直播专属样式的跨端适配
    • 选中医患卡片样式(selectedCardborderWidth: 2 + borderColor: '#0284c7')为通用样式属性,鸿蒙端适配层会将边框属性转换为 ArkUI 的 border 相关属性,选中医患的高亮边框视觉效果跨端统一,帮助用户快速识别选择状态;
    • 直播控制按钮样式(liveButton/liveButtonActive)采用蓝/红背景色区分直播状态,为通用样式属性,鸿蒙端适配层直接解析,按钮的视觉状态与点击区域跨端统一,方便医护人员快速控制直播启停;
    • 家属授权按钮样式(authorizeButton)采用绿色背景(#10b981)、小尺寸内边距设计,为通用样式属性,鸿蒙端适配层直接解析,按钮的视觉辨识度与点击区域跨端统一,方便管理员快速完成家属授权;
    • 评论输入框样式(commentInput)采用浅蓝背景(#f0f9ff)、圆角(8)、内边距(12/8)设计,为通用样式属性,鸿蒙端适配层直接解析,输入框的视觉质感与输入体验跨端统一,符合家属/医护人员输入评论的操作习惯;
    • 评论列表容器样式(commentsContainer)设置 maxHeight: 150,为通用样式属性,鸿蒙端适配层直接解析,评论列表的滚动区域限制跨端统一,避免评论区域占用过多屏幕空间;
  • 屏幕适配与层级兼容Dimensions.get('window') 获取设备宽高的 API 在鸿蒙端已完成原生映射,为不同尺寸鸿蒙设备(手机、平板)的自适应布局预留基础,尤其适配平板设备的手术直播大屏展示场景;shadow + elevation 的双层阴影设计,鸿蒙系统对 elevation 属性的支持与 Android 端完全兼容,保证各类卡片、信息卡片的视觉层级跨端统一,同时阴影透明度(0.1)的低饱和度设计,避免视觉干扰,符合手术直播场景专业、清晰的视觉需求;
  • 安全区域适配SafeAreaView 组件在鸿蒙端已适配为 ArkUI 的 SafeArea 组件,保证头部手术直播标题区域在不同鸿蒙设备上的展示完整性,避免标题被刘海屏、全面屏遮挡,尤其适配医护人员的视觉聚焦习惯。

(1)医患信息管理组件

医患信息管理是手术直播的基础功能,核心适配逻辑如下:

  • 患者/医生列表渲染采用 map 方法遍历 patients/doctors 数组,该逻辑为纯 JS 数组操作,鸿蒙端通过 JS 引擎直接执行,列表渲染的顺序与医患信息展示的完整性跨端一致,保证医患信息的准确展示;
  • 医患选择逻辑(handleSelectPatient/handleSelectDoctor)包含状态更新(setSelectedPatient/setSelectedDoctor)与弹窗反馈(Alert.alert),状态更新为基础字符串赋值,弹窗反馈转换为鸿蒙 AlertDialog 组件,选择操作的反馈逻辑跨端一致。
(2)家属授权与详情展示组件

家属授权是手术直播的核心权限管理功能,核心适配逻辑如下:

  • 家属列表渲染采用 map 方法遍历 familyMembers 数组,授权按钮的显隐逻辑(!family.authorized && <TouchableOpacity/>)为纯 JS 条件渲染,鸿蒙端直接执行,按钮显隐的规则跨端一致;
  • 家属授权逻辑(handleAuthorizeFamily)包含数组映射更新(familyMembers.map)与弹窗反馈,数组映射更新为 JS 原生方法,鸿蒙端直接执行,授权状态更新的规则跨端一致,弹窗反馈转换为鸿蒙 AlertDialog 组件,授权成功的提示逻辑跨端一致;
  • 家属详情弹窗逻辑(handleViewFamily)包含家属信息查找、弹窗内容拼接、弹窗显隐控制,家属信息查找为 JS 原生 find 方法,弹窗内容拼接为纯 JS 模板字符串操作,弹窗显隐控制为基础状态赋值,鸿蒙端直接执行,详情展示的逻辑跨端统一。
(3)直播控制与实时评论组件

直播控制与实时评论是手术直播的核心交互功能,核心适配逻辑如下:

  • 直播控制按钮的点击回调(handleStartLiveStream/handleStopLiveStream)包含状态判断(selectedPatient && selectedDoctor)、直播状态更新(setLiveStreamActive)与弹窗反馈,状态判断为纯 JS 布尔运算,直播状态更新为基础布尔值赋值,弹窗反馈转换为鸿蒙 AlertDialog 组件,直播启停的逻辑跨端一致;
  • 直播按钮的样式切换(liveStreamActive && styles.liveButtonActive)为条件样式绑定,鸿蒙端适配层可直接解析,按钮样式随直播状态切换的逻辑跨端统一;
  • 实时评论输入采用 TextInput 组件实现,onChangeText/placeholder 属性在鸿蒙端已适配,输入框的交互逻辑跨端统一;
  • 评论提交逻辑(handleAddComment)包含表单校验(newComment.trim())、评论新增(setComments)、状态重置(setNewComment),表单校验为纯 JS 字符串操作,评论新增使用数组扩展运算符,状态重置为基础字符串赋值,鸿蒙端直接执行,评论提交的规则跨端一致;
  • 评论列表渲染采用 map 方法遍历 comments 数组,该逻辑为纯 JS 数组操作,鸿蒙端直接执行,评论展示的顺序与内容跨端一致。

1. 家属授权全流程逻辑

handleAuthorizeFamily 是手术直播的核心权限管理机制,实现了“家属状态更新-授权反馈提示”的全流程授权处理,核心适配逻辑如下:

  • 家属状态更新逻辑(familyMembers.map(member => member.id === familyId ? { ...member, authorized: true } : member))为 JS 原生数组方法,无任何平台依赖,鸿蒙端直接执行,授权状态更新的规则跨端一致,保证家属观看权限的跨端同步;
  • 授权反馈提示逻辑(Alert.alert)转换为鸿蒙 AlertDialog 组件,提示文案为纯 JS 字符串,鸿蒙端直接执行,提示展示的逻辑跨端一致。

2. 直播启停全流程逻辑

handleStartLiveStream/handleStopLiveStream 是手术直播的核心控制机制,实现了“状态校验-直播状态更新-反馈提示”的全流程直播控制处理,核心适配逻辑如下:

  • 状态校验逻辑(selectedPatient && selectedDoctor)为纯 JS 布尔运算,鸿蒙端直接执行,校验规则跨端一致,保证直播启动的前提条件完整;
  • 直播状态更新逻辑(setLiveStreamActive(true/false))为基础布尔值赋值,鸿蒙端直接执行,直播状态更新的规则跨端一致;
  • 反馈提示逻辑(Alert.alert)转换为鸿蒙 AlertDialog 组件,提示文案为纯 JS 字符串,鸿蒙端直接执行,提示展示的逻辑跨端一致。

3. 实时评论全流程逻辑

handleAddComment 是手术直播的核心交互机制,实现了“表单校验-评论新增-状态重置”的全流程评论处理,核心适配逻辑如下:

  • 表单校验逻辑(newComment.trim())为纯 JS 字符串操作,鸿蒙端直接执行,校验规则跨端一致,保证评论内容的有效性;
  • 评论新增逻辑(setComments([...comments, newComment]))使用数组扩展运算符,鸿蒙端直接执行,评论新增的规则跨端一致;
  • 状态重置逻辑(setNewComment(''))为基础字符串赋值,鸿蒙端直接执行,输入框重置的规则跨端一致。

应用使用的核心 API 均为 React Native 跨端兼容 API,在鸿蒙端可无缝适配,且针对手术直播场景做了适配性验证:

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

该手术直播应用作为智慧医疗外科手术场景核心模块,适配鸿蒙系统的成本极低,核心适配思路与技术要点如下:

应用核心的家属授权、直播启停、实时评论、医患选择等逻辑均为纯 JS 实现,无任何平台相关依赖,这是跨端复用的最大优势——鸿蒙端可通过 JS 引擎直接执行该逻辑,无需适配任何原生能力。在生产环境中扩展直播推流、权限分级、直播回放等逻辑时,新增规则仍为纯 JS 逻辑(直播推流可通过原生模块封装鸿蒙音视频 API,核心业务逻辑复用),鸿蒙端可直接复用,仅需保证规则逻辑的通用性,无需考虑平台差异,这也是手术直播场景跨端开发的核心优势。

该应用当前的列表渲染采用基础 map 方法,在生产环境中若家属/评论/医患数据量较大(如超过50位家属、200条评论、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',
  },
  liveButton: {
    ...styles.liveButton,
    padding: isHarmonyOS ? 14 : 12, // 鸿蒙端增大直播按钮点击区域
    borderRadius: isHarmonyOS ? 10 : 8,
  },
  commentInput: {
    ...styles.commentInput,
    fontSize: isHarmonyOS ? 16 : 14, // 鸿蒙端增大评论输入框字体
    paddingHorizontal: isHarmonyOS ? 16 : 12,
  }
};

这种轻量级的差异化适配,既能保证符合鸿蒙的医疗场景友好设计规范,又能保留现有代码的完整性,尤其在医患信息卡片、直播控制按钮、评论输入框等核心手术直播交互组件的样式适配中,效果显著,同时维持了手术直播场景专业、清晰的视觉调性。

该 React Native 手术直播应用实现了患者信息管理、医生对接、家属授权、直播控制、实时评论等核心智慧医疗服务功能,代码结构符合跨端开发规范,可低成本适配鸿蒙系统。针对生产环境落地,可做以下优化:

  1. 直播推流对接:通过 React Native 原生模块封装鸿蒙的音视频推流 API,实现手术画面的实时推流,核心直播控制逻辑可完全复用现有代码,仅需对接鸿蒙的音视频原生 API,提升手术直播的实景展示能力;
  2. 家属权限分级:新增家属权限等级数据模型与状态管理,区分“观看权限”“评论权限”“提问权限”,该逻辑为纯 JS 布尔值判断,鸿蒙端直接执行,无需适配原生能力,提升手术直播的权限管理精细化程度;
  3. 直播回放与点播:新增直播回放数据模型与播放逻辑,该逻辑为纯 JS 数组操作与日期比较,鸿蒙端直接执行,实现手术直播的事后回放,方便家属/医护人员复盘手术过程;
  4. 手术直播数据云端同步:对接智慧医疗云平台接口,实现患者信息、家属授权状态、直播记录、评论的云端存储与多端同步,数据同步逻辑为纯 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 = {
  surgery: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  family: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  doctor: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  live: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

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

// 患者类型
type Patient = {
  id: string;
  name: string;
  surgeryType: string;
  surgeryDate: string;
};

// 家属类型
type FamilyMember = {
  id: string;
  name: string;
  relationship: string;
  contact: string;
  authorized: boolean;
};

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

// 手术直播应用组件
const SurgeryLiveStreamApp: React.FC = () => {
  const [patients] = useState<Patient[]>([
    {
      id: '1',
      name: '李先生',
      surgeryType: '膝关节置换',
      surgeryDate: '2023-12-10'
    },
    {
      id: '2',
      name: '王女士',
      surgeryType: '心脏搭桥',
      surgeryDate: '2023-12-15'
    }
  ]);

  const [familyMembers, setFamilyMembers] = useState<FamilyMember[]>([
    {
      id: '1',
      name: '张先生',
      relationship: '儿子',
      contact: '13800138000',
      authorized: false
    },
    {
      id: '2',
      name: '李女士',
      relationship: '女儿',
      contact: '13800138001',
      authorized: false
    }
  ]);

  const [doctors] = useState<Doctor[]>([
    {
      id: '1',
      name: '张医生',
      specialty: '骨科',
      experience: '10年经验',
      rating: 4.8
    },
    {
      id: '2',
      name: '王医生',
      specialty: '心胸外科',
      experience: '12年经验',
      rating: 4.9
    }
  ]);

  const [selectedPatient, setSelectedPatient] = useState<string | null>(null);
  const [selectedDoctor, setSelectedDoctor] = useState<string | null>(null);
  const [liveStreamActive, setLiveStreamActive] = useState(false);
  const [comments, setComments] = useState<string[]>([]);
  const [newComment, setNewComment] = useState('');
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [modalContent, setModalContent] = useState('');

  const handleSelectPatient = (patientId: string) => {
    setSelectedPatient(patientId);
    Alert.alert('选择患者', '您已选择该患者进行手术直播');
  };

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

  const handleAuthorizeFamily = (familyId: string) => {
    setFamilyMembers(familyMembers.map(member => 
      member.id === familyId ? { ...member, authorized: true } : member
    ));
    Alert.alert('授权成功', '家属已获得观看权限');
  };

  const handleStartLiveStream = () => {
    if (selectedPatient && selectedDoctor) {
      setLiveStreamActive(true);
      Alert.alert('直播开始', '手术直播已开始');
    } else {
      Alert.alert('提示', '请先选择患者和医生');
    }
  };

  const handleStopLiveStream = () => {
    setLiveStreamActive(false);
    Alert.alert('直播结束', '手术直播已结束');
  };

  const handleAddComment = () => {
    if (newComment.trim()) {
      setComments([...comments, newComment]);
      setNewComment('');
    } else {
      Alert.alert('提示', '请输入评论内容');
    }
  };

  const handleViewFamily = (familyId: string) => {
    const family = familyMembers.find(f => f.id === familyId);
    if (family) {
      setModalContent(`姓名: ${family.name}\n关系: ${family.relationship}\n联系方式: ${family.contact}\n授权状态: ${family.authorized ? '已授权' : '未授权'}`);
      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>
          {patients.map(patient => (
            <TouchableOpacity 
              key={patient.id}
              style={[
                styles.card,
                selectedPatient === patient.id && styles.selectedCard
              ]}
              onPress={() => handleSelectPatient(patient.id)}
            >
              <Text style={styles.icon}>👤</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{patient.name}</Text>
                <Text style={styles.cardDescription}>手术类型: {patient.surgeryType}</Text>
                <Text style={styles.cardDescription}>手术日期: {patient.surgeryDate}</Text>
              </View>
            </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>
            </TouchableOpacity>
          ))}
        </View>

        {/* 家属列表 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>家属列表</Text>
          {familyMembers.map(family => (
            <View key={family.id} style={styles.familyCard}>
              <Text style={styles.icon}>👨‍👩‍👧‍👦</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{family.name}</Text>
                <Text style={styles.cardDescription}>关系: {family.relationship}</Text>
                <Text style={styles.cardDescription}>联系方式: {family.contact}</Text>
                <Text style={styles.cardDescription}>授权状态: {family.authorized ? '已授权' : '未授权'}</Text>
              </View>
              {!family.authorized && (
                <TouchableOpacity 
                  style={styles.authorizeButton}
                  onPress={() => handleAuthorizeFamily(family.id)}
                >
                  <Text style={styles.authorizeText}>授权</Text>
                </TouchableOpacity>
              )}
            </View>
          ))}
        </View>

        {/* 直播控制 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>直播控制</Text>
          <View style={styles.liveControl}>
            <TouchableOpacity 
              style={[styles.liveButton, liveStreamActive && styles.liveButtonActive]}
              onPress={liveStreamActive ? handleStopLiveStream : handleStartLiveStream}
            >
              <Text style={styles.liveButtonText}>
                {liveStreamActive ? '停止直播' : '开始直播'}
              </Text>
            </TouchableOpacity>
          </View>
        </View>

        {/* 实时评论 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>实时评论</Text>
          <View style={styles.commentInputContainer}>
            <TextInput
              style={styles.commentInput}
              placeholder="请输入评论..."
              value={newComment}
              onChangeText={setNewComment}
            />
            <TouchableOpacity 
              style={styles.commentButton}
              onPress={handleAddComment}
            >
              <Text style={styles.commentButtonText}>发送</Text>
            </TouchableOpacity>
          </View>
          <ScrollView style={styles.commentsContainer}>
            {comments.map((comment, index) => (
              <Text key={index} style={styles.commentText}>{comment}</Text>
            ))}
          </ScrollView>
        </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',
  },
  familyCard: {
    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,
  },
  authorizeButton: {
    backgroundColor: '#10b981',
    paddingHorizontal: 12,
    paddingVertical: 6,
    borderRadius: 8,
  },
  authorizeText: {
    color: '#ffffff',
    fontSize: 12,
    fontWeight: '500',
  },
  liveControl: {
    alignItems: 'center',
  },
  liveButton: {
    backgroundColor: '#0284c7',
    padding: 12,
    borderRadius: 8,
    alignItems: 'center',
  },
  liveButtonActive: {
    backgroundColor: '#ef4444',
  },
  liveButtonText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '500',
  },
  commentInputContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 12,
  },
  commentInput: {
    flex: 1,
    backgroundColor: '#f0f9ff',
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingVertical: 8,
    fontSize: 14,
    color: '#0c4a6e',
    marginRight: 8,
  },
  commentButton: {
    backgroundColor: '#0284c7',
    paddingHorizontal: 12,
    paddingVertical: 8,
    borderRadius: 8,
  },
  commentButtonText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '500',
  },
  commentsContainer: {
    maxHeight: 150,
  },
  commentText: {
    fontSize: 14,
    color: '#0c4a6e',
    marginBottom: 4,
  },
  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 SurgeryLiveStreamApp;


请添加图片描述


打包

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

在这里插入图片描述

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

在这里插入图片描述

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

请添加图片描述
本文介绍了一个基于React Native开发的手术直播应用,该应用通过现代技术栈实现医疗领域的创新服务。应用采用TypeScript强类型架构,定义了患者、家属和医生三类核心数据类型,确保数据结构一致性。功能模块包括患者管理、家属授权、医生选择和直播控制,通过React Hooks进行轻量级状态管理,实现手术过程透明化展示。文章重点分析了该应用在鸿蒙OS平台的适配方案,包括组件映射、性能优化和跨端逻辑复用,为医疗领域的跨平台开发提供了实践参考。应用采用模块化设计,具有良好的扩展性,可支持未来集成专业医疗设备和AI分析功能。

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

Logo

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

更多推荐