diff --git a/.gitignore b/.gitignore index 00e0c7f8..78443a9f 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,9 @@ build/ gen/ local.properties .gradle/ +.kotlin/ captures/ +hs_err_pid*.log .idea/modules.xml .idea/workspace.xml @@ -79,6 +81,25 @@ Debug/ # ---------------------------------------------------------------------------- lib/generated_plugin_registrant.dart +# ---------------------------------------------------------------------------- +# Node.js 依赖目录(前端/工具链产物,不需要提交) +# ---------------------------------------------------------------------------- +node_modules/ +**/node_modules/ + +# ---------------------------------------------------------------------------- +# 日志与崩溃转储(本地调试产物,不需要提交) +# ---------------------------------------------------------------------------- +flutter_*.log +test_run.log +*.log +.sentry-native/ + +# ---------------------------------------------------------------------------- +# Office 临时锁文件(Word/Excel 打开时生成,不需要提交) +# ---------------------------------------------------------------------------- +~$* + # ---------------------------------------------------------------------------- # 编辑器与系统文件 # ---------------------------------------------------------------------------- diff --git a/.trae-html-share-packages/satabot-user-guide/satabot-user-guide.html.zip b/.trae-html-share-packages/satabot-user-guide/satabot-user-guide.html.zip new file mode 100644 index 00000000..423eb5b4 Binary files /dev/null and b/.trae-html-share-packages/satabot-user-guide/satabot-user-guide.html.zip differ diff --git a/build_patch.bat b/build_patch.bat new file mode 100644 index 00000000..9e84242e --- /dev/null +++ b/build_patch.bat @@ -0,0 +1,52 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +echo ============================================ +echo Re Build Patch +echo ============================================ +echo. + +set PATCH_VERSION=1.0.2 +set TARGET_VERSION_CODE=1 + +echo [1/3] Building Release APK ... +echo. +call flutter build apk --release +if %errorlevel% neq 0 ( + echo. + echo APK build failed! + pause + exit /b 1 +) +echo. +echo APK build done +echo. + +echo [2/3] Generating patch ... +echo. +call dart run flutter_patcher:pack ^ + --apk build/app/outputs/flutter-apk/app-release.apk ^ + --version %PATCH_VERSION% ^ + --target-version-code %TARGET_VERSION_CODE% +if %errorlevel% neq 0 ( + echo. + echo Patch generation failed! + pause + exit /b 1 +) +echo. +echo Patch generation done +echo. + +echo [3/3] Output: +echo. +echo APK: build\app\outputs\flutter-apk\app-release.apk +echo Patch: dist\libapp.so +echo Manifest: dist\manifest.json +echo. +echo ============================================ +echo Next: Upload dist\libapp.so to server +echo ============================================ +echo. +pause diff --git a/docs/SOP_使用文档.md b/docs/SOP_使用文档.md new file mode 100644 index 00000000..a8b8e888 --- /dev/null +++ b/docs/SOP_使用文档.md @@ -0,0 +1,520 @@ +# 迈步 Satabot App 使用说明书 + +> 版本:1.0.0 | 适用对象:终端用户(运维人员) + +--- + +## 目录 + +1. [应用简介](#1-应用简介) +2. [安装与登录](#2-安装与登录) +3. [首页](#3-首页) +4. [设备管理](#4-设备管理) +5. [机器人控制](#5-机器人控制) +6. [无人机巡检](#6-无人机巡检) +7. [告警中心](#7-告警中心) +8. [工单管理](#8-工单管理) +9. [问题上报](#9-问题上报) +10. [我的](#10-我的) +11. [蓝牙设备绑定](#11-蓝牙设备绑定) +12. [常见问题](#12-常见问题) + +--- + +## 1. 应用概述 + +### 1.1 产品简介 + +迈步 Satabot 是一款面向光伏电站的智能管理移动应用,为电站运维人员提供一站式的设备监控、远程控制、告警处理和工单管理能力。通过本 App,运维人员可以随时随地掌握电站运行状况,快速响应设备异常,提升运维效率。 + +### 1.2 适用人群 + +| 角色 | 说明 | +|------|------| +| 电站运维人员 | 日常巡检、设备监控、告警处理、工单执行 | +| 设备管理人员 | 设备绑定、参数配置、运行状态查看 | +| 管理人员 | 电站发电数据查看、工单统计 | + +### 1.3 核心功能 + +| 功能模块 | 说明 | +|---------|------| +| 首页 | 电站发电概览、实时功率、设备统计、快捷入口 | +| 设备管理 | 设备列表、分类筛选、搜索、蓝牙扫描、设备详情 | +| 机器人控制 | 远程方向控制、任务管理、运行参数设置 | +| 无人机巡检 | 机场状态、实时监控、视频直播、飞行任务管理 | +| 告警中心 | 告警统计、告警处理、派发工单、AI 诊断 | +| 工单管理 | 工单全流程(新建→执行→完成/挂起/转派) | +| 问题上报 | 问题类型选择、媒体上传、设备关联 | +| 个人中心 | 个人信息、系统设置、夜间模式、导航自定义 | + +### 1.4 设备类型 + +本 App 管理以下类型的设备: + +| 设备类型 | 说明 | +|---------|------| +| 光伏逆变器 | 将直流电转换为交流电的核心设备 | +| 汇流箱 | 汇集多个光伏组件的直流电 | +| 光伏组件 | 将太阳能转化为直流电的组件 | +| 监控设备 | 数据采集与传输设备 | +| 清洁除草机器人 | MC700 系列,光伏面板清洁除草机器人 | +| 无人机机场 | 无人机自动机巢,含无人机巡检 | + +### 1.5 底部导航栏 + +App 底部有以下功能页签,可在"我的 → 底部导航设置"中自定义显示和排序: + +| 页签 | 名称 | 说明 | +|------|------|------| +| 首页 | 电站概览 | 发电数据、设备统计、快捷入口 | +| 设备 | 设备管理 | 设备列表、机器人、无人机 | +| 告警 | 告警中心 | 查看和处理设备告警 | +| 工单 | 工单管理 | 工单全流程管理 | +| 上报 | 问题上报 | 上报设备问题 | +| 我的 | 个人中心 | 个人信息、系统设置 | + +--- + +## 2. 安装与登录 + +### 2.1 安装 + +- **Android**:扫描二维码下载 APK 安装 +- **iOS**:扫描二维码跳转 App Store 安装 +- 安装时如提示"未知来源",请在手机设置中允许安装 + +### 2.2 登录 + +1. 打开 App,进入登录页面 +2. 输入**用户名**和**密码** +3. 勾选"已阅读并同意用户协议" +4. 点击**登录**按钮 +5. 登录成功后自动跳转到首页 + +> **提示**:如果忘记密码,请联系管理员重置。 + +### 2.3 注册 + +1. 在登录页面点击**注册账号** +2. 填写用户名、密码等信息 +3. 提交后等待管理员审核 + +### 2.4 修改密码 + +1. 登录后进入"我的"页面 +2. 点击"修改密码" +3. 输入旧密码和新密码 +4. 提交完成修改 + +--- + +## 3. 首页 + +### 3.1 页面说明 + +首页展示当前选中电站的整体运行情况。 + +### 3.2 切换电站 + +- 页面顶部左侧显示当前电站名称 +- 点击电站名称可下拉切换其他电站 +- 切换后所有数据自动刷新 + +### 3.3 功能区域 + +| 区域 | 说明 | +|------|------| +| 天气信息 | 显示电站所在地天气 | +| 电站概览 | 装机容量、今日发电量等 | +| 功率卡片 | 实时功率、今日累计发电量、功率趋势图 | +| 统计网格 | 设备总数、在线数、离线数、异常数 | +| 工单卡片 | 待处理工单数量,点击进入工单页 | +| 快捷入口 | 设备管理、告警、工单等快速跳转 | +| TCP 状态 | 右上角圆点显示通信连接状态(绿色=正常) | + +### 3.4 下拉刷新 + +- 在首页任意位置**下拉**可刷新所有数据 + +--- + +## 4. 设备管理 + +### 4.1 进入设备页 + +点击底部导航栏的**设备**页签。 + +### 4.2 切换电站 + +- 页面顶部左侧可切换电站,切换后设备列表自动刷新 + +### 4.3 搜索设备 + +- 页面上方搜索框中输入设备名称 +- 点击搜索按钮或按确认键进行搜索 + +### 4.4 设备分类筛选 + +页面中部有设备类型筛选条: + +| 筛选项 | 说明 | +|--------|------| +| 全部 | 显示所有设备 | +| 逆变器 | 仅显示逆变器设备 | +| 汇流箱 | 仅显示汇流箱设备 | +| 组件 | 仅显示光伏组件 | +| 监控 | 仅显示监控设备 | +| 机器人 | 仅显示清洁除草机器人 | +| 无人机机场 | 仅显示无人机机巢 | + +### 4.5 添加设备 + +- 点击页面右上角 **+** 按钮 +- 可选择**扫一扫**(扫码绑定)或**蓝牙**(蓝牙搜索绑定) + +### 4.6 蓝牙扫描 + +- 点击搜索框旁边的**蓝牙图标** +- App 开始扫描附近蓝牙设备 +- 扫描结果中,名称为纯数字的设备(时间戳格式)自动**置顶**显示 +- 可在搜索框中输入关键词过滤设备 +- 点击设备可进入设备详情页 + +### 4.7 设备详情 + +点击设备列表中的设备,进入设备详情页: + +- **光伏设备**:显示设备运行参数(功率、电压、电流、温度等) +- **机器人**:进入机器人控制页(详见第 5 章) +- **无人机机场**:进入机场详情页(详见第 6 章) + +--- + +## 5. 机器人控制 + +### 5.1 进入方式 + +设备页 → 筛选"机器人" → 点击机器人设备 + +### 5.2 机器人详情页 + +| 区域 | 说明 | +|------|------| +| 设备信息卡 | 显示机器人名称、序列号、在线状态、电量 | +| 状态栏 | 运行状态、工作模式、当前位置 | +| 控制面板 | 方向控制(前进/后退/左转/右转/停止) | +| 检查清单 | 任务执行前的检查项 | +| 任务信息 | 当前任务详情 | +| 操作按钮 | 启动任务、暂停、取消等 | + +### 5.3 远程控制 + +1. 进入机器人详情页后,App 自动申请远程控制权限 +2. 获得权限后可使用控制面板上的方向按钮 +3. 点击**停止**按钮停止移动 +4. 退出页面时自动释放控制权限 + +### 5.4 任务管理 + +| 操作 | 说明 | +|------|------| +| 创建任务 | 设置工作区域参数后创建清洁任务 | +| 启动任务 | 选择任务后点击启动 | +| 暂停任务 | 执行中点击暂停 | +| 恢复任务 | 暂停后点击恢复 | +| 取消任务 | 取消当前任务 | + +### 5.5 运行参数设置 + +1. 在机器人详情页点击设置图标 +2. 可调整运行参数(速度、切割高度等) +3. 点击保存生效 + +--- + +## 6. 无人机巡检 + +### 6.1 进入方式 + +设备页 → 筛选"无人机机场" → 点击机场设备 + +### 6.2 机场详情页 + +| 信息 | 说明 | +|------|------| +| 机场状态 | 在线状态、仓内温度 | +| 无人机状态 | 电量、位置、飞行状态 | +| 视频监控 | 仓内监控画面 | + +### 6.3 实时监控 + +- 点击"实时监控"进入无人机监控页 +- 显示无人机 OSD 数据:经纬度、高度、速度、电量、航向等 + +### 6.4 视频直播 + +1. 点击"视频直播"进入直播页面 +2. 可切换摄像头:广角 / 变焦 / 红外 +3. 支持画面全屏、方向控制 + +### 6.5 飞行任务 + +| 操作 | 说明 | +|------|------| +| 查看任务 | 查看已有飞行任务列表 | +| 创建任务 | 选择航线、设置参数后创建 | +| 执行任务 | 选择任务后点击执行 | +| 暂停任务 | 飞行中可暂停 | +| 返航 | 一键返航 | + +--- + +## 7. 告警中心 + +### 7.1 进入方式 + +点击底部导航栏的**告警**页签。 + +### 7.2 告警统计 + +- 页面上方显示告警数量统计卡片 +- 按状态分类:待处理、处理中、已处理、已关闭 + +### 7.3 告警列表 + +- 按状态 Tab 分类展示 +- 下拉刷新,上拉加载更多 +- 点击告警条目进入详情页 + +### 7.4 告警详情 + +| 信息 | 说明 | +|------|------| +| 告警信息 | 告警名称、级别、时间、设备 | +| 告警详情 | 详细描述、可能原因 | +| AI 诊断 | AI 辅助分析告警原因和建议 | + +### 7.5 处理告警 + +1. 在告警详情页点击"处理" +2. 选择处理方式(确认/关闭) +3. 填写处理说明 +4. 提交完成处理 + +### 7.6 派发工单 + +1. 在告警详情页点击"派发工单" +2. 选择工单模型 +3. 填写派发信息 +4. 提交后自动生成工单 + +--- + +## 8. 工单管理 + +### 8.1 进入方式 + +点击底部导航栏的**工单**页签。 + +### 8.2 工单统计 + +- 页面上方显示各状态工单数量统计 +- 点击数字可快速筛选对应状态的工单 + +### 8.3 工单列表 + +- 按状态 Tab 分类展示:待处理、处理中、已完成、已挂起 +- 下拉刷新,上拉加载更多 +- 点击工单条目进入详情页 + +### 8.4 工单详情 + +显示工单编号、类型、设备、描述、处理记录等信息。 + +### 8.5 工单操作 + +| 操作 | 说明 | +|------|------| +| 开始执行 | 接收工单后开始处理 | +| 完成 | 处理完毕后标记完成 | +| 挂起 | 暂时无法处理,挂起工单 | +| 恢复 | 挂起的工单恢复处理 | +| 转派 | 将工单转给其他人员 | + +### 8.6 新建工单 + +1. 在工单页面点击"上报"按钮 +2. 选择工单类型 +3. 填写问题描述 +4. 关联设备 +5. 提交生成工单 + +--- + +## 9. 问题上报 + +### 9.1 进入方式 + +点击底部导航栏的**上报**页签。 + +### 9.2 上报流程 + +1. **选择上报类型**:故障 / 建议 / 投诉等 +2. **选择严重等级**:紧急 / 严重 / 一般 / 轻微 +3. **选择设备**:从设备列表中关联相关设备 +4. **上传媒体**:拍照、录像或选择图片/视频 +5. **填写描述**:文字描述问题详情 +6. 点击**提交**完成上报 + +### 9.3 媒体上传 + +- 点击拍照按钮直接拍照 +- 或从手机相册选择图片/视频 +- 点击已上传的媒体可预览大图/视频 + +--- + +## 10. 我的 + +### 10.1 进入方式 + +点击底部导航栏的**我的**页签。 + +### 10.2 功能列表 + +| 功能 | 说明 | +|------|------| +| 用户信息卡 | 头像、昵称、联系方式,点击进入编辑页 | +| 快捷操作 | 常用功能快速入口 | +| 个人资料 | 修改昵称、头像等 | +| 系统设置 | 夜间模式、语言切换、清除缓存 | +| 底部导航设置 | 自定义底部 Tab 显示/隐藏和排序 | +| 版本更新 | 检查并下载新版本 | +| 退出登录 | 清除登录状态返回登录页 | + +### 10.3 夜间模式 + +- 我的 → 系统设置 → 夜间模式开关 +- 开启后 App 切换为深色主题 + +### 10.4 底部导航设置 + +1. 我的 → 底部导航设置(或首页 → 设置入口) +2. 可开关每个 Tab 的显示/隐藏 +3. 至少保留一个 Tab +4. 可调整 Tab 排列顺序 +5. 设置即时生效 + +--- + +## 11. 蓝牙设备绑定 + +### 11.1 方式一:扫码绑定 + +1. 设备页 → 点击右上角 **+** +2. 选择"扫一扫" +3. 扫描设备上的二维码 +4. App 获取设备名称(如 `MC700AIR-CN-JS-1777272534998-0000000A-75`) +5. 进入绑定页面 +6. 选择所属组织和场站 +7. 点击提交完成绑定 + +### 11.2 方式二:蓝牙搜索绑定 + +1. 设备页 → 点击搜索框旁的**蓝牙图标** +2. App 扫描附近蓝牙设备 +3. 在搜索框输入关键词可过滤设备 +4. 蓝牙名为纯数字的设备(时间戳格式)自动置顶 +5. 点击目标设备进入设备详情页 +6. 点击**连接设备**按钮连接蓝牙 +7. 连接成功后,**绑定设备**按钮变为可点击状态 +8. 未连接时"绑定设备"按钮为灰色,不可点击 +9. 点击"绑定设备" + - App 自动获取全部设备列表 + - 用蓝牙名(时间戳,如 `1777272534998`)匹配设备 + - 匹配成功后自动跳转到绑定页面 +10. 选择所属组织和场站 +11. 点击提交完成绑定 + +### 11.3 设备名说明 + +| 位置 | 名称示例 | 说明 | +|------|---------|------| +| 蓝牙广播名 | `1777272534998` | 纯数字时间戳 | +| 设备完整名 | `MC700AIR-CN-JS-1777272534998-0000000A-75` | 设备序列号 | +| 匹配方式 | 完整名包含蓝牙名 | 蓝牙名是完整名的一部分 | + +--- + +## 12. 常见问题 + +### Q1:登录提示"登录失败"? + +- 检查用户名和密码是否正确 +- 检查网络是否正常 +- 联系管理员确认账号是否已开通 + +### Q2:蓝牙扫描不到设备? + +- 确认手机蓝牙已开启 +- 确认已授予 App 蓝牙权限和定位权限 +- 靠近设备后重试 +- 安卓手机需开启"位置信息"开关 + +### Q3:蓝牙连接失败? + +- 确认设备已通电 +- 确认设备未被其他手机连接 +- 靠近设备重试 +- 重启手机蓝牙后重试 + +### Q4:绑定设备按钮灰色不可点击? + +- "绑定设备"按钮需要**先连接蓝牙**后才能使用 +- 请先点击"连接设备"按钮,连接成功后按钮变为可点击 + +### Q5:点击绑定设备后提示"未匹配到设备"? + +- 确认设备已录入后台系统 +- 联系管理员确认设备名中是否包含当前蓝牙名(时间戳) + +### Q6:首页数据显示"加载失败"? + +- 检查网络连接 +- 点击"重试"按钮 +- 确认当前账号有权限访问该电站 + +### Q7:机器人控制无反应? + +- 确认机器人在线 +- 确认已获得远程控制权限 +- 确认机器人未在执行其他任务 +- 退出页面重新进入 + +### Q8:无人机视频不显示? + +- 确认无人机和机场在线 +- 确认网络畅通 +- 尝试切换摄像头 + +### Q9:TCP 状态显示异常? + +- 首页右上角圆点显示 TCP 连接状态 +- 红色表示未连接,绿色表示正常 +- 如持续异常,检查网络或联系管理员 + +### Q10:App 版本过旧无法使用? + +- 进入"我的"→"版本更新"检查新版本 +- 下载并安装最新版本 + +--- + +## 联系与反馈 + +如遇到本说明书未涵盖的问题,请通过以下方式联系: + +- **客服电话**:请联系管理员获取 +- **问题反馈**:App 内"上报"页面提交问题反馈 +- **技术支持**:请联系管理员获取联系方式 diff --git a/lib/core/bluetooth/ble_manager.dart b/lib/core/bluetooth/ble_manager.dart index e769428a..a7b30ccc 100644 --- a/lib/core/bluetooth/ble_manager.dart +++ b/lib/core/bluetooth/ble_manager.dart @@ -33,6 +33,7 @@ class BleManager { StreamSubscription>? _readSubscription; StreamSubscription? _adapterStateSubscription; StreamSubscription? _deviceConnectionSubscription; + StreamSubscription? _mtuSubscription; /// 防止异步竞态:stopScan() 后 in-flight 的 startScan() 不应生效 int _scanGen = 0; @@ -266,14 +267,8 @@ class BleManager { }); _connectionController.add(device); await _discoverServices(device); - // 确认协商后的 MTU - try { - final mtu = await device.requestMtu(512); - _negotiatedMtu = mtu; - developer.log('[BLE] MTU: $mtu', name: 'BleManager'); - } catch (e) { - developer.log('[BLE] requestMtu failed: $e', name: 'BleManager'); - } + // 确认协商后的 MTU(Android 主动请求;iOS 由 CoreBluetooth 自动协商) + await _setupMtu(device); return null; // 成功 } catch (e) { // 连接失败,清除连接中状态 @@ -287,6 +282,49 @@ class BleManager { } } + /// 平台差异化的 MTU 协商 + /// - Android: 主动 requestMtu(512),一般协商到 247/517 + /// - iOS: CoreBluetooth 自动协商,requestMtu 会抛异常;读 mtuNow 并订阅 mtu 流 + Future _setupMtu(BluetoothDevice device) async { + if (Platform.isAndroid) { + try { + final mtu = await device.requestMtu(512); + _negotiatedMtu = mtu; + developer.log('[BLE] Android MTU negotiated: $mtu', name: 'BleManager'); + } catch (e) { + developer.log('[BLE] requestMtu failed: $e', name: 'BleManager'); + } + return; + } + if (Platform.isIOS) { + // iOS 上 connect 完成后系统会异步协商 MTU,稍等一拍再读取实际值 + try { + await Future.delayed(const Duration(milliseconds: 300)); + final mtu = device.mtuNow; + // iOS 保底 185(现代 iPhone CoreBluetooth 常见协商值),避免默认 23 把长帧切成 9 片 + _negotiatedMtu = mtu > 23 ? mtu : 185; + developer.log( + '[BLE] iOS MTU (auto-negotiated): mtuNow=$mtu, using=$_negotiatedMtu', + name: 'BleManager', + ); + // 订阅后续 MTU 变化(部分外设会在服务发现后再次协商) + _mtuSubscription?.cancel(); + _mtuSubscription = device.mtu.listen((m) { + if (m > 23 && m != _negotiatedMtu) { + _negotiatedMtu = m; + developer.log('[BLE] iOS MTU updated: $m', name: 'BleManager'); + } + }); + } catch (e) { + _negotiatedMtu = 185; + developer.log( + '[BLE] iOS MTU setup failed, fallback to 185: $e', + name: 'BleManager', + ); + } + } + } + void _onDeviceDisconnected() { _connectedDevice = null; _connectingDevice = null; @@ -295,6 +333,7 @@ class BleManager { _negotiatedMtu = 23; _readSubscription?.cancel(); _deviceConnectionSubscription?.cancel(); + _mtuSubscription?.cancel(); _connectionController.add(null); _connectingController.add(null); // 清空协议解析器缓冲区 @@ -407,7 +446,7 @@ class BleManager { final totalChunks = (frame.length + maxWriteLen - 1) ~/ maxWriteLen; if (totalChunks > 1) { developer.log( - '[BLE] 🔀 分${totalChunks}片写入 (MTU=$_negotiatedMtu, 每片≤${maxWriteLen}B)', + '[BLE] 🔀 分${totalChunks}片写入 (platform=${Platform.isIOS ? "iOS" : "Android"}, MTU=$_negotiatedMtu, 每片≤${maxWriteLen}B)', name: 'BleManager', ); } @@ -424,6 +463,13 @@ class BleManager { ); } await char.write(chunk, withoutResponse: false); + // iOS 分片间加小延时,给 MCU 侧协议解析器留出帧间处理时间, + // 避免长帧(如 0x06 写配置 176B)被拆多片时因间隔过短触发丢帧 + if (Platform.isIOS && + totalChunks > 1 && + offset + maxWriteLen < frame.length) { + await Future.delayed(const Duration(milliseconds: 20)); + } } developer.log('[BLE] ✅ 写入完成', name: 'BleManager'); } @@ -442,6 +488,7 @@ class BleManager { _readSubscription?.cancel(); _adapterStateSubscription?.cancel(); _deviceConnectionSubscription?.cancel(); + _mtuSubscription?.cancel(); _scanController.close(); _packetController.close(); _connectionController.close(); diff --git a/lib/core/env/env_config.dart b/lib/core/env/env_config.dart index c9bdfd1d..3000f9a3 100644 --- a/lib/core/env/env_config.dart +++ b/lib/core/env/env_config.dart @@ -1,7 +1,7 @@ class EnvConfig { static const String environment = String.fromEnvironment( 'ENV', - defaultValue: 'prod', + defaultValue: 'test', ); static String get sentryDsn { diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..648e2d80 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,204 @@ +{ + "name": "flutter-app-02", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "docx": "^9.7.1" + } + }, + "node_modules/@types/node": { + "version": "25.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", + "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/docx": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/docx/-/docx-9.7.1.tgz", + "integrity": "sha512-ilXFf9Moz47ABjFpDiA5s1w9lpb4EFSp7+5iiJSbfyYDM+bpZdAgLlSr7fW4aXhVe/E+F6QCv0EvRVFEd5CsWg==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.2.3", + "hash.js": "^1.1.7", + "jszip": "^3.10.1", + "nanoid": "^5.1.3", + "xml": "^1.0.1", + "xml-js": "^1.6.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz", + "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "license": "MIT" + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..18a8d347 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "docx": "^9.7.1" + } +} diff --git a/satabot-user-guide/_shared/fonts/Outfit-Bold.ttf b/satabot-user-guide/_shared/fonts/Outfit-Bold.ttf new file mode 100644 index 00000000..f9f2f72a Binary files /dev/null and b/satabot-user-guide/_shared/fonts/Outfit-Bold.ttf differ diff --git a/satabot-user-guide/_shared/fonts/Outfit-OFL.txt b/satabot-user-guide/_shared/fonts/Outfit-OFL.txt new file mode 100644 index 00000000..fd0cb995 --- /dev/null +++ b/satabot-user-guide/_shared/fonts/Outfit-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2021 The Outfit Project Authors (https://github.com/Outfitio/Outfit-Fonts) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/satabot-user-guide/_shared/fonts/Outfit-Regular.ttf b/satabot-user-guide/_shared/fonts/Outfit-Regular.ttf new file mode 100644 index 00000000..3939ab24 Binary files /dev/null and b/satabot-user-guide/_shared/fonts/Outfit-Regular.ttf differ diff --git a/satabot-user-guide/satabot-user-guide.html b/satabot-user-guide/satabot-user-guide.html new file mode 100644 index 00000000..1b7de812 --- /dev/null +++ b/satabot-user-guide/satabot-user-guide.html @@ -0,0 +1,1200 @@ + + + + + + + Maibu Satabot V2 — 用户使用手册 + + + + + + +
+ + +
+ +

