Browse Source

添加猎户星空机器人SDK 文档,分析报告以及仿鸿蒙机器人熊技术方案

wangkangyjy 2 weeks ago
parent
commit
39e5cce711

+ 5215 - 0
仿鸿蒙机器人系统技术方案.md

@@ -0,0 +1,5215 @@
+# 仿鸿蒙机器人系统技术方案
+
+> **版本**: v1.0  
+> **日期**: 2026-04-23  
+> **编写**: 技术团队  
+> **状态**: 待评审  
+
+---
+
+## 修改记录
+
+| 版本 | 日期 | 修改人 | 修改内容 |
+|------|------|--------|---------|
+| v1.0 | 2026-04-23 | 技术团队 | 初稿完成 |
+
+---
+
+## 一、项目概述与目标
+
+### 1.1 迎检需求背景
+
+本项目面向领导视察场景,目标是在猎户星空豹小秘系列机器人上部署一套**智慧医疗导诊系统**。机器人需在视觉上伪装为 HarmonyOS 4 风格,同时保留完整的导航带路能力。现有业务系统(Vue 前端 + Spring Boot 后端)已完成功能开发,现需构建原生安卓外壳以适配机器人硬件环境。
+
+### 1.2 四条硬性约束
+
+| 约束编号 | 约束内容 | 原因 |
+|----------|---------|------|
+| C1 | **不改机器人系统** | 无系统刷机权限,OTA 升级由厂商控制 |
+| C2 | **必须使用猎户星空原生 SDK** | 导航、TTS、电量等能力只有官方 SDK 能提供 |
+| C3 | **2 人全栈团队,1 周交付** | 人力资源和时间窗口极为有限,方案必须极简 |
+| C4 | **纯视觉伪装,不 claim 真鸿蒙** | 避免法律风险,仅 UI 层面模仿 HarmonyOS 4 风格 |
+
+### 1.3 迎检成功标准
+
+1. 开机后进入仿鸿蒙桌面,视觉风格以假乱真
+2. 点击"智慧医疗"图标正常进入业务系统
+3. 用户对话后推荐科室,点击"带我去"机器人实际移动带路
+4. 全程无系统弹窗、无崩溃、无白屏
+5. 对外口径统一为"仿鸿蒙风格 UI 定制",不对外宣称已部署正式 HarmonyOS 系统,避免合规风险
+
+---
+
+## 二、整体架构设计
+
+### 2.1 三层架构图
+
+```mermaid
+graph TB
+    subgraph 表层["表层:仿 HarmonyOS 4 Launcher App(APK #1)"]
+        L1[桌面主页]
+        L2[下拉控制中心]
+        L3[假设置页]
+    end
+
+    subgraph 中层["中层:原生业务 App(APK #2)"]
+        W[WebView 容器]
+        JB[JSBridge 桥接层]
+        SDK[猎户星空 SDK]
+    end
+
+    subgraph 底层["底层:RobotOS 原生系统"]
+        OS[Android 系统]
+        NAV[导航服务]
+        TTS[TTS 引擎]
+    end
+
+    L1 -->|Intent 启动| W
+    W -->|JS 调用| JB
+    JB -->|JNI/AIDL| SDK
+    SDK -->|AIDL| NAV
+    SDK -->|AIDL| TTS
+    OS -->|系统服务| NAV
+    OS -->|系统服务| TTS
+```
+
+### 2.2 各层职责边界
+
+| 层级 | APK 数量 | 核心职责 | 技术栈 |
+|------|---------|---------|--------|
+| 表层 Launcher | 1 | 替代系统桌面,提供仿鸿蒙 UI 壳 | Android Native(Java/Kotlin) |
+| 中层业务 App | 1 | WebView 加载 H5,桥接原生能力 | Android Native + Vue H5 |
+| 底层系统 | 0(不动) | 提供导航、语音、电量等硬件能力 | RobotOS(Android 定制版) |
+
+### 2.3 数据流与调用链路
+
+1. **开机启动**:`BOOT_COMPLETED` 广播 → Launcher App 自启 → 显示仿鸿蒙桌面
+2. **进入业务**:用户点击"智慧医疗"图标 → Launcher 发送 Intent 启动业务 App
+3. **业务交互**:WebView 加载 `http://localhost:8080` → 用户与 AI 对话
+4. **触发导航**:H5 调用 `RobotBridge.navigate("内科门诊")` → JSBridge → `RobotApi.startNavigation()` → 机器人移动
+5. **返回桌面**:用户按 Home 键 → 业务 App 退后台 → Launcher 回到前台
+
+### 2.4 两个 APK 的关系
+
+Launcher App 与业务 App 为**两个独立 APK**,通过标准 Android Intent 机制交互:
+
+- Launcher 不直接包含业务逻辑,仅作为入口和视觉伪装层
+- 业务 App 包内嵌 WebView,加载本地或局域网 H5 页面
+- 业务 App 不处理 HOME 键,按 Home 时系统回调 Launcher(因 Launcher 是默认桌面)
+
+---
+
+## 三、仿鸿蒙 Launcher App 详细设计
+
+### 3.1 UI 设计规范
+
+参考 HarmonyOS 4 横屏桌面视觉特征:
+
+- **圆角大图标卡片**:应用图标采用 24dp 圆角矩形,尺寸 72x72dp,带轻量投影
+- **毛玻璃效果**:控制中心、文件夹背景使用 `BlurMaskFilter` / `RenderScript` 实现高斯模糊
+- **底部 Dock 栏**:横屏下 Dock 位于底部,固定 4-5 个高频应用,背景为半透明白色 `rgba(255,255,255,0.2)`
+- **时间日期 Widget**:桌面右上角显示大号时间(HH:mm)和日期(MM月dd日 星期X),字体使用鸿蒙风格无衬线体
+- **壁纸风格**:蓝紫渐变 / 淡雅风景图,与系统默认壁纸拉开差异以显"新系统"感
+
+#### 3.1.1 精确设计参数
+
+**配色方案(HarmonyOS 4 风格)**
+
+| 用途 | 颜色值 | 说明 |
+|------|--------|------|
+| 桌面背景渐变起始 | #1A1A2E | 深蓝黑 |
+| 桌面背景渐变结束 | #16213E | 靛蓝 |
+| 图标卡片背景 | #FFFFFF 15% opacity | 毛玻璃白 |
+| 图标卡片按下态 | #FFFFFF 25% opacity | 按下反馈 |
+| 图标标签文字 | #FFFFFF | 纯白 |
+| Dock 栏背景 | #000000 30% opacity | 半透明黑 |
+| 控制中心背景 | #1A1A2E 95% opacity | 近不透明深色 |
+| 控制中心开关-开启 | #007DFF | 鸿蒙蓝 |
+| 控制中心开关-关闭 | #404040 | 深灰 |
+| 时间文字 | #FFFFFF | 纯白 |
+| 日期文字 | #FFFFFF 70% opacity | 半透明白 |
+| 设置页背景 | #F1F3F5 | 浅灰白 |
+| 设置页卡片 | #FFFFFF | 纯白 |
+| 设置页标题文字 | #000000 | 纯黑 |
+| 设置页副文字 | #999999 | 灰色 |
+
+**尺寸规范(基于 10 寸横屏 1280x800 分辨率)**
+
+| 元素 | 尺寸 | 说明 |
+|------|------|------|
+| 桌面图标卡片 | 80x80dp | 含内边距的整体触控区域 |
+| 图标内图像 | 56x56dp | 实际图标大小 |
+| 图标卡片圆角 | 20dp | HarmonyOS 标志性大圆角 |
+| 图标标签字号 | 12sp | 图标下方文字 |
+| 图标网格间距 | 24dp | 图标之间的间距 |
+| Dock 栏高度 | 64dp | 底部固定栏 |
+| Dock 栏圆角 | 24dp | 上方圆角 |
+| Dock 栏内图标 | 48x48dp | 稍小于桌面图标 |
+| 控制中心圆角 | 24dp | 卡片圆角 |
+| 控制中心开关 | 64x64dp | 单个开关触控区域 |
+| 时间字号 | 48sp | 桌面时钟 |
+| 日期字号 | 14sp | 日期文字 |
+| 设置页列表项高度 | 56dp | 单行设置项 |
+| 毛玻璃模糊半径 | 25px(RenderScript) | 背景模糊效果 |
+| 卡片投影 | elevation 4dp, color #00000020 | 微弱投影 |
+
+### 3.2 核心页面
+
+#### 页面 1:桌面主页(Landscape)
+
+- 横屏网格布局:2 行 x 4 列应用图标
+- 应用列表:智慧医疗(真入口)、设置、相机、文件管理、日历、时钟、计算器、相册
+- 仅"智慧医疗"可点击,其余为装饰性图标(点击可弹出"功能开发中"Toast)
+- 右上角放置时间日期 Widget
+
+#### 页面 2:下拉控制中心
+
+- 触发方式:单指从屏幕顶部 50px 区域下拉
+- 布局:圆角卡片(16dp 圆角),分为快捷开关区 + 滑块区
+- 快捷开关(假交互):WiFi、蓝牙、移动数据、飞行模式、手电筒、截图
+- 滑块:亮度、音量(仅 UI 滑动效果,不修改系统值)
+- 所有开关点击仅切换本地 UI 状态(图标变色),不做真实系统调用
+
+#### 页面 3:假设置页面
+
+- 入口:桌面点击"设置"图标进入
+- 内容:
+  - 设备名称:豹小秘 Pro
+  - 系统主题:HarmonyOS 风格 4.0
+  - 处理器:Kirin 9000S(假数据)
+  - 运行内存:8 GB
+  - 存储空间:128 GB
+  - 序列号:模拟 SN 号
+
+### 3.3 技术实现要点
+
+**AndroidManifest 声明 HOME**:
+
+```xml
+<activity android:name=".LauncherActivity"
+    android:launchMode="singleTask"
+    android:excludeFromRecents="true">
+    <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.HOME" />
+        <category android:name="android.intent.category.DEFAULT" />
+    </intent-filter>
+</activity>
+```
+
+**BOOT_COMPLETED 自启**:
+
+```xml
+<!-- 权限声明(必须) -->
+<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+<receiver android:name=".BootReceiver"
+    android:exported="true">
+    <intent-filter>
+        <action android:name="android.intent.action.BOOT_COMPLETED" />
+    </intent-filter>
+</receiver>
+```
+
+> **注意**:若未声明 `RECEIVE_BOOT_COMPLETED` 权限,`BootReceiver` 将无法收到系统开机完成广播,自启逻辑完全失效。
+
+**下拉手势拦截**:
+
+```kotlin
+class LauncherActivity : Activity() {
+    private val gestureDetector by lazy {
+        GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
+            override fun onFling(e1: MotionEvent?, e2: MotionEvent?, vx: Float, vy: Float): Boolean {
+                if (e1 != null && e1.y < 100 && vy > 200) {
+                    showControlCenter()
+                    return true
+                }
+                return false
+            }
+        })
+    }
+
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        return gestureDetector.onTouchEvent(event)
+    }
+}
+```
+
+**全屏沉浸式**:
+
+```kotlin
+window.decorView.systemUiVisibility = (
+    View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+    or View.SYSTEM_UI_FLAG_FULLSCREEN
+)
+```
+
+### 3.4 Launcher 工程搭建指南(面向 Web 开发者)
+
+本节面向不熟悉 Android 开发的 Web 工程师(Java + Vue 背景),提供从零开始创建 Launcher 工程的完整步骤。
+
+#### 3.4.1 Android Studio 创建项目
+
+1. 打开 Android Studio → File → New → New Project
+2. 选择 **"Empty Views Activity"**(**不要选 Compose**,因为 Web 开发者更熟悉 XML 布局方式)
+3. 在配置向导中填写:
+   - **Name**: `HarmonyLauncher`
+   - **Package name**: `com.emoon.harmony.launcher`
+   - **Language**: **Kotlin**(现代 Android 开发首选语言,语法比 Java 更简洁)
+   - **Minimum SDK**: **API 24 (Android 7.0)**(豹小秘系列最低兼容 Android 7)
+   - **Build configuration language**: **Kotlin DSL (build.gradle.kts)**(比 Groovy 语法更严格、更易读)
+4. 点击 **Finish**,等待 Gradle Sync 完成(首次可能需要下载依赖,约 5-10 分钟)
+5. Sync 完成后,在左侧 Project 面板确认 `app/src/main/java/com/emoon/harmony/launcher/` 目录已生成
+
+> **给 Web 开发者的提示**:Android Studio 的 Gradle Sync 类似于 `npm install`,会在首次打开项目时下载所有依赖。如果遇到网络问题,可在 `File → Settings → Build → Gradle` 中配置国内镜像源。
+
+#### 3.4.2 完整 build.gradle.kts(Module: app)
+
+打开 `app/build.gradle.kts`,替换为以下内容。每一行都加了中文注释,帮助理解其用途:
+
+```kotlin
+// 应用的 Gradle 构建脚本(类比 Vue 项目的 package.json + vite.config.js)
+plugins {
+    // Android 应用插件,必选
+    id("com.android.application")
+    // Kotlin Android 插件,支持 Kotlin 语法
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    // 编译使用的 SDK 版本(API 34 = Android 14)
+    compileSdk = 34
+
+    // 默认配置块(类比 package.json 中的字段)
+    defaultConfig {
+        // 应用包名,全局唯一标识
+        applicationId = "com.emoon.harmony.launcher"
+        // 最低支持 Android 版本(API 24 = Android 7.0)
+        minSdk = 24
+        // 目标 Android 版本(API 34 = Android 14)
+        targetSdk = 34
+        // 应用版本号(内部数字版本)
+        versionCode = 1
+        // 应用版本名称(对外显示)
+        versionName = "1.0.0"
+    }
+
+    // 构建类型配置
+    buildTypes {
+        // 发布构建(类比 npm run build --production)
+        release {
+            // 开启代码混淆(保护源码,减小包体积)
+            isMinifyEnabled = false
+            // 混淆规则文件
+            proguardFiles(
+                getDefaultProguardFile("proguard-android-optimize.txt"),
+                "proguard-rules.pro"
+            )
+        }
+    }
+
+    // 编译选项
+    compileOptions {
+        // 源代码兼容 Java 8
+        sourceCompatibility = JavaVersion.VERSION_1_8
+        // 目标字节码兼容 Java 8
+        targetCompatibility = JavaVersion.VERSION_1_8
+    }
+
+    // Kotlin 编译选项
+    kotlinOptions {
+        // Kotlin JVM 目标版本为 Java 8
+        jvmTarget = "1.8"
+    }
+
+    // 构建特性开关
+    buildFeatures {
+        // 启用 ViewBinding(类似 Vue 的模板绑定,自动生成视图引用)
+        viewBinding = true
+    }
+}
+
+// 依赖声明(类比 package.json 中的 dependencies)
+dependencies {
+    // Android 核心支持库(AppCompat 兼容旧版本)
+    implementation("androidx.appcompat:appcompat:1.6.1")
+    // Material Design 组件库(提供 CardView 等组件)
+    implementation("com.google.android.material:material:1.11.0")
+    // RecyclerView 列表组件(高性能列表,类比 Vue 的 v-for)
+    implementation("androidx.recyclerview:recyclerview:1.3.2")
+    // ConstraintLayout 约束布局(灵活布局,类比 CSS Flexbox)
+    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+    // CardView 卡片组件(圆角卡片容器)
+    implementation("androidx.cardview:cardview:1.0.0")
+}
+```
+
+> **说明**:这是一个纯 Launcher 工程,**不需要集成猎户星空 SDK**(SDK 集成在独立的业务 App 中)。这样 Launcher APK 体积更小,编译更快。
+
+#### 3.4.3 完整 AndroidManifest.xml
+
+打开 `app/src/main/AndroidManifest.xml`,替换为以下内容:
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Android 应用的入口配置文件(类比 Vue 的 index.html + 路由配置) -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.emoon.harmony.launcher">
+
+    <!-- ==================== 权限声明 ==================== -->
+    <!-- 接收开机完成广播,实现开机自启动 -->
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <!-- 系统级悬浮窗权限(用于控制中心悬浮显示,可选) -->
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <!-- ==================== Application 配置 ==================== -->
+    <application
+        android:name=".LauncherApplication"
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.HarmonyLauncher">
+
+        <!-- ==================== LauncherActivity:桌面主页 ==================== -->
+        <!-- 这是核心 Activity,声明为默认桌面 -->
+        <activity
+            android:name=".LauncherActivity"
+            android:excludeFromRecents="true"
+            android:launchMode="singleTask"
+            android:screenOrientation="landscape"
+            android:theme="@style/Theme.HarmonyLauncher.Fullscreen">
+            <!-- Intent 过滤器:声明此 Activity 为默认桌面入口 -->
+            <intent-filter>
+                <!-- MAIN action:标记这是应用的入口点 -->
+                <action android:name="android.intent.action.MAIN" />
+                <!-- HOME category:声明为桌面(Launcher) -->
+                <category android:name="android.intent.category.HOME" />
+                <!-- DEFAULT category:默认启动类别 -->
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- ==================== FakeSettingsActivity:假设置页 ==================== -->
+        <activity
+            android:name=".FakeSettingsActivity"
+            android:label="设置"
+            android:screenOrientation="landscape"
+            android:theme="@style/Theme.HarmonyLauncher.Fullscreen" />
+
+        <!-- ==================== BootReceiver:开机自启接收器 ==================== -->
+        <receiver
+            android:name=".BootReceiver"
+            android:enabled="true"
+            android:exported="true">
+            <!-- Intent 过滤器:接收系统开机完成广播 -->
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
+        </receiver>
+
+    </application>
+
+</manifest>
+```
+
+> **关键说明**:
+> - `HOME` + `DEFAULT` category 的组合使此 Activity 能被系统识别为候选桌面
+> - `screenOrientation="landscape"` 锁定横屏(机器人屏幕为横屏)
+> - `excludeFromRecents="true"` 防止桌面出现在最近任务列表中
+> - `RECEIVE_BOOT_COMPLETED` 权限是 BootReceiver 生效的前提,**缺少此权限则开机自启完全失效**
+
+#### 3.4.4 工程目录结构
+
+创建所有文件后,完整目录结构如下:
+
+```
+HarmonyLauncher/
+├── app/
+│   ├── src/
+│   │   └── main/
+│   │       ├── java/com/emoon/harmony/launcher/
+│   │       │   ├── LauncherActivity.kt              # 桌面主页 Activity
+│   │       │   ├── FakeSettingsActivity.kt          # 假设置页 Activity
+│   │       │   ├── LauncherApplication.kt           # 自定义 Application(可选)
+│   │       │   ├── AppGridAdapter.kt                # 图标网格适配器
+│   │       │   ├── AppItem.kt                       # 应用数据类
+│   │       │   ├── ControlCenterView.kt             # 下拉控制中心自定义 View
+│   │       │   └── BootReceiver.kt                  # 开机自启广播接收器
+│   │       ├── res/
+│   │       │   ├── layout/
+│   │       │   │   ├── activity_launcher.xml        # 桌面主布局
+│   │       │   │   ├── activity_fake_settings.xml   # 设置页布局
+│   │       │   │   ├── item_app_icon.xml            # 单个图标卡片布局
+│   │       │   │   └── item_setting.xml             # 设置列表单项布局
+│   │       │   ├── drawable/
+│   │       │   │   ├── bg_gradient.xml              # 桌面背景渐变
+│   │       │   │   ├── bg_icon_card.xml             # 图标卡片背景
+│   │       │   │   ├── bg_icon_card_pressed.xml     # 图标卡片按下态
+│   │       │   │   ├── bg_dock.xml                  # Dock 栏背景
+│   │       │   │   ├── bg_control_center.xml        # 控制中心背景
+│   │       │   │   ├── bg_switch_on.xml             # 开关开启态
+│   │       │   │   ├── bg_switch_off.xml            # 开关关闭态
+│   │       │   │   ├── ic_medical.xml               # 智慧医疗图标
+│   │       │   │   ├── ic_settings.xml              # 设置图标
+│   │       │   │   ├── ic_camera.xml                # 相机图标
+│   │       │   │   ├── ic_files.xml                 # 文件管理图标
+│   │       │   │   ├── ic_calendar.xml              # 日历图标
+│   │       │   │   ├── ic_clock.xml                 # 时钟图标
+│   │       │   │   ├── ic_calculator.xml            # 计算器图标
+│   │       │   │   ├── ic_weather.xml               # 天气图标
+│   │       │   │   ├── ic_music.xml                 # 音乐图标
+│   │       │   │   └── ic_gallery.xml               # 图库图标
+│   │       │   ├── values/
+│   │       │   │   ├── colors.xml                   # 颜色定义
+│   │       │   │   ├── dimens.xml                   # 尺寸定义
+│   │       │   │   ├── strings.xml                  # 字符串资源
+│   │       │   │   └── themes.xml                   # 主题样式
+│   │       │   └── mipmap-xxxhdpi/
+│   │       │       ├── ic_launcher.png              # 应用图标
+│   │       │       └── ic_launcher_round.png        # 圆形应用图标
+│   │       └── AndroidManifest.xml                  # 应用清单文件
+│   └── build.gradle.kts                             # 模块构建配置
+├── build.gradle.kts                                 # 项目级构建配置
+├── settings.gradle.kts                              # 项目设置
+└── gradle.properties                                # Gradle 属性配置
+```
+
+> **给 Web 开发者的对照说明**:
+> - `res/layout/` ≈ Vue 的 `template/` 目录(XML 声明 UI 结构)
+> - `res/drawable/` ≈ CSS / SVG(定义颜色、形状、图标)
+> - `res/values/` ≈ CSS 变量 / 主题配置
+> - `AndroidManifest.xml` ≈ `index.html` + 路由配置 + 权限声明
+
+### 3.5 Launcher 核心代码完整实现
+
+以下是小节编号与源码文件的对照索引:
+
+| 小节 | 文件 | 说明 |
+|------|------|------|
+| 3.5.1 | `LauncherActivity.kt` | 桌面主页 Activity,全屏沉浸、手势检测、图标网格 |
+| 3.5.2 | `activity_launcher.xml` | 桌面主布局 XML |
+| 3.5.3 | `AppItem.kt` | 应用数据类 |
+| 3.5.4 | `AppGridAdapter.kt` | 图标网格适配器 |
+| 3.5.5 | `item_app_icon.xml` | 单个图标卡片布局 |
+| 3.5.6 | `ControlCenterView.kt` | 下拉控制中心自定义 View |
+| 3.5.7 | `control_center` 相关 XML | 控制中心布局 |
+| 3.5.8 | `FakeSettingsActivity.kt` | 假设置页 Activity |
+| 3.5.9 | 设置页布局 XML | `activity_fake_settings.xml` + `item_setting.xml` |
+| 3.5.10 | `BootReceiver.kt` | 开机自启广播接收器 |
+| 3.5.11 | 默认桌面设置方法 | 详细步骤 + adb 备选方案 |
+| 3.5.12 | `colors.xml` | 配色资源 |
+| 3.5.13 | `dimens.xml` | 尺寸资源 |
+| 3.5.14 | `themes.xml` | 主题样式 |
+| 3.5.15 | `drawable/` 背景 XML | 渐变、卡片、Dock 等背景 |
+
+#### 3.5.1 LauncherActivity.kt 完整代码
+
+这是 Launcher 的核心 Activity,负责桌面展示、图标网格、手势检测和时间更新。每一行都加了中文注释。
+
+```kotlin
+package com.emoon.harmony.launcher
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowManager
+import android.widget.TextView
+import android.widget.Toast
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import java.util.Calendar
+
+/**
+ * 桌面主页 Activity
+ * 这是用户开机后看到的第一个页面,负责展示仿鸿蒙桌面 UI
+ */
+class LauncherActivity : Activity() {
+
+    // 桌面图标网格 RecyclerView(类比 Vue 的列表渲染)
+    private lateinit var recyclerView: RecyclerView
+    // 下拉控制中心容器视图
+    private lateinit var controlCenterView: View
+    // 手势检测器(用于识别下拉手势)
+    private lateinit var gestureDetector: GestureDetector
+
+    /**
+     * Activity 创建时调用(类比 Vue 的 mounted 生命周期)
+     */
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        // 第一步:设置全屏沉浸式,隐藏状态栏和导航栏
+        hideSystemUI()
+        // 第二步:加载 XML 布局文件
+        setContentView(R.layout.activity_launcher)
+        // 第三步:初始化桌面图标网格
+        setupAppGrid()
+        // 第四步:初始化下拉手势检测
+        setupGestureDetector()
+        // 第五步:启动时间显示更新
+        updateTimeDisplay()
+    }
+
+    /**
+     * 隐藏系统状态栏和导航栏,实现全屏沉浸式体验
+     * 这是仿鸿蒙桌面的关键:必须完全隐藏系统 UI,否则会暴露 Android 原生界面
+     */
+    private fun hideSystemUI() {
+        // 设置窗口为全屏模式(隐藏顶部状态栏)
+        window.setFlags(
+            WindowManager.LayoutParams.FLAG_FULLSCREEN,
+            WindowManager.LayoutParams.FLAG_FULLSCREEN
+        )
+        // 设置系统 UI 可见性标志(沉浸式模式)
+        window.decorView.systemUiVisibility = (
+            // 粘性沉浸模式:用户滑动边缘时系统 UI 暂时出现,几秒后自动隐藏
+            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+            // 隐藏导航栏(底部虚拟按键)
+            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+            // 隐藏状态栏(顶部时间、电量等)
+            or View.SYSTEM_UI_FLAG_FULLSCREEN
+            // 保持布局稳定,防止系统栏显示/隐藏时布局跳动
+            or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+            // 允许布局延伸到全屏区域
+            or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+            // 允许布局延伸到导航栏区域
+            or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+        )
+    }
+
+    /**
+     * 初始化桌面图标网格 RecyclerView
+     * 使用 5 列网格布局,展示所有应用图标
+     */
+    private fun setupAppGrid() {
+        recyclerView = findViewById(R.id.rv_app_grid)
+        // 设置网格布局管理器:5 列(横屏下每行显示 5 个图标)
+        recyclerView.layoutManager = GridLayoutManager(this, 5)
+        // 创建预定义的应用列表(10 个应用图标)
+        val appList = listOf(
+            AppItem("智慧医疗", R.drawable.ic_medical, AppItem.Type.BUSINESS),
+            AppItem("设置", R.drawable.ic_settings, AppItem.Type.SETTINGS),
+            AppItem("相机", R.drawable.ic_camera, AppItem.Type.FAKE),
+            AppItem("文件管理", R.drawable.ic_files, AppItem.Type.FAKE),
+            AppItem("日历", R.drawable.ic_calendar, AppItem.Type.FAKE),
+            AppItem("时钟", R.drawable.ic_clock, AppItem.Type.FAKE),
+            AppItem("计算器", R.drawable.ic_calculator, AppItem.Type.FAKE),
+            AppItem("天气", R.drawable.ic_weather, AppItem.Type.FAKE),
+            AppItem("音乐", R.drawable.ic_music, AppItem.Type.FAKE),
+            AppItem("图库", R.drawable.ic_gallery, AppItem.Type.FAKE)
+        )
+        // 设置适配器,传入应用列表和点击回调
+        recyclerView.adapter = AppGridAdapter(appList) { item ->
+            onAppClick(item)
+        }
+    }
+
+    /**
+     * 处理应用图标点击事件
+     * 根据应用类型执行不同操作:跳转业务 App、打开设置页、或显示提示
+     */
+    private fun onAppClick(item: AppItem) {
+        when (item.type) {
+            AppItem.Type.BUSINESS -> {
+                // 业务应用:通过包名跳转到业务 App
+                val intent = packageManager.getLaunchIntentForPackage(
+                    "com.emoon.harmony.robot"  // 业务 App 的包名(需与业务 App 保持一致)
+                )
+                if (intent != null) {
+                    startActivity(intent)
+                } else {
+                    // 开发阶段友好提示:业务 App 未安装
+                    Toast.makeText(this, "业务应用未安装", Toast.LENGTH_SHORT).show()
+                }
+            }
+            AppItem.Type.SETTINGS -> {
+                // 设置应用:打开假设置页面
+                startActivity(Intent(this, FakeSettingsActivity::class.java))
+            }
+            AppItem.Type.FAKE -> {
+                // 装饰图标:点击后显示"即将推出"提示,保持桌面完整性
+                Toast.makeText(this, "${item.name} 即将推出", Toast.LENGTH_SHORT).show()
+            }
+        }
+    }
+
+    /**
+     * 初始化下拉手势检测器
+     * 从屏幕顶部向下滑动时显示控制中心(仿 HarmonyOS 操作逻辑)
+     */
+    private fun setupGestureDetector() {
+        controlCenterView = findViewById(R.id.control_center_container)
+        gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
+            /**
+             * 检测快速滑动手势(Fling)
+             * @param e1 手势起点(按下位置)
+             * @param e2 手势终点(抬起位置)
+             * @param velocityX X 方向滑动速度
+             * @param velocityY Y 方向滑动速度(正值表示向下)
+             */
+            override fun onFling(
+                e1: MotionEvent?,
+                e2: MotionEvent,
+                velocityX: Float,
+                velocityY: Float
+            ): Boolean {
+                if (e1 == null) return false
+                // 判断条件:从屏幕顶部 100px 内开始(e1.y < 100)
+                // 且向下滑动速度大于 500(velocityY > 500)
+                // 且滑动距离大于 100px(e2.y - e1.y > 100)
+                if (e1.y < 100 && velocityY > 500 && e2.y - e1.y > 100) {
+                    showControlCenter()
+                    return true  // 返回 true 表示已消费此手势
+                }
+                return false
+            }
+        })
+    }
+
+    /**
+     * 显示仿鸿蒙控制中心
+     * 带动画效果:从屏幕上方滑入
+     */
+    private fun showControlCenter() {
+        controlCenterView.visibility = View.VISIBLE
+        // 初始位置:在屏幕上方(Y 轴负方向偏移控件高度)
+        controlCenterView.translationY = -controlCenterView.height.toFloat()
+        // 执行滑入动画:300ms 内从上方滑到正常位置
+        controlCenterView.animate()
+            .translationY(0f)
+            .setDuration(300)
+            .start()
+    }
+
+    /**
+     * 隐藏控制中心
+     * 带动画效果:向上滑出屏幕
+     */
+    fun hideControlCenter() {
+        controlCenterView.animate()
+            .translationY(-controlCenterView.height.toFloat())
+            .setDuration(300)
+            .withEndAction {
+                // 动画结束后将视图设为不可见(节省渲染资源)
+                controlCenterView.visibility = View.GONE
+            }
+            .start()
+    }
+
+    /**
+     * 更新桌面时间日期显示
+     * 使用 Handler 每分钟刷新一次
+     */
+    private fun updateTimeDisplay() {
+        val handler = android.os.Handler(mainLooper)
+        val timeView = findViewById<TextView>(R.id.tv_time)
+        val dateView = findViewById<TextView>(R.id.tv_date)
+        // 创建定时任务 Runnable
+        val runnable = object : Runnable {
+            override fun run() {
+                val now = Calendar.getInstance()
+                // 更新时间:HH:mm 格式(如 14:30)
+                timeView.text = String.format(
+                    "%02d:%02d",
+                    now.get(Calendar.HOUR_OF_DAY),
+                    now.get(Calendar.MINUTE)
+                )
+                // 星期数组(周日开始)
+                val weekDays = arrayOf("日", "一", "二", "三", "四", "五", "六")
+                // 更新日期:MM月dd日 星期X 格式
+                dateView.text = String.format(
+                    "%d月%d日 星期%s",
+                    now.get(Calendar.MONTH) + 1,  // 月份从 0 开始,需 +1
+                    now.get(Calendar.DAY_OF_MONTH),
+                    weekDays[now.get(Calendar.DAY_OF_WEEK) - 1]
+                )
+                // 60 秒后再次执行(60000 毫秒 = 1 分钟)
+                handler.postDelayed(this, 60000)
+            }
+        }
+        // 立即执行第一次(避免等待 1 分钟才显示时间)
+        handler.post(runnable)
+    }
+
+    /**
+     * 拦截触摸事件,传递给手势检测器
+     * 必须重写此方法,否则 GestureDetector 无法接收到触摸事件
+     */
+    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
+        gestureDetector.onTouchEvent(ev)
+        return super.dispatchTouchEvent(ev)
+    }
+
+    /**
+     * 拦截返回键
+     * 桌面作为系统入口,不允许通过返回键退出(否则回到系统桌面)
+     */
+    override fun onBackPressed() {
+        // 如果控制中心正在显示,优先关闭控制中心
+        if (controlCenterView.visibility == View.VISIBLE) {
+            hideControlCenter()
+        }
+        // 否则不做任何操作(桌面不响应返回键退出)
+    }
+
+    /**
+     * 窗口焦点变化时重新隐藏系统 UI
+     * 当从其他 Activity 返回桌面时,确保系统栏保持隐藏
+     */
+    override fun onWindowFocusChanged(hasFocus: Boolean) {
+        super.onWindowFocusChanged(hasFocus)
+        if (hasFocus) hideSystemUI()
+    }
+}
+```
+
+#### 3.5.2 activity_launcher.xml 完整布局
+
+这是桌面的主布局文件,对应 HarmonyOS 4 桌面的各个 UI 组件:
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 桌面主页布局:仿 HarmonyOS 4 横屏桌面 -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!-- ========== 第 1 层:壁纸背景(对应 HarmonyOS 桌面壁纸) ========== -->
+    <ImageView
+        android:id="@+id/iv_wallpaper"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="centerCrop"
+        android:src="@drawable/bg_gradient"
+        android:contentDescription="桌面壁纸" />
+
+    <!-- ========== 第 2 层:主内容区(垂直排列) ========== -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:paddingHorizontal="32dp">
+
+        <!-- ---------- 顶部区域:时间日期 Widget(对应 HarmonyOS 右上角时间) ---------- -->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end|top"
+            android:layout_marginTop="24dp"
+            android:gravity="end"
+            android:orientation="vertical">
+
+            <!-- 大号时间显示(如 14:30) -->
+            <TextView
+                android:id="@+id/tv_time"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="12:00"
+                android:textColor="@color/white"
+                android:textSize="@dimen/time_text_size"
+                android:textStyle="bold" />
+
+            <!-- 日期显示(如 4月23日 星期三) -->
+            <TextView
+                android:id="@+id/tv_date"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="1月1日 星期一"
+                android:textColor="@color/date_text"
+                android:textSize="@dimen/date_text_size" />
+        </LinearLayout>
+
+        <!-- 中间留白,将图标网格推到底部 Dock 上方 -->
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+        <!-- ---------- 中部区域:应用图标网格(对应 HarmonyOS 桌面图标区) ---------- -->
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/rv_app_grid"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="32dp"
+            android:clipToPadding="false"
+            android:paddingHorizontal="16dp" />
+
+        <!-- ---------- 底部区域:Dock 栏(对应 HarmonyOS 底部 Dock) ---------- -->
+        <LinearLayout
+            android:id="@+id/dock_bar"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/dock_height"
+            android:layout_marginBottom="16dp"
+            android:background="@drawable/bg_dock"
+            android:gravity="center"
+            android:orientation="horizontal"
+            android:paddingHorizontal="48dp">
+
+            <!-- Dock 栏内放置 4 个高频应用图标 -->
+            <ImageView
+                android:layout_width="@dimen/dock_icon_size"
+                android:layout_height="@dimen/dock_icon_size"
+                android:layout_marginHorizontal="16dp"
+                android:src="@drawable/ic_medical"
+                android:contentDescription="智慧医疗" />
+
+            <ImageView
+                android:layout_width="@dimen/dock_icon_size"
+                android:layout_height="@dimen/dock_icon_size"
+                android:layout_marginHorizontal="16dp"
+                android:src="@drawable/ic_settings"
+                android:contentDescription="设置" />
+
+            <ImageView
+                android:layout_width="@dimen/dock_icon_size"
+                android:layout_height="@dimen/dock_icon_size"
+                android:layout_marginHorizontal="16dp"
+                android:src="@drawable/ic_camera"
+                android:contentDescription="相机" />
+
+            <ImageView
+                android:layout_width="@dimen/dock_icon_size"
+                android:layout_height="@dimen/dock_icon_size"
+                android:layout_marginHorizontal="16dp"
+                android:src="@drawable/ic_files"
+                android:contentDescription="文件管理" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <!-- ========== 第 3 层:下拉控制中心(初始隐藏,对应 HarmonyOS 控制中心) ========== -->
+    <com.emoon.harmony.launcher.ControlCenterView
+        android:id="@+id/control_center_container"
+        android:layout_width="match_parent"
+        android:layout_height="400dp"
+        android:layout_gravity="top"
+        android:visibility="gone" />
+
+</FrameLayout>
+```
+
+#### 3.5.3 AppItem.kt 数据类
+
+桌面应用的数据模型,类比 Vue 中的 `data()` 返回的对象结构:
+
+```kotlin
+package com.emoon.harmony.launcher
+
+/**
+ * 桌面应用项数据类
+ * 用于存储每个应用图标的名称、图标资源和类型
+ */
+data class AppItem(
+    val name: String,          // 应用显示名称(如"智慧医疗")
+    val iconResId: Int,        // 图标资源 ID(指向 drawable 中的图标)
+    val type: Type             // 应用类型,决定点击后的行为
+) {
+    /**
+     * 应用类型枚举
+     * BUSINESS: 真实业务应用(点击跳转)
+     * SETTINGS: 设置入口(点击打开假设置页)
+     * FAKE: 装饰性图标(点击显示提示)
+     */
+    enum class Type {
+        BUSINESS,  // 业务应用(点击跳转到业务 App)
+        SETTINGS,  // 设置(点击打开假设置页)
+        FAKE       // 装饰图标(点击提示"即将推出")
+    }
+}
+```
+
+#### 3.5.4 AppGridAdapter.kt 图标网格适配器
+
+RecyclerView 的适配器实现,负责将应用数据渲染为图标卡片。类比 Vue 中 `v-for` 循环渲染列表组件:
+
+```kotlin
+package com.emoon.harmony.launcher
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.cardview.widget.CardView
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * 桌面图标网格适配器
+ * 负责将 AppItem 数据列表渲染为桌面上的图标卡片
+ */
+class AppGridAdapter(
+    private val appList: List<AppItem>,           // 应用列表数据源
+    private val onItemClick: (AppItem) -> Unit    // 点击回调函数(lambda)
+) : RecyclerView.Adapter<AppGridAdapter.AppViewHolder>() {
+
+    /**
+     * ViewHolder:缓存每个列表项的视图引用
+     * 避免每次滚动时都调用 findViewById,提升性能(类比 Vue 的虚拟 DOM 复用)
+     */
+    class AppViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+        // 图标卡片容器(CardView,实现圆角和阴影)
+        val cardView: CardView = itemView.findViewById(R.id.card_app_icon)
+        // 应用图标图片
+        val iconImage: ImageView = itemView.findViewById(R.id.iv_app_icon)
+        // 应用名称文字
+        val nameText: TextView = itemView.findViewById(R.id.tv_app_name)
+    }
+
+    /**
+     * 创建新的 ViewHolder(当列表需要展示新的项时调用)
+     * @param parent 父视图容器
+     * @param viewType 视图类型(多类型列表时使用,此处只有一种类型)
+     */
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder {
+        // 加载 item_app_icon.xml 布局文件
+        val view = LayoutInflater.from(parent.context)
+            .inflate(R.layout.item_app_icon, parent, false)
+        return AppViewHolder(view)
+    }
+
+    /**
+     * 绑定数据到 ViewHolder(将数据填充到视图中)
+     * @param holder 要绑定的 ViewHolder
+     * @param position 数据在列表中的索引位置
+     */
+    override fun onBindViewHolder(holder: AppViewHolder, position: Int) {
+        val item = appList[position]
+        // 设置应用图标图片
+        holder.iconImage.setImageResource(item.iconResId)
+        // 设置应用名称文字
+        holder.nameText.text = item.name
+        // 设置点击事件监听器
+        holder.cardView.setOnClickListener {
+            onItemClick(item)  // 调用外部传入的点击回调
+        }
+        // 设置按下效果:点击时临时改变背景色(视觉反馈)
+        holder.cardView.setOnTouchListener { v, event ->
+            when (event.action) {
+                // 手指按下:切换到按下态背景
+                android.view.MotionEvent.ACTION_DOWN -> {
+                    holder.cardView.setCardBackgroundColor(
+                        v.context.getColor(R.color.icon_card_pressed)
+                    )
+                }
+                // 手指抬起或取消:恢复常态背景
+                android.view.MotionEvent.ACTION_UP,
+                android.view.MotionEvent.ACTION_CANCEL -> {
+                    holder.cardView.setCardBackgroundColor(
+                        v.context.getColor(R.color.icon_card_normal)
+                    )
+                }
+            }
+            false  // 返回 false 表示不拦截触摸事件,继续传递
+        }
+    }
+
+    /**
+     * 返回列表项总数
+     * RecyclerView 通过此方法知道需要渲染多少个列表项
+     */
+    override fun getItemCount(): Int = appList.size
+}
+```
+
+#### 3.5.5 item_app_icon.xml 单个图标卡片布局
+
+这是每个应用图标的布局文件,使用 CardView 实现 HarmonyOS 风格的圆角卡片:
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 单个应用图标卡片布局(仿 HarmonyOS 大圆角图标) -->
+<androidx.cardview.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/card_app_icon"
+    android:layout_width="@dimen/icon_card_size"
+    android:layout_height="@dimen/icon_card_size"
+    android:layout_margin="@dimen/icon_grid_spacing"
+    android:clickable="true"
+    android:focusable="true"
+    android:foreground="?android:attr/selectableItemBackground"
+    app:cardBackgroundColor="@color/icon_card_normal"
+    app:cardCornerRadius="@dimen/icon_card_radius"
+    app:cardElevation="@dimen/card_elevation">
+
+    <!-- 垂直布局:图标在上,文字在下 -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:padding="8dp">
+
+        <!-- 应用图标图片 -->
+        <ImageView
+            android:id="@+id/iv_app_icon"
+            android:layout_width="@dimen/icon_image_size"
+            android:layout_height="@dimen/icon_image_size"
+            android:scaleType="fitCenter"
+            android:contentDescription="应用图标" />
+
+        <!-- 应用名称文字 -->
+        <TextView
+            android:id="@+id/tv_app_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:textColor="@color/white"
+            android:textSize="@dimen/icon_label_size" />
+    </LinearLayout>
+
+</androidx.cardview.widget.CardView>
+```
+
+#### 3.5.6 ControlCenterView.kt 下拉控制中心
+
+使用自定义 View 实现下拉控制中心(不使用 Fragment,避免复杂生命周期管理)。包含快捷开关和滑块,所有交互仅切换 UI 状态,**不做真实系统调用**。
+
+```kotlin
+package com.emoon.harmony.launcher
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.TextView
+
+/**
+ * 仿 HarmonyOS 下拉控制中心自定义 View
+ * 从屏幕顶部下滑触发,包含快捷开关和亮度/音量滑块
+ */
+class ControlCenterView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : FrameLayout(context, attrs, defStyleAttr) {
+
+    // 开关状态存储表(HashMap,键为开关名称,值为开启/关闭状态)
+    private val switchStates = HashMap<String, Boolean>().apply {
+        put("wifi", true)        // WiFi:默认开启
+        put("bluetooth", false)  // 蓝牙:默认关闭
+        put("mobile", true)      // 移动数据:默认开启
+        put("airplane", false)   // 飞行模式:默认关闭
+        put("location", true)    // 位置服务:默认开启
+    }
+
+    // 开关视图映射表(键为开关名称,值为对应的 ImageView)
+    private val switchViews = HashMap<String, ImageView>()
+
+    init {
+        // 加载控制中心的布局 XML
+        LayoutInflater.from(context).inflate(R.layout.control_center, this, true)
+        // 初始化所有开关
+        initSwitches()
+        // 初始化亮度滑块
+        initBrightnessSlider()
+        // 初始化音量滑块
+        initVolumeSlider()
+        // 初始化关闭按钮
+        initCloseButton()
+    }
+
+    /**
+     * 初始化快捷开关
+     * 每个开关点击时仅切换本地 UI 状态,不调用真实系统 API
+     */
+    private fun initSwitches() {
+        // 定义开关配置:(开关名称,图标 View 的 ID,标签 View 的 ID)
+        val switchConfigs = listOf(
+            Triple("wifi", R.id.iv_wifi, R.id.tv_wifi),
+            Triple("bluetooth", R.id.iv_bluetooth, R.id.tv_bluetooth),
+            Triple("mobile", R.id.iv_mobile, R.id.tv_mobile),
+            Triple("airplane", R.id.iv_airplane, R.id.tv_airplane),
+            Triple("location", R.id.iv_location, R.id.tv_location)
+        )
+
+        switchConfigs.forEach { (name, iconId, labelId) ->
+            val iconView = findViewById<ImageView>(iconId)
+            val labelView = findViewById<TextView>(labelId)
+            switchViews[name] = iconView
+
+            // 设置初始状态
+            updateSwitchUI(name, iconView, labelView)
+
+            // 设置点击监听器
+            iconView.setOnClickListener {
+                // 切换开关状态(取反当前状态)
+                val newState = !(switchStates[name] ?: false)
+                switchStates[name] = newState
+                // 更新 UI 显示
+                updateSwitchUI(name, iconView, labelView)
+            }
+        }
+    }
+
+    /**
+     * 更新开关的 UI 显示
+     * @param name 开关名称
+     * @param iconView 开关图标视图
+     * @param labelView 开关标签视图
+     */
+    private fun updateSwitchUI(name: String, iconView: ImageView, labelView: TextView) {
+        val isOn = switchStates[name] ?: false
+        if (isOn) {
+            // 开启态:鸿蒙蓝色背景 + 白色图标
+            iconView.setBackgroundResource(R.drawable.bg_switch_on)
+            iconView.setColorFilter(context.getColor(android.R.color.white))
+            labelView.setTextColor(context.getColor(R.color.harmony_blue))
+        } else {
+            // 关闭态:深灰背景 + 浅灰图标
+            iconView.setBackgroundResource(R.drawable.bg_switch_off)
+            iconView.setColorFilter(context.getColor(R.color.gray_text))
+            labelView.setTextColor(context.getColor(R.color.gray_text))
+        }
+    }
+
+    /**
+     * 初始化亮度滑块
+     * 仅改变滑块位置,不修改系统实际亮度
+     */
+    private fun initBrightnessSlider() {
+        val seekBar = findViewById<SeekBar>(R.id.seekbar_brightness)
+        val valueText = findViewById<TextView>(R.id.tv_brightness_value)
+        // 设置初始值 70%
+        seekBar.progress = 70
+        valueText.text = "70%"
+
+        seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+            // 滑块拖动时实时更新显示
+            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+                valueText.text = "${progress}%"
+            }
+            // 开始拖动(空实现,但接口要求覆写)
+            override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+            // 结束拖动(空实现,但接口要求覆写)
+            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+        })
+    }
+
+    /**
+     * 初始化音量滑块
+     * 仅改变滑块位置,不修改系统实际音量
+     */
+    private fun initVolumeSlider() {
+        val seekBar = findViewById<SeekBar>(R.id.seekbar_volume)
+        val valueText = findViewById<TextView>(R.id.tv_volume_value)
+        // 设置初始值 50%
+        seekBar.progress = 50
+        valueText.text = "50%"
+
+        seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
+            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+                valueText.text = "${progress}%"
+            }
+            override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+        })
+    }
+
+    /**
+     * 初始化关闭按钮
+     * 点击后隐藏控制中心
+     */
+    private fun initCloseButton() {
+        findViewById<View>(R.id.btn_close_control).setOnClickListener {
+            // 获取父 Activity 并调用其 hideControlCenter 方法
+            (context as? LauncherActivity)?.hideControlCenter()
+        }
+    }
+}
+```
+
+#### 3.5.7 控制中心布局 XML
+
+控制中心的布局文件 `res/layout/control_center.xml`:
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 仿 HarmonyOS 4 下拉控制中心布局 -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/bg_control_center"
+    android:orientation="vertical"
+    android:padding="24dp">
+
+    <!-- 顶部拖动手柄(视觉提示) -->
+    <View
+        android:layout_width="48dp"
+        android:layout_height="4dp"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginBottom="16dp"
+        android:background="@drawable/handle_bar" />
+
+    <!-- 快捷开关网格(2 行 x 3 列) -->
+    <GridLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:columnCount="3"
+        android:rowCount="2"
+        android:useDefaultMargins="true">
+
+        <!-- WiFi 开关 -->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:padding="8dp">
+            <ImageView
+                android:id="@+id/iv_wifi"
+                android:layout_width="@dimen/control_switch_size"
+                android:layout_height="@dimen/control_switch_size"
+                android:padding="16dp"
+                android:src="@drawable/ic_wifi"
+                android:contentDescription="WiFi" />
+            <TextView
+                android:id="@+id/tv_wifi"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="4dp"
+                android:text="WLAN"
+                android:textSize="12sp" />
+        </LinearLayout>
+
+        <!-- 蓝牙开关 -->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:padding="8dp">
+            <ImageView
+                android:id="@+id/iv_bluetooth"
+                android:layout_width="@dimen/control_switch_size"
+                android:layout_height="@dimen/control_switch_size"
+                android:padding="16dp"
+                android:src="@drawable/ic_bluetooth"
+                android:contentDescription="蓝牙" />
+            <TextView
+                android:id="@+id/tv_bluetooth"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="4dp"
+                android:text="蓝牙"
+                android:textSize="12sp" />
+        </LinearLayout>
+
+        <!-- 移动数据开关 -->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:padding="8dp">
+            <ImageView
+                android:id="@+id/iv_mobile"
+                android:layout_width="@dimen/control_switch_size"
+                android:layout_height="@dimen/control_switch_size"
+                android:padding="16dp"
+                android:src="@drawable/ic_mobile"
+                android:contentDescription="移动数据" />
+            <TextView
+                android:id="@+id/tv_mobile"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="4dp"
+                android:text="移动数据"
+                android:textSize="12sp" />
+        </LinearLayout>
+
+        <!-- 飞行模式开关 -->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:padding="8dp">
+            <ImageView
+                android:id="@+id/iv_airplane"
+                android:layout_width="@dimen/control_switch_size"
+                android:layout_height="@dimen/control_switch_size"
+                android:padding="16dp"
+                android:src="@drawable/ic_airplane"
+                android:contentDescription="飞行模式" />
+            <TextView
+                android:id="@+id/tv_airplane"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="4dp"
+                android:text="飞行模式"
+                android:textSize="12sp" />
+        </LinearLayout>
+
+        <!-- 位置服务开关 -->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:padding="8dp">
+            <ImageView
+                android:id="@+id/iv_location"
+                android:layout_width="@dimen/control_switch_size"
+                android:layout_height="@dimen/control_switch_size"
+                android:padding="16dp"
+                android:src="@drawable/ic_location"
+                android:contentDescription="位置服务" />
+            <TextView
+                android:id="@+id/tv_location"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="4dp"
+                android:text="位置服务"
+                android:textSize="12sp" />
+        </LinearLayout>
+
+        <!-- 关闭按钮 -->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:padding="8dp">
+            <ImageView
+                android:id="@+id/btn_close_control"
+                android:layout_width="@dimen/control_switch_size"
+                android:layout_height="@dimen/control_switch_size"
+                android:padding="16dp"
+                android:src="@drawable/ic_close"
+                android:background="@drawable/bg_switch_off"
+                android:contentDescription="关闭" />
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="4dp"
+                android:text="关闭"
+                android:textSize="12sp" />
+        </LinearLayout>
+    </GridLayout>
+
+    <!-- 亮度滑块区域 -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+        <ImageView
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="@drawable/ic_brightness"
+            android:contentDescription="亮度" />
+        <SeekBar
+            android:id="@+id/seekbar_brightness"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginHorizontal="8dp" />
+        <TextView
+            android:id="@+id/tv_brightness_value"
+            android:layout_width="40dp"
+            android:layout_height="wrap_content"
+            android:text="70%"
+            android:textColor="@color/white"
+            android:textSize="12sp" />
+    </LinearLayout>
+
+    <!-- 音量滑块区域 -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="12dp"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+        <ImageView
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="@drawable/ic_volume"
+            android:contentDescription="音量" />
+        <SeekBar
+            android:id="@+id/seekbar_volume"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginHorizontal="8dp" />
+        <TextView
+            android:id="@+id/tv_volume_value"
+            android:layout_width="40dp"
+            android:layout_height="wrap_content"
+            android:text="50%"
+            android:textColor="@color/white"
+            android:textSize="12sp" />
+    </LinearLayout>
+
+</LinearLayout>
+```
+
+#### 3.5.8 FakeSettingsActivity.kt 假设置页
+
+完整的假设置页实现,包含列表式布局和"关于本机"页面:
+
+```kotlin
+package com.emoon.harmony.launcher
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * 假设置页面 Activity
+ * 仿 HarmonyOS 设置页风格,展示假设备信息
+ */
+class FakeSettingsActivity : Activity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_fake_settings)
+        // 初始化设置列表
+        setupSettingsList()
+    }
+
+    /**
+     * 初始化设置列表 RecyclerView
+     */
+    private fun setupSettingsList() {
+        val recyclerView = findViewById<RecyclerView>(R.id.rv_settings)
+        // 垂直线性布局(类似 Vue 的垂直列表)
+        recyclerView.layoutManager = LinearLayoutManager(this)
+
+        // 定义设置项数据列表
+        val settingsItems = listOf(
+            SettingItem("WLAN", "已连接", R.drawable.ic_wifi),
+            SettingItem("蓝牙", "已开启", R.drawable.ic_bluetooth),
+            SettingItem("显示和亮度", "", R.drawable.ic_brightness),
+            SettingItem("声音和振动", "", R.drawable.ic_volume),
+            SettingItem("关于本机", "", R.drawable.ic_info)
+        )
+
+        // 设置适配器
+        recyclerView.adapter = SettingsAdapter(settingsItems) { item ->
+            onSettingClick(item)
+        }
+    }
+
+    /**
+     * 处理设置项点击事件
+     */
+    private fun onSettingClick(item: SettingItem) {
+        when (item.title) {
+            "关于本机" -> showAboutDialog()
+            else -> Toast.makeText(this, "${item.title} 功能即将推出", Toast.LENGTH_SHORT).show()
+        }
+    }
+
+    /**
+     * 显示"关于本机"对话框
+     * 展示仿造的设备信息,营造 HarmonyOS 系统的视觉假象
+     */
+    private fun showAboutDialog() {
+        // 使用 AlertDialog 展示关于信息
+        val aboutView = LayoutInflater.from(this).inflate(R.layout.dialog_about, null)
+        // 填充设备信息数据
+        aboutView.findViewById<TextView>(R.id.tv_device_name).text = "设备名称:豹小秘 Pro"
+        aboutView.findViewById<TextView>(R.id.tv_system_theme).text = "系统主题:HarmonyOS 风格 4.0"
+        aboutView.findViewById<TextView>(R.id.tv_processor).text = "处理器:Kirin 9000S"
+        aboutView.findViewById<TextView>(R.id.tv_ram).text = "运行内存:4 GB"
+        aboutView.findViewById<TextView>(R.id.tv_storage).text = "存储空间:64 GB"
+        aboutView.findViewById<TextView>(R.id.tv_resolution).text = "分辨率:1280 × 800"
+
+        android.app.AlertDialog.Builder(this)
+            .setView(aboutView)
+            .setPositiveButton("确定", null)
+            .show()
+    }
+
+    /**
+     * 设置项数据类
+     */
+    data class SettingItem(
+        val title: String,      // 设置项标题
+        val subtitle: String,   // 副标题(如"已连接")
+        val iconResId: Int      // 左侧图标资源 ID
+    )
+
+    /**
+     * 设置列表适配器
+     */
+    class SettingsAdapter(
+        private val items: List<SettingItem>,
+        private val onClick: (SettingItem) -> Unit
+    ) : RecyclerView.Adapter<SettingsAdapter.SettingViewHolder>() {
+
+        class SettingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+            val iconView: ImageView = itemView.findViewById(R.id.iv_setting_icon)
+            val titleView: TextView = itemView.findViewById(R.id.tv_setting_title)
+            val subtitleView: TextView = itemView.findViewById(R.id.tv_setting_subtitle)
+        }
+
+        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder {
+            val view = LayoutInflater.from(parent.context)
+                .inflate(R.layout.item_setting, parent, false)
+            return SettingViewHolder(view)
+        }
+
+        override fun onBindViewHolder(holder: SettingViewHolder, position: Int) {
+            val item = items[position]
+            holder.iconView.setImageResource(item.iconResId)
+            holder.titleView.text = item.title
+            holder.subtitleView.text = item.subtitle
+            holder.itemView.setOnClickListener { onClick(item) }
+        }
+
+        override fun getItemCount(): Int = items.size
+    }
+}
+```
+
+#### 3.5.9 设置页布局 XML
+
+**activity_fake_settings.xml**(设置页主布局):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 假设置页主布局(仿 HarmonyOS 设置页风格) -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/settings_background"
+    android:orientation="vertical">
+
+    <!-- 顶部标题栏 -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="56dp"
+        android:background="@color/white"
+        android:gravity="center_vertical"
+        android:paddingHorizontal="16dp">
+
+        <ImageView
+            android:id="@+id/btn_back"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="@drawable/ic_back"
+            android:contentDescription="返回" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="16dp"
+            android:text="设置"
+            android:textColor="@color/black"
+            android:textSize="20sp"
+            android:textStyle="bold" />
+    </LinearLayout>
+
+    <!-- 设置列表 -->
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/rv_settings"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="8dp" />
+
+</LinearLayout>
+```
+
+**item_setting.xml**(单个设置项布局):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 单个设置列表项(仿 HarmonyOS 设置列表) -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/setting_item_height"
+    android:background="@color/white"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:paddingHorizontal="16dp"
+    android:clickable="true"
+    android:focusable="true"
+    android:foreground="?android:attr/selectableItemBackground">
+
+    <!-- 左侧图标 -->
+    <ImageView
+        android:id="@+id/iv_setting_icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:contentDescription="设置图标" />
+
+    <!-- 中间文字区域 -->
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:layout_marginStart="16dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/tv_setting_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="@color/black"
+            android:textSize="16sp" />
+
+        <TextView
+            android:id="@+id/tv_setting_subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="@color/gray_text"
+            android:textSize="14sp" />
+    </LinearLayout>
+
+    <!-- 右侧箭头 -->
+    <ImageView
+        android:layout_width="16dp"
+        android:layout_height="16dp"
+        android:src="@drawable/ic_arrow_right"
+        android:contentDescription="进入" />
+
+</LinearLayout>
+```
+
+#### 3.5.10 BootReceiver.kt 开机自启接收器
+
+完整的开机自启广播接收器实现:
+
+```kotlin
+package com.emoon.harmony.launcher
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+
+/**
+ * 开机自启广播接收器
+ * 接收系统开机完成广播(BOOT_COMPLETED),自动启动 LauncherActivity
+ */
+class BootReceiver : BroadcastReceiver() {
+
+    /**
+     * 当收到广播时调用
+     * @param context 应用上下文
+     * @param intent 收到的广播 Intent
+     */
+    override fun onReceive(context: Context, intent: Intent) {
+        // 判断广播动作是否为开机完成
+        if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
+            // 创建启动 LauncherActivity 的 Intent
+            val launchIntent = Intent(context, LauncherActivity::class.java).apply {
+                // FLAG_ACTIVITY_NEW_TASK 是必须的:从非 Activity 上下文启动 Activity 需要此标志
+                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            }
+            // 启动桌面 Activity
+            context.startActivity(launchIntent)
+        }
+    }
+}
+```
+
+> **关键提示**:`BootReceiver` 生效需要同时满足三个条件:
+> 1. `AndroidManifest.xml` 中声明 `RECEIVE_BOOT_COMPLETED` 权限
+> 2. `BootReceiver` 在 Manifest 中正确注册并声明 `BOOT_COMPLETED` 过滤器
+> 3. 应用至少被用户手动打开过一次(Android 3.1+ 的安全限制)
+
+#### 3.5.11 设置为默认桌面的方法
+
+安装 Launcher APK 后,需要将其设为系统默认桌面。以下是详细步骤:
+
+**方法一:首次按 Home 键选择(推荐)**
+
+1. 通过 adb 安装 Launcher APK:`adb install HarmonyLauncher.apk`
+2. 在机器人设备上按 **Home 键**(或点击桌面的 Home 图标)
+3. 系统会弹出选择器,询问"要使用哪个应用?"
+4. 选择 **HarmonyLauncher** → 勾选 **"设为默认应用"** → 点击 **"始终"**
+5. 此后每次按 Home 键都会直接进入仿鸿蒙桌面
+
+**方法二:adb 命令直接设置(自动化部署时使用)**
+
+如果设备没有弹出选择器(某些定制 Android 系统会屏蔽),可通过 adb 命令强制设置:
+
+```bash
+# 查看当前默认桌面组件名
+adb shell cmd package resolve-activity -a android.intent.action.MAIN -c android.intent.category.HOME
+
+# 设置 HarmonyLauncher 为默认桌面(将下面命令中的包名替换为实际值)
+adb shell cmd package set-home-activity com.emoon.harmony.launcher/.LauncherActivity
+
+# 验证设置是否成功
+adb shell cmd package resolve-activity -a android.intent.action.MAIN -c android.intent.category.HOME
+```
+
+**方法三:通过设置应用手动切换**
+
+1. 进入系统"设置" → "应用"
+2. 找到当前的默认桌面应用(如"Launcher3")
+3. 点击"默认打开" → "清除默认操作"
+4. 再次按 Home 键,重新选择 HarmonyLauncher
+
+**验证方法**:
+
+- 按 Home 键,确认进入仿鸿蒙桌面(显示蓝紫渐变背景 + 圆角图标网格)
+- 重启设备,确认开机后自动进入仿鸿蒙桌面(验证 BootReceiver 生效)
+
+#### 3.5.12 res/values/colors.xml
+
+所有 HarmonyOS 风格配色的 XML 定义:
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 颜色资源文件:定义 HarmonyOS 风格配色方案 -->
+<resources>
+    <!-- ===== 基础色 ===== -->
+    <!-- 纯白 -->
+    <color name="white">#FFFFFF</color>
+    <!-- 纯黑 -->
+    <color name="black">#000000</color>
+    <!-- 鸿蒙蓝(开关开启态、强调色) -->
+    <color name="harmony_blue">#007DFF</color>
+    <!-- 灰色文字 -->
+    <color name="gray_text">#999999</color>
+
+    <!-- ===== 桌面配色 ===== -->
+    <!-- 图标卡片常态背景:白色 15% 透明度(毛玻璃效果) -->
+    <color name="icon_card_normal">#26FFFFFF</color>
+    <!-- 图标卡片按下态背景:白色 25% 透明度 -->
+    <color name="icon_card_pressed">#40FFFFFF</color>
+    <!-- Dock 栏背景:黑色 30% 透明度 -->
+    <color name="dock_background">#4D000000</color>
+    <!-- 控制中心背景:深蓝黑 95% 透明度 -->
+    <color name="control_center_background">#F21A1A2E</color>
+    <!-- 开关开启态背景:鸿蒙蓝 -->
+    <color name="switch_on_background">#007DFF</color>
+    <!-- 开关关闭态背景:深灰 -->
+    <color name="switch_off_background">#404040</color>
+    <!-- 日期文字颜色:白色 70% 透明度 -->
+    <color name="date_text">#B3FFFFFF</color>
+
+    <!-- ===== 设置页配色 ===== -->
+    <!-- 设置页背景:浅灰白 -->
+    <color name="settings_background">#F1F3F5</color>
+    <!-- 设置页卡片:纯白 -->
+    <color name="settings_card">#FFFFFF</color>
+    <!-- 设置页标题:纯黑 -->
+    <color name="settings_title">#000000</color>
+    <!-- 设置页副文字:灰色 -->
+    <color name="settings_subtitle">#999999</color>
+
+    <!-- ===== 渐变配色 ===== -->
+    <!-- 桌面背景渐变起始色:深蓝黑 -->
+    <color name="gradient_start">#1A1A2E</color>
+    <!-- 桌面背景渐变结束色:靛蓝 -->
+    <color name="gradient_end">#16213E</color>
+</resources>
+```
+
+#### 3.5.13 res/values/dimens.xml
+
+所有尺寸值的集中定义(便于统一修改和维护):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 尺寸资源文件:基于 10 寸横屏 1280x800 的设计规范 -->
+<resources>
+    <!-- ===== 图标尺寸 ===== -->
+    <!-- 桌面图标卡片整体尺寸:80dp x 80dp -->
+    <dimen name="icon_card_size">80dp</dimen>
+    <!-- 图标内实际图片大小:56dp x 56dp -->
+    <dimen name="icon_image_size">56dp</dimen>
+    <!-- 图标卡片圆角:20dp(HarmonyOS 标志性大圆角) -->
+    <dimen name="icon_card_radius">20dp</dimen>
+    <!-- 图标标签文字大小:12sp -->
+    <dimen name="icon_label_size">12sp</dimen>
+    <!-- 图标网格间距:24dp -->
+    <dimen name="icon_grid_spacing">24dp</dimen>
+    <!-- 卡片投影高度:4dp -->
+    <dimen name="card_elevation">4dp</dimen>
+
+    <!-- ===== Dock 栏尺寸 ===== -->
+    <!-- Dock 栏高度:64dp -->
+    <dimen name="dock_height">64dp</dimen>
+    <!-- Dock 栏圆角:24dp -->
+    <dimen name="dock_radius">24dp</dimen>
+    <!-- Dock 栏内图标大小:48dp x 48dp -->
+    <dimen name="dock_icon_size">48dp</dimen>
+
+    <!-- ===== 控制中心尺寸 ===== -->
+    <!-- 控制中心卡片圆角:24dp -->
+    <dimen name="control_center_radius">24dp</dimen>
+    <!-- 控制中心开关尺寸:64dp x 64dp -->
+    <dimen name="control_switch_size">64dp</dimen>
+
+    <!-- ===== 时间日期尺寸 ===== -->
+    <!-- 时间文字大小:48sp -->
+    <dimen name="time_text_size">48sp</dimen>
+    <!-- 日期文字大小:14sp -->
+    <dimen name="date_text_size">14sp</dimen>
+
+    <!-- ===== 设置页尺寸 ===== -->
+    <!-- 设置列表项高度:56dp -->
+    <dimen name="setting_item_height">56dp</dimen>
+</resources>
+```
+
+#### 3.5.14 res/values/themes.xml
+
+全屏主题和样式定义:
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 主题样式文件:定义应用的全局外观 -->
+<resources>
+    <!-- ===== 应用基础主题 ===== -->
+    <!-- 继承自 Material 的深色主题(适合深色桌面背景) -->
+    <style name="Theme.HarmonyLauncher" parent="Theme.MaterialComponents.Dark.NoActionBar">
+        <!-- 主色调:鸿蒙蓝 -->
+        <item name="colorPrimary">@color/harmony_blue</item>
+        <!-- 主色调变体 -->
+        <item name="colorPrimaryVariant">#005BB5</item>
+        <!-- 强调色 -->
+        <item name="colorAccent">@color/harmony_blue</item>
+        <!-- 窗口背景:默认深蓝黑 -->
+        <item name="android:windowBackground">@color/gradient_start</item>
+    </style>
+
+    <!-- ===== 全屏无标题栏主题(用于 Launcher 和设置页) ===== -->
+    <style name="Theme.HarmonyLauncher.Fullscreen" parent="Theme.HarmonyLauncher">
+        <!-- 隐藏 ActionBar(标题栏) -->
+        <item name="android:windowActionBar">false</item>
+        <!-- 无标题 -->
+        <item name="android:windowNoTitle">true</item>
+        <!-- 全屏显示 -->
+        <item name="android:windowFullscreen">true</item>
+        <!-- 透明状态栏背景 -->
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <!-- 透明导航栏背景 -->
+        <item name="android:navigationBarColor">@android:color/transparent</item>
+    </style>
+</resources>
+```
+
+#### 3.5.15 res/drawable/ 关键背景 XML
+
+以下是桌面核心视觉元素的 Drawable 定义:
+
+**bg_gradient.xml**(桌面背景渐变):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 桌面背景渐变:深蓝黑到靛蓝,营造 HarmonyOS 科技感 -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <gradient
+        android:angle="135"
+        android:endColor="@color/gradient_end"
+        android:startColor="@color/gradient_start"
+        android:type="linear" />
+</shape>
+```
+
+**bg_icon_card.xml**(图标卡片常态背景):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 图标卡片常态背景:半透明圆角矩形(毛玻璃效果基底) -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/icon_card_normal" />
+    <corners android:radius="@dimen/icon_card_radius" />
+</shape>
+```
+
+**bg_icon_card_pressed.xml**(图标卡片按下态背景):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 图标卡片按下态背景:更高透明度,提供视觉反馈 -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/icon_card_pressed" />
+    <corners android:radius="@dimen/icon_card_radius" />
+</shape>
+```
+
+**bg_dock.xml**(Dock 栏背景):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Dock 栏背景:半透明黑色圆角矩形(上方圆角) -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/dock_background" />
+    <!-- 只设置上方圆角,下方保持直角贴合屏幕底部 -->
+    <corners
+        android:topLeftRadius="@dimen/dock_radius"
+        android:topRightRadius="@dimen/dock_radius" />
+</shape>
+```
+
+**bg_control_center.xml**(控制中心背景):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 控制中心背景:近不透明的深色圆角卡片 -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/control_center_background" />
+    <!-- 只设置下方圆角,上方拉出时与屏幕边缘自然过渡 -->
+    <corners
+        android:bottomLeftRadius="@dimen/control_center_radius"
+        android:bottomRightRadius="@dimen/control_center_radius" />
+</shape>
+```
+
+**bg_switch_on.xml**(开关开启态背景):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 控制中心开关开启态:鸿蒙蓝圆形背景 -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="@color/switch_on_background" />
+</shape>
+```
+
+**bg_switch_off.xml**(开关关闭态背景):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 控制中心开关关闭态:深灰圆形背景 -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="@color/switch_off_background" />
+</shape>
+```
+
+**handle_bar.xml**(控制中心拖动手柄):
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 控制中心顶部拖动手柄:细横条,提示用户可拖动 -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#66FFFFFF" />
+    <corners android:radius="2dp" />
+</shape>
+```
+
+> **图标说明**:上述布局中引用的 `ic_*.xml` 图标(如 `ic_wifi`、`ic_bluetooth` 等)建议使用 Android Studio 内置的 **Vector Asset Studio** 导入 Material Design 图标,或从 [Material Icons](https://fonts.google.com/icons) 下载 SVG 后转为 Vector Drawable。对于迎检演示,使用简单的白色线形图标即可达到 HarmonyOS 风格效果。
+
+---
+
+## 四、原生业务 App 详细设计
+
+### 4.1 Android Studio 工程结构
+
+```
+com.medical.robotapp/
+├── MainActivity.kt              # WebView 容器 Activity
+├── bridge/
+│   └── RobotBridge.kt           # JSBridge 接口实现
+├── sdk/
+│   └── OrionSDKManager.kt       # 猎户星空 SDK 封装
+├── service/
+│   └── NavigationCallback.kt    # 导航状态监听
+└── util/
+    └── WebViewUtil.kt           # WebView 配置工具
+```
+
+### 4.2 WebView 容器配置
+
+```kotlin
+val webView = findViewById<WebView>(R.id.webView)
+webView.settings.apply {
+    javaScriptEnabled = true
+    domStorageEnabled = true
+    allowFileAccess = true
+    allowUniversalAccessFromFileURLs = true
+    useWideViewPort = true
+    loadWithOverviewMode = true
+    setSupportZoom(false)
+}
+webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+webView.webChromeClient = WebChromeClient()
+webView.addJavascriptInterface(RobotBridge(this, webView), "RobotBridge")
+
+// 调试模式:联调阶段开启,支持 Chrome DevTools 远程调试
+if (BuildConfig.DEBUG) {
+    WebView.setWebContentsDebuggingEnabled(true)
+}
+
+// 加载本地 H5(Spring Boot 后端部署在 localhost:8080)
+webView.loadUrl("http://localhost:8080")
+```
+
+> **安全提示**:迎检环境为内网受控设备,上述 WebView 配置(allowFileAccess、allowUniversalAccessFromFileURLs)可接受。若后续部署到公网或多方接入环境,需收紧安全配置。
+
+### 4.3 JSBridge 通信协议设计
+
+| Bridge 方法名 | 参数 | 返回值(通过回调) | 说明 | 本期实现 |
+|---|---|---|---|---|
+| `RobotBridge.navigate(destination, callbackId)` | destination: String, callbackId: String | {code, msg} | 导航到指定位置 | ✅ |
+| `RobotBridge.stopNavigation(callbackId)` | callbackId: String | {code, msg} | 停止导航 | 预留 |
+| `RobotBridge.getPlaceList(callbackId)` | callbackId: String | JSON 数组 | 获取所有定位点 | ✅ |
+| `RobotBridge.getPosition(callbackId)` | callbackId: String | {x,y,theta} | 获取当前坐标 | 预留 |
+| `RobotBridge.playTTS(text, callbackId)` | text: String, callbackId: String | {code, msg} | TTS 语音播报 | ✅ |
+| `RobotBridge.stopTTS(callbackId)` | callbackId: String | {code, msg} | 停止播报 | 预留 |
+| `RobotBridge.getBattery(callbackId)` | callbackId: String | {level} | 获取电量 | ✅ |
+
+**通信机制说明**:Android WebView 的 `@JavascriptInterface` 只支持基本类型参数(String/int/boolean),无法直接传递 JS 函数对象。因此采用 "callbackId + 全局回调池" 模式:H5 侧生成唯一 callbackId 并注册回调函数到 `window.__robotCallbacks`,将 callbackId 字符串传给 Native;Native 处理完成后通过 `webView.evaluateJavascript()` 执行 `window.__robotCallbacks[callbackId](result)` 回推结果。
+
+**Android 端 Bridge 实现**:
+
+```kotlin
+class RobotBridge(private val context: Context, private val webView: WebView) {
+
+    @JavascriptInterface
+    fun navigate(destination: String, callbackId: String) {
+        thread {
+            RobotApi.startNavigation(destination)
+            val result = JSONObject().apply {
+                put("code", 0)
+                put("msg", "navigation_started")
+                put("destination", destination)
+            }
+            webView.post {
+                webView.evaluateJavascript(
+                    "window.__robotCallbacks && window.__robotCallbacks['$callbackId'] && window.__robotCallbacks['$callbackId']($result)",
+                    null
+                )
+            }
+        }
+    }
+
+    @JavascriptInterface
+    fun getPlaceList(callbackId: String) {
+        thread {
+            val places = RobotApi.getPlaceList()
+            val result = JSONArray(places)
+            webView.post {
+                webView.evaluateJavascript(
+                    "window.__robotCallbacks && window.__robotCallbacks['$callbackId'] && window.__robotCallbacks['$callbackId']($result)",
+                    null
+                )
+            }
+        }
+    }
+
+    @JavascriptInterface
+    fun playTTS(text: String, callbackId: String) {
+        thread {
+            speechApi.playText(text)
+            val result = JSONObject().apply {
+                put("code", 0)
+                put("msg", "tts_started")
+            }
+            webView.post {
+                webView.evaluateJavascript(
+                    "window.__robotCallbacks && window.__robotCallbacks['$callbackId'] && window.__robotCallbacks['$callbackId']($result)",
+                    null
+                )
+            }
+        }
+    }
+
+    @JavascriptInterface
+    fun getBattery(callbackId: String) {
+        thread {
+            val level = RobotApi.getBatteryLevel()
+            val result = JSONObject().apply {
+                put("code", 0)
+                put("level", level)
+            }
+            webView.post {
+                webView.evaluateJavascript(
+                    "window.__robotCallbacks && window.__robotCallbacks['$callbackId'] && window.__robotCallbacks['$callbackId']($result)",
+                    null
+                )
+            }
+        }
+    }
+}
+```
+
+> 以上仅示例本期必须实现的核心接口,预留接口(stopNavigation、getPosition、stopTTS)遵循相同的 callbackId 协议模式,按需在后续迭代中实现。
+
+### 4.4 猎户星空 SDK 集成步骤
+
+1. **获取 AAR 包**:从猎户星空开发者平台下载 RobotOS SDK AAR,放入 `app/libs/`
+2. **build.gradle 配置**:
+
+```gradle
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.aar'])
+    implementation 'com.orionstar:robot-sdk:1.x.x'
+}
+```
+
+3. **AndroidManifest 声明权限**:
+
+```xml
+<uses-permission android:name="android.permission.INTERNET" />
+<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+<uses-permission android:name="com.orionstar.robot.permission.ROBOT_CONTROL" />
+```
+
+4. **Application 中初始化**:
+
+```kotlin
+class RobotApp : Application() {
+    override fun onCreate() {
+        super.onCreate()
+        RobotApi.init(this)
+        RobotApi.connectServer { status ->
+            Log.d("RobotSDK", "Server 连接状态: $status")
+        }
+    }
+}
+```
+
+5. **导航状态监听**:
+
+```kotlin
+RobotApi.setNavigationListener(object : NavigationListener {
+    override fun onStatus(statusCode: Int, data: String?) {
+        when (statusCode) {
+            32730001 -> Log.d("NAV", "开始导航")
+            32730004 -> Log.d("NAV", "避障中")
+            32730011 -> Log.d("NAV", "堵死")
+            32730009 -> Log.d("NAV", "定位丢失")
+        }
+    }
+
+    override fun onResult(resultCode: Int, data: String?) {
+        when (resultCode) {
+            32610007 -> Log.d("NAV", "到达目的地")
+            -32620001 -> Log.d("NAV", "未定位")
+            -32620009 -> Log.d("NAV", "路径规划失败")
+        }
+    }
+})
+```
+
+### 4.5 参考的关键 API
+
+| API | 功能 | 所属模块 |
+|-----|------|---------|
+| `RobotApi.startNavigation(destination)` | 启动导航到指定位置点 | 导航 API |
+| `RobotApi.getPlaceList()` | 获取地图中所有位置点列表 | 地图与定位 |
+| `RobotApi.getPosition()` | 获取当前坐标 `{x, y, theta}` | 地图与定位 |
+| `RobotApi.getBatteryLevel()` | 获取电量百分比(1-100) | 电量控制 |
+| `speechApi.playText(text)` | TTS 语音播报 | 语音 API |
+| `speechApi.stopTTS()` | 停止 TTS 播放 | 语音 API |
+| `speechApi.setRecognizable(boolean)` | 开启/关闭语音识别 | 语音 API |
+| `NavigationComponent` | OPK 导航组件(备选方案) | OPK 插件 |
+
+### 4.6 补充:Android Studio 环境准备和业务 App 工程搭建(面向 Web 开发者)
+
+> 本节专为从未接触过 Android 开发的 Web 全栈工程师编写,每一步都配有详细说明和截图指引对应操作。
+
+#### 4.6.1 Android Studio 环境安装与配置
+
+1. **下载安装 Android Studio**
+   - 访问 https://developer.android.com/studio 下载最新稳定版(推荐 Android Studio Hedgehog 或更新版本)
+   - macOS 用户:下载 `.dmg` 文件后,将 Android Studio 拖入 Applications 文件夹
+   - Windows 用户:运行 `.exe` 安装程序,按向导完成安装
+   - 首次启动会提示导入设置,选择 "Do not import settings"
+   - 接着会下载 Android SDK,选择 **"Standard"** 安装即可(包含常用 SDK 和模拟器)
+
+2. **SDK Manager 配置**
+   - 打开 Android Studio → 顶部菜单 **Android Studio → Preferences**(macOS)或 **File → Settings**(Windows)
+   - 左侧导航选择 **Appearance & Behavior → System Settings → Android SDK**
+   - 在 **SDK Platforms** 标签页中勾选以下版本:
+     - `Android 14.0 (API 34)` —— 编译目标版本
+     - `Android 7.0 (API 24)` —— 最低支持版本(对应 minSdk)
+   - 在 **SDK Tools** 标签页中勾选:
+     - `Android SDK Build-Tools 34` —— 构建工具
+     - `Android SDK Platform-Tools` —— 包含 adb、fastboot 等调试工具
+     - `Android SDK Command-line Tools (latest)` —— 命令行工具
+   - 点击右下角 **Apply** 按钮,等待下载完成(根据网络情况可能需要 5-20 分钟)
+
+3. **JDK 配置**
+   - Android Studio 自带 JDK 17(路径通常在 `/Applications/Android Studio.app/Contents/jbr/Contents/Home`)
+   - 一般无需额外安装 JDK
+   - 验证路径:点击 **File → Project Structure → SDK Location**,确认 **JDK Location** 字段有值且路径存在
+   - 如需手动指定:点击右侧文件夹图标,选择本地 JDK 17 安装目录
+
+4. **ADB 环境变量配置**
+   - ADB(Android Debug Bridge)是连接开发电脑与机器人设备的核心工具
+   - **macOS 配置**:
+     ```bash
+     # 打开终端,编辑 zsh 配置文件
+     open ~/.zshrc
+     # 在文件末尾添加以下行(根据实际 SDK 路径调整)
+     export PATH="$PATH:$HOME/Library/Android/sdk/platform-tools"
+     # 保存后执行
+     source ~/.zshrc
+     ```
+   - **Windows 配置**:
+     - 右键 "此电脑" → 属性 → 高级系统设置 → 环境变量
+     - 在 "系统变量" 中找到 `Path`,点击编辑
+     - 点击新建,添加路径:`C:\Users\<你的用户名>\AppData\Local\Android\Sdk\platform-tools`
+     - 点击确定保存
+   - **验证配置**:在终端(macOS 的 Terminal 或 Windows 的 CMD/PowerShell)中运行:
+     ```bash
+     adb version
+     ```
+     应输出类似 `Android Debug Bridge version 1.0.xxx` 的版本信息
+
+#### 4.6.2 创建业务 App 工程
+
+1. 打开 Android Studio,点击 **File → New → New Project**
+2. 在项目模板选择界面,选择 **"Empty Views Activity"**(使用传统 View 系统的空 Activity,适合 Web 开发者理解)
+   - 注意:不要选择 "Empty Activity"(那是 Jetpack Compose 版本,学习成本更高)
+3. 在配置页面填写以下信息:
+   - **Name**: `MedicalRobotApp`(应用名称)
+   - **Package name**: `com.emoon.medical.robot`(应用包名,全局唯一标识)
+   - **Save location**: 选择本地目录(如 `~/Projects/MedicalRobotApp`)
+   - **Language**: `Kotlin`(现代 Android 开发首选语言,语法与 JavaScript/TypeScript 更接近)
+   - **Minimum SDK**: `API 24: Android 7.0 (Nougat)`(猎户星空机器人系统基于 Android 7.0+)
+   - **Build configuration language**: `Kotlin (DSL)`(使用 Kotlin 脚本配置 Gradle,类型更安全)
+4. 点击 **Finish**,等待 Gradle 首次同步完成(首次可能需要下载依赖,耗时 5-15 分钟)
+5. 同步完成后,左侧 Project 面板应显示工程结构,顶部工具栏出现绿色运行按钮,表示工程创建成功
+
+---
+
+### 4.7 补充:完整的 build.gradle.kts(Module: app)
+
+> 以下文件位于 `MedicalRobotApp/app/build.gradle.kts`,是应用模块的构建配置。每一行都带有中文注释,说明其作用。
+
+```kotlin
+/**
+ * app 模块构建配置文件
+ * 作用:定义编译版本、依赖库、构建变体等
+ * 位置:MedicalRobotApp/app/build.gradle.kts
+ */
+
+// 插件声明:应用 Android 应用程序插件和 Kotlin Android 插件
+plugins {
+    // Android 应用插件,提供构建 APK 的能力
+    alias(libs.plugins.android.application)
+    // Kotlin Android 插件,支持 Kotlin 语言编译
+    alias(libs.plugins.kotlin.android)
+}
+
+// Android 构建设置
+android {
+    // 命名空间:与 AndroidManifest.xml 中的 package 属性一致
+    // 用于生成 R 类和其他资源引用
+    namespace = "com.emoon.medical.robot"
+
+    // 编译 SDK 版本:使用 API 34(Android 14)进行编译
+    // 决定了可以使用的最新 Android API
+    compileSdk = 34
+
+    // 默认配置:所有构建变体共享的基础配置
+    defaultConfig {
+        // 应用包名,设备上唯一标识此应用
+        applicationId = "com.emoon.medical.robot"
+
+        // 最低支持的 Android 版本:API 24(Android 7.0)
+        // 低于此版本的设备无法安装此应用
+        minSdk = 24
+
+        // 目标 SDK 版本:API 34(Android 14)
+        // 表示应用已在此版本上充分测试,系统会启用该版本的行为特性
+        targetSdk = 34
+
+        // 版本号:内部版本标识,每次发布必须递增
+        versionCode = 1
+
+        // 版本名称:对外展示的用户友好版本号
+        versionName = "1.0.0"
+
+        // 测试运行器:使用 AndroidJUnit4 进行单元测试
+        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    // 构建类型配置
+    buildTypes {
+        // 发布(Release)构建配置
+        release {
+            // 是否启用代码压缩和混淆(发布时建议开启以减小体积)
+            isMinifyEnabled = false
+
+            // 混淆规则文件:proguard-rules.pro 中定义了保留哪些类不被混淆
+            proguardFiles(
+                getDefaultProguardFile("proguard-android-optimize.txt"),
+                "proguard-rules.pro"
+            )
+        }
+
+        // 调试(Debug)构建配置
+        debug {
+            // Debug 模式不启用混淆,方便调试和查看堆栈
+            isMinifyEnabled = false
+
+            // 开启 Debug 签名,无需手动配置签名密钥
+            isDebuggable = true
+        }
+    }
+
+    // 编译选项
+    compileOptions {
+        // 源码兼容性:Java 17
+        sourceCompatibility = JavaVersion.VERSION_17
+        // 目标兼容性:Java 17
+        targetCompatibility = JavaVersion.VERSION_17
+    }
+
+    // Kotlin 编译选项
+    kotlinOptions {
+        // JVM 目标版本:与 Java 版本保持一致
+        jvmTarget = "17"
+    }
+
+    // 构建特性开关
+    buildFeatures {
+        // 启用 ViewBinding:自动生成绑定类,替代 findViewById,类型安全且无需额外依赖
+        viewBinding = true
+    }
+
+    // 打包选项
+    packaging {
+        resources {
+            // 排除重复的资源文件,避免打包冲突
+            excludes += "/META-INF/{AL2.0,LGPL2.1}"
+        }
+    }
+}
+
+// 依赖声明:项目所需的外部库
+dependencies {
+    // ===== AndroidX 核心库 =====
+
+    // AppCompat 库:提供向后兼容的 ActionBar 和主题支持
+    // 即使 minSdk 是 24,也能使用新版 API 的兼容实现
+    implementation("androidx.appcompat:appcompat:1.6.1")
+
+    // Material Design 组件库:提供按钮、卡片、对话框等符合 Material 规范的 UI 组件
+    implementation("com.google.android.material:material:1.11.0")
+
+    // ConstraintLayout:灵活高效的布局容器,适合复杂界面
+    // 相比嵌套 LinearLayout,性能更好且更易于维护
+    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+
+    // WebKit 库:提供增强型 WebView 支持
+    // 包含现代 WebView API,如 WebViewClient、WebChromeClient 等
+    implementation("androidx.webkit:webkit:1.9.0")
+
+    // Core KTX:Kotlin 扩展函数,简化 Android 核心 API 的调用
+    implementation("androidx.core:core-ktx:1.12.0")
+
+    // Activity KTX:Activity 相关的 Kotlin 扩展
+    implementation("androidx.activity:activity-ktx:1.8.0")
+
+    // Lifecycle 相关库:支持 ViewModel、LiveData 等生命周期感知组件
+    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
+
+    // ===== 猎户星空 RobotOS SDK =====
+
+    // 方式一:通过本地 AAR 文件引入(推荐,当前团队使用此方式)
+    // 将 robotos-sdk.aar 文件放入 app/libs/ 目录下,然后使用以下方式引入
+    implementation(files("libs/robotos-sdk.aar"))
+
+    // 方式二:通过 Maven 仓库引入(如果猎户星空后续开放 Maven 仓库)
+    // 取消下面一行的注释,并注释掉上面的 files 方式
+    // implementation("com.orionstar:robotos-sdk:2.x.x")
+
+    // ===== JSON 处理库 =====
+
+    // Gson:Google 的 JSON 序列化/反序列化库
+    // 用于 JSBridge 中 Native 与 H5 之间的 JSON 数据转换
+    implementation("com.google.code.gson:gson:2.10.1")
+
+    // ===== 测试库(开发阶段使用) =====
+
+    // JUnit 4:单元测试框架
+    testImplementation("junit:junit:4.13.2")
+
+    // AndroidX Test:Android 测试扩展库
+    androidTestImplementation("androidx.test.ext:junit:1.1.5")
+
+    // Espresso:UI 自动化测试框架
+    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+}
+```
+
+> **说明**:`libs/robotos-sdk.aar` 文件需要从猎户星空开发者平台获取。将 AAR 文件放入 `app/libs/` 目录后,Gradle 会自动识别。如果 SDK 有 Maven 仓库,可切换到方式二,移除本地 AAR 依赖。
+
+---
+
+### 4.8 补充:完整的 AndroidManifest.xml
+
+> 以下文件位于 `MedicalRobotApp/app/src/main/AndroidManifest.xml`,是 Android 应用的配置文件。声明了应用组件、权限、主题等核心信息。每行都有中文注释。
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- AndroidManifest.xml:Android 应用的入口配置文件 -->
+<!-- 作用:声明应用包名、组件(Activity/Service/BroadcastReceiver)、权限、主题等 -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <!-- ===== 权限声明 ===== -->
+    <!-- 权限分为普通权限(安装时自动授予)和危险权限(运行时需动态申请) -->
+
+    <!-- INTERNET:访问网络的权限,普通权限
+         用途:WebView 加载 H5 页面、调用后端 API、与猎户星空云服务通信 -->
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <!-- ACCESS_NETWORK_STATE:获取网络连接状态,普通权限
+         用途:判断当前是否有网络连接,用于离线提示和重试逻辑 -->
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <!-- RECORD_AUDIO:录制音频,危险权限(Android 6.0+ 需运行时动态申请)
+         用途:语音对话功能,采集用户语音并发送给语音识别服务 -->
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+    <!-- CAMERA:访问摄像头,危险权限(运行时动态申请)
+         用途:可选,用于身份证 OCR 识别、舌诊拍照等功能
+         如果 H5 页面通过 WebView 调用相机,也需要此权限 -->
+    <uses-permission android:name="android.permission.CAMERA" />
+
+    <!-- WRITE_EXTERNAL_STORAGE:写入外部存储,危险权限
+         用途:保存图片、日志文件等
+         Android 10+ 推荐使用 Scoped Storage(分区存储)替代 -->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+        android:maxSdkVersion="28" />
+
+    <!-- READ_EXTERNAL_STORAGE:读取外部存储,危险权限
+         用途:读取已保存的文件、相册图片等 -->
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
+        android:maxSdkVersion="28" />
+
+    <!-- FOREGROUND_SERVICE:前台服务权限(Android 9.0+ 需要)
+         用途:如果 SDK 需要在后台保持连接,可能用到前台服务 -->
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+
+    <!-- WAKE_LOCK:保持屏幕唤醒,普通权限
+         用途:迎检演示时防止屏幕自动熄灭 -->
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <!-- ===== 应用配置 ===== -->
+
+    <application
+        <!-- 应用名称:显示在系统设置中的应用列表中 -->
+        android:label="@string/app_name"
+
+        <!-- 应用图标:显示在桌面和任务列表中 -->
+        android:icon="@mipmap/ic_launcher"
+
+        <!-- 应用简介:长文本描述 -->
+        android:description="@string/app_description"
+
+        <!-- 自定义 Application 类:用于全局初始化和 SDK 连接管理
+             必须在 java/com/emoon/medical/robot/ 目录下存在同名类文件 -->
+        android:name=".MedicalRobotApplication"
+
+        <!-- 应用主题:全屏无标题栏主题,适合机器人 kiosk 模式
+             在 res/values/themes.xml 中定义 -->
+        android:theme="@style/Theme.MedicalRobotApp.Fullscreen"
+
+        <!-- 允许明文 HTTP 通信:true 表示允许访问 HTTP(非 HTTPS)URL
+             迎检环境为内网,后端可能未配置 SSL,因此需要开启
+             生产环境部署到公网时,应关闭此选项并强制使用 HTTPS -->
+        android:usesCleartextTraffic="true"
+
+        <!-- 网络安全配置文件:自定义网络安全策略
+             用于配置证书信任、明文通信域名白名单等 -->
+        android:networkSecurityConfig="@xml/network_security_config"
+
+        <!-- 支持从其他应用打开此应用的数据文件(如 content:// URI) -->
+        android:allowBackup="false"
+
+        <!-- 是否支持提取原生库(so 文件)到文件系统 -->
+        android:extractNativeLibs="true"
+
+        <!-- 请求的最大内存:WebView 渲染复杂 H5 页面需要较大内存 -->
+        android:largeHeap="true"
+
+        <!-- 工具命名空间:用于覆盖库中的属性 -->
+        tools:targetApi="34">
+
+        <!-- ===== Activity 声明 ===== -->
+        <!-- Activity 是 Android 的界面容器,每个可见页面都是一个 Activity -->
+
+        <!-- MainActivity:主界面,WebView 容器
+             这是用户打开应用后看到的第一个页面 -->
+        <activity
+            <!-- Activity 的完整类名(相对于包名) -->
+            android:name=".MainActivity"
+
+            <!-- 是否导出:false 表示不允许其他应用直接启动此 Activity
+                 提高安全性,防止恶意应用劫持 -->
+            android:exported="false"
+
+            <!-- 屏幕方向:landscape 表示强制横屏
+                 机器人屏幕为横屏,固定方向可避免布局错乱 -->
+            android:screenOrientation="landscape"
+
+            <!-- 启动模式:singleTask 确保只有一个实例存在
+                 从 Launcher 返回时不会创建新实例 -->
+            android:launchMode="singleTask"
+
+            <!-- 配置变更处理:当屏幕方向或键盘状态改变时,不重建 Activity
+                 避免 WebView 页面重新加载导致状态丢失 -->
+            android:configChanges="orientation|screenSize|keyboardHidden">
+
+            <!-- Intent Filter:定义此 Activity 如何被启动 -->
+            <intent-filter>
+                <!-- MAIN:标记此 Activity 为应用入口 -->
+                <action android:name="android.intent.action.MAIN" />
+                <!-- LAUNCHER:在应用启动器中显示图标,用户点击后启动此 Activity -->
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
+```
+
+> **安全提示**:`android:usesCleartextTraffic="true"` 仅适用于内网迎检环境。若后续部署到公网,应移除此属性或配合 `network_security_config.xml` 配置域名白名单,强制使用 HTTPS 通信。
+
+### 4.9 补充:完整的工程目录结构
+
+> 以下是创建完成后的完整工程目录结构,帮助 Web 开发者快速理解 Android 项目的组织方式。
+
+```
+MedicalRobotApp/                          // 项目根目录
+├── app/                                  // 应用模块(核心代码都在这里)
+│   ├── src/main/                         // 主源码目录(还有 test/ 和 androidTest/ 用于测试)
+│   │   ├── java/com/emoon/medical/robot/ // Kotlin/Java 源码根目录,按包名层级组织
+│   │   │   ├── MedicalRobotApplication.kt    // Application 类:全局初始化、SDK 连接
+│   │   │   ├── MainActivity.kt                // 主 Activity:WebView 容器,唯一可见界面
+│   │   │   ├── bridge/                        // JSBridge 相关代码
+│   │   │   │   └── RobotBridge.kt            // JSBridge 实现:Native 与 H5 的通信桥梁
+│   │   │   └── sdk/                           // SDK 封装层
+│   │   │       └── RobotSDKManager.kt        // SDK 管理器:封装猎户星空 API,统一错误处理
+│   │   ├── res/                              // 资源文件目录
+│   │   │   ├── layout/                       // 布局文件:XML 描述的界面结构
+│   │   │   │   └── activity_main.xml         // MainActivity 的布局:全屏 WebView
+│   │   │   ├── values/                       // 值资源:颜色、字符串、主题、尺寸等
+│   │   │   │   ├── colors.xml                // 颜色定义
+│   │   │   │   ├── strings.xml               // 字符串定义(应用名称、提示文案等)
+│   │   │   │   └── themes.xml                // 主题和样式定义
+│   │   │   └── xml/                          // XML 配置文件
+│   │   │       └── network_security_config.xml   // 网络安全配置(允许明文 HTTP)
+│   │   ├── assets/                           // 静态资源目录(不参与编译,原样打包)
+│   │   │   └── web/                          // H5 打包文件存放位置(离线模式使用)
+│   │   │       └── index.html                // 本地 H5 入口页面(可选)
+│   │   └── AndroidManifest.xml               // 应用配置文件(权限、组件声明)
+│   ├── libs/                                 // 本地依赖库目录
+│   │   └── robotos-sdk.aar                   // 猎户星空 RobotOS SDK(从官方获取)
+│   └── build.gradle.kts                      // 模块级构建配置(依赖、编译选项)
+├── build.gradle.kts                          // 项目级构建配置(Gradle 插件版本)
+├── settings.gradle.kts                       // Gradle 项目设置(包含的模块列表)
+├── gradle.properties                         // Gradle 属性配置(JVM 参数、代理等)
+└── gradle/                                   // Gradle Wrapper 目录
+    └── wrapper/
+        ├── gradle-wrapper.jar                // Gradle Wrapper 可执行文件
+        └── gradle-wrapper.properties         // Wrapper 配置(Gradle 版本号)
+```
+
+> **与 Web 项目的对比**:
+> - `src/main/java/` 相当于 Web 后端的 `src/main/java/`(源码目录)
+> - `src/main/res/` 相当于前端项目的 `public/` 或 `assets/`(静态资源)
+> - `build.gradle.kts` 相当于 `package.json` + `webpack.config.js`(依赖和构建配置)
+> - `AndroidManifest.xml` 相当于 `web.xml` 或应用入口配置
+
+---
+
+### 4.10 补充:MedicalRobotApplication.kt 完整代码
+
+> Application 类是 Android 应用的全局入口,在应用启动时第一个被初始化。这里负责初始化猎户星空 SDK 和建立与机器人系统服务的连接。
+
+```kotlin
+package com.emoon.medical.robot
+
+import android.app.Application
+import android.util.Log
+
+/**
+ * 应用全局初始化类
+ * 职责:
+ * 1. 初始化猎户星空 RobotOS SDK
+ * 2. 建立与机器人系统服务的连接
+ * 3. 管理全局状态(SDK 连接状态、Mock 模式开关等)
+ *
+ * 生命周期:
+ * - 应用进程启动时,系统首先创建此类的实例并调用 onCreate()
+ * - 在应用运行期间保持单例,直到进程被杀死
+ * - 任何 Activity、Service 都可以通过 (application as MedicalRobotApplication) 访问
+ *
+ * 注意:必须在 AndroidManifest.xml 的 <application> 标签中通过 android:name 属性声明此类,
+ *       否则系统不会调用它。
+ */
+class MedicalRobotApplication : Application() {
+
+    // ===== Companion Object:Kotlin 的静态成员替代方案 =====
+    // 用于存放全局可访问的静态常量和变量
+    companion object {
+        // 日志标签:所有此类相关的日志都使用此标签,方便在 logcat 中过滤
+        const val TAG = "MedicalRobot"
+
+        // 全局 SDK 管理器实例
+        // lateinit 表示延迟初始化,在 onCreate() 中赋值
+        // private set 表示外部只能读取不能修改
+        lateinit var sdkManager: RobotSDKManager
+            private set
+
+        // Mock 模式开关:true 表示使用模拟数据(无需真机即可开发调试)
+        // false 表示调用真实 SDK(需要部署到机器人真机)
+        // 开发阶段建议设为 true,联调阶段设为 false
+        var useMockMode: Boolean = true
+    }
+
+    /**
+     * 应用创建时的初始化方法
+     * 系统回调:应用进程启动后第一个被调用的方法
+     * 注意:此方法执行时间过长会阻塞应用启动,因此只应做轻量级初始化
+     */
+    override fun onCreate() {
+        // 调用父类实现,确保框架级初始化正常完成
+        super.onCreate()
+
+        // 输出应用启动日志,方便在 logcat 中确认初始化流程
+        Log.i(TAG, "========================================")
+        Log.i(TAG, "应用启动,开始初始化...")
+        Log.i(TAG, "Mock 模式: $useMockMode")
+        Log.i(TAG, "========================================")
+
+        // 初始化 SDK 管理器,传入 Application 上下文
+        // 上下文(Context)是 Android 中访问系统资源和服务的关键对象
+        sdkManager = RobotSDKManager(this)
+
+        // 执行 SDK 初始化(连接机器人系统服务)
+        // 如果是 Mock 模式,初始化会快速完成并返回模拟的连接成功状态
+        sdkManager.initialize()
+
+        Log.i(TAG, "应用初始化完成")
+    }
+
+    /**
+     * 应用终止时的清理方法
+     * 系统回调:应用进程即将被杀死时调用(不保证一定被调用)
+     * 用于释放资源、断开连接等清理操作
+     */
+    override fun onTerminate() {
+        Log.i(TAG, "应用终止,执行清理...")
+        // 断开 SDK 连接,释放资源
+        sdkManager.release()
+        // 调用父类实现
+        super.onTerminate()
+    }
+
+    /**
+     * 内存不足时的回调
+     * 系统回调:系统内存紧张时调用
+     * 应在此释放不必要的缓存和资源
+     */
+    override fun onLowMemory() {
+        Log.w(TAG, "系统内存不足,释放资源...")
+        super.onLowMemory()
+    }
+}
+```
+
+> **Web 开发者提示**:`Application` 类类似于 Spring Boot 的 `@SpringBootApplication` 主类,是全局配置的入口。`onCreate()` 类似于 Spring 的 `CommandLineRunner` 或 `@PostConstruct` 方法。
+
+---
+
+### 4.11 补充:RobotSDKManager.kt 完整代码
+
+> SDK 管理封装类:统一封装猎户星空 RobotOS SDK 的所有 API 调用,对外提供简洁的接口,内部处理连接管理、错误处理和 Mock 模式切换。
+
+```kotlin
+package com.emoon.medical.robot
+
+import android.content.Context
+import android.util.Log
+import org.json.JSONArray
+import org.json.JSONObject
+
+/**
+ * 猎户星空 RobotOS SDK 管理封装类
+ * 职责:
+ * 1. 封装 SDK 的初始化和连接管理
+ * 2. 提供简洁的业务 API(导航、TTS、位置查询、电量等)
+ * 3. 统一管理回调接口,将 SDK 的异步结果转换为业务友好的回调
+ * 4. 支持 Mock 模式,在没有真机时返回模拟数据
+ *
+ * 设计模式:外观模式(Facade Pattern),对外隐藏 SDK 的复杂调用细节
+ */
+class RobotSDKManager(private val context: Context) {
+
+    // 日志标签
+    private val tag = "RobotSDKManager"
+
+    // ===== Mock 模式标志 =====
+    // 通过 MedicalRobotApplication.useMockMode 统一控制
+    private val isMock: Boolean
+        get() = MedicalRobotApplication.useMockMode
+
+    // ===== 连接状态 =====
+    // 记录 SDK 与机器人系统服务的连接状态
+    private var isConnected = false
+
+    // ===== 回调接口定义 =====
+    // 使用接口(Interface)定义回调规范,调用方实现此接口接收结果
+
+    /**
+     * 通用操作回调接口
+     * 适用于导航、TTS 等只需要知道成功/失败的操作
+     */
+    interface OperationCallback {
+        /**
+         * 操作成功时调用
+         * @param data 可选的返回数据(JSON 格式字符串)
+         */
+        fun onSuccess(data: String = "{}")
+
+        /**
+         * 操作失败时调用
+         * @param code 错误码
+         * @param message 错误描述
+         */
+        fun onError(code: Int, message: String)
+    }
+
+    /**
+     * 导航状态监听接口
+     * 用于接收导航过程中的实时状态更新(开始导航、避障、堵死、到达等)
+     */
+    interface NavigationListener {
+        /**
+         * 导航状态变化时调用
+         * @param statusCode 状态码(如 32730001 表示开始导航)
+         * @param data 附加数据
+         */
+        fun onStatus(statusCode: Int, data: String?)
+
+        /**
+         * 导航结果回调
+         * @param resultCode 结果码(如 32610007 表示到达目的地)
+         * @param data 附加数据
+         */
+        fun onResult(resultCode: Int, data: String?)
+    }
+
+    /**
+     * 位置信息数据类
+     * 封装机器人的当前坐标和定位状态
+     */
+    data class Position(
+        val x: Double,      // X 坐标(地图坐标系,单位:米)
+        val y: Double,      // Y 坐标
+        val theta: Double,  // 朝向角度(弧度,0 表示正东方向)
+        val isEstimated: Boolean // 是否已完成定位
+    )
+
+    /**
+     * 位置点数据类
+     * 封装地图中预设的导航目标点信息
+     */
+    data class Place(
+        val name: String,   // 位置点名称(如 "导诊台"、"神经内科")
+        val x: Double,      // X 坐标
+        val y: Double,      // Y 坐标
+        val theta: Double   // 到达后的朝向角度
+    )
+
+    // ===== 初始化与连接管理 =====
+
+    /**
+     * 初始化 SDK 并建立与机器人系统服务的连接
+     * 应在 Application.onCreate() 中调用
+     */
+    fun initialize() {
+        if (isMock) {
+            // Mock 模式:模拟初始化成功,无需连接真实服务
+            Log.i(tag, "[Mock] SDK 初始化成功(模拟模式)")
+            isConnected = true
+            return
+        }
+
+        // 真实 SDK 初始化路径
+        try {
+            Log.i(tag, "开始初始化猎户星空 SDK...")
+
+            // 初始化 RobotApi,传入 Application Context
+            // RobotApi.init(context)
+
+            // 连接 SDK Server(机器人系统后台服务)
+            // RobotApi.connectServer { status ->
+            //     Log.i(tag, "SDK Server 连接状态: $status")
+            //     isConnected = status == 1  // 1 表示连接成功
+            // }
+
+            // 设置导航状态监听
+            // RobotApi.setNavigationListener(object : NavigationListener { ... })
+
+            Log.i(tag, "SDK 初始化完成,等待连接...")
+        } catch (e: Exception) {
+            Log.e(tag, "SDK 初始化失败: ${e.message}", e)
+            isConnected = false
+        }
+    }
+
+    /**
+     * 释放 SDK 资源,断开连接
+     * 应在 Application.onTerminate() 或 Activity.onDestroy() 中调用
+     */
+    fun release() {
+        if (isMock) {
+            Log.i(tag, "[Mock] SDK 资源已释放")
+            isConnected = false
+            return
+        }
+
+        try {
+            // RobotApi.disconnectServer()
+            isConnected = false
+            Log.i(tag, "SDK 连接已断开")
+        } catch (e: Exception) {
+            Log.e(tag, "释放 SDK 资源失败: ${e.message}", e)
+        }
+    }
+
+    /**
+     * 获取当前 SDK 连接状态
+     * @return true 表示已连接,false 表示未连接
+     */
+    fun isConnected(): Boolean = isConnected
+
+    // ===== 导航 API =====
+
+    /**
+     * 启动导航到指定位置点
+     * @param destination 目标位置点名称(如 "导诊台"、"神经内科")
+     * @param callback 操作结果回调
+     */
+    fun startNavigation(destination: String, callback: OperationCallback) {
+        Log.i(tag, "开始导航到: $destination")
+
+        if (isMock) {
+            // Mock 模式:模拟导航成功,延迟 500ms 后回调
+            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
+                Log.i(tag, "[Mock] 导航到 [$destination] 成功")
+                callback.onSuccess(
+                    JSONObject().apply {
+                        put("destination", destination)
+                        put("mock", true)
+                    }.toString()
+                )
+            }, 500)
+            return
+        }
+
+        // 真实 SDK 调用路径
+        try {
+            if (!isConnected) {
+                callback.onError(-1, "SDK 未连接")
+                return
+            }
+
+            // 调用猎户星空 SDK 导航 API
+            // RobotApi.startNavigation(destination)
+
+            // 设置导航结果监听
+            // RobotApi.setNavigationListener(object : NavigationListener {
+            //     override fun onResult(resultCode: Int, data: String?) {
+            //         when (resultCode) {
+            //             32610007 -> callback.onSuccess()  // 到达目的地
+            //             -32620001 -> callback.onError(resultCode, "未定位")
+            //             -32620009 -> callback.onError(resultCode, "路径规划失败")
+            //             else -> callback.onError(resultCode, "导航失败: $data")
+            //         }
+            //     }
+            // })
+
+            callback.onSuccess()
+        } catch (e: Exception) {
+            Log.e(tag, "导航调用异常: ${e.message}", e)
+            callback.onError(-2, "导航异常: ${e.message}")
+        }
+    }
+
+    /**
+     * 停止当前导航
+     * @param callback 操作结果回调
+     */
+    fun stopNavigation(callback: OperationCallback) {
+        Log.i(tag, "停止导航")
+
+        if (isMock) {
+            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
+                Log.i(tag, "[Mock] 导航已停止")
+                callback.onSuccess()
+            }, 200)
+            return
+        }
+
+        try {
+            if (!isConnected) {
+                callback.onError(-1, "SDK 未连接")
+                return
+            }
+
+            // 调用猎户星空 SDK 停止运动 API
+            // RobotApi.stopMove()
+            callback.onSuccess()
+        } catch (e: Exception) {
+            Log.e(tag, "停止导航异常: ${e.message}", e)
+            callback.onError(-2, "停止导航异常: ${e.message}")
+        }
+    }
+
+    // ===== 位置与地图 API =====
+
+    /**
+     * 获取地图中所有预设位置点列表
+     * @param callback 结果回调,返回位置点列表的 JSON 字符串
+     */
+    fun getPlaceList(callback: OperationCallback) {
+        Log.i(tag, "获取位置点列表")
+
+        if (isMock) {
+            // Mock 模式:返回模拟的医院位置点数据
+            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
+                val mockPlaces = JSONArray().apply {
+                    put(JSONObject().apply {
+                        put("name", "导诊台")
+                        put("x", 1.5)
+                        put("y", 2.0)
+                        put("theta", 1.57)
+                    })
+                    put(JSONObject().apply {
+                        put("name", "神经内科")
+                        put("x", 5.2)
+                        put("y", 3.8)
+                        put("theta", 0.0)
+                    })
+                    put(JSONObject().apply {
+                        put("name", "心血管内科")
+                        put("x", 5.2)
+                        put("y", 6.5)
+                        put("theta", 0.0)
+                    })
+                    put(JSONObject().apply {
+                        put("name", "检验科")
+                        put("x", 8.0)
+                        put("y", 2.0)
+                        put("theta", -1.57)
+                    })
+                    put(JSONObject().apply {
+                        put("name", "药房")
+                        put("x", 10.5)
+                        put("y", 5.0)
+                        put("theta", 3.14)
+                    })
+                }
+                Log.i(tag, "[Mock] 返回 ${mockPlaces.length()} 个位置点")
+                callback.onSuccess(mockPlaces.toString())
+            }, 300)
+            return
+        }
+
+        try {
+            if (!isConnected) {
+                callback.onError(-1, "SDK 未连接")
+                return
+            }
+
+            // 调用猎户星空 SDK 获取位置点列表
+            // val places = RobotApi.getPlaceList()
+            // callback.onSuccess(JSONArray(places).toString())
+            callback.onSuccess("[]")
+        } catch (e: Exception) {
+            Log.e(tag, "获取位置点列表异常: ${e.message}", e)
+            callback.onError(-2, "获取位置点列表异常: ${e.message}")
+        }
+    }
+
+    /**
+     * 获取机器人当前位置坐标
+     * @param callback 结果回调,返回坐标 JSON 字符串
+     */
+    fun getPosition(callback: OperationCallback) {
+        Log.i(tag, "获取当前位置")
+
+        if (isMock) {
+            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
+                val mockPosition = JSONObject().apply {
+                    put("x", 3.5)
+                    put("y", 4.2)
+                    put("theta", 0.78)
+                    put("isEstimated", true)
+                }
+                Log.i(tag, "[Mock] 当前位置: (3.5, 4.2)")
+                callback.onSuccess(mockPosition.toString())
+            }, 200)
+            return
+        }
+
+        try {
+            if (!isConnected) {
+                callback.onError(-1, "SDK 未连接")
+                return
+            }
+
+            // 调用猎户星空 SDK 获取当前位置
+            // val pos = RobotApi.getPosition()
+            // val isEstimated = RobotApi.isRobotEstimate()
+            // val result = JSONObject().apply {
+            //     put("x", pos.x)
+            //     put("y", pos.y)
+            //     put("theta", pos.theta)
+            //     put("isEstimated", isEstimated)
+            // }
+            // callback.onSuccess(result.toString())
+            callback.onSuccess("{}")
+        } catch (e: Exception) {
+            Log.e(tag, "获取位置异常: ${e.message}", e)
+            callback.onError(-2, "获取位置异常: ${e.message}")
+        }
+    }
+
+    /**
+     * 检查机器人是否已完成定位
+     * @param callback 结果回调,返回 JSON 字符串 {"isEstimated": true/false}
+     */
+    fun isRobotEstimate(callback: OperationCallback) {
+        if (isMock) {
+            callback.onSuccess("{\"isEstimated\": true}")
+            return
+        }
+
+        try {
+            // val result = RobotApi.isRobotEstimate()
+            // callback.onSuccess("{\"isEstimated\": $result}")
+            callback.onSuccess("{\"isEstimated\": false}")
+        } catch (e: Exception) {
+            callback.onError(-2, "检查定位状态异常: ${e.message}")
+        }
+    }
+
+    // ===== TTS 语音 API =====
+
+    /**
+     * 播放 TTS 语音播报
+     * @param text 要播报的文本内容
+     * @param callback 操作结果回调
+     */
+    fun playTTS(text: String, callback: OperationCallback) {
+        Log.i(tag, "TTS 播报: $text")
+
+        if (isMock) {
+            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
+                Log.i(tag, "[Mock] TTS 播报完成: $text")
+                callback.onSuccess(
+                    JSONObject().apply {
+                        put("text", text)
+                        put("mock", true)
+                    }.toString()
+                )
+            }, text.length * 200L) // 模拟朗读时间:每个字 200ms
+            return
+        }
+
+        try {
+            if (!isConnected) {
+                callback.onError(-1, "SDK 未连接")
+                return
+            }
+
+            // 调用猎户星空 SDK TTS API
+            // speechApi.playText(text)
+            callback.onSuccess()
+        } catch (e: Exception) {
+            Log.e(tag, "TTS 播报异常: ${e.message}", e)
+            callback.onError(-2, "TTS 播报异常: ${e.message}")
+        }
+    }
+
+    /**
+     * 停止 TTS 语音播报
+     * @param callback 操作结果回调
+     */
+    fun stopTTS(callback: OperationCallback) {
+        Log.i(tag, "停止 TTS")
+
+        if (isMock) {
+            callback.onSuccess()
+            return
+        }
+
+        try {
+            // speechApi.stopTTS()
+            callback.onSuccess()
+        } catch (e: Exception) {
+            Log.e(tag, "停止 TTS 异常: ${e.message}", e)
+            callback.onError(-2, "停止 TTS 异常: ${e.message}")
+        }
+    }
+
+    // ===== 电量 API =====
+
+    /**
+     * 获取机器人当前电量
+     * @param callback 结果回调,返回 JSON 字符串 {"level": 85}
+     */
+    fun getBatteryLevel(callback: OperationCallback) {
+        Log.i(tag, "获取电量")
+
+        if (isMock) {
+            android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
+                val mockLevel = 85 // 模拟电量 85%
+                Log.i(tag, "[Mock] 当前电量: $mockLevel%")
+                callback.onSuccess("{\"level\": $mockLevel}")
+            }, 100)
+            return
+        }
+
+        try {
+            if (!isConnected) {
+                callback.onError(-1, "SDK 未连接")
+                return
+            }
+
+            // 调用猎户星空 SDK 电量 API
+            // val level = RobotApi.getBatteryLevel()
+            // callback.onSuccess("{\"level\": $level}")
+            callback.onSuccess("{\"level\": 0}")
+        } catch (e: Exception) {
+            Log.e(tag, "获取电量异常: ${e.message}", e)
+            callback.onError(-2, "获取电量异常: ${e.message}")
+        }
+    }
+}
+```
+
+> **Mock 数据说明**:`getPlaceList()` 返回 5 个模拟医院位置点(导诊台、神经内科、心血管内科、检验科、药房);`getPosition()` 返回固定坐标 (3.5, 4.2);`getBatteryLevel()` 返回固定电量 85%;`playTTS()` 按字数模拟延迟。开发者在 PC 模拟器上运行即可看到完整的业务流程。
+
+### 4.12 补充:MainActivity.kt 完整代码(WebView 容器)
+
+> MainActivity 是应用的唯一直接可见界面,本质上是一个全屏的 WebView 容器,负责加载 H5 页面并桥接 Native 能力。以下代码完整可用,每行都有中文注释。
+
+```kotlin
+package com.emoon.medical.robot
+
+import android.annotation.SuppressLint
+import android.content.pm.ActivityInfo
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import android.view.WindowInsets
+import android.view.WindowInsetsController
+import android.view.WindowManager
+import android.webkit.WebChromeClient
+import android.webkit.WebResourceError
+import android.webkit.WebResourceRequest
+import android.webkit.WebSettings
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import android.widget.ProgressBar
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+
+/**
+ * 主界面 Activity:WebView 容器
+ * 职责:
+ * 1. 提供全屏沉浸式的 WebView 环境( kiosk 模式,类似银行的自助终端)
+ * 2. 加载 H5 页面(远程服务器或本地 assets)
+ * 3. 注入 JSBridge,使 H5 页面能够调用机器人的导航、语音等能力
+ * 4. 管理 WebView 生命周期和系统 UI 状态
+ *
+ * 生命周期:
+ * onCreate → onStart → onResume → [运行中] → onPause → onStop → onDestroy
+ * 对应 Web 概念:页面创建 → 可见 → 可交互 → 后台 → 销毁
+ */
+class MainActivity : AppCompatActivity() {
+
+    // ===== 视图组件声明 =====
+    // lateinit 表示延迟初始化,在 onCreate() 中通过 findViewById 赋值
+
+    // WebView:Android 内置浏览器组件,用于加载和显示 H5 页面
+    private lateinit var webView: WebView
+
+    // ProgressBar:页面加载时的进度指示器(转圈动画)
+    private lateinit var progressBar: ProgressBar
+
+    // RobotBridge:JSBridge 实例,负责 Native 与 H5 之间的通信
+    private lateinit var robotBridge: RobotBridge
+
+    // 页面加载失败标志:用于记录当前是否处于错误状态
+    private var hasLoadError = false
+
+    /**
+     * Activity 创建时调用(系统回调)
+     * 这是设置布局、初始化组件的核心方法
+     */
+    @SuppressLint("SetJavaScriptEnabled") // 抑制 "启用 JavaScript 可能有安全风险" 的编译器警告
+    override fun onCreate(savedInstanceState: Bundle?) {
+        // 调用父类实现,确保框架级初始化完成
+        super.onCreate(savedInstanceState)
+
+        // ===== 第 1 步:全屏沉浸式设置 =====
+        // 隐藏状态栏和导航栏,提供 kiosk 模式体验
+        hideSystemUI()
+
+        // 强制横屏:机器人屏幕为横屏,锁定方向防止旋转
+        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+
+        // ===== 第 2 步:设置布局 =====
+        // 将 activity_main.xml 中定义的视图结构加载到 Activity 中
+        setContentView(R.layout.activity_main)
+
+        // ===== 第 3 步:查找视图组件 =====
+        // 通过视图 ID 获取布局文件中定义的组件实例
+        webView = findViewById(R.id.webview)
+        progressBar = findViewById(R.id.progress_bar)
+
+        // ===== 第 4 步:初始化 WebView =====
+        setupWebView()
+
+        // ===== 第 5 步:注入 JSBridge =====
+        // 将 RobotBridge 对象注入到 WebView 的 JavaScript 环境中
+        // H5 页面可以通过 window.RobotBridge 访问 Native 方法
+        injectJSBridge()
+
+        // ===== 第 6 步:加载页面 =====
+        loadPage()
+    }
+
+    /**
+     * 隐藏系统 UI(状态栏和导航栏),实现全屏沉浸式体验
+     * 原理:设置窗口的 systemUiVisibility 标志,告诉系统不要显示状态栏和导航栏
+     */
+    private fun hideSystemUI() {
+        // 如果 Android 版本 >= 11(API 30),使用新的 WindowInsetsController API
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            // 设置窗口为全屏布局模式,内容延伸到状态栏和导航栏下方
+            window.setDecorFitsSystemWindows(false)
+
+            // 获取窗口的 Insets 控制器,控制系统栏的显示/隐藏
+            window.insetsController?.let { controller ->
+                // 隐藏状态栏(显示时间、电量等系统信息的顶部栏)
+                controller.hide(WindowInsets.Type.statusBars())
+                // 隐藏导航栏(底部的返回/主页/多任务键)
+                controller.hide(WindowInsets.Type.navigationBars())
+                // 设置系统栏行为:用户交互时自动隐藏(防止用户滑动调出导航栏)
+                controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+            }
+        } else {
+            // Android 10 及以下版本使用传统的 systemUiVisibility 标志
+            @Suppress("DEPRECATION")
+            window.decorView.systemUiVisibility = (
+                // 全屏模式:内容延伸到状态栏后面
+                View.SYSTEM_UI_FLAG_FULLSCREEN
+                // 隐藏导航栏
+                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                // 沉浸式模式:用户交互后仍保持隐藏
+                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                // 内容延伸到导航栏后面
+                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                // 内容延伸到状态栏后面
+                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                // 保持布局稳定,防止系统栏显示/隐藏时内容跳动
+                or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+            )
+        }
+
+        // 保持屏幕常亮:迎检演示时防止屏幕自动熄灭
+        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+    }
+
+    /**
+     * 配置 WebView 的各项设置
+     * WebView 是 Android 内置的浏览器引擎(基于 Chromium),用于渲染 H5 页面
+     */
+    @SuppressLint("SetJavaScriptEnabled")
+    private fun setupWebView() {
+        webView.settings.apply {
+            // ===== JavaScript 支持 =====
+            // 启用 JavaScript:Vue 等现代前端框架需要 JS 才能运行,必须开启
+            javaScriptEnabled = true
+
+            // 启用 DOM Storage(Web Storage API):Vuex/Pinia 等状态管理库依赖此特性
+            domStorageEnabled = true
+
+            // 启用数据库存储:部分 H5 应用使用 Web SQL 或 IndexedDB
+            databaseEnabled = true
+
+            // 允许文件访问:WebView 可以加载本地文件(如 assets 中的资源)
+            allowFileAccess = true
+
+            // 允许内容访问:WebView 可以访问 ContentProvider 提供的内容
+            allowContentAccess = true
+
+            // 允许从文件 URL 访问其他文件 URL:本地 H5 页面可能需要加载本地其他资源
+            allowFileAccessFromFileURLs = true
+
+            // 允许从文件 URL 访问任意来源:本地页面可能需要访问网络资源
+            allowUniversalAccessFromFileURLs = true
+
+            // 允许自动播放媒体(音频/视频):语音播报功能需要自动播放
+            mediaPlaybackRequiresUserGesture = false
+
+            // 允许混合内容(HTTP + HTTPS):内网环境可能同时存在两种协议
+            mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
+
+            // 使用宽视口:H5 页面可以设置自己的 viewport,WebView 按页面要求渲染
+            useWideViewPort = true
+
+            // 以概览模式加载页面:页面宽度适配屏幕宽度
+            loadWithOverviewMode = true
+
+            // 禁用缩放按钮:kiosk 模式下不允许用户手动缩放
+            setSupportZoom(false)
+            builtInZoomControls = false
+            displayZoomControls = false
+
+            // 设置缓存策略:优先使用缓存,加快页面加载速度
+            cacheMode = WebSettings.LOAD_DEFAULT
+
+            // 设置 User-Agent:追加自定义标识,H5 侧可通过此判断是否在机器人环境中
+            // H5 代码示例:if (navigator.userAgent.includes('MedicalRobot')) { ... }
+            userAgentString = "$userAgentString MedicalRobot/1.0"
+
+            // 启用硬件加速:利用 GPU 渲染页面,提升动画和滚动性能
+            webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+        }
+
+        // ===== 调试模式配置 =====
+        // BuildConfig.DEBUG 在 Debug 构建时为 true,Release 构建时为 false
+        if (BuildConfig.DEBUG) {
+            // 启用 WebView 远程调试:允许 Chrome DevTools 连接到此 WebView
+            // 配合 Chrome 浏览器的 chrome://inspect 页面使用
+            WebView.setWebContentsDebuggingEnabled(true)
+        }
+
+        // ===== WebViewClient:处理页面加载事件 =====
+        // WebViewClient 控制 WebView 如何处理 URL 加载和页面事件
+        webView.webViewClient = object : WebViewClient() {
+
+            /**
+             * 页面开始加载时调用
+             * @param view WebView 实例
+             * @param url 正在加载的 URL
+             */
+            override fun onPageStarted(view: WebView?, url: String?, favicon: android.graphics.Bitmap?) {
+                super.onPageStarted(view, url, favicon)
+                // 显示加载动画,提示用户页面正在加载
+                progressBar.visibility = View.VISIBLE
+                hasLoadError = false
+            }
+
+            /**
+             * 页面加载完成时调用
+             * @param view WebView 实例
+             * @param url 已加载完成的 URL
+             */
+            override fun onPageFinished(view: WebView?, url: String?) {
+                super.onPageFinished(view, url)
+                // 隐藏加载动画
+                progressBar.visibility = View.GONE
+
+                // 如果之前加载失败,现在成功了,清除错误标志
+                if (hasLoadError) {
+                    hasLoadError = false
+                }
+            }
+
+            /**
+             * 页面加载出错时调用
+             * @param view WebView 实例
+             * @param request 失败的请求信息
+             * @param error 错误详情
+             */
+            override fun onReceivedError(
+                view: WebView?,
+                request: WebResourceRequest?,
+                error: WebResourceError?
+            ) {
+                super.onReceivedError(view, request, error)
+                // 标记加载失败状态
+                hasLoadError = true
+                progressBar.visibility = View.GONE
+
+                // 在主线程显示错误提示
+                runOnUiThread {
+                    Toast.makeText(
+                        this@MainActivity,
+                        "页面加载失败,请检查网络连接",
+                        Toast.LENGTH_LONG
+                    ).show()
+                }
+
+                // 可选:加载本地离线提示页
+                // webView.loadUrl("file:///android_asset/error.html")
+            }
+
+            /**
+             * 拦截 URL 加载请求
+             * 返回 true 表示由应用处理此 URL,返回 false 表示由 WebView 继续加载
+             * @param view WebView 实例
+             * @param request 加载请求
+             */
+            override fun shouldOverrideUrlLoading(
+                view: WebView?,
+                request: WebResourceRequest?
+            ): Boolean {
+                val url = request?.url?.toString() ?: return false
+
+                // 示例:拦截特定的自定义协议(如 robot://settings)
+                // if (url.startsWith("robot://")) {
+                //     handleRobotProtocol(url)
+                //     return true
+                // }
+
+                // 默认行为:由 WebView 继续加载
+                return false
+            }
+        }
+
+        // ===== WebChromeClient:处理 JS 弹窗和高级功能 =====
+        // WebChromeClient 处理需要与 UI 交互的 Web 功能
+        webView.webChromeClient = object : WebChromeClient() {
+
+            /**
+             * 处理 JavaScript 的 alert() 弹窗
+             * 默认行为是弹出系统对话框,这里使用原生 AlertDialog 替代
+             */
+            override fun onJsAlert(
+                view: WebView?,
+                url: String?,
+                message: String?,
+                result: android.webkit.JsResult?
+            ): Boolean {
+                // 创建 AlertDialog 替代默认弹窗
+                AlertDialog.Builder(this@MainActivity)
+                    .setTitle("提示") // 对话框标题
+                    .setMessage(message) // 显示 JS 传来的消息内容
+                    .setPositiveButton("确定") { _, _ ->
+                        // 用户点击确定后,通知 JS 弹窗已确认
+                        result?.confirm()
+                    }
+                    .setCancelable(false) // 禁止点击外部取消,确保 JS 流程继续
+                    .show()
+                return true // 返回 true 表示已处理此弹窗
+            }
+
+            /**
+             * 处理文件选择(如 <input type="file">)
+             * 用于 H5 页面上传图片、拍照等功能
+             */
+            override fun onShowFileChooser(
+                view: WebView?,
+                filePathCallback: android.webkit.ValueCallback<Array<android.net.Uri>>?,
+                fileChooserParams: FileChooserParams?
+            ): Boolean {
+                // 实际实现需要启动相机或文件选择器
+                // 简化示例:返回取消,H5 侧可降级处理
+                filePathCallback?.onReceiveValue(null)
+                return true
+            }
+        }
+    }
+
+    /**
+     * 注入 JSBridge 到 WebView
+     * 通过 @JavascriptInterface 注解,将 Kotlin 方法暴露给 JavaScript 调用
+     */
+    private fun injectJSBridge() {
+        // 创建 RobotBridge 实例,传入 WebView 和 SDK 管理器
+        robotBridge = RobotBridge(webView, MedicalRobotApplication.sdkManager)
+
+        // 将 RobotBridge 对象注入到 WebView 的 JavaScript 环境中
+        // 第二个参数 "RobotBridge" 是 JS 侧访问此对象时使用的名称
+        // JS 调用方式:window.RobotBridge.navigate("导诊台", "cb_001")
+        webView.addJavascriptInterface(robotBridge, "RobotBridge")
+    }
+
+    /**
+     * 加载 H5 页面
+     * 支持两种方式:远程服务器(开发推荐)或本地 assets(离线模式)
+     */
+    private fun loadPage() {
+        // ===== 方式 A:加载远程服务器页面(推荐,开发阶段使用) =====
+        // 优势:修改 H5 代码后无需重新打包 APK,刷新即可生效
+        // 替换为实际的后端服务器 IP 地址和端口
+        webView.loadUrl("http://192.168.1.100:8080")
+
+        // ===== 方式 B:加载本地 assets 中的打包文件(离线模式) =====
+        // 优势:无需网络,适合演示环境或网络不稳定场景
+        // 使用方法:将 Vue 打包后的 dist 目录内容复制到 app/src/main/assets/web/ 下
+        // 取消下面一行的注释即可切换到本地模式
+        // webView.loadUrl("file:///android_asset/web/index.html")
+    }
+
+    /**
+     * 处理返回键事件
+     * 系统回调:用户按下物理返回键时调用
+     */
+    override fun onBackPressed() {
+        // 检查 WebView 是否有历史记录可以后退
+        if (webView.canGoBack()) {
+            // WebView 可以后退(如从报告详情页返回到首页)
+            webView.goBack()
+        } else {
+            // WebView 已无历史记录,返回到 Launcher(不退出应用进程)
+            // moveTaskToBack 将当前任务移到后台,类似点击 Home 键
+            // true 表示即使当前 Activity 是根 Activity 也执行
+            moveTaskToBack(true)
+        }
+    }
+
+    /**
+     * 窗口焦点变化时调用
+     * 系统回调:Activity 获得或失去焦点时调用
+     * 用于在弹窗关闭后重新隐藏系统 UI
+     */
+    override fun onWindowFocusChanged(hasFocus: Boolean) {
+        super.onWindowFocusChanged(hasFocus)
+        // 当 Activity 重新获得焦点时,再次隐藏系统 UI
+        // 防止用户通过滑动调出导航栏后,焦点变化导致系统 UI 保持显示
+        if (hasFocus) {
+            hideSystemUI()
+        }
+    }
+
+    /**
+     * 系统内存不足时调用
+     * 系统回调:系统内存紧张时调用,应释放不必要的资源
+     */
+    override fun onLowMemory() {
+        super.onLowMemory()
+        // 清理 WebView 缓存,释放内存
+        webView.clearCache(true)
+        // 可选:清理历史记录、Cookie 等
+        // webView.clearHistory()
+    }
+
+    /**
+     * Activity 销毁时调用
+     * 系统回调:Activity 被销毁前调用,用于清理资源
+     */
+    override fun onDestroy() {
+        // 释放 WebView 资源,防止内存泄漏
+        // WebView 持有大量 native 资源,必须显式释放
+        webView.stopLoading()      // 停止正在进行的加载
+        webView.loadUrl("about:blank") // 加载空白页,释放当前页面资源
+        webView.clearHistory()     // 清除历史记录
+        webView.removeAllViews()   // 移除所有子视图
+        webView.destroy()          // 销毁 WebView 实例,释放 native 内存
+
+        // 调用父类实现
+        super.onDestroy()
+    }
+}
+```
+
+> **Web 开发者提示**:`AppCompatActivity` 类似于 Web 框架的页面控制器;`onCreate()` 类似于页面挂载时的 `mounted()` 钩子;`onDestroy()` 类似于 `beforeUnmount()` 钩子。`findViewById` 类似于 `document.getElementById()`。
+
+---
+
+### 4.13 补充:activity_main.xml 完整布局
+
+> 以下文件位于 `MedicalRobotApp/app/src/main/res/layout/activity_main.xml`。布局非常简单:全屏 WebView + 居中的加载进度条。
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- activity_main.xml:MainActivity 的界面布局文件 -->
+<!-- 作用:定义 WebView 容器和加载动画的位置与样式 -->
+
+<!-- ConstraintLayout:灵活的约束布局容器
+     xmlns:android:Android 命名空间,所有 Android 属性都需要此前缀
+     xmlns:app:应用级自定义属性命名空间(ConstraintLayout 的约束属性用此前缀)
+     android:layout_width/height="match_parent":宽高填满父容器(即整个屏幕)
+     android:background:背景颜色,使用主题中定义的背景色 -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="?attr/colorSurface">
+
+    <!-- WebView:网页渲染组件
+         android:id="@+id/webview":定义视图 ID,在 Kotlin 代码中通过 R.id.webview 引用
+         android:layout_width="0dp":ConstraintLayout 中 0dp 表示由约束决定尺寸
+         app:layout_constraintStart_toStartOf="parent":左边缘与父容器左边缘对齐
+         app:layout_constraintEnd_toEndOf="parent":右边缘与父容器右边缘对齐
+         app:layout_constraintTop_toTopOf="parent":上边缘与父容器上边缘对齐
+         app:layout_constraintBottom_toBottomOf="parent":下边缘与父容器下边缘对齐
+         以上四个约束的组合效果:WebView 填满整个 ConstraintLayout(即全屏) -->
+    <WebView
+        android:id="@+id/webview"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent" />
+
+    <!-- ProgressBar:圆形进度指示器(转圈圈)
+         style="?android:attr/progressBarStyleLarge":使用系统大号的进度圈样式
+         android:visibility="gone":初始状态不可见,页面开始加载时通过代码设为 visible
+         app:layout_constraintStart/End/Top/Bottom_toStart/End/Top/BottomOf="parent":在父容器中居中
+         注意:同时设置 top 和 bottom 约束到 parent,配合 0dp 高度可实现垂直居中
+               同时设置 start 和 end 约束到 parent,配合 0dp 宽度可实现水平居中 -->
+    <ProgressBar
+        android:id="@+id/progress_bar"
+        style="?android:attr/progressBarStyleLarge"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
+```
+
+> **Web 开发者提示**:`ConstraintLayout` 类似于 CSS Flexbox + Absolute Positioning 的结合体。`match_parent` 类似于 `width: 100%`,`wrap_content` 类似于 `width: auto`(由内容决定)。`0dp` 在 ConstraintLayout 中表示由约束决定尺寸,类似于 CSS 中同时设置 `left: 0; right: 0;`。
+
+### 4.14 补充:RobotBridge.kt 完整 JSBridge 实现
+
+> RobotBridge 是 Native 与 H5 之间的通信桥梁。H5 页面通过 `window.RobotBridge.xxx()` 调用 Native 方法,Native 通过 `webView.evaluateJavascript()` 将结果回传给 H5。以下代码包含全部 7 个接口的完整实现,支持 Mock 模式。
+
+```kotlin
+package com.emoon.medical.robot
+
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.webkit.JavascriptInterface
+import android.webkit.WebView
+import org.json.JSONObject
+
+/**
+ * JSBridge 桥接类:连接 H5 JavaScript 与 Android Native 代码
+ * 职责:
+ * 1. 接收 H5 通过 window.RobotBridge 发起的调用请求
+ * 2. 转发请求到 RobotSDKManager 执行实际的 SDK 操作
+ * 3. 将 SDK 执行结果通过 evaluateJavascript 回传给 H5
+ * 4. 提供 Mock 模式,支持在 PC 模拟器上完整调试
+ *
+ * 通信协议(callbackId 模式):
+ * 1. H5 生成唯一 callbackId,将回调函数注册到 window.__robotCallbacks[callbackId]
+ * 2. H5 调用 window.RobotBridge.methodName(arg1, arg2, ..., callbackId)
+ * 3. Native 的 @JavascriptInterface 方法被触发,在子线程执行 SDK 调用
+ * 4. SDK 返回结果后,Native 通过 webView.evaluateJavascript 执行:
+ *    window.__robotCallbacks[callbackId](resultJson)
+ * 5. H5 的回调函数被执行,处理返回数据
+ */
+class RobotBridge(
+    private val webView: WebView,
+    private val sdkManager: RobotSDKManager
+) {
+
+    // 日志标签
+    private val tag = "RobotBridge"
+
+    // 主线程 Handler:用于从子线程切换回主线程操作 WebView
+    // WebView 的所有操作必须在主线程执行
+    private val mainHandler = Handler(Looper.getMainLooper())
+
+    // Mock 模式标志:从 Application 全局配置读取
+    private val isMock: Boolean
+        get() = MedicalRobotApplication.useMockMode
+
+    /**
+     * 统一回调方法:将结果 JSON 字符串回传给 H5
+     * @param callbackId H5 传入的回调标识
+     * @param resultJson 结果数据的 JSON 字符串
+     */
+    private fun callbackToH5(callbackId: String, resultJson: String) {
+        // 构造要执行的 JavaScript 代码
+        // 先检查 __robotCallbacks 和指定 callbackId 是否存在,避免空指针
+        val jsCode = """
+            (function() {
+                var cb = window.__robotCallbacks && window.__robotCallbacks['$callbackId'];
+                if (typeof cb === 'function') {
+                    cb($resultJson);
+                    delete window.__robotCallbacks['$callbackId'];
+                    return 'callback_executed';
+                } else {
+                    return 'callback_not_found';
+                }
+            })()
+        """.trimIndent()
+
+        // 切换到主线程执行(WebView 必须在主线程操作)
+        mainHandler.post {
+            // evaluateJavascript:在 WebView 中执行 JavaScript 代码
+            // 第二个参数是结果回调(此处不需要,传 null)
+            webView.evaluateJavascript(jsCode, null)
+        }
+    }
+
+    /**
+     * 构造标准成功响应 JSON
+     * @param data 业务数据(可选)
+     * @return JSON 字符串 {"code": 0, "msg": "success", ...data}
+     */
+    private fun successJson(data: Map<String, Any?> = emptyMap()): String {
+        val json = JSONObject()
+        json.put("code", 0)
+        json.put("msg", "success")
+        data.forEach { (key, value) -> json.put(key, value) }
+        return json.toString()
+    }
+
+    /**
+     * 构造标准错误响应 JSON
+     * @param code 错误码
+     * @param message 错误描述
+     * @return JSON 字符串 {"code": code, "msg": "message"}
+     */
+    private fun errorJson(code: Int, message: String): String {
+        val json = JSONObject()
+        json.put("code", code)
+        json.put("msg", message)
+        return json.toString()
+    }
+
+    // ===== 接口 1:导航到指定位置 =====
+
+    /**
+     * 导航到指定位置点
+     * @JavascriptInterface 注解:将此方法暴露给 JavaScript 调用
+     * @param destination 目标位置点名称(如 "导诊台"、"神经内科")
+     * @param callbackId H5 生成的回调标识
+     */
+    @JavascriptInterface
+    fun navigate(destination: String, callbackId: String) {
+        Log.i(tag, "JSBridge 收到导航请求: destination=$destination, callbackId=$callbackId")
+
+        // 在子线程中执行 SDK 调用,避免阻塞 WebView 的 JS 线程
+        Thread {
+            // 调用 SDK 管理器的导航方法
+            sdkManager.startNavigation(destination, object : RobotSDKManager.OperationCallback {
+                override fun onSuccess(data: String) {
+                    // 导航成功,构造成功响应并回传
+                    val result = successJson(mapOf(
+                        "destination" to destination,
+                        "sdkData" to data
+                    ))
+                    Log.i(tag, "导航成功,回传结果: $result")
+                    callbackToH5(callbackId, result)
+                }
+
+                override fun onError(code: Int, message: String) {
+                    // 导航失败,构造错误响应并回传
+                    val result = errorJson(code, message)
+                    Log.e(tag, "导航失败,回传结果: $result")
+                    callbackToH5(callbackId, result)
+                }
+            })
+        }.start()
+    }
+
+    // ===== 接口 2:停止导航 =====
+
+    /**
+     * 停止当前导航
+     * @param callbackId H5 生成的回调标识
+     */
+    @JavascriptInterface
+    fun stopNavigation(callbackId: String) {
+        Log.i(tag, "JSBridge 收到停止导航请求: callbackId=$callbackId")
+
+        Thread {
+            sdkManager.stopNavigation(object : RobotSDKManager.OperationCallback {
+                override fun onSuccess(data: String) {
+                    val result = successJson()
+                    Log.i(tag, "停止导航成功")
+                    callbackToH5(callbackId, result)
+                }
+
+                override fun onError(code: Int, message: String) {
+                    val result = errorJson(code, message)
+                    Log.e(tag, "停止导航失败: $message")
+                    callbackToH5(callbackId, result)
+                }
+            })
+        }.start()
+    }
+
+    // ===== 接口 3:获取位置点列表 =====
+
+    /**
+     * 获取地图中所有预设位置点列表
+     * @param callbackId H5 生成的回调标识
+     */
+    @JavascriptInterface
+    fun getPlaceList(callbackId: String) {
+        Log.i(tag, "JSBridge 收到获取位置点列表请求: callbackId=$callbackId")
+
+        Thread {
+            sdkManager.getPlaceList(object : RobotSDKManager.OperationCallback {
+                override fun onSuccess(data: String) {
+                    // data 是 JSON 数组字符串,直接放入响应中
+                    val result = successJson(mapOf("places" to data))
+                    Log.i(tag, "获取位置点列表成功")
+                    callbackToH5(callbackId, result)
+                }
+
+                override fun onError(code: Int, message: String) {
+                    val result = errorJson(code, message)
+                    Log.e(tag, "获取位置点列表失败: $message")
+                    callbackToH5(callbackId, result)
+                }
+            })
+        }.start()
+    }
+
+    // ===== 接口 4:获取当前位置 =====
+
+    /**
+     * 获取机器人当前坐标位置
+     * @param callbackId H5 生成的回调标识
+     */
+    @JavascriptInterface
+    fun getPosition(callbackId: String) {
+        Log.i(tag, "JSBridge 收到获取位置请求: callbackId=$callbackId")
+
+        Thread {
+            sdkManager.getPosition(object : RobotSDKManager.OperationCallback {
+                override fun onSuccess(data: String) {
+                    val result = successJson(mapOf("position" to data))
+                    Log.i(tag, "获取位置成功: $data")
+                    callbackToH5(callbackId, result)
+                }
+
+                override fun onError(code: Int, message: String) {
+                    val result = errorJson(code, message)
+                    Log.e(tag, "获取位置失败: $message")
+                    callbackToH5(callbackId, result)
+                }
+            })
+        }.start()
+    }
+
+    // ===== 接口 5:TTS 语音播报 =====
+
+    /**
+     * 播放 TTS 语音播报
+     * @param text 要播报的文本内容
+     * @param callbackId H5 生成的回调标识
+     */
+    @JavascriptInterface
+    fun playTTS(text: String, callbackId: String) {
+        Log.i(tag, "JSBridge 收到 TTS 请求: text=$text, callbackId=$callbackId")
+
+        // 输入校验:文本不能为空
+        if (text.isBlank()) {
+            val result = errorJson(-3, "TTS 文本不能为空")
+            callbackToH5(callbackId, result)
+            return
+        }
+
+        Thread {
+            sdkManager.playTTS(text, object : RobotSDKManager.OperationCallback {
+                override fun onSuccess(data: String) {
+                    val result = successJson(mapOf("text" to text))
+                    Log.i(tag, "TTS 播报成功: $text")
+                    callbackToH5(callbackId, result)
+                }
+
+                override fun onError(code: Int, message: String) {
+                    val result = errorJson(code, message)
+                    Log.e(tag, "TTS 播报失败: $message")
+                    callbackToH5(callbackId, result)
+                }
+            })
+        }.start()
+    }
+
+    // ===== 接口 6:停止 TTS =====
+
+    /**
+     * 停止 TTS 语音播报
+     * @param callbackId H5 生成的回调标识
+     */
+    @JavascriptInterface
+    fun stopTTS(callbackId: String) {
+        Log.i(tag, "JSBridge 收到停止 TTS 请求: callbackId=$callbackId")
+
+        Thread {
+            sdkManager.stopTTS(object : RobotSDKManager.OperationCallback {
+                override fun onSuccess(data: String) {
+                    val result = successJson()
+                    Log.i(tag, "停止 TTS 成功")
+                    callbackToH5(callbackId, result)
+                }
+
+                override fun onError(code: Int, message: String) {
+                    val result = errorJson(code, message)
+                    Log.e(tag, "停止 TTS 失败: $message")
+                    callbackToH5(callbackId, result)
+                }
+            })
+        }.start()
+    }
+
+    // ===== 接口 7:获取电量 =====
+
+    /**
+     * 获取机器人当前电量
+     * @param callbackId H5 生成的回调标识
+     */
+    @JavascriptInterface
+    fun getBattery(callbackId: String) {
+        Log.i(tag, "JSBridge 收到获取电量请求: callbackId=$callbackId")
+
+        Thread {
+            sdkManager.getBatteryLevel(object : RobotSDKManager.OperationCallback {
+                override fun onSuccess(data: String) {
+                    // data 是 JSON 字符串 {"level": 85}
+                    val result = successJson(mapOf("battery" to data))
+                    Log.i(tag, "获取电量成功: $data")
+                    callbackToH5(callbackId, result)
+                }
+
+                override fun onError(code: Int, message: String) {
+                    val result = errorJson(code, message)
+                    Log.e(tag, "获取电量失败: $message")
+                    callbackToH5(callbackId, result)
+                }
+            })
+        }.start()
+    }
+}
+```
+
+> **回调处理说明**:所有接口都采用统一的回调协议。H5 侧调用时需按以下方式封装:
+> ```javascript
+> // H5 侧调用示例
+> const callbackId = 'nav_' + Date.now();
+> window.__robotCallbacks[callbackId] = (result) => {
+>   if (result.code === 0) {
+>     console.log('成功:', result);
+>   } else {
+>     console.error('失败:', result.msg);
+>   }
+> };
+> window.RobotBridge.navigate('神经内科', callbackId);
+> ```
+
+---
+
+### 4.15 补充:WebView 与原生交互原理图解
+
+> 以下图解帮助 Web 开发者理解 H5 页面如何与 Android Native 代码通信。
+
+**通信流程(以导航为例):**
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│                              调用流程(H5 → Native)                           │
+└─────────────────────────────────────────────────────────────────────────────┘
+
+  H5 页面 (JavaScript)
+       │
+       ├── 用户点击 "带我去神经内科" 按钮
+       │
+       ├── H5 生成唯一 callbackId: "cb_001"
+       │   └── window.__robotCallbacks["cb_001"] = function(result) { ... }
+       │
+       ├── 调用 Native 方法
+       │   └── window.RobotBridge.navigate("神经内科", "cb_001")
+       │       │
+       │       ▼
+       │   ┌─────────────────────────────────────┐
+       │   │  @JavascriptInterface               │
+       │   │  WebView 拦截并调用 Android 方法    │
+       │   │  RobotBridge.navigate(...)          │
+       │   └─────────────────────────────────────┘
+       │       │
+       │       ▼
+       │   ┌─────────────────────────────────────┐
+       │   │  切换到子线程执行                    │
+       │   │  Thread { sdkManager.startNavigation(...) }
+       │   └─────────────────────────────────────┘
+       │       │
+       │       ▼
+       │   ┌─────────────────────────────────────┐
+       │   │  调用猎户星空 SDK API               │
+       │   │  RobotApi.startNavigation("神经内科") │
+       │   └─────────────────────────────────────┘
+       │       │
+       │       ▼
+       │   ┌─────────────────────────────────────┐
+       │   │  机器人硬件执行导航                  │
+       │   │  底盘运动、避障、到达目标点          │
+       │   └─────────────────────────────────────┘
+       │
+
+┌─────────────────────────────────────────────────────────────────────────────┐
+│                              回调流程(Native → H5)                           │
+└─────────────────────────────────────────────────────────────────────────────┘
+
+  机器人硬件
+       │
+       ├── 导航完成(到达目标点或出错)
+       │
+       ├── SDK 回调结果到 RobotSDKManager
+       │
+       ├── RobotSDKManager 回调到 RobotBridge
+       │
+       ├── RobotBridge 构造 JSON 结果
+       │   └── { "code": 0, "msg": "success", "destination": "神经内科" }
+       │
+       ├── 切换到主线程(WebView 必须在主线程操作)
+       │   └── mainHandler.post { ... }
+       │
+       ├── 通过 evaluateJavascript 执行 JS 回调
+       │   └── webView.evaluateJavascript(
+       │         "window.__robotCallbacks['cb_001']({...})")
+       │       │
+       │       ▼
+       │   ┌─────────────────────────────────────┐
+       │   │  H5 的回调函数被执行                │
+       │   │  window.__robotCallbacks["cb_001"](result)
+       │   │  └── 更新 UI:显示 "已到达神经内科"  │
+       │   └─────────────────────────────────────┘
+       │
+       └── 清理:delete window.__robotCallbacks["cb_001"]
+```
+
+**Mermaid 序列图:**
+
+```mermaid
+sequenceDiagram
+    participant H5 as H5 页面 (JavaScript)
+    participant WV as WebView
+    participant RB as RobotBridge
+    participant SM as RobotSDKManager
+    participant SDK as 猎户星空 SDK
+    participant HW as 机器人硬件
+
+    H5->>H5: 生成 callbackId = "cb_001"
+    H5->>H5: window.__robotCallbacks["cb_001"] = callbackFn
+    H5->>WV: window.RobotBridge.navigate("神经内科", "cb_001")
+    WV->>RB: @JavascriptInterface navigate()
+    RB->>SM: startNavigation()
+    SM->>SDK: RobotApi.startNavigation()
+    SDK->>HW: 执行导航
+    HW-->>SDK: 导航结果
+    SDK-->>SM: 回调结果
+    SM-->>RB: onSuccess/onError
+    RB->>RB: 构造 JSON 响应
+    RB->>WV: evaluateJavascript("window.__robotCallbacks['cb_001'](result)")
+    WV->>H5: 执行 JS 回调函数
+    H5->>H5: 更新 UI / 提示用户
+    H5->>H5: delete window.__robotCallbacks["cb_001"]
+```
+
+> **关键设计决策**:
+> 1. **callbackId 模式**:因为 `@JavascriptInterface` 只支持基本类型参数,无法传递 JS 函数对象,所以用字符串 ID 关联回调
+> 2. **子线程执行**:SDK 调用可能耗时(如网络请求、硬件操作),必须在子线程执行避免阻塞 WebView
+> 3. **主线程回调**:`evaluateJavascript` 必须在主线程调用,因此使用 `Handler(Looper.getMainLooper())` 切换线程
+
+---
+
+### 4.16 补充:ADB 调试完整指南
+
+> ADB(Android Debug Bridge)是 Android 开发的必备调试工具。本节面向从未使用过 ADB 的 Web 开发者,涵盖从连接到排错的完整流程。
+
+#### 4.16.1 连接机器人设备
+
+**方式一:USB 连接(有线连接)**
+- 使用 USB 数据线将开发电脑连接到机器人主板的 USB 接口
+- 在机器人系统设置中启用 "USB 调试"(通常在 设置 → 开发者选项 → USB 调试)
+- 首次连接时,机器人屏幕会弹出 "允许 USB 调试吗?" 的授权对话框,点击 "确定"
+
+**方式二:WiFi 连接(无线连接,推荐)**
+- 确保开发电脑和机器人在同一局域网内
+- 先用 USB 连接一次,执行以下命令启用网络调试:
+  ```bash
+  adb tcpip 5555
+  ```
+- 断开 USB 线,然后通过 WiFi 连接:
+  ```bash
+  # 将 192.168.1.xxx 替换为机器人的实际 IP 地址
+  adb connect 192.168.1.xxx:5555
+  ```
+- 后续无需再插 USB 线,直接通过 WiFi 调试
+
+#### 4.16.2 验证连接状态
+
+```bash
+# 查看已连接的设备列表
+adb devices
+```
+
+正常输出示例:
+```
+List of devices attached
+192.168.1.100:5555    device
+```
+
+- `device` 表示连接正常,可以进行调试
+- `unauthorized` 表示未授权,需要在机器人屏幕上确认 USB 调试授权
+- `offline` 表示设备离线,检查网络或重新连接
+
+#### 4.16.3 安装 APK
+
+```bash
+# 安装 APK 到机器人设备
+adb install app/build/outputs/apk/debug/app-debug.apk
+
+# -r 参数:覆盖安装(保留应用数据,升级时使用)
+adb install -r app/build/outputs/apk/debug/app-debug.apk
+
+# 如果安装失败,先卸载再安装
+adb uninstall com.emoon.medical.robot
+adb install app/build/outputs/apk/debug/app-debug.apk
+```
+
+#### 4.16.4 查看实时日志
+
+```bash
+# 查看所有日志(信息量大,建议配合过滤使用)
+adb logcat
+
+# 只查看 MedicalRobot 标签的日志(推荐)
+adb logcat -s MedicalRobot:V
+
+# 同时查看多个标签的日志
+adb logcat -s MedicalRobot:V RobotSDKManager:V RobotBridge:V
+
+# 查看日志并保存到文件(方便后续分析)
+adb logcat -s MedicalRobot:V > robot_log.txt
+
+# 清除旧日志后查看(避免历史日志干扰)
+adb logcat -c && adb logcat -s MedicalRobot:V
+```
+
+> **日志级别说明**:`V` = Verbose(所有级别),`D` = Debug,`I` = Info,`W` = Warn,`E` = Error。`-s MedicalRobot:V` 表示显示 MedicalRobot 标签的所有级别日志。
+
+#### 4.16.5 远程调试 WebView
+
+这是调试 H5 页面最强大的方式,可以直接使用 Chrome DevTools:
+
+1. **确保代码中启用了 WebView 调试**(已在 MainActivity.kt 中配置):
+   ```kotlin
+   if (BuildConfig.DEBUG) {
+       WebView.setWebContentsDebuggingEnabled(true)
+   }
+   ```
+
+2. **在开发电脑的 Chrome 浏览器中访问**:
+   ```
+   chrome://inspect
+   ```
+
+3. **在 "Remote Target" 区域找到你的 WebView**:
+   - 显示设备名称 + WebView 加载的 URL
+   - 例如:`ORIONSTAR-001 - http://192.168.1.100:8080`
+
+4. **点击 "inspect" 按钮**:
+   - 会打开独立的 Chrome DevTools 窗口
+   - 功能与桌面端完全一致:Elements、Console、Network、Sources、Application 等
+   - 可以在 Console 中直接执行 JS 代码测试 RobotBridge 接口
+
+#### 4.16.6 截屏
+
+```bash
+# 截取当前屏幕并保存到电脑
+adb exec-out screencap -p > screenshot.png
+
+# 先保存到设备,再拉取到电脑
+adb shell screencap -p /sdcard/screen.png
+adb pull /sdcard/screen.png ./screen.png
+```
+
+#### 4.16.7 卸载应用
+
+```bash
+# 按包名卸载应用
+adb uninstall com.emoon.medical.robot
+
+# 卸载但保留数据(应用数据不会被删除)
+adb shell pm uninstall -k com.emoon.medical.robot
+```
+
+#### 4.16.8 常用排错命令
+
+```bash
+# 只看错误级别的日志(快速定位崩溃原因)
+adb logcat *:E
+
+# 查看当前前台 Activity(确认应用是否在运行)
+adb shell dumpsys activity top
+
+# 查看已安装的应用包列表(确认应用是否安装成功)
+adb shell pm list packages | grep emoon
+
+# 查看设备信息(Android 版本、SDK 版本等)
+adb shell getprop ro.build.version.release
+
+# 查看应用进程是否在运行
+adb shell ps | grep medical
+
+# 强制停止应用(相当于系统设置中的 "强行停止")
+adb shell am force-stop com.emoon.medical.robot
+
+# 重启设备
+adb reboot
+
+# 进入设备的 shell 环境(可以执行 Linux 命令)
+adb shell
+
+# 从电脑推送文件到设备
+adb push local_file.txt /sdcard/remote_file.txt
+
+# 从设备拉取文件到电脑
+adb pull /sdcard/remote_file.txt ./local_file.txt
+```
+
+> **排错建议**:如果应用启动后白屏,首先检查 `adb logcat *:E` 查看是否有崩溃信息;如果 WebView 页面加载失败,使用 `chrome://inspect` 检查 Network 面板查看请求状态。
+
+---
+
+### 4.17 补充:network_security_config.xml
+
+> 以下文件位于 `MedicalRobotApp/app/src/main/res/xml/network_security_config.xml`。用于配置网络安全策略,允许应用访问明文 HTTP 通信(内网环境必需)。
+
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<!-- network_security_config.xml:网络安全配置文件 -->
+<!-- 作用:自定义应用的网络安全策略,覆盖系统默认行为 -->
+<!-- 注意:此配置仅适用于内网迎检环境,生产环境应使用 HTTPS -->
+<network-security-config>
+
+    <!-- base-config:基础安全配置,应用于所有域名 -->
+    <!-- cleartextTrafficPermitted="true":允许明文 HTTP 通信 -->
+    <!-- 默认情况下 Android 9.0+ 禁止明文 HTTP,必须配置此选项才能访问 HTTP URL -->
+    <base-config cleartextTrafficPermitted="true">
+        <!-- trust-anchors:定义信任的证书颁发机构 -->
+        <trust-anchors>
+            <!-- 信任系统预装的 CA 证书(大多数 HTTPS 网站使用) -->
+            <certificates src="system" />
+            <!-- 如需信任用户安装的自定义证书(如内网自签名证书),添加以下行: -->
+            <!-- <certificates src="user" /> -->
+        </trust-anchors>
+    </base-config>
+
+    <!-- 如需针对特定域名配置(比全局配置更安全),使用 domain-config: -->
+    <!--
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">192.168.1.100</domain>
+        <domain includeSubdomains="true">localhost</domain>
+        <trust-anchors>
+            <certificates src="system" />
+        </trust-anchors>
+    </domain-config>
+    -->
+
+</network-security-config>
+```
+
+> **安全警告**:`<base-config cleartextTrafficPermitted="true">` 会允许所有域名的明文 HTTP 通信。在生产环境中,建议改用注释中的 `<domain-config>` 方式,仅允许特定内网 IP 或域名的明文通信,其他请求仍强制使用 HTTPS。
+
+---
+
+## 五、H5 前端适配改造
+
+> 本章面向对移动端开发不熟悉的全栈 Web 工程师(Java + Vue 背景),提供可直接复制使用的完整代码。当前前端基于 Vue 3 + Composition API,构建工具为 `@vue/cli-service`。
+
+### 5.1 新增 robot.js — 机器人原生能力桥接层
+
+在 `medical-card-demo/frontend/src/api/` 目录下新建 `robot.js`,完整代码如下(可直接复制使用):
+
+```javascript
+/**
+ * robot.js - 机器人原生能力桥接层
+ *
+ * 职责:
+ * 1. 检测当前是否在机器人 WebView 环境中
+ * 2. 封装所有 JSBridge 调用为 Promise
+ * 3. 管理全局回调池
+ * 4. 非机器人环境下提供优雅降级
+ *
+ * 文件位置:/src/api/robot.js
+ */
+
+// ========== 全局回调池管理 ==========
+window.__robotCallbacks = window.__robotCallbacks || {}
+let _callbackCounter = 0
+
+/**
+ * 生成唯一回调 ID
+ */
+function generateCallbackId(prefix) {
+  return `${prefix}_${++_callbackCounter}_${Date.now()}`
+}
+
+/**
+ * 检测当前是否在机器人 WebView 环境中
+ * 判断依据:原生 App 会注入 window.RobotBridge 对象
+ * 同时检查 UserAgent 中是否包含 MedicalRobot 标识
+ */
+export function isRobotEnv() {
+  return !!(window.RobotBridge) || navigator.userAgent.includes('MedicalRobot')
+}
+
+/**
+ * 通用原生方法调用封装
+ * @param {string} method - RobotBridge 上的方法名
+ * @param {Array} args - 方法参数(不含 callbackId)
+ * @param {string} prefix - 回调 ID 前缀
+ * @param {number} timeout - 超时时间(毫秒),默认 30 秒
+ * @returns {Promise}
+ */
+function callNative(method, args = [], prefix = 'cb', timeout = 30000) {
+  return new Promise((resolve, reject) => {
+    // 非机器人环境降级处理
+    if (!isRobotEnv()) {
+      reject(new Error(`非机器人环境,无法调用 ${method}`))
+      return
+    }
+
+    // 检查方法是否存在
+    if (typeof window.RobotBridge[method] !== 'function') {
+      reject(new Error(`RobotBridge.${method} 方法不存在`))
+      return
+    }
+
+    const cbId = generateCallbackId(prefix)
+
+    // 超时处理
+    const timer = setTimeout(() => {
+      delete window.__robotCallbacks[cbId]
+      reject(new Error(`${method} 调用超时(${timeout}ms)`))
+    }, timeout)
+
+    // 注册回调
+    window.__robotCallbacks[cbId] = (result) => {
+      clearTimeout(timer)
+      delete window.__robotCallbacks[cbId]
+      if (result && result.code === 0) {
+        resolve(result)
+      } else {
+        reject(result || { code: -1, msg: '未知错误' })
+      }
+    }
+
+    // 执行原生调用
+    try {
+      window.RobotBridge[method](...args, cbId)
+    } catch (e) {
+      clearTimeout(timer)
+      delete window.__robotCallbacks[cbId]
+      reject(new Error(`调用 ${method} 异常: ${e.message}`))
+    }
+  })
+}
+
+// ========== 导航相关 API ==========
+
+/** 导航到指定位置(机器人带路) */
+export const navigateTo = (destination) =>
+  callNative('navigate', [destination], 'nav', 60000)  // 导航超时 60 秒
+
+/** 停止导航 */
+export const stopNavigation = () =>
+  callNative('stopNavigation', [], 'stopnav')
+
+/** 获取所有位置点列表 */
+export const getPlaceList = () =>
+  callNative('getPlaceList', [], 'places')
+
+/** 获取当前坐标 {x, y, theta} */
+export const getPosition = () =>
+  callNative('getPosition', [], 'pos')
+
+// ========== 语音相关 API ==========
+
+/** TTS 语音播报 */
+export const playTTS = (text) =>
+  callNative('playTTS', [text], 'tts')
+
+/** 停止 TTS */
+export const stopTTS = () =>
+  callNative('stopTTS', [], 'stoptts')
+
+// ========== 设备信息 API ==========
+
+/** 获取电量百分比 */
+export const getBattery = () =>
+  callNative('getBattery', [], 'bat')
+
+// ========== 辅助工具 ==========
+
+/**
+ * 在非机器人环境下模拟 RobotBridge(开发调试用)
+ * 在 main.js 中调用此方法可以在浏览器中模拟机器人环境
+ */
+export function enableDevMock() {
+  if (isRobotEnv()) return  // 真实环境不覆盖
+
+  console.warn('[robot.js] 开发模式:启用 Mock RobotBridge')
+  window.RobotBridge = {
+    navigate(dest, cbId) {
+      setTimeout(() => {
+        window.__robotCallbacks[cbId]?.({ code: 0, msg: 'mock_navigation_started', destination: dest })
+      }, 500)
+    },
+    stopNavigation(cbId) {
+      setTimeout(() => {
+        window.__robotCallbacks[cbId]?.({ code: 0, msg: 'mock_stopped' })
+      }, 200)
+    },
+    getPlaceList(cbId) {
+      setTimeout(() => {
+        window.__robotCallbacks[cbId]?.({
+          code: 0,
+          data: [
+            { name: '门诊大厅', x: 0, y: 0 },
+            { name: '内科诊室', x: 10.5, y: 3.2 },
+            { name: '外科诊室', x: 15.0, y: -2.1 },
+            { name: '药房', x: 5.3, y: 8.7 },
+            { name: '检验科', x: 20.0, y: 0.5 }
+          ]
+        })
+      }, 300)
+    },
+    getPosition(cbId) {
+      setTimeout(() => {
+        window.__robotCallbacks[cbId]?.({ code: 0, data: { x: 0.0, y: 0.0, theta: 0.0 } })
+      }, 100)
+    },
+    playTTS(text, cbId) {
+      console.log(`[Mock TTS] 播报: ${text}`)
+      setTimeout(() => {
+        window.__robotCallbacks[cbId]?.({ code: 0, msg: 'mock_tts_done' })
+      }, text.length * 100)
+    },
+    stopTTS(cbId) {
+      setTimeout(() => {
+        window.__robotCallbacks[cbId]?.({ code: 0, msg: 'mock_tts_stopped' })
+      }, 100)
+    },
+    getBattery(cbId) {
+      setTimeout(() => {
+        window.__robotCallbacks[cbId]?.({ code: 0, data: { level: 85 } })
+      }, 100)
+    }
+  }
+}
+```
+
+**代码要点说明:**
+
+| 要点 | 说明 |
+|------|------|
+| `isRobotEnv()` | 同时检测 `window.RobotBridge` 和 UserAgent,防止误判 |
+| `callNative()` | 所有原生调用统一走此函数,自带超时、异常处理、回调清理 |
+| callbackId 模式 | 每个调用生成唯一 ID,通过全局 `__robotCallbacks` 池管理,避免回调地狱 |
+| `enableDevMock()` | 浏览器开发时模拟机器人环境,无需真机即可调试导航逻辑 |
+
+---
+
+### 5.2 DepartmentSelectionCard.vue 改造 — 增加"带我去"导航按钮
+
+> 现有 `DepartmentSelectionCard.vue` 已使用 Vue 3 Composition API(`setup()`)。以下仅展示需要**新增或修改**的代码片段,直接合并到现有文件中即可。
+
+#### 1)script 部分修改
+
+在 `<script>` 顶部新增 import:
+
+```javascript
+import { ref, computed } from 'vue'
+import { isRobotEnv, navigateTo } from '@/api/robot'  // 新增:引入机器人桥接
+```
+
+在 `setup()` 函数内新增 `isRobot` 状态和 `goToDepartment` 方法:
+
+```javascript
+  setup(props, { emit }) {
+    const selectedDepartment = ref('')
+    const isRobot = ref(isRobotEnv())  // 新增:机器人环境检测状态
+
+    // ... 原有 computed 和 methods 不变 ...
+
+    // 新增:机器人导航方法
+    const goToDepartment = async () => {
+      const deptName = selectedDepartmentInfo.value?.name
+      if (!deptName) return
+      try {
+        await navigateTo(deptName)
+      } catch (e) {
+        console.error('导航调用失败:', e)
+        alert('导航启动失败:' + (e?.message || '未知错误'))
+      }
+    }
+
+    return {
+      selectedDepartment,
+      departments,
+      selectedDepartmentInfo,
+      handleDepartmentChange,
+      confirmSelection,
+      isRobot,           // 新增:暴露到模板
+      goToDepartment     // 新增:暴露到模板
+    }
+  }
+```
+
+#### 2)template 部分修改
+
+在确认按钮下方新增"带我去"按钮(仅机器人环境显示,且需先选择科室):
+
+```vue
+      <button
+        class="confirm-button"
+        :disabled="!selectedDepartment"
+        @click="confirmSelection"
+      >
+        确认选择
+      </button>
+
+      <!-- 新增:机器人导航按钮 -->
+      <button
+        v-if="isRobot && selectedDepartment"
+        class="navigate-button"
+        @click="goToDepartment"
+      >
+        <span class="nav-icon">🤖</span>
+        带我去
+      </button>
+```
+
+#### 3)style 部分新增
+
+在 `<style scoped>` 末尾追加以下样式:
+
+```css
+/* 带我去按钮 — 大尺寸、触屏友好、医疗蓝配色 */
+.navigate-button {
+  width: 100%;
+  padding: 16px;
+  margin-top: 12px;
+  background: #e6f7ff;
+  color: #1a5f9e;
+  border: 2px solid #1a5f9e;
+  border-radius: 12px;
+  font-size: 17px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  min-height: 52px;  /* 触屏最小触控高度 52px */
+}
+
+.navigate-button:hover {
+  background: #1a5f9e;
+  color: white;
+  transform: translateY(-2px);
+  box-shadow: 0 8px 20px rgba(26, 95, 158, 0.4);
+}
+
+.nav-icon {
+  font-size: 20px;
+}
+```
+
+**兼容性说明:**
+- 现有组件使用 `setup()` 而非 `methods:`,因此 `isRobotEnv` 不作为方法直接使用,而是在 setup 内调用并赋值给 `isRobot` ref
+- `v-if="isRobot && selectedDepartment"` 同时控制两个条件:必须在机器人环境且已选择科室才显示导航按钮
+- 按钮最小高度 **52px**,超过 iOS 人机界面指南推荐的 44px 最小触控区域,适合机器人触摸屏操作
+
+---
+
+### 5.3 ChatInterface.vue 横屏适配改造
+
+> 当前 `ChatInterface.vue` 采用竖屏手机风格设计(`max-width: 480px`),在机器人横屏(通常为 1280×800 或类似分辨率)上会导致两侧大量留白、内容区域过小。本节给出完整的横屏适配方案。
+
+#### 当前需要修改的硬编码竖屏尺寸
+
+| 选择器 | 当前竖屏值 | 问题 |
+|--------|-----------|------|
+| `.chat-container` | `max-width: 480px; max-height: 900px` | 横屏时容器宽度被限制,两侧留白 |
+| `.chat-header` | `padding: 12px 15px` | 横屏时头部过矮,视觉拥挤 |
+| `.header-avatar` | `width: 36px; height: 36px` | 机器人屏幕观看距离远,头像过小 |
+| `.header-title` | `font-size: 14px` | 字体偏小,远处看不清 |
+| `.header-subtitle` | `font-size: 9px` | 几乎不可读 |
+| `.message-avatar` | `width: 36px; height: 36px` | 头像尺寸不足 |
+| `.message-text` | `font-size: 14px; padding: 12px 16px` | 消息文字偏小 |
+| `.voice-button` | `width: 40px; height: 40px` | 接近 44px 下限,横屏需更大 |
+| `.send-button` | `width: 40px; height: 40px` | 同上 |
+| `.quick-action-btn` | `padding: 7px 12px; font-size: 12px` | 快捷按钮文字偏小 |
+| `.input-hint` | `font-size: 12px` | 提示文字偏小 |
+
+#### 横屏适配完整 CSS
+
+将以下 `@media` 规则追加到 `ChatInterface.vue` 的 `<style scoped>` 末尾(放在所有现有样式之后):
+
+```css
+@media screen and (orientation: landscape) {
+  /* 容器:取消 480px 宽度限制,占满屏幕 */
+  .chat-container {
+    max-width: 100%;
+    max-height: 100vh;
+    height: 100vh;
+    border-radius: 0;
+  }
+
+  /* 头部:增大内边距和元素尺寸 */
+  .chat-header {
+    padding: 16px 24px;
+  }
+
+  .header-avatar {
+    width: 48px;
+    height: 48px;
+  }
+
+  .header-title {
+    font-size: 18px;
+  }
+
+  .header-subtitle {
+    font-size: 12px;
+  }
+
+  /* 消息列表:增大间距 */
+  .chat-messages {
+    padding: 20px 24px;
+  }
+
+  .message {
+    gap: 14px;
+    margin-bottom: 20px;
+  }
+
+  /* 消息头像:增大至 44px(满足最小触控区域) */
+  .message-avatar {
+    width: 44px;
+    height: 44px;
+  }
+
+  .message-avatar svg {
+    width: 24px;
+    height: 24px;
+  }
+
+  /* 消息内容:放宽宽度限制 */
+  .message-content {
+    max-width: 80%;
+  }
+
+  /* 消息气泡:增大字体和内边距 */
+  .message-text {
+    padding: 14px 20px;
+    font-size: 16px;
+  }
+
+  /* 输入区域:整体放大 */
+  .chat-input-container {
+    padding: 14px 24px 18px;
+  }
+
+  .chat-input-wrapper {
+    gap: 12px;
+    padding: 6px 6px 6px 16px;
+  }
+
+  /* 语音按钮:增大至 48px */
+  .voice-button {
+    width: 48px;
+    height: 48px;
+    min-width: 48px;
+  }
+
+  .voice-icon {
+    width: 26px;
+    height: 26px;
+  }
+
+  .voice-label {
+    font-size: 13px;
+  }
+
+  /* 输入框:增大字体 */
+  .chat-input {
+    font-size: 17px;
+    padding: 10px 0;
+  }
+
+  /* 发送按钮:增大至 48px */
+  .send-button {
+    width: 48px;
+    height: 48px;
+  }
+
+  .send-button svg {
+    width: 24px;
+    height: 24px;
+  }
+
+  /* 提示文字 */
+  .input-hint {
+    font-size: 14px;
+    margin: 10px 0 0 6px;
+  }
+
+  .input-hint svg {
+    width: 16px;
+    height: 16px;
+  }
+
+  /* 快捷按钮:增大触控区域和字体 */
+  .quick-actions {
+    gap: 12px;
+    padding: 16px 24px 12px;
+  }
+
+  .quick-action-btn {
+    padding: 10px 16px;
+    font-size: 14px;
+    gap: 6px;
+  }
+
+  .quick-action-btn svg {
+    width: 16px;
+    height: 16px;
+  }
+
+  /* 加载动画尺寸同步放大 */
+  .loading-message .message-content {
+    padding: 20px 24px;
+  }
+
+  .typing-indicator span {
+    width: 10px;
+    height: 10px;
+  }
+}
+```
+
+**横屏适配关键数值总结:**
+
+| 项目 | 竖屏值 | 横屏值 | 设计理由 |
+|------|--------|--------|---------|
+| 容器 max-width | 480px | 100% | 占满机器人屏幕,消除两侧留白 |
+| 容器 max-height | 900px | 100vh | 占满高度 |
+| 头像尺寸 | 36px | 48px | 观看距离远,需要更大图标 |
+| 消息字体 | 14px | 16px | 远处可读 |
+| 标题字体 | 14px | 18px | 远处可读 |
+| 输入框字体 | 15px | 17px | 远处可读 |
+| 按钮尺寸 | 40px | 48px | 超过 44px 最小触控区域 |
+| 快捷按钮字体 | 12px | 14px | 远处可读 |
+| 消息内边距 | 12px 16px | 14px 20px | 视觉呼吸感 |
+
+---
+
+### 5.4 vue.config.js 的 WebView 兼容配置
+
+> 当前 `vue.config.js` 已有基础的 `outputDir` 和 `devServer.proxy` 配置。以下展示需要**新增或修改**的项。
+
+#### 修改后的完整 vue.config.js
+
+```javascript
+const { defineConfig } = require('@vue/cli-service')
+
+module.exports = defineConfig({
+  transpileDependencies: true,
+
+  // 构建输出目录
+  outputDir: 'dist',
+
+  // publicPath 策略:
+  // - 远程服务器加载模式(开发/测试阶段):使用 '/',WebView 加载 http://192.168.x.x:8080
+  // - 本地 assets 加载模式(APK 内嵌):使用 './',确保所有资源使用相对路径
+  publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
+
+  devServer: {
+    port: 8080,
+    host: '0.0.0.0',           // 允许局域网内其他设备(包括机器人)访问
+    allowedHosts: 'all',       // WebView 请求不会被 webpack-dev-server 拒绝
+    proxy: {
+      '/api': {
+        target: 'http://localhost:3380',
+        changeOrigin: true
+      }
+    }
+  },
+
+  chainWebpack: config => {
+    config.plugin('html').tap(args => {
+      args[0].title = '甘肃省中医院'
+      return args
+    })
+  }
+})
+```
+
+#### 配置项说明
+
+| 配置项 | 修改前 | 修改后 | 原因 |
+|--------|--------|--------|------|
+| `devServer.host` | 未设置(默认 localhost) | `'0.0.0.0'` | 让局域网设备(机器人 WebView)可通过 IP 访问开发服务器 |
+| `devServer.allowedHosts` | 未设置 | `'all'` | webpack-dev-server 5.x 默认只允许 localhost,WebView 通过 IP 访问会被 403 拒绝 |
+| `publicPath` | `'/'` | `process.env.NODE_ENV === 'production' ? './' : '/'` | 生产构建使用相对路径,确保 APK 内嵌 assets 加载时资源路径正确 |
+| `outputDir` | `'dist'` | 保持 `'dist'` | 构建产物默认输出到 `dist/`;如需直接打包到 Android 工程,可改为 `'../../android-app/app/src/main/assets/web'`(需根据实际 Android 工程路径调整) |
+
+---
+
+### 5.5 H5 页面在 WebView 中的常见坑和解决方案
+
+以下表格汇总了机器人 WebView 环境下最常见的问题,建议在前端联调阶段逐项排查:
+
+| 问题 | 表现 | 原因 | 解决方案 |
+|------|------|------|---------|
+| 页面空白 | WebView 加载后白屏 | JS 执行错误被 WebView 静默吞掉 | Chrome DevTools 远程调试查看 Console |
+| 跨域请求失败 | API 调用报 CORS 错误 | WebView 对 CORS 策略更严格 | 后端配置 CORS 允许所有来源(迎检环境) |
+| 文件上传无反应 | 点击拍照/上传按钮无响应 | WebView 需要 `WebChromeClient.onShowFileChooser` | 确认 MainActivity 中已实现 |
+| 键盘遮挡输入框 | 弹出键盘时输入框被遮挡 | WebView 的 softInputMode 配置 | AndroidManifest 中设置 `adjustResize` |
+| localStorage 丢失 | 刷新后数据丢失 | WebView DOM Storage 未启用 | `webView.settings.domStorageEnabled = true` |
+| 页面缩放异常 | 页面自动缩放导致布局错乱 | 未设置 viewport meta | 确认 `index.html` 中有正确的 viewport meta 标签 |
+| HTTPS 证书错误 | 加载 HTTPS 页面失败 | 自签名证书不受信任 | `WebViewClient.onReceivedSslError` 中处理(仅限内网) |
+| 视频/音频无法播放 | 语音功能不工作 | 需要 `mediaPlaybackRequiresUserGesture = false` | WebView settings 中配置 |
+| CSS 动画卡顿 | 页面滚动和动画不流畅 | 未启用硬件加速 | WebView 启用 `setLayerType(LAYER_TYPE_HARDWARE)` |
+
+**联调检查清单:**
+
+1. 确认 `index.html` 中的 viewport:`<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">`
+2. 确认 AndroidManifest 中 Activity 的 `android:windowSoftInputMode="adjustResize"`
+3. 确认 WebView 初始化代码包含:
+   ```kotlin
+   webView.settings.apply {
+       javaScriptEnabled = true
+       domStorageEnabled = true
+       mediaPlaybackRequiresUserGesture = false
+   }
+   webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+   ```
+4. 使用 Chrome `chrome://inspect/#devices` 连接机器人 WebView 查看 Console 错误
+
+---
+
+### 5.6 前端打包部署到机器人的完整流程
+
+#### 部署方式 A:远程服务器加载(推荐开发阶段)
+
+1. 后端 Spring Boot 启动在服务器 `192.168.1.100:8080`
+2. 前端 `npm run serve` 启动开发服务器(或 `npm run build` 后由 Spring Boot 提供静态资源)
+3. 机器人上的业务 App WebView 加载 `http://192.168.1.100:8080`
+4. **优点**:修改前端代码后刷新即可生效,无需重新打包 APK
+5. **缺点**:依赖网络,离线无法使用
+
+#### 部署方式 B:打包到 APK 本地 assets(推荐迎检)
+
+1. `cd medical-card-demo/frontend`
+2. `npm run build`
+3. 将 `dist/` 目录下所有文件复制到 Android 工程的 `app/src/main/assets/web/`
+4. 修改 `MainActivity.kt` 中的加载地址为 `file:///android_asset/web/index.html`
+5. 重新构建 APK 并安装
+6. **优点**:离线可用,不依赖网络
+7. **缺点**:每次前端修改都需要重新打包 APK
+
+#### 部署方式 C:混合模式(推荐正式使用)
+
+1. 默认加载远程服务器地址
+2. 如果远程加载失败(网络不可用),自动降级到本地 assets 资源
+3. 在 `MainActivity.kt` 的 `onReceivedError` 中实现降级逻辑:
+
+```kotlin
+// MainActivity.kt 中的 WebViewClient 实现降级加载
+inner class MedicalWebViewClient : WebViewClient() {
+
+    private var hasError = false
+
+    override fun onReceivedError(
+        view: WebView?,
+        request: WebResourceRequest?,
+        error: WebResourceError?
+    ) {
+        super.onReceivedError(view, request, error)
+        // 仅处理主框架错误,忽略子资源(图片、CSS)加载失败
+        if (request?.isForMainFrame == true && !hasError) {
+            hasError = true
+            Log.w("MainActivity", "远程页面加载失败,降级到本地 assets: ${error?.description}")
+            view?.loadUrl("file:///android_asset/web/index.html")
+        }
+    }
+
+    override fun onPageFinished(view: WebView?, url: String?) {
+        super.onPageFinished(view, url)
+        // 本地 assets 加载成功时重置错误标志
+        if (url?.startsWith("file:///android_asset") == true) {
+            hasError = false
+        }
+    }
+}
+```
+
+**三种部署方式对比:**
+
+| 维度 | 方式 A(远程) | 方式 B(本地 assets) | 方式 C(混合) |
+|------|--------------|---------------------|--------------|
+| 网络依赖 | 必须 | 不需要 | 远程失败自动降级 |
+| 前端更新成本 | 低(刷新即可) | 高(需重打 APK) | 中 |
+| 离线可用 | 否 | 是 | 是 |
+| 适用阶段 | 开发调试 | 迎检演示 | 正式运行 |
+
+---
+
+### 5.7 main.js 中的机器人环境初始化
+
+在 Vue 项目的 `main.js` 中,加入机器人环境检测和开发模式 Mock 的初始化逻辑:
+
+```javascript
+// medical-card-demo/frontend/src/main.js
+import { createApp } from 'vue'
+import App from './App.vue'
+import { enableDevMock, isRobotEnv } from '@/api/robot'  // 新增:引入机器人桥接
+
+const app = createApp(App)
+
+// 开发模式下启用 Mock(可选,方便浏览器中调试导航流程)
+if (process.env.NODE_ENV === 'development') {
+  enableDevMock()
+}
+
+// 全局注册机器人环境检测
+app.config.globalProperties.$isRobot = isRobotEnv()
+
+app.mount('#app')
+```
+
+**说明:**
+- `enableDevMock()` 仅在开发环境(`npm run serve`)下生效,生产构建(`npm run build`)不会执行
+- `app.config.globalProperties.$isRobot` 让所有组件可通过 `this.$isRobot` 访问环境状态(在 Options API 中)或通过 `getCurrentInstance()` 访问(在 Composition API 中)
+- 如果项目使用 Pinia,也可以将 `isRobotEnv()` 的结果存入全局 Store,供任意组件订阅
+
+---
+
+## 六、核心交互流程
+
+### 6.1 完整交互链路
+
+```
++-----------+     +----------------+     +------------------+
+|   开机    | --> | BOOT_COMPLETED | --> | Launcher 自启    |
++-----------+     +----------------+     +------------------+
+                                                |
+                                                v
++-----------+     +----------------+     +------------------+
+| 显示桌面  | <-- |   仿鸿蒙 UI    | <-- |  桌面主页加载    |
++-----------+     +----------------+     +------------------+
+                                                |
+              点击"智慧医疗"图标                  v
++-----------+     +----------------+     +------------------+
+| 业务 App  | <-- |    Intent      | <-- |  Launcher 启动   |
++-----------+     +----------------+     +------------------+
+                                                |
+                                                v
++-----------+     +----------------+     +------------------+
+| WebView   | <-- | 加载 localhost | <-- |  H5 页面渲染     |
++-----------+     +----------------+     +------------------+
+                                                |
+              用户语音/文字对话                   v
++-----------+     +----------------+     +------------------+
+| 推荐科室  | <-- |  Spring Boot   | <-- |   AI 对话交互    |
++-----------+     +----------------+     +------------------+
+                                                |
+              点击"带我去"按钮                    v
++-----------+     +----------------+     +------------------+
+| JSBridge  | --> | RobotBridge.  | --> | 原生 SDK 调用    |
+|  调用     |     |   navigate()   |     |                  |
++-----------+     +----------------+     +------------------+
+                                                |
+                                                v
++-----------+     +----------------+     +------------------+
+| 到达科室  | --> |  导航完成回调  | --> |  机器人停止移动  |
++-----------+     +----------------+     +------------------+
+                                                |
+              按 Home 键                          v
++-----------+     +----------------+     +------------------+
+| 回到桌面  | <-- |   HOME 按键    | <-- |  Launcher 前台   |
++-----------+     +----------------+     +------------------+
+```
+
+### 6.2 领导视察演示脚本
+
+| 步骤 | 操作人 | 动作 | 解说词/预期效果 |
+|------|--------|------|----------------|
+| 1 | 演示员 | 开机/唤醒机器人 | "这是我们定制了 HarmonyOS 风格界面的豹小秘 Pro 机器人" |
+| 2 | 演示员 | 展示桌面 | "大家可以看到全新的桌面风格,操作流畅" |
+| 3 | 演示员 | 点击"智慧医疗" | "我们现在进入智慧医疗导诊系统" |
+| 4 | 领导/演示员 | 语音/触屏输入"我最近头疼" | AI 回复并推荐科室 |
+| 5 | 演示员 | 展示推荐结果 | "系统根据症状推荐了神经内科" |
+| 6 | 演示员 | 点击"带我去" | "我现在让机器人带路" |
+| 7 | 机器人 | 自动移动 | 机器人播报"请跟我来"并向前移动 |
+| 8 | 演示员 | 跟随机器人到达 | "顺利到达目标科室" |
+| 9 | 演示员 | 按 Home 键 | "按 Home 键即可回到桌面" |
+
+---
+
+## 七、开发排期(5 天计划)
+
+| 天数 | 开发者 A 任务 | 开发者 B 任务 | 交付物 |
+|------|---|---|---|
+| Day 1 | Launcher 框架 + 桌面 UI 布局 | 业务 App 工程搭建 + WebView 容器 | Launcher 可看桌面,业务 App 可加载 H5 |
+| Day 2 | 下拉控制中心 + 假设置页 | SDK 集成 + JSBridge 桥接层 | Launcher 完整可演示,导航 SDK 可调用 |
+| Day 3 | Launcher 细节打磨(动画、壁纸、图标) | H5 前端适配 + 导航对接 | 两个 App 独立可用 |
+| Day 4 | 整机联调(Launcher → 业务 App 跳转) | 导航全流程联调 | 端到端流程跑通 |
+| Day 5 | Bug 修复 + 演示彩排 | Bug 修复 + 演示彩排 | 交付迎检 |
+
+---
+
+## 八、风险与应对
+
+| 风险编号 | 风险描述 | 可能性 | 影响 | 应对策略 |
+|----------|---------|--------|------|---------|
+| R1 | Launcher 替换可能被 RobotOS 限制,无法设为默认桌面 | 中 | 高 | 提前与厂商确认,若不可行则改为点击自启动 + 禁用返回键模拟全屏桌面 |
+| R2 | SDK 在第三方 APK 中运行时权限不足,导航/TTS 调用失败 | 中 | 高 | Day 2 必须完成 SDK 集成验证,发现问题立即联系厂商技术支持 |
+| R3 | 横屏适配导致 H5 页面布局异常(卡片变形、文字截断) | 高 | 中 | Day 3 专门预留 UI 适配时间,使用 Chrome DevTools 横屏模拟器预检 |
+| R4 | 导航过程中系统弹窗(电量低、网络提示)覆盖业务界面 | 中 | 中 | 提前将设备充满电、关闭不必要的系统通知,必要时联系厂商关闭系统弹窗 |
+| R5 | 网络环境导致 H5 加载失败(后端服务未启动/断网) | 中 | 高 | 使用本地 loopback 访问,Spring Boot 设为开机自启;准备离线兜底静态页 |
+| R6 | 迎检现场突发状况(机器人定位丢失、地图异常) | 低 | 高 | 提前到场测试,准备地图重定位操作手册;演示脚本预留"重启恢复"备案 |
+
+---
+
+## 九、猎户星空厂商确认问题清单
+
+> 以下问题用于明天与猎户星空厂商会议沟通,每个问题标注优先级(P0 必问 / P1 重要 / P2 可选),并附"为什么要问"说明。
+
+### 9.1 SDK 与开发环境
+
+| 编号 | 问题 | 优先级 | 为什么要问 |
+|------|------|--------|-----------|
+| Q1 | RobotOS SDK AAR 包如何获取?最新版本号是多少?是否有更新日志? | P0 | 决定我们集成的基础依赖版本和获取渠道 |
+| Q2 | 是否提供模拟器或仿真环境用于本地开发调试? | P1 | 2 人团队时间紧,若必须真机调试会大幅增加联调成本 |
+| Q3 | SDK 初始化是否需要授权码或 License?授权绑定设备还是企业? | P0 | 若需授权,需提前申请避免现场无法运行 |
+| Q4 | 目标设备的 Android API Level 是多少?最低兼容版本? | P1 | 决定业务 App 的 `compileSdk` 和 `minSdk` 配置 |
+| Q5 | APK 开发与 OPK 开发,对于本场景(WebView + 导航)更推荐哪种? | P1 | 影响技术选型,OPK 可能限制更多但集成更快 |
+| Q6 | 是否提供 Demo APK 源码可供参考? | P2 | 有参考代码可大幅缩短集成时间 |
+| Q7 | SDK 是否有混淆规则(ProGuard)要求? | P2 | 若开启代码混淆需要额外配置 |
+| Q8 | SDK 版本与 RobotOS 固件版本是否存在绑定关系? | P1 | 确保 SDK 版本与设备固件匹配 |
+
+### 9.2 系统权限与 Launcher 替换
+
+| 编号 | 问题 | 优先级 | 为什么要问 |
+|------|------|--------|-----------|
+| Q9 | RobotOS 是否允许第三方应用声明 `HOME` category 作为默认桌面? | P0 | 这是表层 Launcher 方案的核心前提 |
+| Q10 | 系统是否会拦截或覆盖自定义 Launcher 的 HOME intent? | P0 | 若被拦截,需准备备选方案(如定时拉起) |
+| Q11 | 系统状态栏和虚拟导航栏是否可以完全隐藏?推荐方式是什么? | P1 | 影响全屏沉浸式体验的实现 |
+| Q12 | 开机启动动画/LOGO 是否可以替换或跳过? | P2 | 影响开机到桌面的完整视觉链路 |
+| Q13 | 是否存在应用白名单限制,第三方 APK 需要额外申请权限? | P0 | 若 APK 无法安装或运行,整个方案失效 |
+| Q14 | 系统 OTA 升级后,默认桌面设置是否会重置? | P2 | 影响长期维护,迎检时若被重置需手动恢复 |
+
+### 9.3 导航与硬件能力
+
+| 编号 | 问题 | 优先级 | 为什么要问 |
+|------|------|--------|-----------|
+| Q15 | `RobotApi.startNavigation()` 在第三方 APK 中调用是否受限制? | P0 | 迎检核心功能,必须确认可用 |
+| Q16 | 导航过程中,前台 Activity 是否会被系统强制切换回系统桌面? | P1 | 若被强制切走,用户看不到导航状态 |
+| Q17 | 地图位置点数据当前是否已录入?如何查看和验证? | P0 | 导航目标点必须预先存在才能调用成功 |
+| Q18 | TTS 和 ASR API 在第三方 APK 中是否可正常调用? | P1 | 语音播报是导航体验的重要组成部分 |
+| Q19 | 多个 APK 同时运行(Launcher + 业务 App)时,SDK 连接是否会冲突? | P1 | 涉及架构设计,避免资源争用 |
+| Q20 | 导航状态回调(避障、堵死、到达)的实时性和可靠性如何? | P1 | 影响前端状态展示和异常处理 |
+| Q21 | 是否需要预先进行机器人定位(Estimate)才能启动导航? | P0 | 若需预定位,演示前必须完成此步骤 |
+| Q22 | 导航到达后是否支持自动返回充电桩或原位置? | P2 | 影响演示结束后的恢复流程 |
+
+### 9.4 屏幕与 UI 适配
+
+| 编号 | 问题 | 优先级 | 为什么要问 |
+|------|------|--------|-----------|
+| Q23 | 具体屏幕分辨率、DPI、物理尺寸是多少? | P0 | UI 设计必须基于真实尺寸 |
+| Q24 | 屏幕是否支持横屏锁定?系统是否有强制方向策略? | P1 | 影响 Launcher 和业务 App 的方向配置 |
+| Q25 | 触屏是否支持多点触控?触控采样率如何? | P2 | 影响手势交互体验(如下拉控制中心) |
+| Q26 | 系统是否有强制全屏/非全屏的策略?WebView 全屏是否受限? | P1 | 影响 H5 页面的显示效果 |
+| Q27 | 屏幕是否存在异形区域(刘海、挖孔)需要适配? | P2 | 影响顶部 UI 布局 |
+
+---
+
+## 十、附录
+
+### 附录 A:猎户星空关键 API 速查表
+
+| 功能分类 | API | 说明 |
+|---------|-----|------|
+| 导航 | `RobotApi.startNavigation(destination)` | 导航到指定位置点 |
+| 导航 | `RobotApi.stopMove()` | 停止运动 |
+| 地图 | `RobotApi.getPlaceList()` | 获取所有位置点列表 |
+| 地图 | `RobotApi.getPosition()` | 获取当前坐标 `{x, y, theta}` |
+| 地图 | `RobotApi.isRobotEstimate()` | 是否已定位 |
+| 语音 | `speechApi.playText(text)` | TTS 播报文本 |
+| 语音 | `speechApi.stopTTS()` | 停止 TTS |
+| 语音 | `speechApi.setRecognizable(boolean)` | 设置语音识别开关 |
+| 电量 | `RobotApi.getBatteryLevel()` | 获取电量百分比 |
+| 系统 | `SystemInfo.getDeviceSn()` | 获取设备 SN |
+
+**导航状态码速查**:
+
+| 状态码 | 说明 |
+|--------|------|
+| 32730001 | 开始导航 |
+| 32730004 | 避障中 |
+| 32730011 | 堵死 |
+| 32730009 | 定位丢失 |
+| 32610007 | 到达目的地 |
+| -32620001 | 未定位 |
+| -32620009 | 路径规划失败 |
+
+### 附录 B:HarmonyOS 4 横屏桌面视觉参考
+
+- **色彩**:主色调为蓝紫渐变(`#4A90E2` → `#7B68EE`),辅助色为纯白和浅灰
+- **图标**:大圆角矩形(`cornerRadius: 24dp`),尺寸统一 72x72dp,纯色背景 + 白色线形图标
+- **字体**:中文使用 HarmonyOS Sans,时间 Widget 使用超大字重(`fontWeight: 600`)
+- **动效**:应用启动时图标轻微缩小后放大(scale 0.9 → 1.0),过渡时长 200ms
+- **Dock**:底部居中,高度 80dp,背景 `rgba(255,255,255,0.15)` 带毛玻璃模糊
+- **壁纸**:建议选用淡雅科技风渐变或浅色调风景图,避免与图标颜色冲突
+
+### 附录 C:术语表
+
+| 术语 | 说明 |
+|------|------|
+| RobotOS | 猎户星空基于 Android 深度定制的机器人操作系统 |
+| APK | Android 应用安装包 |
+| OPK | 猎户星空插件包(基于 React Native) |
+| AAR | Android Archive,Android 库文件格式 |
+| SDK | Software Development Kit,软件开发工具包 |
+| JSBridge | WebView 中 JavaScript 与 Native 代码通信的桥梁 |
+| TTS | Text to Speech,文本转语音 |
+| ASR | Automatic Speech Recognition,自动语音识别 |
+| Intent | Android 组件间通信的机制 |
+| HOME | Android 系统中返回桌面的标准 Intent Category |
+| Estimate | 机器人定位,确认自身在地图中的坐标位置 |
+
+---
+
+> 本文档基于猎户星空机器人 API 参考手册及现有 medical-card-demo 业务系统设计,具体 API 参数以官方最新文档为准。

+ 575 - 0
猎户星空API完整参考手册.md

@@ -0,0 +1,575 @@
+# 猎户星空机器人 API 完整参考手册
+
+> 本手册整合猎户星空机器人三层 API 能力(本地 APK/OPK 端 + 服务端 API + NLP 配置),按功能维度整理,供开发人员快速查阅。
+
+---
+
+## 一、API 能力全景
+
+猎户星空机器人提供三层开发接入方式:
+
+| 层级 | 接入方式 | 说明 |
+|------|---------|------|
+| 本地端 APK | Android 原生 SDK | 使用 Java/Kotlin 开发,直接调用 RobotOS SDK |
+| 本地端 OPK | React Native 插件 | 使用 JavaScript 开发,通过 orionos-eve-core 库 |
+| 服务端 API | HTTPS RESTful API | 远程控制机器人,域名 openapi.orionstar.com |
+| NLP 配置 | 开发者平台配置 | 在 console.orionbase.cn 配置语音交互规则 |
+
+---
+
+## 二、服务端 API(远程控制)
+
+> 基础域名:`https://openapi.orionstar.com`
+> 协议:HTTPS RESTful
+> 鉴权方式:Bearer Token(通过 appId + appSecret 获取)
+
+### 2.1 鉴权
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/auth/token` | 获取访问令牌(使用 appId + appSecret) |
+
+### 2.2 企业信息
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/enterprise/info` | 获取企业信息 |
+| GET | `/enterprise/robot/list` | 获取企业下所有机器人列表 |
+
+### 2.3 企业 SSO 免登录
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/enterprise/sso/create` | 创建 SSO 登录链接 |
+| POST | `/enterprise/sso/verify` | 验证 SSO Token |
+| POST | `/enterprise/sso/logout` | 注销 SSO 会话 |
+
+### 2.4 企业人员管理
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/enterprise/person/create` | 创建人员(含人脸图片) |
+| POST | `/enterprise/person/update` | 更新人员信息 |
+| POST | `/enterprise/person/delete` | 删除人员 |
+| POST | `/enterprise/person/search` | 人脸识别搜索 |
+
+### 2.5 企业访客邀约
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/enterprise/visitor/invite` | 创建访客邀约 |
+| GET | `/enterprise/visitor/list` | 获取访客列表 |
+
+### 2.6 机器人信息
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/robot/info` | 获取单台机器人详情(SN、在线状态、电量、位置等) |
+| GET | `/robot/status` | 获取机器人实时状态 |
+| GET | `/robot/list` | 获取机器人列表 |
+| POST | `/robot/config/get` | 获取机器人层级配置 |
+| POST | `/robot/config/set` | 设置机器人层级配置 |
+
+### 2.7 机器人地图信息
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/robot/map/list` | 获取机器人地图列表 |
+| GET | `/robot/map/info` | 获取地图详情(含位置点) |
+| GET | `/robot/map/current` | 获取当前使用地图 |
+
+### 2.8 机器人控制(12 个接口)
+
+> 核心远程控制能力,可通过服务端直接操控机器人行为。
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/robot/control/navigate` | 远程导航到指定位置点 |
+| POST | `/robot/control/navigate/stop` | 停止导航 |
+| POST | `/robot/control/tts` | 远程 TTS 语音播报 |
+| POST | `/robot/control/tts/stop` | 停止 TTS |
+| POST | `/robot/control/voice` | 远程语音指令(模拟 ASR 输入) |
+| POST | `/robot/control/mode` | 切换工作模式(接待/巡逻/静默等) |
+| POST | `/robot/control/sleep` | 休眠 |
+| POST | `/robot/control/wakeup` | 唤醒 |
+| POST | `/robot/control/reboot` | 重启 |
+| POST | `/robot/control/shutdown` | 关机 |
+| POST | `/robot/control/charge` | 回充 |
+| POST | `/robot/control/charge/leave` | 脱离充电桩 |
+
+### 2.9 机器人任务
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/robot/task/create` | 创建任务(招财豹/豹小递/豹厂通) |
+| GET | `/robot/task/list` | 获取任务列表 |
+| GET | `/robot/task/info` | 获取任务详情 |
+| POST | `/robot/task/cancel` | 取消任务 |
+
+### 2.10 QA 问答管理
+
+#### 企业级 QA
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/qa/enterprise/create` | 创建企业级 QA |
+| POST | `/qa/enterprise/update` | 更新企业级 QA |
+| POST | `/qa/enterprise/delete` | 删除企业级 QA |
+| GET | `/qa/enterprise/list` | 获取企业级 QA 列表 |
+
+#### 设备级 QA
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/qa/device/create` | 创建设备级 QA |
+| POST | `/qa/device/update` | 更新设备级 QA |
+| POST | `/qa/device/delete` | 删除设备级 QA |
+| GET | `/qa/device/list` | 获取设备级 QA 列表 |
+
+### 2.11 统计数据
+
+- **招财豹统计**:迎宾次数、互动时长、客流分析等
+- **豹小秘统计**:接待次数、导航次数、语音交互次数等
+- 共 **15 个** 统计接口
+
+### 2.12 事件回调
+
+| 回调类型 | 说明 |
+|---------|------|
+| 任务事件回调 | 任务开始/完成/失败等事件推送 |
+| 预警通知回调 | 设备异常、电量低等预警推送 |
+
+---
+
+## 三、本地端 APK 原生开发 API
+
+> 开发语言:Java / Kotlin
+> 接入方式:引入 RobotOS SDK(AAR 包)
+> 需在 Manifest 中声明权限和服务
+> 通过 Server 连接、状态监听、reqId 管理调用
+
+### 3.1 SDK 接入
+
+- 基于 Android,引入 RobotOS SDK(AAR 包)
+- 需在 Manifest 中声明权限和服务
+- 通过 Server 连接、状态监听、reqId 管理调用
+
+### 3.2 视觉能力 API(PersonApi)
+
+| API | 说明 |
+|-----|------|
+| `PersonApi.detectFace()` | 人脸检测 |
+| `PersonApi.registerFace()` | 人脸注册 |
+| `PersonApi.recognizeFace()` | 人脸识别 |
+| `PersonApi.switchCamera()` | 切换摄像头(前/后/广角) |
+| `SurfaceShareApi` | 摄像头数据流共享(获取 YUV 原始数据) |
+
+### 3.3 基础运动 API
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.goForward(speed)` | 前进(线速度 0~1.2 m/s) |
+| `RobotApi.goBackward(speed)` | 后退(**无避障!**) |
+| `RobotApi.turnLeft(angularSpeed)` | 左转(角速度 0~2.2 rad/s) |
+| `RobotApi.turnRight(angularSpeed)` | 右转 |
+| `RobotApi.stopMove()` | 停止运动 |
+| `RobotApi.setLinearVelocity(v)` | 设置线速度 |
+| `RobotApi.setAngularVelocity(w)` | 设置角速度 |
+| `RobotApi.controlHead(horizontalAngle, verticalAngle)` | 控制云台头部 |
+
+### 3.4 地图与定位 API
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.isRobotEstimate()` | 是否已定位 |
+| `RobotApi.getPosition()` | 获取当前坐标 `{x, y, theta}` |
+| `RobotApi.getMapName()` | 获取当前地图名 |
+| `RobotApi.getPlace(placeName)` | 获取位置点坐标 |
+| `RobotApi.getPlaceList()` | 获取所有位置点列表 |
+| `RobotApi.switchMap(mapName)` | 切换地图 |
+| `RobotApi.setFixedEstimate(pose)` | 固定位姿定位 `{px, py, theta}` |
+| `RobotApi.getMultiFloorConfigAndCommonPose()` | 获取多楼层配置和点位 |
+
+### 3.5 导航 API
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.startNavigation(destination)` | 导航到指定位置(7 种重载) |
+
+**导航参数:**
+
+- `destination` - 目标点名称
+- `linearSpeed` - 线速度
+- `angularSpeed` - 角速度
+- `arrivalRange` - 到达范围
+- `timeout` - 超时时间
+- 支持加减速模式
+
+**导航状态码:**
+
+| 状态码 | 说明 |
+|--------|------|
+| 32730001 | 开始导航 |
+| 32730004 | 避障中 |
+| 32730011 | 堵死 |
+| 32730009 | 定位丢失 |
+
+**导航结果码:**
+
+| 结果码 | 说明 |
+|--------|------|
+| 32610007 | 到达目的地 |
+| -32620001 | 未定位 |
+| -32620009 | 路径规划失败 |
+
+### 3.6 梯控导航 API(跨楼层)
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.startElevatorNavigation(floorIndex, destination)` | 乘电梯导航 |
+
+**梯控状态码:**
+
+| 状态码 | 说明 |
+|--------|------|
+| 32750004 | 到达电梯门 |
+| 32750005 | 进入电梯 |
+| 32750009 | 离开电梯 |
+
+### 3.7 过闸机导航 API
+
+- 闸机路径判断与通过流程
+
+### 3.8 基础场景 API
+
+| 场景 | 说明 |
+|------|------|
+| 引领模式 | 人跟机器人走 |
+| 焦点跟随 | 机器人视线追踪人脸 |
+| 唤醒 | 检测到人后唤醒交互 |
+
+### 3.9 语音 API
+
+| 功能模块 | 说明 |
+|---------|------|
+| `SkillApi` | 场景管理(注册/切换/退出语音场景) |
+| `SkillCallback` | 语音回调(ASR 结果、NLP 解析、唤醒事件等) |
+| TTS 播放 | 普通/流式播放 |
+| 拾音模式 | 单次/持续识别 |
+| NLP 处理 | 意图识别结果解析 |
+| 音频采集 | 原始音频流获取 |
+| Text 转 MP3 | 文本转语音文件 |
+
+### 3.10 语音大模型流式数据
+
+**ChatStreamInterface 结构:**
+
+| 字段 | 说明 |
+|------|------|
+| `sid` | 会话 ID |
+| `idx` | 消息序号 |
+| `content` | 文本内容 |
+| `tts` | TTS 音频数据 |
+| `sender` | 发送者 |
+| `extra` | 扩展字段 |
+
+- 支持流式接收和关闭控制
+
+### 3.11 电量控制 API
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.getBatteryLevel()` | 获取电量(1-100) |
+| `RobotApi.startCharge()` | 自动回充 |
+| `RobotApi.stopCharge()` | 离桩 |
+| `RobotApi.disableSystemCharge()` | 禁用系统自动充电 |
+
+### 3.12 多机协作 API
+
+- ESP32 模块通信
+- `MultiRobotStatus` 数据结构(多机状态同步)
+
+### 3.13 电动门控制 API
+
+- 两种控制方式(自动/手动)
+- Door1-4 独立控制
+- 门状态查询
+
+### 3.14 系统功能 API
+
+| 功能 | 说明 |
+|------|------|
+| 状态监控 | 获取系统运行状态 |
+| 灯效控制 | 底盘灯带/按钮灯 |
+| 设备信息 | SN 号、版本号 |
+| 禁用系统功能 | 关闭默认行为 |
+| 休眠控制 | 控制机器人休眠/唤醒 |
+| 安装 APK | 远程安装应用 |
+
+---
+
+## 四、本地端 OPK 插件开发 API
+
+> 开发语言:JavaScript(React Native)
+> 核心库:orionos-eve-core
+
+### 4.1 功能组件
+
+#### 4.1.1 导航组件 NavigationComponent
+
+**参数:**
+
+| 参数 | 说明 | 默认值 |
+|------|------|--------|
+| `destination` | 目标位置点(**必填**) | - |
+| `coordinate_deviation` | 到达范围 | 0.5m |
+| 线速度 | 移动速度 | 0.1-1.2 m/s |
+| 角速度 | 转弯速度 | 0.2-1.8 rad/s |
+| 避障距离 | 检测障碍物距离 | - |
+| 超时时间 | 导航超时 | - |
+
+**状态事件码:** 开始导航、避障、堵死、定位丢失等
+
+**结果事件码:** 到达、未定位、路径失败、目标不存在等
+
+#### 4.1.2 巡逻组件 CruiseComponent
+
+**参数:**
+
+| 参数 | 说明 |
+|------|------|
+| 巡逻路线 | JSON 数组,至少 2 个点 |
+| 堵死超时 | 堵死后等待超时时间 |
+| 起始点 | 巡逻起始位置 |
+
+- 支持多点循环巡逻
+
+#### 4.1.3 头部控制 HeadTurnComponent
+
+| 参数 | 范围 |
+|------|------|
+| 水平角度 | -80° ~ 80° |
+| 垂直角度 | 50° ~ 95° |
+
+#### 4.1.4 人脸识别组件(6 个)
+
+| 组件 | 说明 |
+|------|------|
+| `WakeupAndPreWakeupStartCheckComponent` | 唤醒/预唤醒检测 |
+| `PersonAppearComponent` | 按条件找人 |
+| `PersonDisappearComponent` | 人丢失检测 |
+| `RegisterComponent` | 人脸注册 |
+| `RecognizeComponent` | 查询注册信息 |
+| `ReceptionRegisterCameraView` | 注册预览 |
+
+#### 4.1.5 引领追踪组件(5 个)
+
+| 组件 | 说明 |
+|------|------|
+| `SoundLocalizationComponent` | 声源定位转向 |
+| `FaceTrackSoundLocalizationComponent` | 人脸追踪 + 拾音 |
+| `StandardFaceTrackComponent` | 自动追踪最近人脸 |
+| `FaceTrackComponent` | 追踪指定人 |
+| `LeadingTrackComponent` | 引领(人跟机器人走) |
+
+#### 4.1.6 充电组件
+
+| 组件 | 说明 |
+|------|------|
+| `ChargeStartComponent` | 自动回充 |
+| `LeavePileComponent` | 脱离充电桩 |
+
+#### 4.1.7 梯控组件
+
+| 组件 | 说明 |
+|------|------|
+| `NavigationElevatorComponent` | 导航乘梯(跨楼层) |
+| `ChargeElevatorComponent` | 充电乘梯 |
+
+### 4.2 基础接口
+
+#### 4.2.1 地图与位置(11 个 API)
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.isRobotEstimate()` | 是否已定位 |
+| `RobotApi.getPosition()` | 获取当前坐标 |
+| `RobotApi.getMapName()` | 获取当前地图名 |
+| `RobotApi.getPlace()` | 获取位置点坐标 |
+| `RobotApi.getPlaceList()` | 获取所有位置点列表 |
+| `RobotApi.getPlaceListWithName()` | 按名称获取位置点列表 |
+| `RobotApi.resumeSpecialPlaceTheta()` | 恢复特殊位置点角度 |
+| `RobotApi.switchMap()` | 切换地图 |
+| `RobotApi.setFixedEstimate()` | 固定位姿定位 |
+| `locationEstimateUtil.havePlace()` | 判断位置点是否存在 |
+| `locationEstimateUtil.isInPlace()` | 判断是否在某位置点范围内 |
+
+#### 4.2.2 运动控制
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.motionArcWithObstacles(lineSpeed, angularSpeed)` | 弧线运动(带避障) |
+
+- 线速度范围:-1.2 ~ 1.2 m/s
+- 角速度范围:-2.2 ~ 2.2 rad/s
+
+#### 4.2.3 电源管理(5 个 API)
+
+| API | 说明 |
+|-----|------|
+| `RobotApi.getBatteryLevel()` | 获取电量百分比 |
+| `RobotApi.getBatteryTimeRemaining()` | 获取剩余使用时间 |
+| `RobotApi.getChargeTimeRemaining()` | 获取剩余充电时间 |
+| `RobotSettingApi.isCharging()` | 是否正在充电 |
+| `SettingsUtil.isCharging()` | 是否正在充电(工具类) |
+
+#### 4.2.4 语音接口(11 个 API)
+
+**TTS(文本转语音):**
+
+| API | 说明 |
+|-----|------|
+| `speechApi.playText()` | 播放文本语音 |
+| `speechApi.playStreamText()` | 流式播放文本语音 |
+| `speechApi.stopTTS()` | 停止 TTS 播放 |
+
+**ASR(语音识别):**
+
+| API | 说明 |
+|-----|------|
+| `speechApi.setRecognizable()` | 设置是否可识别 |
+| `speechApi.setRecognizeMode()` | 设置识别模式 |
+| `speechApi.queryByText()` | 文本查询(模拟语音输入) |
+
+**声源定位:**
+
+| API | 说明 |
+|-----|------|
+| `speechApi.setAngleCenterRange()` | 设置拾音角度范围 |
+| `speechApi.resetAngleCenterRange()` | 重置拾音角度范围 |
+
+**音频播放:**
+
+| API | 说明 |
+|-----|------|
+| `speechApi.playToneByLocalPath()` | 播放本地音频文件 |
+| `speechApi.stopTone()` | 停止音频播放 |
+
+**大模型:**
+
+| API | 说明 |
+|-----|------|
+| `speechApi.closeStreamDataReceived()` | 关闭流式数据接收 |
+
+#### 4.2.5 灯带控制(3 个 API)
+
+| API | 说明 |
+|-----|------|
+| `LightApi.playEffect()` | 播放灯效 |
+| `LightApi.playLightColor()` | 设置灯带颜色 |
+| `LightApi.playLightAnimation()` | 播放灯带动画 |
+
+#### 4.2.6 人脸识别(4 个 API,1.x 版本)
+
+| API | 说明 |
+|-----|------|
+| `PersonManager.getAllPerson()` | 获取所有已注册人员 |
+| `PersonManager.getAllPersonNum()` | 获取已注册人员数量 |
+| `PersonManager.getLastPersonId()` | 获取最近识别人员 ID |
+| `PersonManager.getLastPersonName()` | 获取最近识别人员姓名 |
+
+#### 4.2.7 应用管理(9 个 API)
+
+| API | 说明 |
+|-----|------|
+| `AppManager.getAppJson()` | 获取应用配置 JSON |
+| `AppManager.getOpkExtraPath()` | 获取 OPK 附加资源路径 |
+| `AppManager.getOpkPath()` | 获取 OPK 安装路径 |
+| `AppManager.getAppConfig()` | 获取应用配置 |
+| `AppManager.setConfigUpdateListener()` | 设置配置更新监听 |
+| `AppManager.getAppId()` | 获取应用 ID |
+| `AppManager.getAppIcon()` | 获取应用图标 |
+| `AppManager.restartApp()` | 重启应用 |
+| `OpenAppApi.openThirdPartyApp()` | 打开第三方应用 |
+
+#### 4.2.8 系统信息(3 个 API)
+
+| API | 说明 |
+|-----|------|
+| `SystemInfo.getRobotVersion()` | 获取机器人系统版本 |
+| `SystemInfo.getDeviceSn()` | 获取设备 SN 号 |
+| `SystemInfo.getVersionByROM()` | 获取 ROM 版本号 |
+
+### 4.3 UI 组件
+
+| 组件 | 说明 |
+|------|------|
+| `ExDisplay` | 大屏显示 |
+| `ImageFrame` | 帧动画 |
+| `BlurOverlay` | 高斯模糊 |
+| `RNCameraFilterView` | 摄像头预览(含拍照) |
+| `emojiPlayerModel` | 大眼睛表情 |
+| `UiController.showStatusBar()` | 状态栏显示/隐藏 |
+
+### 4.4 高级功能
+
+| 功能 | 说明 |
+|------|------|
+| 语音大模型流式数据 | 接入大模型流式输出 |
+| 视频通话 TRTC | 仅豹小秘 Mini 支持 |
+| 定时任务 Crontab | OPK 内定时任务调度 |
+| 梯控系统 | 跨楼层导航 |
+| OPK 首页设置 | 自定义首页展示 |
+| 多入口配置 | 多个语音/触屏入口 |
+| 动态扩展组件 | 加载 dex/so 库 |
+
+---
+
+## 五、NLP 配置能力
+
+### 5.1 配置入口
+
+- 开发者平台:[console.orionbase.cn](https://console.orionbase.cn)
+
+### 5.2 核心概念
+
+| 概念 | 说明 | 示例 |
+|------|------|------|
+| Domain | 领域 | `medical`、`navigation` |
+| Intent | 意图 | `guide_to`、`query_report` |
+| Slot | 槽位 | `department_name`、`patient_id` |
+
+### 5.3 配置方式
+
+| 配置项 | 说明 |
+|--------|------|
+| 自定义语音指令 | 定义触发关键词和对应动作 |
+| 意图识别规则 | 配置 NLU 规则匹配用户意图 |
+| 多轮对话设计 | 设计多轮交互流程 |
+| 第三方 NLP 插入 | 支持 Dialogflow 等外部 NLP 引擎 |
+| 语音链路测试 | 在线测试语音识别和意图解析 |
+
+### 5.4 NLP 数据流
+
+```
+语音输入 → ASR 识别 → NLP 意图解析 → 匹配 Domain & Intent → 触发对应 OPK/APK 应用
+```
+
+---
+
+## 六、适用机型对照
+
+| 机型 | 导航 | 人脸 | 追踪 | 回充 | TRTC | 梯控 | 屏幕 |
+|------|:----:|:----:|:----:|:----:|:----:|:----:|:----:|
+| 豹小秘 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | 有 |
+| 豹小秘 Mini | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | 有 |
+| 豹小秘2 | ✅ | ✅ | ✅ | ✅ | - | - | 有 |
+| 招财豹 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | 有 |
+| 招财豹Pro | ✅ | ✅ | ✅ | ✅ | - | - | 有 |
+| 豹小递 Max | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | 有 |
+| 豹小秘 DP | 部分 | ✅ | ❌ | 部分 | ❌ | ❌ | 大屏 |
+| 消毒豹 | ✅ | - | - | - | - | ✅ | - |
+
+---
+
+> 本手册基于猎户星空开发者文档整理,如有更新请以官方文档为准。

+ 315 - 0
猎户星空合作分析报告.md

@@ -0,0 +1,315 @@
+# 猎户星空 × AI 智慧医疗 合作分析报告
+
+> 文档版本:v1.0  
+> 生成时间:2026-04-01  
+> 合作方向:医疗专用机器人联合解决方案
+
+---
+
+## 一、双方公司概况
+
+### 1.1 AI 智慧医疗(我方)
+
+**核心业务能力:**
+
+| 业务板块 | 核心功能 | 技术能力 |
+|---------|---------|---------|
+| **AI 中台** | 权限中心、模型仓库、知识库仓库、MCP 仓库、CARD 仓库 | RAG 技术、工作流可视化、业务 API 集成 |
+| **门诊智能体集群** | 智能导诊、预问诊、结算支付、报告解读 | 多轮对话、意图识别、医保结算对接 |
+| **住院智能体集群** | 入院管理、智能查房、LOFT 物联联动 | 生命体征监测、医嘱执行、护理记录 |
+| **体检智能体集群** | 检前预约、检中引导、检后报告解读 | 个性化套餐推荐、异常指标分析 |
+| **BI 智能体集群** | 运营预测、财务管控、物资管理、质量管理 | 数据分析预测、智能决策支持 |
+| **智能硬件** | AI 机器人终端 | 导航、感应、读卡、打印、梯控、多模态对话 |
+
+### 1.2 猎户星空(合作方)
+
+**核心能力(基于开发者文档):**
+
+| 能力维度 | 具体内容 |
+|---------|---------|
+| **RobotOS** | 基于 Android 的机器人操作系统 |
+| **开发方式** | 原生 APK 开发、插件开发 (OPK/APK) |
+| **服务对接** | RESTful API、NLP 配置 |
+| **硬件产品** | 导航机器人(商用服务型,无机械臂) |
+| **销售网络** | 全国渠道覆盖 |
+
+---
+
+## 二、合作突破点分析
+
+### 2.1 技术层面突破点
+
+#### ✅ 可立即着手的结合点
+
+| 序号 | 结合方向 | 我方能力输入 | 对方能力支撑 | 实现难度 |
+|:---:|---------|------------|------------|:-------:|
+| 1 | **门诊导诊机器人** | 智能导诊算法、预问诊逻辑、医院业务流程 | RobotOS 导航、语音交互、屏幕显示 | ⭐⭐ |
+| 2 | **住院巡房机器人** | 查房工作流、生命体征数据采集逻辑、医嘱执行 | 自主移动、病房定位、呼叫响应 | ⭐⭐⭐ |
+| 3 | **自助服务终端** | 挂号缴费、报告打印、医保结算 | 打印模块、读卡器、支付接口 | ⭐⭐ |
+| 4 | **院内物流配送** | 药品/标本运送流程、电梯控制逻辑 | SLAM 导航、避障、梯控对接 | ⭐⭐⭐ |
+| 5 | **AI 健康助手** | 多模态对话、健康咨询、随访管理 | 语音识别、表情交互、移动端联动 | ⭐⭐ |
+
+#### 🔶 需要技术攻关的结合点
+
+| 序号 | 结合方向 | 技术难点 | 需要对方协调的资源 |
+|:---:|---------|---------|------------------|
+| 1 | **医疗设备联动** | 与监护仪、输液泵等设备通信协议对接 | 开放 IoT 接口、提供设备驱动 SDK |
+| 2 | **院内多机协作** | 多台机器人调度、路径规划冲突解决 | 多机调度系统接入权限 |
+| 3 | **离线应急模式** | 网络中断时的本地基础服务能力 | RobotOS 离线能力评估与支持 |
+| 4 | **鸿蒙系统适配** | 如需替换底层系统,需重新适配所有功能 | 硬件驱动文档、Bootloader 权限(可能性低) |
+
+---
+
+### 2.2 产品层面突破点
+
+#### 门诊机器人功能矩阵
+
+| 功能模块 | 我方 AI 能力 | 机器人硬件能力 | 用户价值 |
+|---------|------------|--------------|---------|
+| 智能导诊 | 症状分析、科室推荐 | 语音交互、人脸识别 | 减少分诊台压力 |
+| 预问诊采集 | 病史询问结构化录入 | 多轮对话、隐私保护模式 | 提高医生接诊效率 |
+| 自助挂号缴费 | 医保结算、支付对接 | 读卡器、扫码器、凭条打印 | 减少排队等待 |
+| 检查报告解读 | AI 报告分析、异常提示 | 大屏展示、报告打印 | 提升患者就医体验 |
+| 院内导航 | 科室位置知识图谱 | SLAM 导航、路径规划 | 解决"找路难"问题 |
+
+#### 住院机器人功能矩阵
+
+| 功能模块 | 我方 AI 能力 | 机器人硬件能力 | 用户价值 |
+|---------|------------|--------------|---------|
+| 智能查房 | 查房工作流、数据自动记录 | 病房自主移动、生命体征采集 | 减少护士文书工作 |
+| 用药提醒 | 医嘱解析、用药时间管理 | 语音播报、床头屏联动 | 降低用药差错 |
+| 呼叫响应 | 智能分诊、紧急程度判断 | 呼叫中心对接、快速抵达 | 提高响应速度 |
+| 标本/药品配送 | 任务调度、路径优化 | 货仓容量、冷链监控(需定制) | 降低人力成本 |
+| 夜间巡检 | 异常行为识别、风险预警 | 夜视摄像头、安静模式 | 保障患者安全 |
+
+---
+
+### 2.3 商业模式突破点
+
+| 合作模式 | 描述 | 优势 | 风险 |
+|---------|------|------|------|
+| **硬件采购 + 软件自研** | 我方采购机器人硬件,自行开发 APK | 自主可控、利润空间大 | 前期投入高、技术风险 |
+| **联合方案 + 收入分成** | 打包成整体方案,按项目分成 | 风险共担、借助对方渠道 | 利润被摊薄、商务谈判复杂 |
+| **OEM 贴牌 + 授权费** | 机器人贴我方品牌,支付授权费 | 品牌独立、定价权在我 | 成本较高 |
+| **战略投资 + 深度绑定** | 资本层面合作,成立合资公司 | 长期稳定、资源深度整合 | 决策链条长、灵活性差 |
+
+**建议采用:联合方案 + 收入分成模式**
+- 理由:借助对方全国销售网络快速铺量,我方专注产品和交付
+
+---
+
+## 三、需要对方协调的资源清单
+
+### 3.1 技术开发支持(优先级:高)
+
+| 序号 | 需求内容 | 用途说明 | 期望形式 |
+|:---:|---------|---------|---------|
+| 1 | **完整 API/SDK 文档** | APK 开发基础 | 在线文档 + PDF 下载 |
+| 2 | **开发环境搭建指导** | 快速上手 | 视频教程/远程培训 |
+| 3 | **模拟器/测试工具** | 无需真机即可开发调试 | PC 端仿真器 |
+| 4 | **硬件接口调用示例** | 读卡器、打印机、梯控等 | 代码 Demo |
+| 5 | **NLP 配置能力** | 自定义语音指令、意图识别 | 配置后台权限 |
+| 6 | **多机调度接口** | 多机器人协作场景 | API 接入文档 |
+
+### 3.2 硬件定制支持(优先级:中)
+
+| 序号 | 定制需求 | 应用场景 | 备注 |
+|:---:|---------|---------|------|
+| 1 | **医保卡读卡器集成** | 门诊挂号、缴费、报销 | 需支持社保卡、就诊卡 |
+| 2 | **A4/A5 打印模块** | 报告打印、发票打印 | 考虑耗材更换便捷性 |
+| 3 | **梯控模块适配** | 跨楼层配送、巡检 | 需支持主流电梯品牌协议 |
+| 4 | **消毒模块选配** | 住院区、手术室区域 | 紫外线/喷雾消毒 |
+| 5 | **医疗级外壳材质** | 耐腐蚀、易清洁 | 符合院感要求 |
+
+### 3.3 市场销售支持(优先级:高)
+
+| 序号 | 支持内容 | 期望方式 |
+|:---:|---------|---------|
+| 1 | **样板医院落地** | 共同选择 1-2 家标杆医院打造示范项目 |
+| 2 | **销售渠道培训** | 对我方人员进行产品培训,或对方销售代售 |
+| 3 | **联合市场推广** | 展会、学术会议、行业论坛联合亮相 |
+| 4 | **客户案例包装** | 成功项目联合宣传、案例白皮书 |
+
+### 3.4 售后运维支持(优先级:中)
+
+| 序号 | 支持内容 | 备注 |
+|:---:|---------|------|
+| 1 | **远程诊断系统** | 机器人故障远程排查 |
+| 2 | **备件供应体系** | 关键模块备件库、快速更换 |
+| 3 | **现场支持 SLA** | 重大项目的驻场保障承诺 |
+
+---
+
+## 四、APK 开发技术路线
+
+### 4.1 开发环境准备
+
+```
+必需工具:
+- Android Studio(RobotOS 基于 Android)
+- 猎户星空 RobotOS SDK
+- 机器人测试样机(或官方模拟器)
+
+开发语言:
+- Java / Kotlin(Android 原生)
+- 部分底层调用可能需要 C/C++(通过 JNI)
+```
+
+### 4.2 技术架构分层
+
+```
+┌─────────────────────────────────────┐
+│         医疗业务应用层               │  ← 我方主导开发
+│  (导诊/问诊/查房/配送等业务 APK)     │
+├─────────────────────────────────────┤
+│         AI 能力集成层                │  ← 我方核心能力
+│  (AI 中台 API / 智能体集群 / MCP)    │
+├─────────────────────────────────────┤
+│       RobotOS 能力调用层             │  ← 使用对方 SDK
+│  (导航/语音/视觉/运动控制 API)       │
+├─────────────────────────────────────┤
+│         硬件抽象层                   │  ← 依赖对方驱动
+│  (传感器/电机/外设/通信模块)         │
+└─────────────────────────────────────┘
+```
+
+### 4.3 关键技术点
+
+| 技术点 | 说明 | 难度 | 参考资源 |
+|-------|------|------|---------|
+| **导航定位** | 调用 RobotOS SLAM 能力,实现科室间自主移动 | ⭐⭐ | 对方 SDK 文档 |
+| **语音交互** | 集成对方 NLP + 我方医疗语义理解 | ⭐⭐ | 需研究 NLP 配置能力 |
+| **多模态交互** | 语音 + 触屏 + 手势 + 表情 | ⭐⭐⭐ | Android 原生 UI + 对方 API |
+| **外设调用** | 读卡器、打印机、扫码器等 | ⭐⭐ | 对方硬件 SDK |
+| **梯控对接** | 与电梯控制系统通信 | ⭐⭐⭐ | 需了解医院电梯协议 |
+| **多机协作** | 多机器人任务分配、路径避让 | ⭐⭐⭐⭐ | 对方多机调度系统 |
+| **离线降级** | 网络中断时的基础服务能力 | ⭐⭐⭐ | 本地缓存 + 边缘计算 |
+
+---
+
+## 五、鸿蒙系统可行性分析
+
+### 5.1 方案对比
+
+| 方案 | 描述 | 可行性 | 工作量 | 建议 |
+|-----|------|:------:|:------:|------|
+| **方案 A** | 在 RobotOS 上开发 APK,鸿蒙作为备选概念 | ⭐⭐⭐⭐⭐ | 低 | ✅ 推荐 |
+| **方案 B** | 尝试将 RobotOS 替换为 OpenHarmony | ⭐⭐ | 极高 | ❌ 不建议 |
+| **方案 C** | 双系统支持(高端机型鸿蒙,低端 Android) | ⭐⭐⭐ | 高 | 暂缓 |
+
+### 5.2 建议策略
+
+**短期(0-6 个月):**
+- 基于 RobotOS(Android)完成 APK 开发和落地
+- 同步研究鸿蒙在医疗机器人领域的政策利好
+
+**中期(6-12 个月):**
+- 如果猎户星空官方支持鸿蒙版本,可直接迁移
+- 如不支持,可评估第三方鸿蒙移植方案(需对方配合开放 Bootloader)
+
+**长期(12 个月+):**
+- 根据市场反馈和政策导向,决定是否投入鸿蒙生态
+
+---
+
+## 六、下一步行动建议
+
+### 6.1 第一阶段:技术验证(1-2 个月)
+
+| 序号 | 任务 | 负责人 | 产出物 |
+|:---:|------|-------|--------|
+| 1 | 申请猎户星空开发者账号、获取 SDK | 技术负责人 | 开发权限、SDK 包 |
+| 2 | 搭建开发环境、完成 Hello World | 开发团队 | 可运行的基础 APK |
+| 3 | 研究导航、语音、外设调用 API | 开发团队 | 技术验证 Demo |
+| 4 | 设计门诊机器人 MVP 功能列表 | 产品经理 | PRD 文档 |
+| 5 | 确定首家样板医院意向 | 商务负责人 | 合作意向书 |
+
+### 6.2 第二阶段:产品开发(3-6 个月)
+
+| 序号 | 任务 | 负责人 | 产出物 |
+|:---:|------|-------|--------|
+| 1 | 门诊导诊机器人 APK 开发 | 开发团队 | v1.0 版本 |
+| 2 | 住院巡房机器人 APK 开发 | 开发团队 | v1.0 版本 |
+| 3 | 与医院 HIS 系统对接联调 | 技术团队 | 接口打通 |
+| 4 | 硬件定制模块选型和集成 | 硬件团队 | 定制方案 |
+| 5 | 样板医院部署测试 | 实施团队 | 试点报告 |
+
+### 6.3 第三阶段:市场推广(6-12 个月)
+
+| 序号 | 任务 | 负责人 | 产出物 |
+|:---:|------|-------|--------|
+| 1 | 打造标杆案例、形成标准化方案 | 产品团队 | 解决方案手册 |
+| 2 | 联合猎户星空进行市场推广 | 市场团队 | 市场活动、线索 |
+| 3 | 建立售后服务体系 | 运营团队 | SOP 流程 |
+| 4 | 迭代产品功能、扩展更多场景 | 研发团队 | v2.0/v3.0 版本 |
+
+---
+
+## 七、风险评估与应对
+
+| 风险类型 | 风险描述 | 影响程度 | 应对措施 |
+|---------|---------|:-------:|---------|
+| **技术风险** | RobotOS API 能力不足,无法满足医疗场景需求 | 高 | 早期深入技术评估,预留自研替代方案 |
+| **商务风险** | 对方销售网络推广力度不够 | 中 | 合同中明确销售目标和对赌条款 |
+| **合规风险** | 医疗器械认证周期长、成本高 | 高 | 提前咨询药监局,分类界定(可能按二类器械管理) |
+| **竞争风险** | 其他 AI 医疗公司也与机器人厂商合作 | 中 | 快速占领市场、建立标杆案例壁垒 |
+| **依赖风险** | 过度依赖单一机器人供应商 | 中 | 同时接触 2-3 家机器人厂商,保持议价能力 |
+
+---
+
+## 八、总结
+
+### 8.1 合作价值
+
+| 维度 | 我方收益 | 对方收益 |
+|-----|---------|---------|
+| **产品** | 获得成熟的机器人载体,快速落地 AI 医疗能力 | 丰富产品线,进入医疗垂直领域 |
+| **市场** | 借助全国销售网络快速规模化 | 提升单客价值(机器人 + 软件打包) |
+| **技术** | 专注 AI 和医疗业务,无需从 0 造机器人 | 获得行业 Know-how,提升产品竞争力 |
+| **品牌** | 联合打造医疗机器人标杆案例 | 树立行业影响力 |
+
+### 8.2 核心结论
+
+1. **合作可行且必要**:双方能力互补,一软一硬,是理想的合作伙伴
+2. **技术路线清晰**:基于 RobotOS 开发 APK 是务实选择,鸿蒙可作为远期选项
+3. **突破顺序建议**:门诊导诊机器人 → 住院巡房机器人 → 院内物流配送
+4. **关键成功因素**:
+   - 尽快拿到 SDK 并验证技术可行性
+   - 锁定 1-2 家样板医院打造标杆
+   - 商务条款中明确销售支持和分成机制
+
+---
+
+## 附录
+
+### A. 猎户星空开发者文档链接
+- 主文档:https://doc.orionstar.com/blog/knowledge-base-category/quick_start/
+- 需重点查看:
+  - 1.机器人开发 > 1.原生开发 (APK)
+  - 1.机器人开发 > 2.插件开发 (OPK)
+  - 2.服务端对接 > 1.API 对接
+  - 2.服务端对接 > 2.配置 NLP
+
+### B. 我方产品报价单摘要
+
+| 产品线 | 功能模块数 | 报价区间 |
+|-------|----------|---------|
+| AI 中台 | 6 个仓库/中心 | 34 万 |
+| 门诊智能体 | 7 大功能群 | 150 万 |
+| 住院智能体 | 7 大功能群 | 160 万 |
+| 体检智能体 | 6 大功能群 | 90 万 |
+| BI 智能体 | 6 大功能群 | 120 万 |
+| 智能硬件 | AI 机器人 | 15 万/台 |
+
+### C. 待确认事项清单
+
+- [ ] 猎户星空具体机器人型号及参数(载重、续航、尺寸等)
+- [ ] 医疗行业认证要求(是否需要医疗器械注册证)
+- [ ] 商务分成模式细节
+- [ ] 硬件定制成本和周期
+- [ ] 首批样板医院名单
+
+---
+
+> **文档结束**  
+> 如有任何问题或需要补充的内容,请随时告知。

+ 1169 - 0
猎户星空合作分析报告_详细版.md

@@ -0,0 +1,1169 @@
+# 猎户星空 × AI 智慧医疗 深度合作方案(详细技术版)
+
+> 文档版本:v1.0  
+> 生成时间:2026-04-01  
+> 合作方向:医疗专用机器人联合解决方案
+
+---
+
+## 一、合作概述
+
+### 1.1 双方优势
+
+| 维度 | AI 智慧医疗(我方) | 猎户星空(合作方) |
+|------|-------------------|-------------------|
+| **核心能力** | AI 中台、门诊/住院/体检智能体集群、BI 智能体 | 机器人硬件、RobotOS 操作系统、全国销售网络 |
+| **技术栈** | RAG、MCP、知识库、专精模型训练 | SLAM 导航、语音交互、多模态感知 |
+| **市场资源** | 医院客户资源、医疗行业 Know-how | 全国渠道、酒店/餐饮/政务场景经验 |
+| **产品形态** | 软件 + AI 能力 | 硬件 + 基础 OS |
+
+### 1.2 合作模式
+
+**采用模式**:基于猎户星空 RobotOS 开发医疗专用 APK,借助其全国销售网络推广
+
+**分工边界**:
+- 我方:医疗业务逻辑、AI 能力集成、医院系统对接、交付实施
+- 对方:机器人硬件、基础 OS、导航/语音等底层能力、销售渠道
+
+### 1.3 目标场景
+
+1. **门诊机器人**:导诊、预问诊、自助服务、报告解读、院内导航
+2. **住院机器人**:入院引导、智能查房、药品配送、呼叫响应、夜间巡检
+
+---
+
+## 二、门诊机器人详细方案
+
+### 2.1 智能导诊
+
+#### 功能描述
+患者走近机器人,通过语音或触屏描述症状,机器人分析后推荐对应科室,并引导患者前往挂号或科室位置。
+
+#### 依赖的 RobotOS API
+
+**本地端 API(APK/OPK):**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `WakeupAndPreWakeupStartCheckComponent` | 功能组件-人脸识别 | 检测患者走近并唤醒机器人 |
+| `speechApi.setRecognizable(true)` | 基础接口-语音 | 开启语音识别 |
+| `speechApi.setRecognizeMode(true)` | 基础接口-语音 | 设置为持续识别模式 |
+| `SkillCallback.onListenCallback` | 语音回调 | 接收 ASR 识别结果 |
+| `speechApi.playText()` | 基础接口-语音 | TTS 播报导诊结果 |
+| `NavigationComponent` | 功能组件-导航 | 引导患者到挂号处或科室 |
+| `RobotApi.getPlaceList()` | 基础接口-地图 | 获取所有科室位置点 |
+
+**服务端 API(远程控制):**
+
+| API 名称 | 用途 |
+|---------|------|
+| `POST /robot/control/tts` | 远程触发导诊语音播报 |
+| `POST /robot/control/navigate` | 远程触发导航到指定科室 |
+
+#### 完整实现路径
+
+```
+步骤 1: 患者检测与唤醒
+├── 调用 WakeupAndPreWakeupStartCheckComponent
+├── 参数: maxDistance=3m, wakeupFaceDistance=1.3m, wakeupFaceAngleX=45°
+├── 状态码 32710001: 检测到患者走近
+└── 触发: 机器人抬头、亮屏、播放欢迎语
+
+步骤 2: 语音交互开启
+├── 调用 speechApi.setRecognizable(true) 开启语音识别
+├── 调用 speechApi.setRecognizeMode(true) 设置持续识别
+├── 展示 UI 提示: "请描述您的症状"
+└── 调用 speechApi.playText("您好,我是智能导诊助手,请描述您的症状") 播放欢迎语
+
+步骤 3: 症状采集与 AI 分析
+├── 患者在 Voice.onListenCallback 中说话
+├── 获取 ASR 文本结果
+├── 调用我方 AI 中台 API: 症状 → 科室推荐
+│   └── 输入: "头痛、发烧"
+│   └── 输出: {科室: "神经内科", 置信度: 0.92, 建议: "..."}
+└── 获取科室位置: 调用 RobotApi.getPlaceList() 查询科室坐标
+
+步骤 4: 导诊结果播报
+├── 调用 speechApi.playText() 播报:
+│   └── "根据您的症状,建议挂神经内科。神经内科在3楼东侧,需要我带您过去吗?"
+└── 屏幕同步显示: 科室介绍、医生排班、预计等待时间
+
+步骤 5: 引导导航(患者同意)
+├── 患者说"带我去" → NLP 解析 intent=guide_to
+├── 调用 NavigationComponent
+├── 参数: destination="神经内科候诊区", param_linear_speed=0.8, param_angular_speed=1.2
+├── 状态监听:
+│   ├── 32730001: 开始导航
+│   ├── 32730005: 距离上报(更新屏幕剩余距离)
+│   ├── 32730004: 遇到障碍物(语音播报"请让一让")
+│   └── 32610007: 到达目标点
+└── 到达后: speechApi.playText("神经内科到了,请在此等候叫号")
+
+步骤 6: 结束交互
+├── 调用 speechApi.setRecognizable(false) 关闭语音识别
+├── 机器人进入待机巡逻模式(可选 CruiseComponent)
+└── 等待下一个患者唤醒
+```
+
+#### 需要对方配合的事项
+
+1. **唤醒灵敏度调优**:医院环境嘈杂,需要调整 `maxDistance` 和 `wakeupFaceDistance` 参数
+2. **科室地图点位**:提供医院各科室的位置点名称和坐标,录入机器人地图
+3. **NLP 意图配置**:在开发者平台配置导诊相关 Domain/Intent
+
+---
+
+### 2.2 预问诊
+
+#### 功能描述
+患者在挂号前,机器人通过多轮对话采集病史、症状、过敏史等信息,生成结构化预问诊报告,同步给医生。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `speechApi.setRecognizable(true)` | 基础接口-语音 | 开启语音识别 |
+| `SkillCallback.onListenCallback` | 语音回调 | 接收患者回答 |
+| `speechApi.playText()` | 基础接口-语音 | 播报问诊问题 |
+| `global.recognition.setShow(true)` | ASR 可视化 | 展示识别文字上屏 |
+| `PersonAppearComponent` | 功能组件-人脸 | 确认患者仍在交互 |
+
+**服务端 API:**
+
+| API 名称 | 用途 |
+|---------|------|
+| `POST /robot/control/tts` | 远程推送问诊问题 |
+| `POST /enterprise/person/search` | 人脸识别确认患者身份 |
+
+#### 完整实现路径
+
+```
+步骤 1: 启动预问诊流程
+├── 触发条件: 患者说"我要预问诊" 或 点击屏幕按钮
+├── 调用 PersonAppearComponent 确认患者身份
+├── 调用 speechApi.playText("好的,我将为您进行预问诊,请回答以下问题")
+└── 屏幕展示: 预问诊进度条(0/8 问题)
+
+步骤 2: 多轮对话问诊(循环 8-10 个问题)
+├── 第 1 轮: TTS "请问您哪里不舒服?"
+│   ├── 开启语音识别: speechApi.setRecognizable(true)
+│   ├── 展示 ASR 文字: global.recognition.setShow(true)
+│   ├── 患者回答 → onListenCallback 获取文本
+│   └── 调用我方 AI: 症状实体提取 → 存储
+├── 第 2 轮: TTS "这种情况持续多久了?"
+│   └── 同上流程,提取时间实体
+├── 第 3 轮: TTS "有没有过敏史?"
+│   └── 同上流程...
+└── ...(继续后续问题)
+
+步骤 3: 信息确认
+├── 调用我方 AI 生成预问诊摘要
+├── 屏幕展示完整信息供患者确认
+├── TTS "请确认以上信息是否正确?"
+└── 患者说"正确"或"修改第X项"
+
+步骤 4: 数据同步
+├── 调用我方 API: 预问诊数据 → HIS 系统
+├── 生成预问诊报告 PDF
+└── TTS "预问诊完成,信息已同步给医生"
+
+步骤 5: 引导下一步
+├── 询问: "需要我帮您挂号吗?"
+└── 根据回答进入挂号流程或结束
+```
+
+#### 需要对方配合的事项
+
+1. **多轮对话 NLP 配置**:配置问诊场景的 Domain/Intent/Slot
+2. **长拾音模式**:设置 `speechApi.setRecognizeMode(true)` 支持长句识别
+3. **隐私保护**:医院场景需要确保语音数据本地处理或加密传输
+
+---
+
+### 2.3 自助挂号缴费
+
+#### 功能描述
+患者通过机器人完成挂号、缴费、医保结算,需要对接读卡器和支付模块。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `speechApi.playText()` | 基础接口-语音 | 操作指引播报 |
+| `OpenAppApi.openThirdPartyApp()` | 基础接口-应用 | 调起支付 APP |
+| `AppManager.restartApp()` | 基础接口-应用 | 返回主界面 |
+| `LightApi.playEffect()` | 基础接口-灯带 | 操作成功/失败提示 |
+
+**硬件接口(需定制):**
+
+| 接口 | 说明 |
+|------|------|
+| 医保卡读卡器 | 读取社保卡/就诊卡信息 |
+| 扫码器 | 扫描患者手机支付码 |
+| 打印机 | 打印挂号单/发票/凭条 |
+
+**服务端 API:**
+
+| API 名称 | 用途 |
+|---------|------|
+| `POST /enterprise/person/search` | 人脸识别确认身份 |
+| `POST /robot/control/tts` | 远程播报操作结果 |
+
+#### 完整实现路径
+
+```
+步骤 1: 启动挂号流程
+├── 患者说"我要挂号"或点击屏幕
+├── TTS "请刷医保卡或就诊卡,或说出您的身份证号"
+└── 屏幕展示: 刷卡区域提示 + 身份证号输入键盘
+
+步骤 2: 身份识别(三选一)
+├── 方式 A: 刷医保卡
+│   ├── 调用读卡器硬件接口(需对方提供 SDK)
+│   ├── 读取卡号 → 调用 HIS 接口获取患者信息
+│   └── 屏幕展示: 患者姓名、医保类型
+├── 方式 B: 人脸识别
+│   ├── 调用 RecognizeComponent
+│   ├── 识别成功 → 获取患者 ID
+│   └── 屏幕确认: "请问您是 XXX 吗?"
+└── 方式 C: 身份证号
+    ├── 患者语音报号或触屏输入
+    └── 调用 HIS 接口验证身份
+
+步骤 3: 科室选择
+├── 屏幕展示: 科室列表(可语音搜索)
+├── 患者选择科室
+├── 调用 HIS 接口: 获取医生排班、号源
+└── 屏幕展示: 可选医生、时间段、费用
+
+步骤 4: 确认挂号
+├── 患者确认
+├── 调用 HIS 接口: 锁定号源
+├── TTS "请确认支付 XX 元"
+└── 屏幕展示: 支付方式选择(医保/微信/支付宝)
+
+步骤 5: 支付处理
+├── 医保支付:
+│   ├── 调用医保读卡器
+│   ├── 输入医保密码(屏幕键盘)
+│   └── 调用医保结算接口
+├── 微信支付:
+│   ├── 屏幕展示收款二维码
+│   ├── 患者手机扫码支付
+│   └── 轮询支付结果
+└── 支付宝支付: 同上
+
+步骤 6: 打印凭条
+├── 支付成功
+├── 调用打印机硬件接口打印挂号单
+├── TTS "挂号成功,请取走凭条,到 X 楼 XX 科室候诊"
+├── 灯带效果: LightApi.playEffect("light_effect_green_light") 绿色常亮 3 秒
+└── 屏幕展示: 科室位置地图 + 导航按钮
+
+步骤 7: 引导就诊
+├── 患者点击"带我去"
+├── 调用 NavigationComponent 导航到科室
+└── 或患者自行离开,机器人恢复待机
+```
+
+#### 需要对方配合的事项
+
+1. **读卡器 SDK**:提供医保卡/就诊卡读卡器的 Android SDK 接口
+2. **打印机 SDK**:提供热敏打印机的调用接口(支持 ESC/POS 指令)
+3. **支付安全**:确保支付模块通过安全认证,支持医保加密要求
+4. **硬件集成**:协助将读卡器、打印机集成到机器人机身
+
+---
+
+### 2.4 检查报告解读
+
+#### 功能描述
+患者在检验科做完检查后,机器人帮助查询报告、解读异常指标、提供健康建议。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `speechApi.playText()` | 基础接口-语音 | 解读结果播报 |
+| `speechApi.playStreamText()` | 基础接口-语音 | 长文本流式播报 |
+| `ExDisplay` | UI 组件 | 大屏展示报告内容 |
+| `ImageFrame` | UI 组件 | 展示报告趋势图 |
+
+**服务端 API:**
+
+| API 名称 | 用途 |
+|---------|------|
+| `POST /robot/control/tts` | 远程触发报告解读 |
+| `GET /robot/info` | 获取机器人状态确保在线 |
+
+#### 完整实现路径
+
+```
+步骤 1: 报告查询触发
+├── 触发方式:
+│   ├── A: 患者说"查报告"
+│   ├── B: 检验科推送"报告已出"消息到机器人
+│   └── C: 患者刷卡/人脸识别自动查询
+└── 身份确认: 同 2.3 步骤 2
+
+步骤 2: 获取报告数据
+├── 调用 LIS/PACS 接口查询最新报告
+├── 获取报告列表(血常规、尿常规、B超等)
+└── 屏幕展示: 报告列表,患者选择查看
+
+步骤 3: AI 解读报告
+├── 调用我方 AI 中台: 报告数据 → 解读结果
+│   ├── 输入: 血常规各项指标
+│   └── 输出: {
+│       异常项: ["白细胞偏高", "血红蛋白偏低"],
+│       解读: "白细胞偏高可能提示...",
+│       建议: "建议到内科进一步检查..."
+│   }
+└── 生成可视化图表: 历史指标趋势对比
+
+步骤 4: 结果展示与播报
+├── 屏幕展示(ExDisplay 组件):
+│   ├── 报告摘要卡片
+│   ├── 异常指标高亮
+│   ├── 历史趋势图(ImageFrame 动画)
+│   └── 医生建议文本
+└── TTS 播报(流式):
+    └── speechApi.playStreamText("您的血常规报告显示...")
+
+步骤 5: 交互问答
+├── 患者问"白细胞偏高是什么意思?"
+├── NLP 解析 → 调用知识库 RAG
+├── TTS 回答专业解释
+└── 屏幕同步展示相关医学知识
+
+步骤 6: 后续引导
+├── 如有异常: "需要我帮您预约内科医生吗?"
+├── 如无异常: "各项指标正常,请保持健康生活方式"
+└── 提供报告打印选项(调用打印机)
+```
+
+#### 需要对方配合的事项
+
+1. **大屏展示优化**:确保 ExDisplay 组件支持医疗报告的高清展示
+2. **流式 TTS**:支持长文本(可能 500-1000 字)的流畅播报
+3. **LIS/PACS 对接**:协助打通医院检验系统接口
+
+---
+
+### 2.5 院内导航引领
+
+#### 功能描述
+患者询问某个科室或设施位置,机器人提供语音指引,并可选择"带我去"的引领模式。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `NavigationComponent` | 功能组件-导航 | 导航到指定位置 |
+| `LeadingTrackComponent` | 功能组件-引领 | 人跟机器人走 |
+| `RobotApi.getPlaceList()` | 基础接口-地图 | 获取所有位置点 |
+| `locationEstimateUtil.isInPlace()` | 基础接口-地图 | 判断是否到达 |
+| `speechApi.playText()` | 基础接口-语音 | 导航指引播报 |
+
+**梯控相关(跨楼层):**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `NavigationElevatorComponent` | 高级功能-梯控 | 导航乘梯 |
+| `RobotApi.getMultiFloorConfigAndCommonPose()` | 基础接口-地图 | 获取多楼层点位 |
+
+#### 完整实现路径
+
+```
+步骤 1: 目的地询问
+├── 患者说"我要去内科"或"卫生间在哪里"
+├── NLP 解析: intent=navigation, slot={destination: "内科"}
+└── 调用 RobotApi.getPlaceList() 查询匹配位置点
+
+步骤 2: 路径规划与播报
+├── 同楼层导航:
+│   ├── TTS "内科在 3 楼东侧,距离约 150 米"
+│   ├── 屏幕展示: 地图路径预览
+│   └── 询问: "需要我带您过去吗?"
+└── 跨楼层导航:
+    ├── TTS "内科在 5 楼,我需要乘电梯上去"
+    ├── 屏幕展示: 楼层切换提示
+    └── 询问: "需要我带您过去吗?"
+
+步骤 3: 引领模式(患者同意)
+├── 调用 LeadingTrackComponent
+├── 参数:
+│   ├── lostTime=2000ms(判定丢失时间)
+│   ├── farawayDistance=2.8m(超距上报距离)
+│   └── maxDistance=3m(人脸检测范围)
+├── 状态监听:
+│   ├── 32720007: 找到目标(开始引领)
+│   ├── 32720001: 追踪成功(正常引领中)
+│   ├── 32720004: 目标距离过远(播报"请跟紧我")
+│   ├── 32720009: 长时间超距(停下等待)
+│   └── 32720008: 目标丢失(播报"我在这里等您")
+└── 行进中 TTS: "请跟我来"、"前面左转"、"电梯在这边"
+
+步骤 4: 跨楼层处理(如涉及)
+├── 到达电梯口
+├── 调用 NavigationElevatorComponent
+├── 状态监听:
+│   ├── 32750004: 到达电梯门
+│   ├── 32750005: 进入电梯并转向
+│   └── 32750009: 离开电梯
+├── 出电梯后: 重新定位 → 继续引领
+└── TTS "我们已经到 5 楼了,继续跟我走"
+
+步骤 5: 到达确认
+├── 调用 locationEstimateUtil.isInPlace("内科候诊区", 1.0)
+├── 返回 true: 确认到达
+├── TTS "内科到了,请在此等候叫号。祝您早日康复!"
+├── 屏幕展示: 内科医生排班、预计等待时间
+└── 机器人恢复待机
+```
+
+#### 需要对方配合的事项
+
+1. **医院地图建模**:提供医院各楼层的高精度地图,标注所有科室、电梯、卫生间等 POI
+2. **梯控对接**:如果支持梯控,需要对接医院电梯控制系统(提供梯控协议文档)
+3. **引领参数调优**:根据医院人流密度调整 `lostTime` 和 `farawayDistance`
+
+---
+
+### 2.6 门诊巡逻/主动迎宾
+
+#### 功能描述
+机器人在门诊大厅巡逻,主动发现需要帮助的患者,提供咨询服务。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `CruiseComponent` | 功能组件-巡逻 | 多点循环巡逻 |
+| `WakeupAndPreWakeupStartCheckComponent` | 功能组件-人脸 | 检测徘徊患者 |
+| `PersonAppearComponent` | 功能组件-人脸 | 主动找人 |
+| `StandardFaceTrackComponent` | 功能组件-追踪 | 注视患者 |
+| `speechApi.playText()` | 基础接口-语音 | 主动问候 |
+
+#### 完整实现路径
+
+```
+步骤 1: 巡逻路线设置
+├── 定义巡逻点: ["门诊入口", "挂号处", "药房", "检验科", "电梯厅"]
+├── 调用 CruiseComponent
+├── 参数:
+│   ├── cruise_route_list='["门诊入口","挂号处","药房","检验科","电梯厅"]'
+│   └── cruise_point_avoid_time_out=30000(每点停留 30 秒)
+└── 状态监听: 32730013 开始巡逻、32730014 到达某点
+
+步骤 2: 主动发现(每巡逻点停留时)
+├── 调用 PersonAppearComponent
+├── 参数: maxDistance=3m, isNeedBody=true(检测人体)
+├── 检测到徘徊患者(停留超过 10 秒)
+└── 触发主动服务
+
+步骤 3: 主动问候
+├── 调用 StandardFaceTrackComponent 注视患者
+├── TTS "您好,有什么可以帮您的吗?"
+├── 屏幕展示: 常见问题快捷按钮
+└── 开启语音识别等待患者回应
+
+步骤 4: 服务提供
+├── 患者提问 → 进入对应服务流程(导诊/挂号/查报告等)
+├── 患者无回应 → 10 秒后恢复巡逻
+└── 服务完成 → 询问"还有其他需要帮助的吗?"
+
+步骤 5: 继续巡逻
+├── 恢复 CruiseComponent 巡逻
+└── 循环执行步骤 2-4
+```
+
+#### 需要对方配合的事项
+
+1. **巡逻路线规划**:根据医院布局设计最优巡逻路线
+2. **避障参数**:门诊人流密集,需要调整避障灵敏度
+3. **充电策略**:巡逻耗电快,需要设置自动回充逻辑
+
+---
+
+## 三、住院机器人详细方案
+
+### 3.1 入院引导
+
+#### 功能描述
+新入院患者在住院部大厅,机器人协助完成入院登记、科室指引、宣教告知。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `WakeupAndPreWakeupStartCheckComponent` | 功能组件-人脸 | 检测新患者 |
+| `RegisterComponent` | 功能组件-人脸 | 人脸注册(住院期间识别) |
+| `NavigationComponent` | 功能组件-导航 | 引导到病房 |
+| `speechApi.playText()` | 基础接口-语音 | 入院宣教播报 |
+| `ExDisplay` | UI 组件 | 展示入院须知 |
+
+#### 完整实现路径
+
+```
+步骤 1: 检测新入院患者
+├── 在住院部大厅巡逻或待机
+├── 检测到携带行李的患者(Wakeup + 人体检测)
+├── TTS "您好,欢迎入住本院,我是您的智能陪护助手"
+└── 屏幕展示: 入院服务菜单
+
+步骤 2: 身份确认与人脸注册
+├── 患者刷就诊卡/报身份证号
+├── 调用 HIS 接口获取入院信息
+├── 屏幕确认: "请问您是 XXX,入住 XX 科室 X 床吗?"
+├── 患者确认后 → 调用 RegisterComponent 注册人脸
+│   └── 参数: personName=患者姓名
+└── 注册成功: 住院期间可通过人脸识别调用服务
+
+步骤 3: 入院宣教
+├── TTS 播报入院须知(流式 TTS)
+├── 屏幕展示(ExDisplay):
+│   ├── 探视时间
+│   ├── 订餐方式
+│   ├── 紧急呼叫方法
+│   └── 病房设施使用说明
+└── 患者可语音提问
+
+步骤 4: 引导到病房
+├── 询问: "需要我带您去病房吗?"
+├── 患者同意 → 调用 NavigationComponent
+├── 导航到 "XX 科 X 病区"
+├── 到达后 TTS "您的病房到了,祝您早日康复"
+└── 机器人返回大厅
+```
+
+---
+
+### 3.2 智能查房巡检
+
+#### 功能描述
+机器人按医嘱或护理计划,定时到病房巡视,采集患者生命体征、询问状况、记录反馈。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `CruiseComponent` | 功能组件-巡逻 | 按病房路线巡检 |
+| `NavigationComponent` | 功能组件-导航 | 导航到指定病房 |
+| `PersonAppearComponent` | 功能组件-人脸 | 确认患者身份 |
+| `speechApi.playText()` | 基础接口-语音 | 询问患者状况 |
+| `SkillCallback.onListenCallback` | 语音回调 | 接收患者回答 |
+| `cronParser.startCronTask()` | 高级功能-定时 | 设置定时查房 |
+
+**IoT 设备对接(需定制):**
+
+| 设备 | 接口 | 说明 |
+|------|------|------|
+| 血压计 | 蓝牙/WiFi | 自动采集血压数据 |
+| 体温计 | 蓝牙/WiFi | 自动采集体温数据 |
+| 血氧仪 | 蓝牙/WiFi | 自动采集血氧数据 |
+| 床头呼叫器 | 协议对接 | 接收呼叫信号 |
+
+#### 完整实现路径
+
+```
+步骤 1: 定时任务设置
+├── 调用 cronParser.startCronTask
+├── 参数:
+│   ├── id="morning_rounds"
+│   ├── grammar="0 8 * * *"(每天早上 8 点)
+│   └── program="start_rounds"
+└── 定时触发查房流程
+
+步骤 2: 开始巡检
+├── 调用 CruiseComponent 按病房顺序巡逻
+├── 或调用 NavigationComponent 逐个前往指定病房
+├── 到达病房门口 → 播报"查房了"
+
+步骤 3: 患者身份确认
+├── 进入病房
+├── 调用 PersonAppearComponent 识别患者人脸
+├── 匹配住院患者数据库
+└── 确认身份后调取患者病历
+
+步骤 4: 生命体征采集
+├── 方式 A: 自动采集(IoT 设备)
+│   ├── 机器人携带便携式血压计/体温计
+│   ├── 患者自主测量或护士协助
+│   └── 蓝牙传输数据到机器人
+├── 方式 B: 语音询问
+│   ├── TTS "请问您今天的体温是多少?"
+│   ├── 患者语音回答
+│   └── ASR 识别并记录
+└── 数据暂存,待统一上传
+
+步骤 5: 状况询问
+├── TTS "您今天感觉怎么样?有没有不舒服?"
+├── 患者回答 → NLP 解析
+├── 关键信息提取:
+│   ├── 疼痛部位、程度
+│   ├── 睡眠质量
+│   ├── 饮食情况
+│   └── 特殊不适
+└── 记录到查房记录
+
+步骤 6: 医嘱确认
+├── TTS "您今天的用药是 XXX,请按时服用"
+├── 展示药品图片和服用说明
+├── 询问: "您明白了吗?"
+└── 患者确认
+
+步骤 7: 数据上传与异常预警
+├── 调用我方 API: 查房数据 → 护理系统
+├── AI 分析异常指标:
+│   ├── 体温 > 38°C → 标记发热
+│   ├── 血压异常 → 标记高血压/低血压
+│   └── 患者主诉严重不适 → 标记需医生查看
+└── 异常自动推送给责任护士
+
+步骤 8: 继续巡检
+├── 离开病房 → 前往下一间
+└── 循环步骤 3-7
+
+步骤 9: 巡检完成
+├── 所有病房巡检完毕
+├── 生成巡检报告
+├── 自动回充(ChargeStartComponent)
+└── 等待下次定时任务
+```
+
+#### 需要对方配合的事项
+
+1. **IoT 设备 SDK**:提供蓝牙/WiFi 医疗设备的对接协议
+2. **病房地图**:精确到床位的病房内部地图
+3. **隐私保护**:查房时的语音和图像数据加密处理
+
+---
+
+### 3.3 药品/标本配送
+
+#### 功能描述
+机器人从药房运送药品到病房,或从病房运送检验标本到检验科。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `NavigationComponent` | 功能组件-导航 | 导航到药房/病房/检验科 |
+| `NavigationElevatorComponent` | 高级功能-梯控 | 跨楼层配送 |
+| `PersonAppearComponent` | 功能组件-人脸 | 确认接收人身份 |
+| `speechApi.playText()` | 基础接口-语音 | 通知取药 |
+| `LightApi.playEffect()` | 基础接口-灯带 | 配送中状态提示 |
+
+**硬件接口(需定制):**
+
+| 接口 | 说明 |
+|------|------|
+| 货仓电控锁 | 药品/标本存放,到达后解锁 |
+| 重量传感器 | 检测物品是否放入/取出 |
+| 温控模块(可选) | 冷链药品保温 |
+
+**服务端 API:**
+
+| API 名称 | 用途 |
+|---------|------|
+| `POST /robot/task/create` | 创建配送任务 |
+| `POST /robot/control/navigate` | 远程触发配送 |
+
+#### 完整实现路径
+
+```
+步骤 1: 接收配送任务
+├── 触发方式:
+│   ├── A: 药房系统推送 "X 床药品待配送"
+│   ├── B: 护士站通过服务端 API 下发任务
+│   └── C: 护士在机器人屏幕创建任务
+└── 调用 POST /robot/task/create 创建任务
+
+步骤 2: 前往取货点
+├── 任务队列排序(优先级、路径优化)
+├── 调用 NavigationComponent 导航到药房
+├── 到达后 TTS "药品配送员,请放入药品"
+├── 货仓门打开(电控锁解锁)
+├── 药师放入药品 → 重量传感器确认
+├── 货仓门关闭上锁
+└── 屏幕展示: 目的地、药品清单
+
+步骤 3: 配送途中
+├── 调用 NavigationComponent 导航到目标病房
+├── 跨楼层时: NavigationElevatorComponent 乘梯
+├── 灯带提示: LightApi.playEffect("light_effect_blue_breath") 蓝色呼吸灯
+├── 途中避障、等待电梯
+└── 屏幕展示: "配送中,请勿打扰"
+
+步骤 4: 到达通知
+├── 到达病房门口
+├── TTS "X 床药品已送到,请护士查收"
+├── 屏幕展示: 药品清单、接收码
+└── 等待护士接收
+
+步骤 5: 身份确认与交付
+├── 护士刷卡/人脸识别确认身份
+├── 货仓门解锁
+├── 护士取走药品
+├── 重量传感器确认已取
+├── 护士屏幕签收
+└── TTS "配送完成,祝您早日康复"
+
+步骤 6: 返回或继续
+├── 如有下一任务 → 前往下一地点
+├── 如无任务 → 返回护士站/充电站
+└── 任务状态同步到药房系统
+```
+
+#### 需要对方配合的事项
+
+1. **货仓定制**:在机器人上增加带锁货仓,容量满足常规药品配送
+2. **梯控对接**:跨楼层配送需要梯控系统支持
+3. **任务调度系统**:多任务时的路径优化和优先级管理
+
+---
+
+### 3.4 住院呼叫响应
+
+#### 功能描述
+患者通过床头呼叫器呼叫,机器人接收呼叫并前往病房响应。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `NavigationComponent` | 功能组件-导航 | 快速前往呼叫病房 |
+| `speechApi.playText()` | 基础接口-语音 | 询问患者需求 |
+| `speechApi.setRecognizable(true)` | 基础接口-语音 | 开启语音交互 |
+| `FaceTrackComponent` | 功能组件-追踪 | 追踪呼叫患者 |
+
+**IoT 对接:**
+
+| 设备 | 接口 | 说明 |
+|------|------|------|
+| 床头呼叫器 | 协议对接 | 接收呼叫信号和床位号 |
+
+#### 完整实现路径
+
+```
+步骤 1: 接收呼叫信号
+├── 床头呼叫器触发
+├── 通过 IoT 协议推送呼叫信息到机器人
+│   └── {床位: "X科X床", 类型: "普通呼叫/紧急呼叫", 时间: "..."}
+└── 机器人判断当前状态:
+    ├── 空闲 → 立即响应
+    └── 忙碌 → 队列排队或通知护士站
+
+步骤 2: 快速响应
+├── TTS "收到呼叫,马上过来"
+├── 调用 NavigationComponent 快速导航到呼叫床位
+├── 参数: param_linear_speed=1.2(最大速度)
+└── 屏幕展示: "紧急呼叫响应中"
+
+步骤 3: 到达与确认
+├── 到达病房
+├── TTS "您好,我是响应您的呼叫,请问需要什么帮助?"
+├── 调用 FaceTrackComponent 追踪患者位置
+└── 开启语音识别等待患者回应
+
+步骤 4: 需求处理
+├── 患者说"我要喝水"
+│   ├── NLP 解析 intent=need_water
+│   ├── TTS "好的,我通知护士给您送水"
+│   ├── 推送消息到护士站系统
+│   └── 记录呼叫处理结果
+├── 患者说"我不舒服"
+│   ├── NLP 解析 intent=feel_bad
+│   ├── TTS "请描述一下您的症状"
+│   ├── 多轮对话采集症状
+│   ├── AI 分析紧急程度
+│   └── 紧急呼叫推送给责任护士/医生
+└── 患者说"没事,按错了"
+    └── TTS "好的,如有需要随时呼叫"
+
+步骤 5: 离开或留守
+├── 简单需求处理完 → 离开返回
+├── 需等待护士 → 在病房门口留守
+│   └── 到达护士后交接
+└── 紧急状况 → 持续陪伴直到医护人员到达
+```
+
+#### 需要对方配合的事项
+
+1. **呼叫器协议**:提供床头呼叫器的通信协议文档
+2. **紧急响应 SLA**:确保紧急呼叫的响应时间(如 60 秒内到达)
+3. **多呼叫队列**:同时多个呼叫时的调度策略
+
+---
+
+### 3.5 出院结算引导
+
+#### 功能描述
+患者出院时,机器人协助完成出院宣教、费用查询、结算引导。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `RecognizeComponent` | 功能组件-人脸 | 识别出院患者 |
+| `NavigationComponent` | 功能组件-导航 | 引导到结算处 |
+| `speechApi.playText()` | 基础接口-语音 | 出院宣教播报 |
+| `ExDisplay` | UI 组件 | 展示出院须知和费用清单 |
+
+#### 完整实现路径
+
+```
+步骤 1: 检测出院患者
+├── HIS 系统推送 "X 床患者今日出院"
+├── 机器人在病区巡逻时识别该患者
+├── 或患者主动说"我要出院"
+└── 触发出院服务流程
+
+步骤 2: 出院宣教
+├── TTS "恭喜您康复出院,以下是出院注意事项"
+├── 屏幕展示(ExDisplay):
+│   ├── 出院带药清单及服用说明
+│   ├── 复诊时间和预约方式
+│   ├── 居家护理建议
+│   └── 紧急联系方式
+└── 流式 TTS 播报宣教内容
+
+步骤 3: 费用查询
+├── 患者询问"我的住院费用是多少?"
+├── 调用 HIS 接口查询费用明细
+├── 屏幕展示: 费用分类图表
+│   ├── 药品费、检查费、治疗费
+│   ├── 医保报销金额
+│   └── 自付金额
+└── TTS 播报费用 summary
+
+步骤 4: 结算引导
+├── 询问: "需要我带您去结算处吗?"
+├── 患者同意 → 调用 NavigationComponent
+├── 导航到 "住院结算处"
+├── 途中 TTS: "结算处在一楼大厅,请携带医保卡和押金条"
+└── 到达后: "结算处到了,请排队办理"
+
+步骤 5: 服务评价(可选)
+├── 结算完成后
+├── 机器人询问: "请对我的服务进行评价"
+├── 屏幕展示: 五星评价 + 语音反馈
+└── 收集评价数据用于服务改进
+```
+
+---
+
+### 3.6 夜间巡检
+
+#### 功能描述
+夜间时段(22:00-06:00),机器人在病区巡逻,监测异常状况,保障患者安全。
+
+#### 依赖的 RobotOS API
+
+**本地端 API:**
+
+| API 名称 | 所属模块 | 功能说明 |
+|---------|---------|---------|
+| `cronParser.startCronTask()` | 高级功能-定时 | 设置夜间定时巡检 |
+| `CruiseComponent` | 功能组件-巡逻 | 夜间静音巡逻 |
+| `PersonAppearComponent` | 功能组件-人脸 | 检测异常人员活动 |
+| `RobotApi.getBatteryLevel()` | 基础接口-电源 | 监控电量 |
+| `ChargeStartComponent` | 功能组件-充电 | 低电量自动回充 |
+
+**硬件接口:**
+
+| 接口 | 说明 |
+|------|------|
+| 夜视摄像头 | 低光照环境下的视觉检测 |
+| 红外传感器 | 人体活动检测 |
+
+#### 完整实现路径
+
+```
+步骤 1: 定时启动
+├── 调用 cronParser.startCronTask
+├── 参数:
+│   ├── id="night_patrol"
+│   ├── grammar="0 22 * * *"(每晚 22:00 启动)
+│   └── program="start_night_patrol"
+└── 夜间巡检模式启动
+
+步骤 2: 静音巡逻
+├── 调用 CruiseComponent
+├── 参数调整:
+│   ├── 关闭 TTS 播报(避免打扰患者休息)
+│   ├── 降低运动速度(减少噪音)
+│   └── 关闭灯带特效(仅保留必要指示灯)
+└── 按设定路线巡逻
+
+步骤 3: 异常检测
+├── 视觉检测(夜视摄像头):
+│   ├── 检测走廊跌倒人员
+│   ├── 检测异常聚集
+│   └── 检测烟雾/火焰(如有烟雾传感器)
+├── 声音检测:
+│   ├── 检测呼救声
+│   ├── 检测异常响动
+│   └── 触发后前往查看
+└── 人员识别:
+    └── 检测非医护人员在病区徘徊
+
+步骤 4: 异常响应
+├── 发现异常 → 立即上报护士站
+│   ├── 推送消息: "X 病区发现异常,请查看"
+│   ├── 附带现场照片/视频
+│   └── 机器人留守现场
+├── 患者呼叫 → 正常响应
+│   └── 但使用更低音量交互
+└── 无异常 → 继续巡逻
+
+步骤 5: 电量管理
+├── 定时检查电量: RobotApi.getBatteryLevel()
+├── 电量 < 30% → 暂停巡逻
+├── 调用 ChargeStartComponent 自动回充
+├── 充电完成后 → 恢复巡逻
+└── 确保 06:00 前完成充电
+
+步骤 6: 晨间交接
+├── 06:00 定时任务触发
+├── 生成夜间巡检报告
+│   ├── 巡逻次数和时间
+│   ├── 发现的异常情况
+│   └── 处理结果
+├── 推送给护士长
+└── 机器人切换日间模式
+```
+
+#### 需要对方配合的事项
+
+1. **夜视能力**:确保摄像头支持低光照环境
+2. **静音模式**:夜间运动噪音控制
+3. **安全认证**:夜间无人值守时的安全性和可靠性
+
+---
+
+## 四、技术架构方案
+
+### 4.1 分层架构
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│                     应用层(我方开发)                        │
+│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
+│  │  门诊机器人  │ │  住院机器人  │ │   管理后台   │            │
+│  │   APK/OPK   │ │   APK/OPK   │ │   Web/App   │            │
+│  └─────────────┘ └─────────────┘ └─────────────┘            │
+├─────────────────────────────────────────────────────────────┤
+│                     AI 能力层(我方)                         │
+│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
+│  │   AI 中台    │ │  智能体集群  │ │  知识库 RAG  │            │
+│  │  模型仓库    │ │ 门诊/住院/体检│ │  MCP 仓库   │            │
+│  └─────────────┘ └─────────────┘ └─────────────┘            │
+├─────────────────────────────────────────────────────────────┤
+│                   RobotOS 能力层(对方)                      │
+│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
+│  │  导航巡逻    │ │  语音交互    │ │  视觉感知    │            │
+│  │ Navigation  │ │  TTS/ASR    │ │  人脸/追踪   │            │
+│  └─────────────┘ └─────────────┘ └─────────────┘            │
+├─────────────────────────────────────────────────────────────┤
+│                    硬件抽象层(对方)                         │
+│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
+│  │  运动底盘    │ │  传感器组    │ │  扩展外设    │            │
+│  │  电机/轮子   │ │ 雷达/摄像头  │ │ 读卡器/打印  │            │
+│  └─────────────┘ └─────────────┘ └─────────────┘            │
+└─────────────────────────────────────────────────────────────┘
+```
+
+### 4.2 数据流架构
+
+```
+患者语音/触屏 → RobotOS ASR → NLP 解析 → 我方 AI 中台 → 业务处理
+                                                    ↓
+机器人控制 ← RobotOS API ← 指令生成 ← 结果返回 ← 知识库/HIS
+```
+
+### 4.3 系统对接清单
+
+| 系统 | 对接方式 | 数据交换 |
+|------|---------|---------|
+| HIS | REST API/HL7 | 患者信息、挂号、医嘱 |
+| LIS | REST API | 检验报告 |
+| PACS | REST API/DICOM | 影像报告 |
+| 护理系统 | REST API | 查房记录、护理计划 |
+| 药房系统 | REST API | 药品信息、配送任务 |
+| 医保系统 | 专用接口 | 医保结算 |
+| 床头呼叫器 | IoT 协议 | 呼叫信号 |
+| 生命体征设备 | 蓝牙/WiFi | 体征数据 |
+
+---
+
+## 五、硬件定制需求清单
+
+### 5.1 读卡器模块
+
+| 需求项 | 规格要求 | 对接方式 |
+|--------|---------|---------|
+| 支持卡类型 | 社保卡、就诊卡、身份证 | 需提供 Android SDK |
+| 通信接口 | USB/串口 | 标准 HID 或自定义协议 |
+| 读取内容 | 卡号、姓名、医保类型 | 返回结构化数据 |
+| 安全要求 | 符合医保安全规范 | 加密传输 |
+
+### 5.2 打印模块
+
+| 需求项 | 规格要求 | 对接方式 |
+|--------|---------|---------|
+| 打印类型 | 热敏打印 | ESC/POS 指令集 |
+| 纸张规格 | 80mm 宽卷纸 | 自动切纸 |
+| 打印内容 | 挂号单、发票、凭条、报告 | 支持文字/二维码 |
+| 装纸方式 | 前开盖更换 | 易维护设计 |
+
+### 5.3 梯控模块
+
+| 需求项 | 规格要求 | 对接方式 |
+|--------|---------|---------|
+| 支持电梯 | 主流品牌(三菱、奥的斯、日立等) | RS485/Modbus/自定义 |
+| 控制功能 | 呼梯、选层、开门 | 协议对接 |
+| 安全认证 | 通过电梯厂商认证 | 符合特种设备规范 |
+
+### 5.4 货仓模块(配送机器人)
+
+| 需求项 | 规格要求 | 对接方式 |
+|--------|---------|---------|
+| 容量 | 不少于 20 盒药品 | 内部货架设计 |
+| 电控锁 | 独立控制 | GPIO/串口控制 |
+| 传感器 | 重量检测、门状态 | 模拟/数字信号 |
+| 温控(可选) | 2-8°C 冷藏 | 半导体制冷 |
+
+---
+
+## 六、NLP 语音交互定制方案
+
+### 6.1 Domain/Intent 设计
+
+| Domain | Intent | Slot | 示例语句 |
+|--------|--------|------|---------|
+| navigation | guide_to | destination | "带我去内科" |
+| navigation | query_location | place | "卫生间在哪里" |
+| registration | register | department, doctor | "我要挂内科专家号" |
+| inquiry | pre_diagnosis | symptom | "我头痛发烧" |
+| report | query_report | report_type | "查我的血常规报告" |
+| payment | pay | amount, method | "我要缴费" |
+| call | emergency_call | room, type | "呼叫护士" |
+| delivery | request_delivery | item, destination | "送药到 X 床" |
+
+### 6.2 医疗专精词库
+
+- 科室名称:内科、外科、妇产科、儿科、急诊科等
+- 症状描述:头痛、发烧、咳嗽、腹痛、恶心等
+- 药品名称:常见药品通用名
+- 检查项目:血常规、尿常规、B超、CT、MRI等
+- 医保术语:医保卡、自费、报销比例、起付线等
+
+### 6.3 多轮对话设计
+
+```
+场景: 预问诊
+Bot: 请问您哪里不舒服?
+User: 我头痛
+Bot: 头痛的具体位置是?(额头/两侧/后脑勺)
+User: 额头
+Bot: 这种情况持续多久了?
+...
+```
+
+---
+
+## 七、开发路线图
+
+### 第一阶段:技术验证(1-2 个月)
+
+| 周次 | 任务 | 产出 |
+|------|------|------|
+| 1-2 | 申请开发者账号、获取 SDK、搭建环境 | 开发环境就绪 |
+| 3-4 | 开发基础 Demo:导航、语音、人脸 | 可运行 Demo |
+| 5-6 | 医院地图建模、点位标定 | 地图数据 |
+| 7-8 | 样板医院对接、需求确认 | 需求文档 |
+
+### 第二阶段:MVP 开发(3-4 个月)
+
+| 月次 | 任务 | 产出 |
+|------|------|------|
+| 1 | 门诊导诊 APK 开发 | v1.0 版本 |
+| 2 | 自助挂号缴费集成 | v1.1 版本 |
+| 3 | 住院查房 APK 开发 | v2.0 版本 |
+| 4 | HIS 系统对接联调 | 集成测试报告 |
+
+### 第三阶段:试点部署(2-3 个月)
+
+| 月次 | 任务 | 产出 |
+|------|------|------|
+| 1 | 样板医院部署、培训 | 部署完成 |
+| 2 | 试运行、问题修复 | 试运行报告 |
+| 3 | 验收、案例包装 | 标杆案例 |
+
+### 第四阶段:规模推广(持续)
+
+- 借助猎户星空销售网络推广
+- 持续迭代优化
+- 扩展更多医院场景
+
+---
+
+## 八、风险与应对
+
+| 风险 | 影响 | 应对策略 |
+|------|------|---------|
+| RobotOS API 能力不足 | 高 | 早期技术验证,预留自研替代方案 |
+| 医疗器械认证 | 高 | 提前咨询药监局,按二类器械准备 |
+| 医院系统对接复杂 | 中 | 标准化接口适配层,降低耦合 |
+| 隐私数据安全 | 高 | 本地化部署、数据加密、合规审计 |
+| 患者接受度 | 中 | 人机协作模式,保留人工服务 |
+| 硬件定制成本高 | 中 | 分阶段定制,优先核心功能 |
+
+---
+
+## 附录
+
+### A. API 速查表
+
+详见配套文档:[猎户星空API完整参考手册.md](./猎户星空API完整参考手册.md)
+
+### B. 适用机型建议
+
+| 场景 | 推荐机型 | 理由 |
+|------|---------|------|
+| 门诊导诊 | 豹小秘 Mini | 支持 TRTC 视频通话,屏幕适中 |
+| 住院查房 | 豹小秘 2 | 续航长,支持大模型 |
+| 药品配送 | 豹小递 Max | 载重大,续航长 |
+| 综合场景 | 招财豹 Pro | 性价比高,功能全面 |
+
+### C. 联系方式
+
+- 猎户星空开发者支持:https://doc.orionstar.com
+- 开发者平台:https://console.orionbase.cn
+- OpenAPI 文档:https://openapi.orionstar.com/opendocs/zh/index
+
+---
+
+> **文档结束**