Maibu Satabot V2

+

智能机器人与无人机管控平台 — 用户使用手册

+
+ 版本 1.0.0 + 适用平台:Android / iOS + 更新日期:2026-09 +
+
+ + + + + +
+

1 应用概览

+

了解 Satabot V2 的核心定位与整体功能架构

+ +

Maibu Satabot V2 是一款面向光伏电站、清洁除草等工业场景的智能机器人与无人机管控平台。通过手机 App,您可以完成设备监控、远程操控、路径规划、告警处理、工单流转、问题上报等全流程操作,实现一人多机的高效运维。

+ +
+
核心能力一览
+
+
+
+ +
+

首页看板

+

电站概览、发电量统计、工单摘要、快捷入口一屏展示

+
+
+
+ +
+

设备管理

+

机器人与无人机列表、实时状态、绑定/解绑、任务管理

+
+
+
+ +
+

远程控制

+

双摇杆操控、WebRTC 实时画面、急停、权限管理

+
+
+
+ +
+

告警与工单

+

告警查看与 AI 诊断、工单流转(派发→到场→处理→回执)

+
+
+
+ +

底部导航栏

+

App 底部导航栏默认提供以下页面入口,您可以在「个人中心 → 底部导航设置」中自定义显示哪些标签页(详见第 13 节)。

+ +
+
+
+ 首页 +
+
+
+ 设备 +
+
+
+ 告警 +
+
+
+ 工单 +
+
+
+ 上报 +
+
+
+ 我的 +
+
+ +
+ 多语言与主题:App 支持中文和英文两种语言,以及浅色/深色两种主题模式。可在「我的 → 系统设置」中切换。 +
+
+ +
+ + +
+

2 账号与登录

+

注册、登录、密码管理及安全机制

+ +

2.1 登录

+
    +
  1. 打开 App,进入登录页面。
  2. +
  3. 输入用户名和密码。
  4. +
  5. 勾选底部的「用户协议」复选框。
  6. +
  7. 点击「登录」按钮。登录成功后自动跳转至首页。
  8. +
+
+ 提示:如果登录失败,页面会显示失败原因提示。请确认用户名和密码正确,以及网络连接正常。 +
+ +

2.2 注册

+
    +
  1. 在登录页面点击「注册」链接,进入注册页面。
  2. +
  3. 填写用户名、密码等必要信息。
  4. +
  5. 提交后即可使用新账号登录。
  6. +
+ +

2.3 修改密码

+

登录后,可在「我的 → 个人信息 → 修改密码」中更新密码。需要输入旧密码和新密码进行验证。

+ +

2.4 会话安全机制

+
+

App 采用了会话续期与安全保护机制,保障您的账号安全:

+
    +
  • 自动续期:App 在前台运行期间会自动维持会话,无需重复登录。
  • +
  • 后台保护:App 进入后台时记录会话状态。恢复时验证会话一致性,防止被异常中断后误操作。
  • +
  • 异地登录检测:检测到其他设备登录同一账号时,当前设备可能被强制退出。在进行远程控制或路径规划等关键操作时,App 会自动进入安全模式,防止操作被中断。
  • +
  • 断线重连:网络恢复后,App 会自动重连 TCP 服务器并恢复设备状态推送。
  • +
+
+
+ +
+ + +
+

3 首页看板

+

一屏掌握场站运行概况、发电量、工单与设备状态

+ +

首页是登录后的主页面,集中展示当前选中场站的核心运行数据和快捷操作入口。

+ +

3.1 场站选择器

+

页面顶部提供场站选择器。点击可切换不同场站,所有页面(首页、告警、工单、设备列表)的数据都会根据当前选中的场站自动刷新。

+ +

3.2 看板内容

+
+
+
+ +
+

电站概览卡片

+

展示当前场站的基本信息和运行概况

+
+
+
+ +
+

发电量卡片

+

显示当日/累计发电量,含趋势图表

+
+
+
+ +
+

统计网格

+

设备总数、在线数、告警数等关键指标

+
+
+
+ +
+

工单摘要卡片

+

待处理工单数量与状态概览

+
+
+
+ +
+

快捷入口

+

快速跳转到远程控制、路径规划等常用功能

+
+
+
+ +
+

连接状态指示器

+

显示 TCP 服务器连接状态(在线/断开)

+
+
+ +
+ 使用技巧:下拉刷新可重新加载首页所有数据。切换场站后,所有页面数据会自动同步更新。 +
+
+ +
+ + +
+

4 设备管理

+

机器人与无人机的列表、状态监控、绑定及任务管理

+ +

点击底部导航栏的「设备」标签进入设备管理页面。设备分为两大类:清洁除草机器人和无人机及机场。

+ +

4.1 机器人管理

+ +

机器人列表

+

页面展示当前场站下所有机器人的列表,包含:

+
    +
  • 统计卡片:机器人总数、在线数、作业中数量等
  • +
  • 快捷操作:快速进入远程控制、路径规划等
  • +
  • 当前任务:展示正在执行的作业任务信息
  • +
  • 机器人卡片:每台机器人的别名、序列号、在线状态、电量、当前状态
  • +
+

支持下拉刷新列表。点击某台机器人可进入机器人控制详情页。

+ +

机器人控制详情页

+
+

进入机器人详情页后,您可以查看完整的设备信息并进行操作:

+
    +
  • 头部信息卡:机器人别名、序列号
  • +
  • 状态栏:实时运行状态、电量、信号等
  • +
  • 控制面板:发送控制指令(启动、停止、暂停等)
  • +
  • 任务信息:当前关联的任务详情
  • +
  • 操作按钮:远程控制、路径规划等快捷入口
  • +
+

退出详情页时,App 会自动释放该设备的远程控制权限。

+
+ +

机器人任务管理

+

在机器人列表页可进入「任务管理」页面,进行作业任务的创建、查看和管理:

+
    +
  1. 点击机器人列表中的任务入口。
  2. +
  3. 查看已有任务列表或创建新任务。
  4. +
  5. 可对任务执行暂停、恢复、取消等操作。
  6. +
  7. 可查看任务执行记录和工作面积参数。
  8. +
+ +

4.2 无人机与机场管理

+ +

无人机机场列表

+

展示当前场站下的所有无人机机场(机巢),包含机场名称、网关序列号、在线状态等。点击进入机场详情页。

+ +

机场详情页

+
+

机场详情页提供完整的无人机和机巢信息:

+
    +
  • 机场 OSD 状态卡:实时显示机巢的温湿度、充电状态、舱门状态等
  • +
  • 无人机 OSD 状态卡:无人机的电量、GPS 信号、飞行状态等
  • +
  • 任务控制入口:进入无人机任务与航线控制页面
  • +
  • 监控入口:进入无人机实时监控页面
  • +
  • 视频入口:进入无人机视频控制页面
  • +
+
+ +

无人机任务与航线控制

+

在任务控制页面可以管理无人机的飞行任务:

+
    +
  • 查看任务详情:航线规划、航点信息、飞行参数
  • +
  • 任务操作:暂停任务、恢复任务、一键返航
  • +
  • 实时状态:当前飞行高度、速度、航向、电量
  • +
+ +

无人机实时监控

+

监控页面展示无人机的实时遥测数据,包括位置坐标、飞行参数、传感器状态等。

+ +

无人机视频控制

+

视频控制页面提供无人机摄像头的实时图传画面,支持镜头参数调整。

+ +

4.3 设备绑定与解绑

+

扫描绑定设备

+
    +
  1. 在设备列表页点击「添加设备」或扫描图标。
  2. +
  3. 使用 App 内置的二维码扫描器扫描设备上的二维码。
  4. +
  5. 确认设备信息后完成绑定。绑定后设备会出现在您的设备列表中。
  6. +
+ +

蓝牙配对

+

部分设备支持通过蓝牙扫描进行配对。在绑定设备页面选择蓝牙扫描,App 会自动搜索附近的可用设备。

+ +

解绑设备

+

在设备详情或设置中可以选择「解绑设备」,解绑后该设备不再出现在您的列表中。

+ +
+ 注意:解绑设备前请确保设备没有正在执行的任务,否则可能导致任务中断。 +
+
+ +
+ + +
+

5 远程控制

+

通过手机实时操控机器人,含双摇杆、视频图传与急停

+ +

远程控制页面提供沉浸式的实时操控体验,支持横屏全屏操作。可从首页快捷入口或机器人详情页进入。

+ +

5.1 页面布局

+
+
控制界面分区
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
区域功能说明
顶部状态栏显示设备名称、连接状态、电量、信号强度、控制权限状态
视频画面WebRTC 实时图传,显示机器人摄像头画面,占据屏幕主要区域
左侧摇杆控制机器人前进/后退及转向方向
右侧摇杆控制机器人附加功能(如刷盘升降等)
中央控制区功能切换、模式选择等操作按钮
急停按钮红色醒目按钮,紧急情况下立即停止机器人一切动作
+
+ +

5.2 使用步骤

+
    +
  1. 确保目标设备已选中并在线(在首页或设备列表中选择设备)。
  2. +
  3. 进入远程控制页面,App 自动锁定为横屏模式。
  4. +
  5. 等待 WebRTC 视频流连接成功,画面开始实时显示。
  6. +
  7. 如需获取控制权限,App 会弹出权限请求弹窗。点击确认后获得控制权。
  8. +
  9. 使用左右摇杆操控机器人。画面会实时反馈机器人视角。
  10. +
  11. 遇到紧急情况,点击急停按钮立即停止所有动作。
  12. +
+ +

5.3 控制权限机制

+
+ 权限说明:同一台设备同一时间只能有一个用户拥有控制权限。当您请求权限时,如果设备被其他人占用,需要等待对方释放权限后才能获取。 +
+ +
+ 安全模式:进入远程控制页面后,App 会自动开启安全模式,防止异地登录推送等操作中断您的控制。退出页面后安全模式会延时 90 秒关闭。 +
+
+ +
+ + +
+

6 路径规划

+

在地图上为机器人规划作业路径

+ +

路径规划页面提供基于地图的可视化路径规划工具,为机器人生成作业路线。可从首页快捷入口或机器人详情页进入。

+ +

使用流程

+
+
+
选择设备
+ → +
地图选点
+ → +
生成路径
+
+ → +
+
参数调整
+ → +
下发任务
+
+
+ +
    +
  1. 选择设备:进入路径规划页面时,确保已选中目标设备。未选择设备时会提示「请先选择设备」。
  2. +
  3. 地图操作:在地图上查看设备当前位置,通过缩放和拖动浏览作业区域。地图支持多种图层切换。
  4. +
  5. 设定起点和作业区域:在地图上标注起点和作业区域的边界。
  6. +
  7. 生成路径:系统根据作业区域自动生成路径规划方案。
  8. +
  9. 调整参数:可调整作业宽度、重叠率等参数,重新生成路径。
  10. +
  11. 下发任务:确认路径无误后,将路径下发给机器人执行。
  12. +
+ +
+ 注意:路径规划页面同样会启用安全模式,防止操作被打断。请确保设备在线且 GPS 信号良好。 +
+ +

地图功能

+
    +
  • 设备位置标定:实时显示机器人当前位置和朝向
  • +
  • 航向指针:地图上的箭头指示机器人当前朝向
  • +
  • 轨迹回放:查看机器人的历史作业轨迹
  • +
  • 坐标系统:全项目使用 WGS84 坐标系统
  • +
+
+ +
+ + +
+

7 告警中心

+

查看告警、AI 诊断、派发工单与告警处理

+ +

告警中心集中展示当前场站的所有告警信息,支持分类查看、详情诊断和工单派发。

+ +

7.1 告警列表

+
    +
  • 告警数量卡片:顶部展示各等级告警的统计数量
  • +
  • 分类标签栏:按告警状态分类筛选(待处理、处理中、已处理等)
  • +
  • 告警趋势图:展示告警数量的变化趋势
  • +
  • 告警列表:支持上拉加载更多,每条告警显示等级、设备、时间、摘要
  • +
+

切换场站后,告警列表会自动重新加载当前场站的数据。

+ +

7.2 告警详情与 AI 诊断

+

点击某条告警进入告警详情页:

+
+
    +
  • 告警基本信息:告警等级、类型、发生时间、关联设备
  • +
  • AI 诊断卡片:系统自动分析告警原因,给出诊断建议
  • +
  • 操作按钮:派发工单、告警处理
  • +
+
+ +

7.3 告警处理流程

+
+
+
查看告警
+ → +
AI 诊断
+ → +
派发工单
+ → +
处理告警
+
+
+ +
    +
  1. 在告警列表中点击需要处理的告警,进入详情页。
  2. +
  3. 查看 AI 诊断建议,了解告警的可能原因。
  4. +
  5. 如需现场处理,点击「派发工单」,将告警转为工单派发给相关人员。
  6. +
  7. 也可直接点击「告警处理」进行处理操作(确认、忽略等)。
  8. +
+
+ +
+ + +
+

8 工单管理

+

工单的全生命周期管理:从派发到回执

+ +

工单管理页面提供工单的完整流转流程管理,覆盖从派发到归档的全生命周期。

+ +

8.1 工单列表

+
    +
  • 工单数量卡片:各状态工单的数量统计
  • +
  • 分类标签栏:按工单状态分类筛选(待处理、进行中、已完成等)
  • +
  • 工单卡片:显示工单编号、类型、关联设备、创建时间、优先级
  • +
  • 支持上拉加载更多,切换场站自动刷新
  • +
+ +

8.2 工单流转流程

+
+
+
工单详情
+ → +
到场确认
+ → +
处理记录
+
+ → +
+
工单汇报
+ → +
回执归档
+
+
+ +

8.3 各环节操作说明

+ +

工单详情

+

点击工单列表中的某一条目进入工单详情页,查看工单的完整信息,包括工单描述、关联设备、处理人、历史记录等。

+ +

到场确认

+

处理人到达现场后,在工单详情页点击「到场」,记录到场时间,工单状态自动变为「处理中」。

+ +

处理记录

+

处理过程中可以添加处理记录,描述处理步骤和发现的问题。支持上传照片作为处理凭证。

+ +

工单汇报

+

处理完成后,在汇报页面填写处理结果、上传现场照片、记录耗材使用情况等。

+ +

回执归档

+

汇报提交后,工单进入待回执状态。确认回执后工单正式归档完成。

+ +

工单转派

+

如果当前处理人无法完成工单,可以在详情页使用「转派」功能,将工单转给其他人员处理。转派时会弹出对话框选择接收人。

+
+ +
+ + +
+

9 问题上报

+

上报现场问题,支持多媒体附件与分级

+ +

上报页面用于提交现场发现的问题或异常情况,提交后可流转为工单进行处理。

+ +

上报流程

+
    +
  1. 选择上报类型:从预设类型中选择问题类别(如设备故障、环境异常等)。
  2. +
  3. 选择关联设备:选择问题涉及的设备(可选)。
  4. +
  5. 选择严重等级:为上报问题设定优先级(高/中/低)。
  6. +
  7. 填写描述:详细描述问题现象和发生情况。
  8. +
  9. 上传媒体:拍照或从相册选取照片/视频作为附件。支持在媒体预览页查看已选内容。
  10. +
  11. 提交上报:确认信息无误后提交。提交成功会显示成功提示。
  12. +
+ +
+ 提示:上报提交后,管理人员可在后台查看并将其转为工单处理。您可以在工单列表中追踪后续处理进度。 +
+
+ +
+ + +
+

10 AI 助手

+

智能问答助手,随时获取操作指引与设备诊断

+ +

AI 助手提供智能问答功能,帮助您快速获取设备操作指引、故障排查建议等信息。可选功能

+ +

使用方式

+
    +
  1. 在底部导航栏点击「AI」标签进入助手页面(如未显示,需在导航设置中开启)。
  2. +
  3. 在底部输入框输入问题,点击发送。
  4. +
  5. AI 会以对话形式回复,支持 Markdown 格式渲染。
  6. +
  7. 点击右上角菜单可以新建会话或查看历史会话记录。
  8. +
+ +

功能说明

+
    +
  • 多会话管理:支持创建多个独立对话会话,互不干扰
  • +
  • 历史记录:可查看和继续之前的对话
  • +
  • Markdown 渲染:回复内容支持表格、代码块、列表等格式
  • +
  • 图片发送:可上传图片辅助描述问题
  • +
+
+ +
+ + +
+

11 个人中心

+

个人信息、系统设置、夜间模式与缓存管理

+ +

点击底部导航栏「我的」进入个人中心页面。

+ +

11.1 页面内容

+
+
    +
  • 用户信息卡片:显示昵称、角色/邮箱、头像。点击进入个人信息详情页可编辑。
  • +
  • 快捷入口:我的消息、我的收藏、我的工单
  • +
  • 菜单列表:系统设置、底部导航设置、关于我们等
  • +
+
+ +

11.2 个人信息详情

+

在个人信息详情页可以:

+
    +
  • 修改昵称和头像
  • +
  • 查看账号信息(用户名、邮箱、手机号)
  • +
  • 修改登录密码
  • +
+ +

11.3 系统设置

+
+
可配置项
+ + + + + + + + + + + + + + + + + + + + + +
设置项说明
夜间模式切换浅色/深色主题,立即生效
语言切换中文 / English 切换
清除缓存清理本地缓存数据,释放存储空间
+
+
+ +
+ + +
+

12 应用更新

+

差量更新与整包更新两种方式

+ +

Satabot V2 支持差量更新(补丁)和整包更新两种更新方式,确保您始终使用最新版本。

+ +

更新流程

+

当检测到新版本时,App 会弹出更新提示窗口,显示版本号、更新类型和更新内容。

+ +

差量更新(补丁)

+
+

仅下载差异部分的补丁文件,体积小、速度快。

+
    +
  1. 点击「立即更新」。
  2. +
  3. 等待补丁下载完成,显示下载进度。
  4. +
  5. 补丁应用成功后,按提示完全关闭 App 并重新打开即可使用新版本。
  6. +
+
+ +

整包更新

+
+

下载完整的 APK 安装包,适用于大版本更新。

+

提供两种下载方式:

+
    +
  • 浏览器下载(推荐):打开浏览器下载 APK,手动安装后卸载旧版本
  • +
  • App 内下载:在 App 内下载 APK,完成后调起系统安装界面
  • +
+
+ 重要:整包更新后必须先卸载旧版本,否则可能无法正常使用新功能! +
+
+ +
+ 强制更新:部分关键版本更新为强制更新,无法跳过,必须更新后才能继续使用 App。 +
+
+ +
+ + +
+

13 底部导航自定义

+

根据使用习惯定制底部导航栏

+ +

Satabot V2 允许您自定义底部导航栏的标签页显示和排序,只保留您常用的功能入口。

+ +

配置方法

+
    +
  1. 进入「我的」页面。
  2. +
  3. 找到「底部导航设置」入口并进入设置页面。
  4. +
  5. 每个标签页旁有开关,打开/关闭即可控制是否显示在底部导航栏。
  6. +
  7. 可通过拖拽调整标签页的排列顺序。
  8. +
  9. 至少保留一个标签页,系统不允许全部关闭。
  10. +
+ +

可配置的标签页

+
+ + + + + + + + + + + + + + + + + +
标签页默认状态说明
首页显示场站看板与快捷入口
设备显示机器人与无人机管理
AI隐藏智能问答助手
告警显示告警中心
工单显示工单管理
上报显示问题上报
我的显示个人中心
+
+
+ +
+ + +
+

14 常见问题

+

使用过程中可能遇到的问题与解决方案

+ +
+

Q1:登录后页面空白或加载失败?

+

请检查网络连接是否正常。如果网络正常但问题持续,尝试在「我的 → 系统设置 → 清除缓存」后重新加载。首页右上角的连接状态指示器可帮助判断服务器是否连通。

+
+ +
+

Q2:远程控制画面不显示?

+

WebRTC 视频流需要一定的连接时间,请耐心等待几秒。如果长时间无画面,请确认:(1) 设备在线且摄像头正常;(2) 网络带宽充足;(3) 退出远程控制页面后重新进入。

+
+ +
+

Q3:无法获取设备控制权限?

+

同一设备同时只能有一个控制者。如果提示权限被占用,说明其他人正在控制该设备。请等待对方释放权限后再试。

+
+ +
+

Q4:路径规划页面提示「请先选择设备」?

+

路径规划需要先选定一台设备作为目标。请在首页或设备列表中选中一台设备后再进入路径规划。

+
+ +
+

Q5:切换场站后数据没有更新?

+

切换场站后各页面会自动重新加载数据。如果数据未及时更新,请尝试下拉刷新当前页面。

+
+ +
+

Q6:App 更新后无法正常使用?

+

如果是整包更新(非差量补丁),请确保已卸载旧版本。整包更新引导弹窗中有详细步骤说明。如果差量更新后出现问题,请尝试完全关闭 App(从后台划掉)后重新打开。

+
+ +
+

Q7:蓝牙扫描不到设备?

+

请确认:(1) 手机蓝牙已开启;(2) 已授予 App 蓝牙权限;(3) 设备已开机且在蓝牙有效范围内(通常 10 米以内);(4) 设备未被其他手机绑定。

+
+
+ +
+

Maibu Satabot V2 用户使用手册 — 文档版本 1.0 | 2026-09

+

本文档基于应用代码分析生成,如有界面差异以实际 App 为准。

+
+ +
+ + diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 3c0d642e..71a40e41 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -20,6 +21,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AgoraRtcEnginePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("AgoraRtcEnginePlugin")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); FlutterBluePlusPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 639fd277..09e2268e 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST agora_rtc_engine + connectivity_plus file_selector_windows flutter_blue_plus_winrt flutter_webrtc diff --git a/草坪作业规划APP功能使用手册.docx b/草坪作业规划APP功能使用手册.docx new file mode 100644 index 00000000..29d5a190 Binary files /dev/null and b/草坪作业规划APP功能使用手册.docx differ diff --git a/草坪作业规划APP功能使用手册_v2.docx b/草坪作业规划APP功能使用手册_v2.docx new file mode 100644 index 00000000..8608efed Binary files /dev/null and b/草坪作业规划APP功能使用手册_v2.docx differ diff --git a/草坪作业规划APP功能使用手册_v3.docx b/草坪作业规划APP功能使用手册_v3.docx new file mode 100644 index 00000000..da0c5290 Binary files /dev/null and b/草坪作业规划APP功能使用手册_v3.docx differ