first commit
This commit is contained in:
197
app_car/README.md
Normal file
197
app_car/README.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# OneApp App Car 车辆相关模块群文档
|
||||
|
||||
## 模块群概述
|
||||
|
||||
`oneapp_app_car` 是 OneApp 中最重要的模块群之一,包含了所有与车辆相关的功能模块。该模块群涵盖了车辆控制、充电管理、虚拟形象、维护保养、订单管理等核心业务功能。
|
||||
|
||||
## 模块结构总览
|
||||
|
||||
```
|
||||
oneapp_app_car/
|
||||
├── ai_chat_assistant/ # AI 聊天助手模块
|
||||
├── amap_flutter_location/ # 高德地图定位插件
|
||||
├── amap_flutter_search/ # 高德地图搜索插件
|
||||
├── app_avatar/ # 虚拟形象应用模块
|
||||
├── app_car/ # 车辆控制主模块
|
||||
├── app_carwatcher/ # 车辆监控模块
|
||||
├── app_charging/ # 充电管理模块
|
||||
├── app_composer/ # 编辑器组件模块
|
||||
├── app_maintenance/ # 维护保养模块
|
||||
├── app_order/ # 订单管理模块
|
||||
├── app_rpa/ # RPA 自动化模块
|
||||
├── app_touchgo/ # Touch&Go 功能模块
|
||||
├── app_vur/ # 车辆更新记录模块
|
||||
├── app_wallbox/ # 家充桩管理模块
|
||||
├── car_services/ # 车辆服务模块
|
||||
├── clr_avatarcore/ # 虚拟形象核心 SDK
|
||||
├── clr_order/ # 订单服务 SDK
|
||||
├── clr_touchgo/ # Touch&Go 服务 SDK
|
||||
├── clr_wallbox/ # 家充桩服务 SDK
|
||||
├── kit_rpa_plugin/ # RPA 插件工具包
|
||||
├── one_app_cache_plugin/ # 缓存插件
|
||||
└── ui_avatarx/ # 虚拟形象 UI 组件
|
||||
```
|
||||
|
||||
## 模块分类
|
||||
|
||||
### 1. 核心车辆功能模块
|
||||
- **app_car** - 车辆控制主模块,提供基础的车辆操作功能
|
||||
- **app_carwatcher** - 车辆监控模块,实时监控车辆状态
|
||||
- **car_services** - 车辆服务模块,提供各种车辆相关服务
|
||||
|
||||
### 2. 充电相关模块
|
||||
- **app_charging** - 充电管理模块,管理车辆充电功能
|
||||
- **app_wallbox** - 家充桩管理模块,管理家用充电桩
|
||||
- **clr_wallbox** - 家充桩服务 SDK
|
||||
|
||||
### 3. 虚拟形象模块群
|
||||
- **app_avatar** - 虚拟形象应用模块
|
||||
- **clr_avatarcore** - 虚拟形象核心 SDK
|
||||
- **ui_avatarx** - 虚拟形象 UI 组件
|
||||
|
||||
### 4. 订单和支付模块
|
||||
- **app_order** - 订单管理模块
|
||||
- **clr_order** - 订单服务 SDK
|
||||
|
||||
### 5. 智能功能模块
|
||||
- **ai_chat_assistant** - AI 聊天助手模块
|
||||
- **app_touchgo** - Touch&Go 功能模块
|
||||
- **clr_touchgo** - Touch&Go 服务 SDK
|
||||
|
||||
### 6. 维护和管理模块
|
||||
- **app_maintenance** - 维护保养模块
|
||||
- **app_vur** - 车辆更新记录模块
|
||||
- **app_composer** - 编辑器组件模块
|
||||
|
||||
### 7. 自动化和工具模块
|
||||
- **app_rpa** - RPA 自动化模块
|
||||
- **kit_rpa_plugin** - RPA 插件工具包
|
||||
- **one_app_cache_plugin** - 缓存插件
|
||||
|
||||
### 8. 地图和定位模块
|
||||
- **amap_flutter_location** - 高德地图定位插件
|
||||
- **amap_flutter_search** - 高德地图搜索插件
|
||||
|
||||
## 模块间依赖关系
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[app_car 车辆控制主模块] --> B[car_services 车辆服务]
|
||||
A --> C[app_carwatcher 车辆监控]
|
||||
A --> D[app_charging 充电管理]
|
||||
|
||||
E[app_avatar 虚拟形象] --> F[clr_avatarcore 虚拟形象核心]
|
||||
E --> G[ui_avatarx 虚拟形象UI]
|
||||
|
||||
H[app_order 订单管理] --> I[clr_order 订单服务]
|
||||
H --> J[app_charging 充电管理]
|
||||
|
||||
K[app_touchgo Touch&Go] --> L[clr_touchgo Touch&Go服务]
|
||||
|
||||
M[app_wallbox 家充桩] --> N[clr_wallbox 家充桩服务]
|
||||
M --> D
|
||||
|
||||
O[ai_chat_assistant AI助手] --> A
|
||||
O --> E
|
||||
```
|
||||
|
||||
## 技术架构特点
|
||||
|
||||
### 1. 分层架构
|
||||
- **应用层** (app_*): 业务逻辑和用户界面
|
||||
- **服务层** (clr_*): 核心服务和 SDK
|
||||
- **工具层** (kit_*, ui_*): 工具和 UI 组件
|
||||
- **插件层** (plugin): 原生功能插件
|
||||
|
||||
### 2. 模块化设计
|
||||
- 每个模块独立开发和测试
|
||||
- 清晰的接口定义和依赖管理
|
||||
- 支持热插拔和动态加载
|
||||
|
||||
### 3. 服务化架构
|
||||
- 微服务设计理念
|
||||
- RESTful API 接口
|
||||
- 统一的错误处理和日志记录
|
||||
|
||||
## 详细模块文档
|
||||
|
||||
- [AI Chat Assistant - AI 聊天助手](./ai_chat_assistant.md)
|
||||
- [App Car - 车辆控制主模块](./app_car.md)
|
||||
- [App Avatar - 虚拟形象模块](./app_avatar.md)
|
||||
- [App Charging - 充电管理模块](./app_charging.md)
|
||||
- [App CarWatcher - 车辆监控模块](./app_carwatcher.md)
|
||||
- [App Order - 订单管理模块](./app_order.md)
|
||||
- [App TouchGo - Touch&Go 功能模块](./app_touchgo.md)
|
||||
- [App Wallbox - 家充桩管理模块](./app_wallbox.md)
|
||||
- [App Maintenance - 维护保养模块](./app_maintenance.md)
|
||||
- [App VUR - 车辆更新记录模块](./app_vur.md)
|
||||
- [Car Services - 车辆服务模块](./car_services.md)
|
||||
- [CLR AvatarCore - 虚拟形象核心 SDK](./clr_avatarcore.md)
|
||||
- [CLR Order - 订单服务 SDK](./clr_order.md)
|
||||
- [CLR TouchGo - Touch&Go 服务 SDK](./clr_touchgo.md)
|
||||
- [CLR Wallbox - 家充桩服务 SDK](./clr_wallbox.md)
|
||||
- [Kit RPA Plugin - RPA 插件工具包](./kit_rpa_plugin.md)
|
||||
- [AMap Flutter Location - 高德地图定位插件](./amap_flutter_location.md)
|
||||
- [AMap Flutter Search - 高德地图搜索插件](./amap_flutter_search.md)
|
||||
- [UI AvatarX - 虚拟形象 UI 组件](./ui_avatarx.md)
|
||||
- [One App Cache Plugin - 缓存插件](./one_app_cache_plugin.md)
|
||||
|
||||
## 开发指南
|
||||
|
||||
### 环境要求
|
||||
- Flutter >=3.0.0
|
||||
- Dart >=3.0.0
|
||||
- Android SDK >=21
|
||||
- iOS >=11.0
|
||||
|
||||
### 构建说明
|
||||
每个模块都可以独立构建和测试,同时支持集成构建。具体的构建方式请参考各模块的详细文档。
|
||||
|
||||
### 测试策略
|
||||
- 单元测试:每个模块的核心功能
|
||||
- 集成测试:模块间的交互
|
||||
- 端到端测试:完整的用户场景
|
||||
|
||||
## 总结
|
||||
|
||||
`oneapp_app_car` 模块群是 OneApp 车主应用的核心,提供了完整的车辆相关功能生态。通过合理的模块化设计和清晰的架构分层,实现了高内聚、低耦合的设计目标,为用户提供了丰富而稳定的车辆服务体验。
|
||||
|
||||
# App Car 车辆功能模块群
|
||||
|
||||
## 模块群概述
|
||||
|
||||
App Car 模块群是 OneApp 车联网生态的核心功能集合,包含了车辆控制、充电管理、虚拟形象、维护保养等全方位的车辆相关功能模块。该模块群为用户提供了完整的智能车辆管理和控制体验。
|
||||
|
||||
## 子模块列表
|
||||
|
||||
### 应用功能模块
|
||||
1. **[ai_chat_assistant](./ai_chat_assistant.md)** - AI聊天助手模块
|
||||
2. **[app_avatar](./app_avatar.md)** - 虚拟形象应用模块
|
||||
3. **[app_car](./app_car.md)** - 车辆控制主模块
|
||||
4. **[app_carwatcher](./app_carwatcher.md)** - 车辆监控模块
|
||||
5. **[app_charging](./app_charging.md)** - 充电管理模块
|
||||
6. **[app_composer](./app_composer.md)** - 车辆编排模块
|
||||
7. **[app_maintenance](./app_maintenance.md)** - 维护保养模块
|
||||
8. **[app_order](./app_order.md)** - 订单管理模块
|
||||
9. **[app_rpa](./app_rpa.md)** - RPA自动化模块
|
||||
10. **[app_touchgo](./app_touchgo.md)** - 触控交互模块
|
||||
11. **[app_vur](./app_vur.md)** - 车辆更新记录模块
|
||||
12. **[app_wallbox](./app_wallbox.md)** - 充电墙盒模块
|
||||
|
||||
### 服务SDK模块
|
||||
13. **[car_services](./car_services.md)** - 车辆服务统一接口
|
||||
14. **[clr_avatarcore](./clr_avatarcore.md)** - 虚拟形象核心服务
|
||||
15. **[clr_order](./clr_order.md)** - 订单服务SDK
|
||||
16. **[clr_touchgo](./clr_touchgo.md)** - 触控服务SDK
|
||||
17. **[clr_wallbox](./clr_wallbox.md)** - 充电墙盒服务SDK
|
||||
|
||||
### 原生插件模块
|
||||
18. **[kit_rpa_plugin](./kit_rpa_plugin.md)** - RPA自动化原生插件
|
||||
19. **[one_app_cache_plugin](./one_app_cache_plugin.md)** - 缓存原生插件
|
||||
|
||||
### UI组件模块
|
||||
20. **[ui_avatarx](./ui_avatarx.md)** - 虚拟形象UI组件库
|
||||
|
||||
### 第三方集成模块
|
||||
21. **amap_flutter_location** - 高德地图定位服务
|
||||
22. **amap_flutter_search** - 高德地图搜索服务
|
||||
383
app_car/ai_chat_assistant.md
Normal file
383
app_car/ai_chat_assistant.md
Normal file
@@ -0,0 +1,383 @@
|
||||
# AI Chat Assistant - AI 聊天助手模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`ai_chat_assistant` 是 OneApp 车辆模块群中的智能交互模块,提供基于人工智能的语音和文字聊天功能。该模块集成了语音识别、自然语言处理、车辆控制等技术,为用户提供智能化的车辆助手服务。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: ai_chat_assistant
|
||||
- **模块路径**: oneapp_app_car/ai_chat_assistant
|
||||
- **类型**: Flutter Package Module
|
||||
- **主要功能**: 智能语音交互、车辆控制、自然语言问答
|
||||
|
||||
### 核心特性
|
||||
- **智能语音识别**: 集成阿里云语音识别SDK
|
||||
- **车辆智能控制**: 支持20+种车辆控制命令
|
||||
- **自然语言处理**: 基于OpenAI GPT的智能问答
|
||||
- **多语言支持**: 中英文双语交互
|
||||
- **实时流式响应**: 基于SSE的实时对话体验
|
||||
- **权限智能管理**: 自动处理麦克风等系统权限
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
ai_chat_assistant/
|
||||
├── lib/
|
||||
│ ├── ai_chat_assistant.dart # 模块入口文件
|
||||
│ ├── app.dart # 应用配置
|
||||
│ ├── manager.dart # 全局管理器
|
||||
│ ├── bloc/ # BLoC状态管理
|
||||
│ │ ├── ai_chat_cubit.dart
|
||||
│ │ ├── easy_bloc.dart
|
||||
│ │ └── command_state.dart
|
||||
│ ├── enums/ # 枚举定义
|
||||
│ │ ├── message_status.dart
|
||||
│ │ ├── message_service_state.dart
|
||||
│ │ └── vehicle_command_type.dart
|
||||
│ ├── models/ # 数据模型
|
||||
│ │ ├── chat_message.dart
|
||||
│ │ ├── vehicle_cmd.dart
|
||||
│ │ ├── vehicle_cmd_response.dart
|
||||
│ │ └── vehicle_status_info.dart
|
||||
│ ├── screens/ # 界面组件
|
||||
│ │ ├── full_screen.dart
|
||||
│ │ ├── part_screen.dart
|
||||
│ │ └── main_screen.dart
|
||||
│ ├── services/ # 业务服务层
|
||||
│ │ ├── message_service.dart
|
||||
│ │ ├── command_service.dart
|
||||
│ │ ├── chat_sse_service.dart
|
||||
│ │ └── classification_service.dart
|
||||
│ ├── utils/ # 工具类
|
||||
│ │ ├── common_util.dart
|
||||
│ │ └── tts_util.dart
|
||||
│ └── widgets/ # UI组件
|
||||
│ ├── chat_box.dart
|
||||
│ ├── chat_bubble.dart
|
||||
│ ├── assistant_avatar.dart
|
||||
│ └── floating_icon.dart
|
||||
└── pubspec.yaml # 依赖配置
|
||||
```
|
||||
|
||||
## 核心架构组件
|
||||
|
||||
### 1. 消息状态枚举 (MessageStatus)
|
||||
|
||||
```dart
|
||||
enum MessageStatus {
|
||||
normal('普通消息', 'Normal'),
|
||||
listening('聆听中', 'Listening'),
|
||||
recognizing('识别中', 'Recognizing'),
|
||||
thinking('思考中', 'Thinking'),
|
||||
completed('完成回答', 'Completed'),
|
||||
executing('执行中', 'Executing'),
|
||||
success('执行成功', 'Success'),
|
||||
failure('执行失败', 'Failure'),
|
||||
aborted('已中止', 'Aborted');
|
||||
|
||||
const MessageStatus(this.chinese, this.english);
|
||||
final String chinese;
|
||||
final String english;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 车辆控制命令枚举 (VehicleCommandType)
|
||||
|
||||
```dart
|
||||
enum VehicleCommandType {
|
||||
unknown('未知', 'unknown'),
|
||||
lock('上锁车门', 'lock'),
|
||||
unlock('解锁车门', 'unlock'),
|
||||
openWindow('打开车窗', 'open window'),
|
||||
closeWindow('关闭车窗', 'close window'),
|
||||
appointAC('预约空调', 'appoint AC'),
|
||||
openAC('打开空调', 'open AC'),
|
||||
closeAC('关闭空调', 'close AC'),
|
||||
changeACTemp('修改空调温度', 'change AC temperature'),
|
||||
coolSharply('极速降温', 'cool sharply'),
|
||||
prepareCar('一键备车', 'prepare car'),
|
||||
meltSnow('一键融雪', 'melt snow'),
|
||||
openTrunk('打开后备箱', 'open trunk'),
|
||||
closeTrunk('关闭后备箱', 'close trunk'),
|
||||
honk('鸣笛', 'honk'),
|
||||
locateCar('定位车辆', 'locate car'),
|
||||
openWheelHeat('开启方向盘加热', 'open wheel heat'),
|
||||
closeWheelHeat('关闭方向盘加热', 'close wheel heat'),
|
||||
openMainSeatHeat('开启主座椅加热', 'open main seat heat'),
|
||||
closeMainSeatHeat('关闭主座椅加热', 'close main seat heat'),
|
||||
openMinorSeatHeat('开启副座椅加热', 'open minor seat heat'),
|
||||
closeMinorSeatHeat('关闭副座椅加热', 'close minor seat heat');
|
||||
|
||||
const VehicleCommandType(this.chinese, this.english);
|
||||
final String chinese;
|
||||
final String english;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 聊天消息模型 (ChatMessage)
|
||||
|
||||
```dart
|
||||
class ChatMessage {
|
||||
final String id;
|
||||
final String text;
|
||||
final bool isUser;
|
||||
final DateTime timestamp;
|
||||
MessageStatus status;
|
||||
|
||||
ChatMessage({
|
||||
required this.id,
|
||||
required this.text,
|
||||
required this.isUser,
|
||||
required this.timestamp,
|
||||
this.status = MessageStatus.normal,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 核心服务类
|
||||
|
||||
### 1. 消息服务 (MessageService)
|
||||
|
||||
MessageService是AI聊天助手的核心服务,采用单例模式,负责管理整个对话流程:
|
||||
|
||||
```dart
|
||||
class MessageService extends ChangeNotifier {
|
||||
static MessageService? _instance;
|
||||
static MessageService get instance => _instance ??= MessageService._internal();
|
||||
factory MessageService() => instance;
|
||||
|
||||
// 核心方法
|
||||
Future<void> startVoiceInput() async
|
||||
Future<void> stopAndProcessVoiceInput() async
|
||||
Future<void> reply(String text) async
|
||||
Future<void> handleVehicleControl(String text, bool isChinese) async
|
||||
Future<bool> processCommand(VehicleCommand command, bool isChinese) async
|
||||
}
|
||||
```
|
||||
|
||||
**主要功能模块:**
|
||||
|
||||
#### 语音交互流程
|
||||
1. **录音开始**: `startVoiceInput()` - 检查麦克风权限,开启阿里云ASR
|
||||
2. **录音识别**: `stopAndProcessVoiceInput()` - 停止录音并获取识别结果
|
||||
3. **文本分类**: 通过 `TextClassificationService` 判断用户意图
|
||||
4. **响应生成**: 根据分类结果调用相应处理方法
|
||||
|
||||
#### 消息状态管理
|
||||
- **listening**: 正在聆听用户语音输入
|
||||
- **recognizing**: 语音识别中
|
||||
- **thinking**: AI思考回复中
|
||||
- **executing**: 车辆控制命令执行中
|
||||
- **completed**: 对话完成
|
||||
|
||||
#### 车辆控制处理
|
||||
```dart
|
||||
Future<void> handleVehicleControl(String text, bool isChinese) async {
|
||||
final vehicleCommandResponse = await _vehicleCommandService.getCommandFromText(text);
|
||||
if (vehicleCommandResponse != null) {
|
||||
// 更新消息状态为执行中
|
||||
replaceMessage(id: _latestAssistantMessageId!,
|
||||
text: vehicleCommandResponse.tips!,
|
||||
status: MessageStatus.executing);
|
||||
|
||||
// 执行车辆控制命令
|
||||
for (var command in vehicleCommandResponse.commands) {
|
||||
if (command.type != VehicleCommandType.unknown && command.error.isEmpty) {
|
||||
bool isSuccess = await processCommand(command, isChinese);
|
||||
// 处理执行结果
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. BLoC状态管理 (AIChatCommandCubit)
|
||||
|
||||
```dart
|
||||
class AIChatCommandCubit extends EasyCubit<AIChatCommandState> {
|
||||
AIChatCommandCubit() : super(const AIChatCommandState());
|
||||
|
||||
void reset() {
|
||||
emit(const AIChatCommandState());
|
||||
}
|
||||
|
||||
String _generateCommandId() {
|
||||
return '${DateTime.now().millisecondsSinceEpoch}_${state.commandType?.name ?? 'unknown'}';
|
||||
}
|
||||
|
||||
bool get isExecuting => state.status == AIChatCommandStatus.executing;
|
||||
String? get currentCommandId => state.commandId;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 主屏幕界面 (MainScreen)
|
||||
|
||||
```dart
|
||||
class MainScreen extends StatefulWidget {
|
||||
const MainScreen({super.key});
|
||||
|
||||
@override
|
||||
State<MainScreen> createState() => _MainScreenState();
|
||||
}
|
||||
|
||||
class _MainScreenState extends State<MainScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
body: Stack(
|
||||
children: [
|
||||
Container(
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/bg.jpg', package: 'ai_chat_assistant'),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
FloatingIcon(), // 浮动聊天入口
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 技术集成
|
||||
|
||||
### 阿里云语音识别集成
|
||||
```dart
|
||||
// 方法通道配置
|
||||
static const MethodChannel _asrChannel = MethodChannel('com.example.ai_chat_assistant/ali_sdk');
|
||||
|
||||
// ASR回调处理
|
||||
Future<dynamic> _handleMethodCall(MethodCall call) async {
|
||||
switch (call.method) {
|
||||
case "onAsrResult":
|
||||
replaceMessage(id: _latestUserMessageId!,
|
||||
text: call.arguments,
|
||||
status: MessageStatus.normal);
|
||||
break;
|
||||
case "onAsrStop":
|
||||
if (_asrCompleter != null && !_asrCompleter!.isCompleted) {
|
||||
_asrCompleter!.complete(messages.last.text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 权限管理
|
||||
```dart
|
||||
Future<void> startVoiceInput() async {
|
||||
if (await Permission.microphone.status == PermissionStatus.denied) {
|
||||
PermissionStatus status = await Permission.microphone.request();
|
||||
if (status == PermissionStatus.permanentlyDenied) {
|
||||
await Fluttertoast.showToast(msg: "请在设置中开启麦克风权限");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 继续语音输入流程
|
||||
}
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 1. 模块导入
|
||||
```dart
|
||||
import 'package:ai_chat_assistant/ai_chat_assistant.dart';
|
||||
```
|
||||
|
||||
### 2. 服务初始化
|
||||
```dart
|
||||
// 获取消息服务实例
|
||||
final messageService = MessageService.instance;
|
||||
|
||||
// 监听消息变化
|
||||
messageService.addListener(() {
|
||||
// 处理消息更新
|
||||
});
|
||||
```
|
||||
|
||||
### 3. 语音交互
|
||||
```dart
|
||||
// 开始语音输入
|
||||
await messageService.startVoiceInput();
|
||||
|
||||
// 停止并处理语音输入
|
||||
await messageService.stopAndProcessVoiceInput();
|
||||
```
|
||||
|
||||
### 4. 文本交互
|
||||
```dart
|
||||
// 直接发送文本消息
|
||||
await messageService.reply("帮我打开空调");
|
||||
```
|
||||
|
||||
## 依赖配置
|
||||
|
||||
### pubspec.yaml 关键依赖
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
# 状态管理
|
||||
provider: ^6.0.0
|
||||
|
||||
# 权限管理
|
||||
permission_handler: ^10.0.0
|
||||
|
||||
# 网络请求
|
||||
dio: ^5.0.0
|
||||
|
||||
# 提示消息
|
||||
fluttertoast: ^8.0.0
|
||||
|
||||
# UUID生成
|
||||
uuid: ^3.0.0
|
||||
|
||||
# 国际化
|
||||
basic_intl:
|
||||
path: ../../oneapp_basic_utils/basic_intl
|
||||
```
|
||||
|
||||
## 扩展开发指南
|
||||
|
||||
### 1. 新增车辆控制命令
|
||||
|
||||
1. 在 `VehicleCommandType` 枚举中添加新命令:
|
||||
```dart
|
||||
enum VehicleCommandType {
|
||||
// 现有命令...
|
||||
newCommand('新命令', 'new command'),
|
||||
}
|
||||
```
|
||||
|
||||
2. 在 `MessageService.processCommand` 中添加处理逻辑。
|
||||
|
||||
### 2. 自定义对话界面
|
||||
|
||||
继承或修改现有的Screen组件,实现自定义的对话界面布局。
|
||||
|
||||
### 3. 集成其他AI服务
|
||||
|
||||
通过修改 `ChatSseService` 或新增服务类,可以集成其他AI对话服务。
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
1. **内存管理**: MessageService使用单例模式,注意在适当时机清理消息历史
|
||||
2. **网络优化**: SSE连接在不使用时应及时断开
|
||||
3. **权限缓存**: 避免重复请求已获取的权限
|
||||
4. **语音资源**: 及时释放语音录制和播放资源
|
||||
|
||||
## 问题排查
|
||||
|
||||
### 常见问题
|
||||
1. **语音识别失效**: 检查麦克风权限和阿里云SDK配置
|
||||
2. **车辆控制失败**: 确认车辆连接状态和控制权限
|
||||
3. **SSE连接断开**: 检查网络状态和服务端配置
|
||||
|
||||
### 调试技巧
|
||||
- 启用详细日志输出
|
||||
- 使用Flutter Inspector检查Widget状态
|
||||
- 通过MethodChannel调试原生交互
|
||||
614
app_car/amap_flutter_location.md
Normal file
614
app_car/amap_flutter_location.md
Normal file
@@ -0,0 +1,614 @@
|
||||
# AMap Flutter Location - 高德地图定位插件
|
||||
|
||||
## 模块概述
|
||||
|
||||
`amap_flutter_location` 是 OneApp 中基于高德地图 SDK 的定位服务插件,提供了高精度的位置定位、地理围栏、轨迹记录等功能。该插件为车辆定位、导航、位置服务等功能提供了可靠的地理位置支持。
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. 位置定位
|
||||
- **GPS 定位**:基于 GPS 卫星的高精度定位
|
||||
- **网络定位**:基于基站和 WiFi 的快速定位
|
||||
- **混合定位**:GPS + 网络的融合定位算法
|
||||
- **室内定位**:支持室内场景的位置识别
|
||||
|
||||
### 2. 地理围栏
|
||||
- **围栏创建**:创建圆形、多边形地理围栏
|
||||
- **进出检测**:实时检测设备进入/离开围栏
|
||||
- **多围栏管理**:同时管理多个地理围栏
|
||||
- **事件通知**:围栏事件的实时推送
|
||||
|
||||
### 3. 轨迹记录
|
||||
- **轨迹采集**:实时记录移动轨迹
|
||||
- **轨迹优化**:去噪、平滑轨迹数据
|
||||
- **轨迹存储**:本地和云端轨迹存储
|
||||
- **轨迹分析**:距离、速度、停留点分析
|
||||
|
||||
### 4. 位置服务
|
||||
- **逆地理编码**:坐标转换为地址信息
|
||||
- **地理编码**:地址转换为坐标信息
|
||||
- **POI 搜索**:兴趣点搜索和信息获取
|
||||
- **距离计算**:两点间距离和路径计算
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 架构设计
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 应用层 │
|
||||
│ (app_car, app_navigation) │
|
||||
├─────────────────────────────────────┤
|
||||
│ AMap Flutter Location │
|
||||
│ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ 定位管理 │ 围栏服务 │ 轨迹记录 │ │
|
||||
│ ├──────────┼──────────┼──────────┤ │
|
||||
│ │ 坐标转换 │ 事件处理 │ 数据存储 │ │
|
||||
│ └──────────┴──────────┴──────────┘ │
|
||||
├─────────────────────────────────────┤
|
||||
│ 高德地图 Native SDK │
|
||||
│ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ Android │ iOS │ 定位引擎 │ │
|
||||
│ └──────────┴──────────┴──────────┘ │
|
||||
├─────────────────────────────────────┤
|
||||
│ 系统定位服务 │
|
||||
│ (GPS, Network, Sensors) │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 核心组件
|
||||
|
||||
#### 1. 定位管理器 (LocationManager)
|
||||
```dart
|
||||
class AMapLocationManager {
|
||||
// 初始化定位服务
|
||||
Future<bool> initialize(LocationConfig config);
|
||||
|
||||
// 开始定位
|
||||
Future<void> startLocation();
|
||||
|
||||
// 停止定位
|
||||
Future<void> stopLocation();
|
||||
|
||||
// 获取当前位置
|
||||
Future<AMapLocation> getCurrentLocation();
|
||||
|
||||
// 设置定位参数
|
||||
Future<void> setLocationOption(LocationOption option);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 地理围栏管理器 (GeofenceManager)
|
||||
```dart
|
||||
class AMapGeofenceManager {
|
||||
// 添加围栏
|
||||
Future<String> addGeofence(GeofenceRegion region);
|
||||
|
||||
// 移除围栏
|
||||
Future<bool> removeGeofence(String geofenceId);
|
||||
|
||||
// 获取围栏列表
|
||||
Future<List<GeofenceRegion>> getGeofences();
|
||||
|
||||
// 开始围栏监控
|
||||
Future<void> startGeofenceMonitoring();
|
||||
|
||||
// 停止围栏监控
|
||||
Future<void> stopGeofenceMonitoring();
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 轨迹记录器 (TrackRecorder)
|
||||
```dart
|
||||
class AMapTrackRecorder {
|
||||
// 开始录制轨迹
|
||||
Future<String> startRecording(TrackConfig config);
|
||||
|
||||
// 停止录制轨迹
|
||||
Future<Track> stopRecording(String trackId);
|
||||
|
||||
// 暂停录制
|
||||
Future<void> pauseRecording(String trackId);
|
||||
|
||||
// 恢复录制
|
||||
Future<void> resumeRecording(String trackId);
|
||||
|
||||
// 获取轨迹数据
|
||||
Future<Track> getTrack(String trackId);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 坐标转换器 (CoordinateConverter)
|
||||
```dart
|
||||
class AMapCoordinateConverter {
|
||||
// 坐标系转换
|
||||
LatLng convertCoordinate(LatLng source, CoordinateType from, CoordinateType to);
|
||||
|
||||
// 批量坐标转换
|
||||
List<LatLng> convertCoordinates(List<LatLng> source, CoordinateType from, CoordinateType to);
|
||||
|
||||
// 逆地理编码
|
||||
Future<RegeocodeResult> reverseGeocode(LatLng location);
|
||||
|
||||
// 地理编码
|
||||
Future<GeocodeResult> geocode(String address);
|
||||
}
|
||||
```
|
||||
|
||||
## 数据模型
|
||||
|
||||
### 位置模型
|
||||
```dart
|
||||
class AMapLocation {
|
||||
final double latitude; // 纬度
|
||||
final double longitude; // 经度
|
||||
final double altitude; // 海拔
|
||||
final double accuracy; // 精度
|
||||
final double speed; // 速度
|
||||
final double bearing; // 方向角
|
||||
final DateTime timestamp; // 时间戳
|
||||
final String address; // 地址信息
|
||||
final String province; // 省份
|
||||
final String city; // 城市
|
||||
final String district; // 区县
|
||||
final String street; // 街道
|
||||
final String streetNumber; // 门牌号
|
||||
final String aoiName; // AOI 名称
|
||||
final String poiName; // POI 名称
|
||||
final LocationType locationType; // 定位类型
|
||||
}
|
||||
|
||||
enum LocationType {
|
||||
gps, // GPS 定位
|
||||
network, // 网络定位
|
||||
passive, // 被动定位
|
||||
offline, // 离线定位
|
||||
lastKnown // 上次定位
|
||||
}
|
||||
```
|
||||
|
||||
### 地理围栏模型
|
||||
```dart
|
||||
class GeofenceRegion {
|
||||
final String id;
|
||||
final String name;
|
||||
final GeofenceType type;
|
||||
final LatLng center;
|
||||
final double radius;
|
||||
final List<LatLng> polygon;
|
||||
final GeofenceAction action;
|
||||
final bool isEnabled;
|
||||
final DateTime createdAt;
|
||||
final Map<String, dynamic> metadata;
|
||||
}
|
||||
|
||||
enum GeofenceType {
|
||||
circle, // 圆形围栏
|
||||
polygon, // 多边形围栏
|
||||
poi, // POI 围栏
|
||||
district // 行政区围栏
|
||||
}
|
||||
|
||||
enum GeofenceAction {
|
||||
enter, // 进入事件
|
||||
exit, // 离开事件
|
||||
dwell, // 停留事件
|
||||
enterOrExit // 进入或离开
|
||||
}
|
||||
```
|
||||
|
||||
### 轨迹模型
|
||||
```dart
|
||||
class Track {
|
||||
final String id;
|
||||
final String name;
|
||||
final DateTime startTime;
|
||||
final DateTime endTime;
|
||||
final List<TrackPoint> points;
|
||||
final double totalDistance;
|
||||
final Duration totalTime;
|
||||
final double averageSpeed;
|
||||
final double maxSpeed;
|
||||
final TrackStatistics statistics;
|
||||
}
|
||||
|
||||
class TrackPoint {
|
||||
final double latitude;
|
||||
final double longitude;
|
||||
final double altitude;
|
||||
final double speed;
|
||||
final double bearing;
|
||||
final DateTime timestamp;
|
||||
final double accuracy;
|
||||
}
|
||||
|
||||
class TrackStatistics {
|
||||
final double totalDistance;
|
||||
final Duration totalTime;
|
||||
final Duration movingTime;
|
||||
final Duration pausedTime;
|
||||
final double averageSpeed;
|
||||
final double maxSpeed;
|
||||
final double totalAscent;
|
||||
final double totalDescent;
|
||||
final List<StopPoint> stopPoints;
|
||||
}
|
||||
```
|
||||
|
||||
## API 接口
|
||||
|
||||
### 定位接口
|
||||
```dart
|
||||
abstract class LocationService {
|
||||
// 获取当前位置
|
||||
Future<ApiResponse<AMapLocation>> getCurrentLocation();
|
||||
|
||||
// 开始连续定位
|
||||
Future<ApiResponse<bool>> startContinuousLocation(LocationOption option);
|
||||
|
||||
// 停止连续定位
|
||||
Future<ApiResponse<bool>> stopContinuousLocation();
|
||||
|
||||
// 获取定位权限状态
|
||||
Future<ApiResponse<LocationPermission>> getLocationPermission();
|
||||
|
||||
// 请求定位权限
|
||||
Future<ApiResponse<bool>> requestLocationPermission();
|
||||
}
|
||||
```
|
||||
|
||||
### 地理围栏接口
|
||||
```dart
|
||||
abstract class GeofenceService {
|
||||
// 创建地理围栏
|
||||
Future<ApiResponse<String>> createGeofence(CreateGeofenceRequest request);
|
||||
|
||||
// 删除地理围栏
|
||||
Future<ApiResponse<bool>> deleteGeofence(String geofenceId);
|
||||
|
||||
// 获取围栏列表
|
||||
Future<ApiResponse<List<GeofenceRegion>>> getGeofences();
|
||||
|
||||
// 获取围栏状态
|
||||
Future<ApiResponse<GeofenceStatus>> getGeofenceStatus(String geofenceId);
|
||||
}
|
||||
```
|
||||
|
||||
### 轨迹接口
|
||||
```dart
|
||||
abstract class TrackService {
|
||||
// 开始轨迹记录
|
||||
Future<ApiResponse<String>> startTrackRecording(TrackConfig config);
|
||||
|
||||
// 停止轨迹记录
|
||||
Future<ApiResponse<Track>> stopTrackRecording(String trackId);
|
||||
|
||||
// 获取轨迹数据
|
||||
Future<ApiResponse<Track>> getTrack(String trackId);
|
||||
|
||||
// 获取轨迹列表
|
||||
Future<ApiResponse<List<TrackSummary>>> getTrackList(TrackQuery query);
|
||||
}
|
||||
```
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 定位配置
|
||||
```dart
|
||||
class LocationOption {
|
||||
final LocationMode locationMode; // 定位模式
|
||||
final int interval; // 定位间隔(毫秒)
|
||||
final bool needAddress; // 是否需要地址信息
|
||||
final bool mockEnable; // 是否允许模拟位置
|
||||
final bool wifiScan; // 是否开启 WiFi 扫描
|
||||
final bool gpsFirst; // 是否 GPS 优先
|
||||
final int httpTimeOut; // 网络超时时间
|
||||
final LocationPurpose locationPurpose; // 定位目的
|
||||
|
||||
static const LocationOption defaultOption = LocationOption(
|
||||
locationMode: LocationMode.hightAccuracy,
|
||||
interval: 2000,
|
||||
needAddress: true,
|
||||
mockEnable: false,
|
||||
wifiScan: true,
|
||||
gpsFirst: false,
|
||||
httpTimeOut: 30000,
|
||||
locationPurpose: LocationPurpose.signIn,
|
||||
);
|
||||
}
|
||||
|
||||
enum LocationMode {
|
||||
batterySaving, // 低功耗模式
|
||||
deviceSensors, // 仅设备传感器
|
||||
hightAccuracy // 高精度模式
|
||||
}
|
||||
```
|
||||
|
||||
### 围栏配置
|
||||
```dart
|
||||
class GeofenceConfig {
|
||||
final bool enableNotification; // 是否启用通知
|
||||
final int dwellDelay; // 停留延迟(毫秒)
|
||||
final double minimumRadius; // 最小围栏半径
|
||||
final double maximumRadius; // 最大围栏半径
|
||||
final int maxGeofenceCount; // 最大围栏数量
|
||||
|
||||
static const GeofenceConfig defaultConfig = GeofenceConfig(
|
||||
enableNotification: true,
|
||||
dwellDelay: 10000,
|
||||
minimumRadius: 50.0,
|
||||
maximumRadius: 100000.0,
|
||||
maxGeofenceCount: 100,
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基本定位示例
|
||||
```dart
|
||||
// 初始化定位服务
|
||||
final locationManager = AMapLocationManager.instance;
|
||||
await locationManager.initialize(LocationConfig.defaultConfig);
|
||||
|
||||
// 设置定位参数
|
||||
await locationManager.setLocationOption(LocationOption.defaultOption);
|
||||
|
||||
// 监听位置变化
|
||||
locationManager.onLocationChanged.listen((location) {
|
||||
print('当前位置: ${location.latitude}, ${location.longitude}');
|
||||
print('地址: ${location.address}');
|
||||
});
|
||||
|
||||
// 开始定位
|
||||
await locationManager.startLocation();
|
||||
```
|
||||
|
||||
### 地理围栏示例
|
||||
```dart
|
||||
// 创建圆形围栏
|
||||
final geofence = GeofenceRegion(
|
||||
id: 'home_fence',
|
||||
name: '家庭围栏',
|
||||
type: GeofenceType.circle,
|
||||
center: LatLng(39.9042, 116.4074), // 北京天安门
|
||||
radius: 500.0, // 500米半径
|
||||
action: GeofenceAction.enterOrExit,
|
||||
isEnabled: true,
|
||||
);
|
||||
|
||||
// 添加围栏
|
||||
final geofenceManager = AMapGeofenceManager.instance;
|
||||
final fenceId = await geofenceManager.addGeofence(geofence);
|
||||
|
||||
// 监听围栏事件
|
||||
geofenceManager.onGeofenceTriggered.listen((event) {
|
||||
switch (event.action) {
|
||||
case GeofenceAction.enter:
|
||||
print('进入围栏: ${event.geofenceId}');
|
||||
// 执行进入围栏的逻辑
|
||||
break;
|
||||
case GeofenceAction.exit:
|
||||
print('离开围栏: ${event.geofenceId}');
|
||||
// 执行离开围栏的逻辑
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 开始围栏监控
|
||||
await geofenceManager.startGeofenceMonitoring();
|
||||
```
|
||||
|
||||
### 轨迹记录示例
|
||||
```dart
|
||||
// 配置轨迹记录
|
||||
final trackConfig = TrackConfig(
|
||||
name: '上班路线',
|
||||
minDistance: 10.0, // 最小记录距离
|
||||
minTime: 5000, // 最小记录时间间隔
|
||||
enableOptimization: true, // 启用轨迹优化
|
||||
);
|
||||
|
||||
// 开始记录轨迹
|
||||
final trackRecorder = AMapTrackRecorder.instance;
|
||||
final trackId = await trackRecorder.startRecording(trackConfig);
|
||||
|
||||
// 监听轨迹点
|
||||
trackRecorder.onTrackPointAdded.listen((point) {
|
||||
print('新轨迹点: ${point.latitude}, ${point.longitude}');
|
||||
});
|
||||
|
||||
// 停止记录并获取轨迹
|
||||
final track = await trackRecorder.stopRecording(trackId);
|
||||
print('轨迹总距离: ${track.totalDistance}米');
|
||||
print('轨迹总时间: ${track.totalTime}');
|
||||
```
|
||||
|
||||
### 坐标转换示例
|
||||
```dart
|
||||
// WGS84 坐标转换为 GCJ02 坐标
|
||||
final wgs84Point = LatLng(39.9042, 116.4074);
|
||||
final gcj02Point = AMapCoordinateConverter.convertCoordinate(
|
||||
wgs84Point,
|
||||
CoordinateType.wgs84,
|
||||
CoordinateType.gcj02,
|
||||
);
|
||||
|
||||
// 逆地理编码
|
||||
final regeocodeResult = await AMapCoordinateConverter.reverseGeocode(gcj02Point);
|
||||
print('地址: ${regeocodeResult.formattedAddress}');
|
||||
|
||||
// 地理编码
|
||||
final geocodeResult = await AMapCoordinateConverter.geocode('北京市天安门广场');
|
||||
if (geocodeResult.geocodes.isNotEmpty) {
|
||||
final location = geocodeResult.geocodes.first.location;
|
||||
print('坐标: ${location.latitude}, ${location.longitude}');
|
||||
}
|
||||
```
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
```dart
|
||||
group('AMapLocation Tests', () {
|
||||
test('should convert coordinates correctly', () {
|
||||
// Given
|
||||
final wgs84Point = LatLng(39.9042, 116.4074);
|
||||
|
||||
// When
|
||||
final gcj02Point = AMapCoordinateConverter.convertCoordinate(
|
||||
wgs84Point,
|
||||
CoordinateType.wgs84,
|
||||
CoordinateType.gcj02,
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(gcj02Point.latitude, isNot(equals(wgs84Point.latitude)));
|
||||
expect(gcj02Point.longitude, isNot(equals(wgs84Point.longitude)));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 集成测试
|
||||
```dart
|
||||
group('Location Integration Tests', () {
|
||||
testWidgets('location service flow', (tester) async {
|
||||
// 1. 初始化定位服务
|
||||
await AMapLocationManager.instance.initialize(LocationConfig.defaultConfig);
|
||||
|
||||
// 2. 开始定位
|
||||
await AMapLocationManager.instance.startLocation();
|
||||
|
||||
// 3. 等待定位结果
|
||||
final location = await AMapLocationManager.instance.getCurrentLocation();
|
||||
|
||||
// 4. 验证定位结果
|
||||
expect(location.latitude, greaterThan(-90));
|
||||
expect(location.latitude, lessThan(90));
|
||||
expect(location.longitude, greaterThan(-180));
|
||||
expect(location.longitude, lessThan(180));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 定位优化
|
||||
- **智能定位策略**:根据场景自动选择最佳定位方式
|
||||
- **缓存机制**:缓存最近的定位结果
|
||||
- **批量处理**:批量处理定位请求
|
||||
- **省电模式**:低功耗的定位策略
|
||||
|
||||
### 数据优化
|
||||
- **数据压缩**:压缩轨迹数据减少存储空间
|
||||
- **增量同步**:只同步变化的数据
|
||||
- **本地缓存**:本地缓存常用的地理信息
|
||||
- **数据清理**:定期清理过期的轨迹数据
|
||||
|
||||
## 权限管理
|
||||
|
||||
### 位置权限
|
||||
```dart
|
||||
enum LocationPermission {
|
||||
denied, // 拒绝
|
||||
deniedForever, // 永久拒绝
|
||||
whileInUse, // 使用时允许
|
||||
always // 始终允许
|
||||
}
|
||||
|
||||
class PermissionManager {
|
||||
// 检查权限状态
|
||||
static Future<LocationPermission> checkPermission();
|
||||
|
||||
// 请求权限
|
||||
static Future<LocationPermission> requestPermission();
|
||||
|
||||
// 打开应用设置
|
||||
static Future<bool> openAppSettings();
|
||||
}
|
||||
```
|
||||
|
||||
### 权限处理示例
|
||||
```dart
|
||||
// 检查和请求位置权限
|
||||
final permission = await PermissionManager.checkPermission();
|
||||
|
||||
if (permission == LocationPermission.denied) {
|
||||
final result = await PermissionManager.requestPermission();
|
||||
if (result != LocationPermission.whileInUse &&
|
||||
result != LocationPermission.always) {
|
||||
// 权限被拒绝,显示说明或引导用户到设置页面
|
||||
await showPermissionDialog();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 权限获取成功,开始定位
|
||||
await startLocationService();
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 定位错误类型
|
||||
```dart
|
||||
enum LocationErrorType {
|
||||
permissionDenied, // 权限被拒绝
|
||||
locationServiceDisabled, // 定位服务未开启
|
||||
networkError, // 网络错误
|
||||
timeout, // 超时
|
||||
unknownError // 未知错误
|
||||
}
|
||||
|
||||
class LocationException implements Exception {
|
||||
final LocationErrorType type;
|
||||
final String message;
|
||||
final int? errorCode;
|
||||
|
||||
const LocationException(this.type, this.message, [this.errorCode]);
|
||||
}
|
||||
```
|
||||
|
||||
## 隐私和安全
|
||||
|
||||
### 数据隐私
|
||||
- **最小权限原则**:只请求必要的定位权限
|
||||
- **数据加密**:敏感位置数据加密存储
|
||||
- **用户控制**:用户可以随时关闭定位服务
|
||||
- **透明度**:明确告知用户数据使用目的
|
||||
|
||||
### 安全措施
|
||||
- **防伪造**:检测和过滤伪造的 GPS 信号
|
||||
- **数据校验**:验证定位数据的有效性
|
||||
- **传输安全**:使用 HTTPS 传输位置数据
|
||||
- **访问控制**:严格控制位置数据的访问权限
|
||||
|
||||
## 版本历史
|
||||
|
||||
### v3.0.3 (当前版本)
|
||||
- 支持 iOS 16 和 Android 13
|
||||
- 优化定位精度和速度
|
||||
- 修复地理围栏稳定性问题
|
||||
- 改进轨迹记录算法
|
||||
|
||||
### v3.0.2
|
||||
- 新增室内定位支持
|
||||
- 优化电池使用效率
|
||||
- 支持自定义坐标系
|
||||
- 修复内存泄漏问题
|
||||
|
||||
## 依赖关系
|
||||
|
||||
### 内部依赖
|
||||
- `basic_platform`: 平台抽象层
|
||||
- `basic_storage`: 本地存储服务
|
||||
- `basic_network`: 网络请求服务
|
||||
|
||||
### 外部依赖
|
||||
- `permission_handler`: 权限管理
|
||||
- `geolocator`: 位置服务补充
|
||||
- `path_provider`: 文件路径管理
|
||||
|
||||
## 总结
|
||||
|
||||
`amap_flutter_location` 作为高德地图定位服务的 Flutter 插件,为 OneApp 提供了可靠、高效的位置服务能力。通过集成 GPS、网络定位、地理围栏、轨迹记录等功能,该插件能够满足车辆定位、导航、位置服务等多种业务需求。
|
||||
|
||||
插件在设计上充分考虑了性能优化、隐私保护、权限管理等关键因素,确保在提供精准位置服务的同时,保护用户隐私和设备安全。这为 OneApp 的车联网服务提供了坚实的技术基础。
|
||||
638
app_car/amap_flutter_search.md
Normal file
638
app_car/amap_flutter_search.md
Normal file
@@ -0,0 +1,638 @@
|
||||
# AMap Flutter Search - 高德地图搜索插件
|
||||
|
||||
## 模块概述
|
||||
|
||||
`amap_flutter_search` 是 OneApp 中基于高德地图 SDK 的搜索服务插件,提供了全面的地理信息搜索功能,包括 POI 搜索、路线规划、地址解析等服务。该插件为车辆导航、位置查找、路径规划等功能提供了强大的搜索能力支持。
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. POI 搜索
|
||||
- **关键词搜索**:基于关键词的兴趣点搜索
|
||||
- **周边搜索**:指定位置周边的 POI 搜索
|
||||
- **分类搜索**:按类别筛选的 POI 搜索
|
||||
- **详情查询**:获取 POI 的详细信息
|
||||
|
||||
### 2. 路线规划
|
||||
- **驾车路线**:多种驾车路径规划策略
|
||||
- **步行路线**:行人路径规划
|
||||
- **骑行路线**:骑行路径规划
|
||||
- **公交路线**:公共交通路径规划
|
||||
- **货车路线**:货车专用路径规划
|
||||
|
||||
### 3. 地址解析
|
||||
- **地理编码**:地址转换为坐标
|
||||
- **逆地理编码**:坐标转换为地址
|
||||
- **输入提示**:地址输入智能提示
|
||||
- **行政区查询**:行政区域信息查询
|
||||
|
||||
### 4. 距离计算
|
||||
- **直线距离**:两点间直线距离计算
|
||||
- **驾车距离**:实际驾车距离和时间
|
||||
- **步行距离**:步行距离和时间
|
||||
- **批量计算**:批量距离矩阵计算
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 架构设计
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 应用层 │
|
||||
│ (app_navigation, app_car) │
|
||||
├─────────────────────────────────────┤
|
||||
│ AMap Flutter Search │
|
||||
│ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ POI搜索 │ 路线规划 │ 地址解析 │ │
|
||||
│ ├──────────┼──────────┼──────────┤ │
|
||||
│ │ 距离计算 │ 缓存管理 │ 数据处理 │ │
|
||||
│ └──────────┴──────────┴──────────┘ │
|
||||
├─────────────────────────────────────┤
|
||||
│ 高德地图 Search SDK │
|
||||
│ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ Android │ iOS │ 搜索引擎 │ │
|
||||
│ └──────────┴──────────┴──────────┘ │
|
||||
├─────────────────────────────────────┤
|
||||
│ 网络服务层 │
|
||||
│ (REST API, WebService) │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 核心组件
|
||||
|
||||
#### 1. POI 搜索管理器 (PoiSearchManager)
|
||||
```dart
|
||||
class AMapPoiSearchManager {
|
||||
// 关键词搜索
|
||||
Future<PoiResult> searchByKeyword(PoiKeywordSearchOption option);
|
||||
|
||||
// 周边搜索
|
||||
Future<PoiResult> searchNearby(PoiNearbySearchOption option);
|
||||
|
||||
// ID 搜索
|
||||
Future<PoiItem> searchById(String poiId);
|
||||
|
||||
// 分类搜索
|
||||
Future<PoiResult> searchByCategory(PoiCategorySearchOption option);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 路线规划管理器 (RouteSearchManager)
|
||||
```dart
|
||||
class AMapRouteSearchManager {
|
||||
// 驾车路线规划
|
||||
Future<DriveRouteResult> calculateDriveRoute(DriveRouteQuery query);
|
||||
|
||||
// 步行路线规划
|
||||
Future<WalkRouteResult> calculateWalkRoute(WalkRouteQuery query);
|
||||
|
||||
// 骑行路线规划
|
||||
Future<RideRouteResult> calculateRideRoute(RideRouteQuery query);
|
||||
|
||||
// 公交路线规划
|
||||
Future<BusRouteResult> calculateBusRoute(BusRouteQuery query);
|
||||
|
||||
// 货车路线规划
|
||||
Future<TruckRouteResult> calculateTruckRoute(TruckRouteQuery query);
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 地理编码管理器 (GeocodeManager)
|
||||
```dart
|
||||
class AMapGeocodeManager {
|
||||
// 地理编码
|
||||
Future<GeocodeResult> geocode(GeocodeQuery query);
|
||||
|
||||
// 逆地理编码
|
||||
Future<RegeocodeResult> reverseGeocode(RegeocodeQuery query);
|
||||
|
||||
// 输入提示
|
||||
Future<List<TipItem>> inputTips(InputTipsQuery query);
|
||||
|
||||
// 行政区查询
|
||||
Future<DistrictResult> searchDistrict(DistrictQuery query);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 距离计算器 (DistanceCalculator)
|
||||
```dart
|
||||
class AMapDistanceCalculator {
|
||||
// 计算两点距离
|
||||
Future<DistanceResult> calculateDistance(DistanceQuery query);
|
||||
|
||||
// 批量距离计算
|
||||
Future<List<DistanceResult>> calculateDistances(List<DistanceQuery> queries);
|
||||
|
||||
// 路径距离计算
|
||||
Future<RouteDistanceResult> calculateRouteDistance(RouteDistanceQuery query);
|
||||
}
|
||||
```
|
||||
|
||||
## 数据模型
|
||||
|
||||
### POI 模型
|
||||
```dart
|
||||
class PoiItem {
|
||||
final String poiId; // POI ID
|
||||
final String title; // POI 名称
|
||||
final String snippet; // POI 描述
|
||||
final LatLng latLng; // POI 坐标
|
||||
final String distance; // 距离
|
||||
final String tel; // 电话
|
||||
final String postcode; // 邮编
|
||||
final String website; // 网站
|
||||
final String email; // 邮箱
|
||||
final String province; // 省份
|
||||
final String city; // 城市
|
||||
final String district; // 区县
|
||||
final String address; // 地址
|
||||
final String direction; // 方向
|
||||
final String businessArea; // 商圈
|
||||
final String typeCode; // 类型编码
|
||||
final String typeDes; // 类型描述
|
||||
final List<Photo> photos; // 照片列表
|
||||
final List<String> shopID; // 商铺ID
|
||||
final IndoorData indoorData; // 室内数据
|
||||
}
|
||||
|
||||
class PoiResult {
|
||||
final List<PoiItem> pois;
|
||||
final int pageCount;
|
||||
final int totalCount;
|
||||
final SearchBound searchBound;
|
||||
final PoiQuery query;
|
||||
}
|
||||
```
|
||||
|
||||
### 路线模型
|
||||
```dart
|
||||
class DriveRouteResult {
|
||||
final List<DrivePath> paths;
|
||||
final RouteQuery startPos;
|
||||
final RouteQuery targetPos;
|
||||
final List<RouteQuery> viaPoints;
|
||||
final int taxiCost;
|
||||
}
|
||||
|
||||
class DrivePath {
|
||||
final String strategy; // 策略
|
||||
final int distance; // 距离(米)
|
||||
final int duration; // 时长(秒)
|
||||
final String tolls; // 过路费
|
||||
final String tollDistance; // 收费距离
|
||||
final String totalTrafficLights; // 红绿灯数
|
||||
final List<DriveStep> steps; // 路径段
|
||||
final List<TMC> tmcs; // 路况信息
|
||||
}
|
||||
|
||||
class DriveStep {
|
||||
final String instruction; // 行驶指示
|
||||
final String orientation; // 方向
|
||||
final String road; // 道路名称
|
||||
final int distance; // 距离
|
||||
final int duration; // 时长
|
||||
final List<LatLng> polyline; // 路径坐标
|
||||
final String action; // 导航动作
|
||||
final String assistantAction; // 辅助动作
|
||||
}
|
||||
```
|
||||
|
||||
### 地址模型
|
||||
```dart
|
||||
class RegeocodeResult {
|
||||
final RegeocodeAddress regeocodeAddress;
|
||||
final List<PoiItem> pois;
|
||||
final List<Road> roads;
|
||||
final List<RoadInter> roadInters;
|
||||
final List<AoiItem> aois;
|
||||
}
|
||||
|
||||
class RegeocodeAddress {
|
||||
final String formattedAddress; // 格式化地址
|
||||
final String country; // 国家
|
||||
final String province; // 省份
|
||||
final String city; // 城市
|
||||
final String district; // 区县
|
||||
final String township; // 乡镇
|
||||
final String neighborhood; // 社区
|
||||
final String building; // 建筑
|
||||
final String adcode; // 区域编码
|
||||
final String citycode; // 城市编码
|
||||
final List<StreetNumber> streetNumbers; // 门牌信息
|
||||
}
|
||||
```
|
||||
|
||||
## API 接口
|
||||
|
||||
### POI 搜索接口
|
||||
```dart
|
||||
abstract class PoiSearchService {
|
||||
// 关键词搜索
|
||||
Future<ApiResponse<PoiResult>> searchByKeyword(PoiKeywordSearchRequest request);
|
||||
|
||||
// 周边搜索
|
||||
Future<ApiResponse<PoiResult>> searchNearby(PoiNearbySearchRequest request);
|
||||
|
||||
// 多边形搜索
|
||||
Future<ApiResponse<PoiResult>> searchInPolygon(PoiPolygonSearchRequest request);
|
||||
|
||||
// POI 详情
|
||||
Future<ApiResponse<PoiItem>> getPoiDetail(String poiId);
|
||||
}
|
||||
```
|
||||
|
||||
### 路线规划接口
|
||||
```dart
|
||||
abstract class RouteSearchService {
|
||||
// 驾车路线规划
|
||||
Future<ApiResponse<DriveRouteResult>> planDriveRoute(DriveRouteRequest request);
|
||||
|
||||
// 步行路线规划
|
||||
Future<ApiResponse<WalkRouteResult>> planWalkRoute(WalkRouteRequest request);
|
||||
|
||||
// 骑行路线规划
|
||||
Future<ApiResponse<RideRouteResult>> planRideRoute(RideRouteRequest request);
|
||||
|
||||
// 公交路线规划
|
||||
Future<ApiResponse<BusRouteResult>> planBusRoute(BusRouteRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
### 地理编码接口
|
||||
```dart
|
||||
abstract class GeocodeService {
|
||||
// 地理编码
|
||||
Future<ApiResponse<GeocodeResult>> geocode(GeocodeRequest request);
|
||||
|
||||
// 逆地理编码
|
||||
Future<ApiResponse<RegeocodeResult>> reverseGeocode(RegeocodeRequest request);
|
||||
|
||||
// 输入提示
|
||||
Future<ApiResponse<List<TipItem>>> getInputTips(InputTipsRequest request);
|
||||
|
||||
// 行政区搜索
|
||||
Future<ApiResponse<DistrictResult>> searchDistrict(DistrictRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 搜索配置
|
||||
```dart
|
||||
class SearchConfig {
|
||||
final String apiKey; // API 密钥
|
||||
final int timeoutMs; // 超时时间
|
||||
final int maxRetries; // 最大重试次数
|
||||
final bool enableCache; // 是否启用缓存
|
||||
final int cacheExpireTime; // 缓存过期时间
|
||||
final String language; // 语言设置
|
||||
final String region; // 区域设置
|
||||
|
||||
static const SearchConfig defaultConfig = SearchConfig(
|
||||
apiKey: '',
|
||||
timeoutMs: 30000,
|
||||
maxRetries: 3,
|
||||
enableCache: true,
|
||||
cacheExpireTime: 3600,
|
||||
language: 'zh-CN',
|
||||
region: 'CN',
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### POI 搜索配置
|
||||
```dart
|
||||
class PoiSearchConfig {
|
||||
final int pageSize; // 每页结果数
|
||||
final int maxPage; // 最大页数
|
||||
final String city; // 搜索城市
|
||||
final String types; // 搜索类型
|
||||
final bool extensions; // 是否返回扩展信息
|
||||
final String sortrule; // 排序规则
|
||||
|
||||
static const PoiSearchConfig defaultConfig = PoiSearchConfig(
|
||||
pageSize: 20,
|
||||
maxPage: 100,
|
||||
city: '',
|
||||
types: '',
|
||||
extensions: false,
|
||||
sortrule: 'distance',
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### POI 搜索示例
|
||||
```dart
|
||||
// 关键词搜索
|
||||
final searchOption = PoiKeywordSearchOption(
|
||||
keyword: '加油站',
|
||||
city: '北京',
|
||||
pageSize: 20,
|
||||
pageNum: 1,
|
||||
extensions: true,
|
||||
);
|
||||
|
||||
final poiResult = await AMapPoiSearchManager.instance.searchByKeyword(searchOption);
|
||||
|
||||
for (final poi in poiResult.pois) {
|
||||
print('POI 名称: ${poi.title}');
|
||||
print('POI 地址: ${poi.address}');
|
||||
print('POI 距离: ${poi.distance}');
|
||||
print('POI 坐标: ${poi.latLng.latitude}, ${poi.latLng.longitude}');
|
||||
}
|
||||
```
|
||||
|
||||
### 周边搜索示例
|
||||
```dart
|
||||
// 周边搜索
|
||||
final nearbyOption = PoiNearbySearchOption(
|
||||
keyword: '餐厅',
|
||||
center: LatLng(39.9042, 116.4074), // 搜索中心点
|
||||
radius: 1000, // 搜索半径 1000 米
|
||||
pageSize: 10,
|
||||
pageNum: 1,
|
||||
);
|
||||
|
||||
final nearbyResult = await AMapPoiSearchManager.instance.searchNearby(nearbyOption);
|
||||
|
||||
print('附近餐厅数量: ${nearbyResult.pois.length}');
|
||||
for (final restaurant in nearbyResult.pois) {
|
||||
print('餐厅: ${restaurant.title} - ${restaurant.distance}');
|
||||
}
|
||||
```
|
||||
|
||||
### 路线规划示例
|
||||
```dart
|
||||
// 驾车路线规划
|
||||
final driveQuery = DriveRouteQuery(
|
||||
fromPoint: RouteQuery(39.9042, 116.4074), // 起点
|
||||
toPoint: RouteQuery(39.9015, 116.3974), // 终点
|
||||
mode: DriveMode.fastest, // 最快路线
|
||||
avoidhighspeed: false, // 不避开高速
|
||||
avoidtolls: false, // 不避开收费
|
||||
avoidtrafficjam: true, // 避开拥堵
|
||||
);
|
||||
|
||||
final driveResult = await AMapRouteSearchManager.instance.calculateDriveRoute(driveQuery);
|
||||
|
||||
if (driveResult.paths.isNotEmpty) {
|
||||
final path = driveResult.paths.first;
|
||||
print('驾车距离: ${path.distance} 米');
|
||||
print('预计时间: ${path.duration} 秒');
|
||||
print('过路费: ${path.tolls} 元');
|
||||
|
||||
for (final step in path.steps) {
|
||||
print('导航指示: ${step.instruction}');
|
||||
print('道路: ${step.road}');
|
||||
print('距离: ${step.distance} 米');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 地理编码示例
|
||||
```dart
|
||||
// 地址转坐标
|
||||
final geocodeQuery = GeocodeQuery(
|
||||
locationName: '北京市朝阳区望京SOHO',
|
||||
city: '北京',
|
||||
);
|
||||
|
||||
final geocodeResult = await AMapGeocodeManager.instance.geocode(geocodeQuery);
|
||||
|
||||
if (geocodeResult.geocodeAddressList.isNotEmpty) {
|
||||
final address = geocodeResult.geocodeAddressList.first;
|
||||
print('地址坐标: ${address.latLonPoint.latitude}, ${address.latLonPoint.longitude}');
|
||||
}
|
||||
|
||||
// 坐标转地址
|
||||
final regeocodeQuery = RegeocodeQuery(
|
||||
latLonPoint: LatLng(39.9915, 116.4684),
|
||||
radius: 200.0,
|
||||
extensions: 'all',
|
||||
);
|
||||
|
||||
final regeocodeResult = await AMapGeocodeManager.instance.reverseGeocode(regeocodeQuery);
|
||||
print('格式化地址: ${regeocodeResult.regeocodeAddress.formattedAddress}');
|
||||
```
|
||||
|
||||
### 输入提示示例
|
||||
```dart
|
||||
// 地址输入提示
|
||||
final tipsQuery = InputTipsQuery(
|
||||
keyword: '王府井',
|
||||
city: '北京',
|
||||
datatype: 'all',
|
||||
);
|
||||
|
||||
final tipsList = await AMapGeocodeManager.instance.inputTips(tipsQuery);
|
||||
|
||||
for (final tip in tipsList) {
|
||||
print('提示: ${tip.name}');
|
||||
print('地址: ${tip.address}');
|
||||
if (tip.point != null) {
|
||||
print('坐标: ${tip.point!.latitude}, ${tip.point!.longitude}');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
```dart
|
||||
group('AMapSearch Tests', () {
|
||||
test('should search POI by keyword', () async {
|
||||
// Given
|
||||
final searchOption = PoiKeywordSearchOption(
|
||||
keyword: '测试POI',
|
||||
city: '北京',
|
||||
);
|
||||
|
||||
// When
|
||||
final result = await AMapPoiSearchManager.instance.searchByKeyword(searchOption);
|
||||
|
||||
// Then
|
||||
expect(result.pois, isNotEmpty);
|
||||
expect(result.pois.first.title, contains('测试POI'));
|
||||
});
|
||||
|
||||
test('should calculate drive route', () async {
|
||||
// Given
|
||||
final query = DriveRouteQuery(
|
||||
fromPoint: RouteQuery(39.9042, 116.4074),
|
||||
toPoint: RouteQuery(39.9015, 116.3974),
|
||||
);
|
||||
|
||||
// When
|
||||
final result = await AMapRouteSearchManager.instance.calculateDriveRoute(query);
|
||||
|
||||
// Then
|
||||
expect(result.paths, isNotEmpty);
|
||||
expect(result.paths.first.distance, greaterThan(0));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 集成测试
|
||||
```dart
|
||||
group('Search Integration Tests', () {
|
||||
testWidgets('complete search flow', (tester) async {
|
||||
// 1. 搜索 POI
|
||||
final pois = await searchNearbyPois('加油站', currentLocation);
|
||||
|
||||
// 2. 选择目标 POI
|
||||
final targetPoi = pois.first;
|
||||
|
||||
// 3. 规划路线
|
||||
final route = await planRouteToDestination(currentLocation, targetPoi.latLng);
|
||||
|
||||
// 4. 验证结果
|
||||
expect(route.paths, isNotEmpty);
|
||||
expect(route.paths.first.steps, isNotEmpty);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 搜索优化
|
||||
- **搜索缓存**:缓存常用搜索结果
|
||||
- **预测搜索**:基于历史预测用户搜索
|
||||
- **分页加载**:大结果集分页加载
|
||||
- **搜索建议**:智能搜索建议减少请求
|
||||
|
||||
### 路线优化
|
||||
- **路线缓存**:缓存常用路线规划结果
|
||||
- **增量更新**:只更新路线变化部分
|
||||
- **压缩传输**:压缩路线数据减少传输量
|
||||
- **多线程处理**:并行处理多个路线请求
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 搜索错误类型
|
||||
```dart
|
||||
enum SearchErrorType {
|
||||
networkError, // 网络错误
|
||||
apiKeyInvalid, // API Key 无效
|
||||
quotaExceeded, // 配额超限
|
||||
invalidParameter, // 参数无效
|
||||
noResult, // 无搜索结果
|
||||
serverError, // 服务器错误
|
||||
timeout // 请求超时
|
||||
}
|
||||
|
||||
class SearchException implements Exception {
|
||||
final SearchErrorType type;
|
||||
final String message;
|
||||
final int? errorCode;
|
||||
|
||||
const SearchException(this.type, this.message, [this.errorCode]);
|
||||
}
|
||||
```
|
||||
|
||||
### 错误处理示例
|
||||
```dart
|
||||
try {
|
||||
final result = await AMapPoiSearchManager.instance.searchByKeyword(searchOption);
|
||||
// 处理搜索结果
|
||||
} on SearchException catch (e) {
|
||||
switch (e.type) {
|
||||
case SearchErrorType.networkError:
|
||||
showErrorDialog('网络连接失败,请检查网络设置');
|
||||
break;
|
||||
case SearchErrorType.noResult:
|
||||
showInfoDialog('未找到相关结果,请尝试其他关键词');
|
||||
break;
|
||||
case SearchErrorType.quotaExceeded:
|
||||
showErrorDialog('搜索次数已达上限,请稍后再试');
|
||||
break;
|
||||
default:
|
||||
showErrorDialog('搜索失败: ${e.message}');
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorDialog('未知错误: $e');
|
||||
}
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### 搜索结果缓存
|
||||
```dart
|
||||
class SearchCache {
|
||||
static const int maxCacheSize = 1000;
|
||||
static const Duration cacheExpiration = Duration(hours: 1);
|
||||
|
||||
// 缓存 POI 搜索结果
|
||||
static Future<void> cachePoiResult(String key, PoiResult result);
|
||||
|
||||
// 获取缓存的 POI 结果
|
||||
static Future<PoiResult?> getCachedPoiResult(String key);
|
||||
|
||||
// 缓存路线规划结果
|
||||
static Future<void> cacheRouteResult(String key, DriveRouteResult result);
|
||||
|
||||
// 获取缓存的路线结果
|
||||
static Future<DriveRouteResult?> getCachedRouteResult(String key);
|
||||
|
||||
// 清理过期缓存
|
||||
static Future<void> cleanExpiredCache();
|
||||
}
|
||||
```
|
||||
|
||||
## 配额管理
|
||||
|
||||
### API 配额监控
|
||||
```dart
|
||||
class QuotaManager {
|
||||
// 获取当前配额使用情况
|
||||
static Future<QuotaInfo> getCurrentQuota();
|
||||
|
||||
// 检查是否可以发起请求
|
||||
static Future<bool> canMakeRequest(RequestType type);
|
||||
|
||||
// 记录请求使用
|
||||
static Future<void> recordRequest(RequestType type);
|
||||
|
||||
// 获取配额重置时间
|
||||
static Future<DateTime> getQuotaResetTime();
|
||||
}
|
||||
|
||||
class QuotaInfo {
|
||||
final int dailyLimit; // 日限额
|
||||
final int dailyUsed; // 日使用量
|
||||
final int monthlyLimit; // 月限额
|
||||
final int monthlyUsed; // 月使用量
|
||||
final DateTime resetTime; // 重置时间
|
||||
}
|
||||
```
|
||||
|
||||
## 版本历史
|
||||
|
||||
### v3.1.22+1 (当前版本)
|
||||
- 支持最新的高德地图 API
|
||||
- 新增货车路线规划功能
|
||||
- 优化搜索性能和准确性
|
||||
- 修复路线规划稳定性问题
|
||||
|
||||
### v3.1.21
|
||||
- 支持室内 POI 搜索
|
||||
- 新增批量距离计算
|
||||
- 优化内存使用
|
||||
- 改进错误处理机制
|
||||
|
||||
## 依赖关系
|
||||
|
||||
### 内部依赖
|
||||
- `amap_flutter_base`: 高德地图基础库
|
||||
- `basic_network`: 网络请求服务
|
||||
- `basic_storage`: 本地存储服务
|
||||
|
||||
### 外部依赖
|
||||
- `dio`: HTTP 客户端
|
||||
- `cached_network_image`: 图片缓存
|
||||
- `sqflite`: 本地数据库
|
||||
|
||||
## 总结
|
||||
|
||||
`amap_flutter_search` 作为高德地图搜索服务的 Flutter 插件,为 OneApp 提供了全面的地理信息搜索能力。通过集成 POI 搜索、路线规划、地理编码、距离计算等功能,该插件能够满足车辆导航、位置服务、路径规划等多种业务需求。
|
||||
|
||||
插件在设计上充分考虑了性能优化、缓存管理、错误处理、配额控制等关键因素,确保在提供高质量搜索服务的同时,保持良好的用户体验和系统稳定性。这为 OneApp 的车联网和导航服务提供了强大的技术支撑。
|
||||
520
app_car/app_avatar.md
Normal file
520
app_car/app_avatar.md
Normal file
@@ -0,0 +1,520 @@
|
||||
# App Avatar - 虚拟形象模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_avatar` 是 OneApp 的虚拟形象管理模块,为用户提供个性化的虚拟车载助手服务。该模块集成了语音克隆技术、3D 虚拟形象渲染、支付服务等功能,让用户可以创建和定制自己的专属虚拟助手。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_avatar
|
||||
- **版本**: 0.6.1+2
|
||||
- **仓库**: https://gitlab-rd0.maezia.com/dssomobile/oneapp/dssomobile-oneapp-app-avatar
|
||||
- **Flutter 版本**: >=3.0.0
|
||||
- **Dart 版本**: >=2.16.2 <4.0.0
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
app_avatar/
|
||||
├── lib/
|
||||
│ ├── app_avatar.dart # 主导出文件
|
||||
│ └── src/ # 源代码目录
|
||||
│ ├── avatar/ # 虚拟形象核心功能
|
||||
│ │ ├── pages/ # 页面组件
|
||||
│ │ │ ├── avatar_building/ # 形象生成页面
|
||||
│ │ │ ├── avatar_copy/ # 形象复制页面
|
||||
│ │ │ ├── avatar_display/ # 形象展示页面
|
||||
│ │ │ ├── no_avatar/ # 未生成形象页面
|
||||
│ │ │ ├── prepare_resource_page/ # 资源准备页面
|
||||
│ │ │ ├── pta_camera/ # 拍照相机页面
|
||||
│ │ │ ├── pta_sex_check/ # 性别确认页面
|
||||
│ │ │ ├── rename/ # 重命名页面
|
||||
│ │ │ └── server_data_dress_up/ # 捏脸界面
|
||||
│ │ ├── provide_external/ # 对外提供组件
|
||||
│ │ └── util/ # 工具类
|
||||
│ ├── common_import.dart # 通用导入
|
||||
│ └── route_export.dart # 路由导出
|
||||
├── assets/ # 静态资源
|
||||
├── pubspec.yaml # 依赖配置
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 核心功能模块
|
||||
|
||||
### 1. 主导出模块
|
||||
|
||||
**文件**: `lib/app_avatar.dart`
|
||||
|
||||
```dart
|
||||
library app_avatar;
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'package:basic_modular_route/basic_modular_route.dart';
|
||||
import 'src/route_export.dart';
|
||||
|
||||
// 导出路由和对外组件
|
||||
export 'src/route_export.dart';
|
||||
export 'src/avatar/provide_external/in_use_avatar_icon.dart';
|
||||
export 'src/avatar/provide_external/avatar_header.dart';
|
||||
export 'src/avatar/util/config.dart';
|
||||
export 'src/avatar/util/avatar_engine_manage.dart';
|
||||
|
||||
/// App Avatar 模块定义
|
||||
class AppAvatarModule extends Module with RouteObjProvider {
|
||||
@override
|
||||
List<Module> get imports => [];
|
||||
|
||||
@override
|
||||
List<Bind> get binds => [];
|
||||
|
||||
@override
|
||||
List<ModularRoute> get routes {
|
||||
// 获取路由元数据
|
||||
final r1 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyHome);
|
||||
final r4 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiAvatarDisplayPage);
|
||||
final r7 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiPtaAvatarCamera);
|
||||
final r8 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiBuilding);
|
||||
final r10 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiDressUpServerDataPage);
|
||||
final r11 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiNonAvatar);
|
||||
final r12 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiRename);
|
||||
final r13 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiStep2GenderCheck);
|
||||
final r14 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiAvatarCopy);
|
||||
final r15 = RouteCenterAPI.routeMetaBy(AvatarRouteExport.keyAvatarUiPrepareResourcePage);
|
||||
|
||||
// 返回子路由列表
|
||||
return [
|
||||
ChildRoute(r1.path, child: (_, args) => r1.provider(args).as()),
|
||||
ChildRoute(r4.path, child: (_, args) => r4.provider(args).as()),
|
||||
ChildRoute(r7.path, child: (_, args) => r7.provider(args).as()),
|
||||
ChildRoute(r8.path, child: (_, args) => r8.provider(args).as()),
|
||||
ChildRoute(r10.path, child: (_, args) => r10.provider(args).as()),
|
||||
ChildRoute(r11.path, child: (_, args) => r11.provider(args).as()),
|
||||
ChildRoute(r12.path, child: (_, args) => r12.provider(args).as()),
|
||||
ChildRoute(r13.path, child: (_, args) => r13.provider(args).as()),
|
||||
ChildRoute(r14.path, child: (_, args) => r14.provider(args).as()),
|
||||
ChildRoute(r15.path, child: (_, args) => r15.provider(args).as()),
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 路由导出管理
|
||||
|
||||
## 核心功能与实现
|
||||
|
||||
### 1. 页面路由系统
|
||||
|
||||
app_avatar 模块基于真实的路由系统实现,主要包含以下功能页面:
|
||||
|
||||
#### 核心页面组件
|
||||
- **AvatarReplaceChild**: 虚拟形象展示页面
|
||||
- **PtaAvatarCamera**: 拍照相机页面
|
||||
- **AvatarBuildingPage**: 形象生成页面
|
||||
- **DressUpServerDataPage**: 捏脸编辑页面
|
||||
- **AvatarCopy**: 形象复制页面
|
||||
- **NonAvatar**: 非形象页面
|
||||
|
||||
#### 页面导航实现
|
||||
```dart
|
||||
// 页面跳转示例
|
||||
class AvatarNavigationHelper {
|
||||
// 跳转到虚拟形象展示页面
|
||||
static void gotoAvatarDisplay() {
|
||||
Modular.to.pushNamed('/avatar/avatarDisplayPage');
|
||||
}
|
||||
|
||||
// 跳转到拍照创建页面
|
||||
static void gotoPtaCamera() {
|
||||
Modular.to.pushNamed('/avatar/PtaAvatarCamera');
|
||||
}
|
||||
|
||||
// 跳转到捏脸编辑页面
|
||||
static void gotoDressUp() {
|
||||
Modular.to.pushNamed('/avatar/DressUpServerDataPage');
|
||||
}
|
||||
|
||||
// 跳转到形象生成页面
|
||||
static void gotoAvatarBuilding({
|
||||
required String sex,
|
||||
required String name,
|
||||
required String photoPath,
|
||||
}) {
|
||||
Modular.to.pushNamed('/avatar/AvatarBuildingPage', arguments: {
|
||||
'sex': sex,
|
||||
'name': name,
|
||||
'photoPath': photoPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 模块架构设计
|
||||
|
||||
#### 基本模块结构
|
||||
```dart
|
||||
// 模块入口点
|
||||
class AppAvatarModule extends Module implements RouteObjProvider {
|
||||
@override
|
||||
List<Bind> get binds => [
|
||||
// 依赖注入配置将在这里定义
|
||||
];
|
||||
|
||||
@override
|
||||
List<ModularRoute> get routes => [
|
||||
// 路由配置通过 AvatarRouteExport 管理
|
||||
];
|
||||
|
||||
@override
|
||||
RouteCenterAPI? get routeObj => RouteCenterAPI(
|
||||
routeExporter: AvatarRouteExport(),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### 页面状态管理
|
||||
```dart
|
||||
// 简化的页面状态管理
|
||||
class AvatarPageState {
|
||||
final bool isLoading;
|
||||
final String? errorMessage;
|
||||
final Map<String, dynamic> data;
|
||||
|
||||
const AvatarPageState({
|
||||
this.isLoading = false,
|
||||
this.errorMessage,
|
||||
this.data = const {},
|
||||
});
|
||||
|
||||
AvatarPageState copyWith({
|
||||
bool? isLoading,
|
||||
String? errorMessage,
|
||||
Map<String, dynamic>? data,
|
||||
}) {
|
||||
return AvatarPageState(
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
data: data ?? this.data,
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 核心功能实现
|
||||
|
||||
#### 虚拟形象创建流程
|
||||
虚拟形象创建遵循以下步骤:
|
||||
|
||||
1. **用户拍照**: 通过 `PtaAvatarCamera` 页面获取用户照片
|
||||
2. **信息确认**: 收集用户基本信息(姓名、性别等)
|
||||
3. **形象生成**: `AvatarBuildingPage` 显示生成进度
|
||||
4. **结果展示**: `AvatarReplaceChild` 展示最终形象
|
||||
|
||||
#### 形象管理功能
|
||||
- **形象展示**: 3D/2D 虚拟形象渲染展示
|
||||
- **形象编辑**: 通过捏脸系统进行外观定制
|
||||
- **形象切换**: 支持多个虚拟形象间的切换
|
||||
- **形象分享**: 虚拟形象内容的分享功能
|
||||
|
||||
### 4. 数据模型定义
|
||||
|
||||
#### 基础数据结构
|
||||
```dart
|
||||
// 虚拟形象基本信息
|
||||
class AvatarInfo {
|
||||
final String id;
|
||||
final String name;
|
||||
final String sex;
|
||||
final String photoPath;
|
||||
final DateTime createdAt;
|
||||
final Map<String, dynamic> customData;
|
||||
|
||||
const AvatarInfo({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.sex,
|
||||
required this.photoPath,
|
||||
required this.createdAt,
|
||||
this.customData = const {},
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'sex': sex,
|
||||
'photoPath': photoPath,
|
||||
'createdAt': createdAt.toIso8601String(),
|
||||
'customData': customData,
|
||||
};
|
||||
}
|
||||
|
||||
factory AvatarInfo.fromMap(Map<String, dynamic> map) {
|
||||
return AvatarInfo(
|
||||
id: map['id'] ?? '',
|
||||
name: map['name'] ?? '',
|
||||
sex: map['sex'] ?? '',
|
||||
photoPath: map['photoPath'] ?? '',
|
||||
createdAt: DateTime.parse(map['createdAt'] ?? DateTime.now().toIso8601String()),
|
||||
customData: map['customData'] ?? const {},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 形象配置信息
|
||||
class AvatarConfiguration {
|
||||
final String avatarId;
|
||||
final Map<String, dynamic> appearanceConfig;
|
||||
final Map<String, dynamic> behaviorConfig;
|
||||
final DateTime updatedAt;
|
||||
|
||||
const AvatarConfiguration({
|
||||
required this.avatarId,
|
||||
required this.appearanceConfig,
|
||||
required this.behaviorConfig,
|
||||
required this.updatedAt,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 5. UI 组件实现
|
||||
|
||||
#### 通用 UI 组件
|
||||
```dart
|
||||
// 形象展示组件
|
||||
class AvatarDisplayWidget extends StatelessWidget {
|
||||
final AvatarInfo avatarInfo;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const AvatarDisplayWidget({
|
||||
Key? key,
|
||||
required this.avatarInfo,
|
||||
this.onTap,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: 200,
|
||||
height: 300,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(10)),
|
||||
image: avatarInfo.photoPath.isNotEmpty
|
||||
? DecorationImage(
|
||||
image: FileImage(File(avatarInfo.photoPath)),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: avatarInfo.photoPath.isEmpty
|
||||
? Center(child: Icon(Icons.person, size: 50, color: Colors.grey))
|
||||
: null,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Text(
|
||||
avatarInfo.name,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 操作按钮组件
|
||||
class AvatarActionButton extends StatelessWidget {
|
||||
final String label;
|
||||
final IconData icon;
|
||||
final VoidCallback onPressed;
|
||||
final bool isLoading;
|
||||
|
||||
const AvatarActionButton({
|
||||
Key? key,
|
||||
required this.label,
|
||||
required this.icon,
|
||||
required this.onPressed,
|
||||
this.isLoading = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ElevatedButton.icon(
|
||||
onPressed: isLoading ? null : onPressed,
|
||||
icon: isLoading
|
||||
? SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(strokeWidth: 2)
|
||||
)
|
||||
: Icon(icon),
|
||||
label: Text(label),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 错误处理与异常管理
|
||||
|
||||
#### 异常定义
|
||||
```dart
|
||||
// 虚拟形象相关异常
|
||||
abstract class AvatarException implements Exception {
|
||||
final String message;
|
||||
const AvatarException(this.message);
|
||||
|
||||
@override
|
||||
String toString() => 'AvatarException: $message';
|
||||
}
|
||||
|
||||
class AvatarCreationException extends AvatarException {
|
||||
const AvatarCreationException(String message) : super(message);
|
||||
}
|
||||
|
||||
class AvatarLoadException extends AvatarException {
|
||||
const AvatarLoadException(String message) : super(message);
|
||||
}
|
||||
|
||||
class AvatarSaveException extends AvatarException {
|
||||
const AvatarSaveException(String message) : super(message);
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误处理机制
|
||||
```dart
|
||||
// 错误处理工具类
|
||||
class AvatarErrorHandler {
|
||||
static void handleError(
|
||||
BuildContext context,
|
||||
Exception error, {
|
||||
VoidCallback? onRetry,
|
||||
}) {
|
||||
String message = '发生未知错误';
|
||||
|
||||
if (error is AvatarException) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('错误'),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
if (onRetry != null)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
onRetry();
|
||||
},
|
||||
child: Text('重试'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
## 技术架构与设计模式
|
||||
|
||||
### 1. 模块化架构
|
||||
|
||||
app_avatar 模块采用标准的 OneApp 模块化架构:
|
||||
|
||||
- **模块定义**: `AppAvatarModule` 继承自 `Module` 并实现 `RouteObjProvider`
|
||||
- **路由管理**: 通过 `AvatarRouteExport` 统一管理所有路由
|
||||
- **依赖注入**: 使用 basic_modular 的依赖注入机制
|
||||
- **页面组织**: 按功能分组的页面结构
|
||||
|
||||
### 2. 核心功能实现
|
||||
|
||||
#### 虚拟形象创建流程
|
||||
1. **拍照页面**: 用户使用相机拍摄照片
|
||||
2. **信息填写**: 确认性别和姓名信息
|
||||
3. **形象生成**: 后台处理生成虚拟形象
|
||||
4. **形象展示**: 展示生成结果
|
||||
|
||||
#### 形象管理功能
|
||||
- **形象展示**: 3D/2D 虚拟形象渲染
|
||||
- **形象编辑**: 捏脸和装扮功能
|
||||
- **形象复制**: 形象模板复制功能
|
||||
- **重命名**: 形象名称管理
|
||||
|
||||
### 3. 与其他模块集成
|
||||
|
||||
```dart
|
||||
// 集成示例 - 从其他模块跳转到虚拟形象相关页面
|
||||
class AvatarNavigationHelper {
|
||||
// 跳转到虚拟形象展示页面
|
||||
static void gotoAvatarDisplay() {
|
||||
Modular.to.pushNamed('/avatar/avatarDisplayPage');
|
||||
}
|
||||
|
||||
// 跳转到拍照创建页面
|
||||
static void gotoPtaCamera() {
|
||||
Modular.to.pushNamed('/avatar/PtaAvatarCamera');
|
||||
}
|
||||
|
||||
// 跳转到捏脸编辑页面
|
||||
static void gotoDressUp() {
|
||||
Modular.to.pushNamed('/avatar/DressUpServerDataPage');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖管理与技术栈
|
||||
|
||||
### 核心依赖
|
||||
- **basic_modular**: 模块化框架
|
||||
- **basic_modular_route**: 路由管理
|
||||
- **flutter**: Flutter 框架
|
||||
|
||||
### UI 组件
|
||||
- **Material Design**: 基础 UI 组件
|
||||
- **Custom Widgets**: 虚拟形象专用组件
|
||||
|
||||
### 数据存储
|
||||
- **SharedPreferences**: 配置信息本地存储
|
||||
- **文件系统**: 图片和资源文件存储
|
||||
|
||||
## 最佳实践与规范
|
||||
|
||||
### 1. 代码组织
|
||||
- 页面文件统一放在 `src/avatar/pages/` 目录
|
||||
- 按功能模块分别组织(拍照、生成、编辑、展示)
|
||||
- 对外组件放在 `provide_external` 目录
|
||||
|
||||
### 2. 路由管理
|
||||
- 采用 `RouteExporter` 接口统一路由导出
|
||||
- 使用 `RouteMeta` 配置路由元数据
|
||||
- 支持路由参数传递和嵌套路由
|
||||
|
||||
### 3. 用户体验优化
|
||||
- 流畅的页面转场动画
|
||||
- 友好的加载进度提示
|
||||
- 响应式布局适配不同屏幕
|
||||
|
||||
### 4. 性能优化
|
||||
- 合理的资源加载和释放
|
||||
- 动画性能优化
|
||||
- 内存使用管理
|
||||
934
app_car/app_car.md
Normal file
934
app_car/app_car.md
Normal file
@@ -0,0 +1,934 @@
|
||||
# App Car - 车辆控制主模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_car` 是 OneApp 车辆功能的核心模块,提供完整的车辆控制、状态监控、远程操作等功能。该模块集成了车联网通信、车辆状态管理、空调控制、车门锁控制、充电管理等核心车辆服务。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_car
|
||||
- **版本**: 0.6.48+4
|
||||
- **仓库**: https://gitlab-rd0.maezia.com/dssomobile/oneapp/dssomobile-oneapp-car-app
|
||||
- **Flutter 版本**: >=3.0.0
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
app_car/
|
||||
├── lib/
|
||||
│ ├── app_car.dart # 主导出文件
|
||||
│ ├── app_car_temp.dart # 临时配置文件
|
||||
│ ├── generated/ # 代码生成文件
|
||||
│ ├── l10n/ # 国际化文件
|
||||
│ └── src/ # 源代码目录
|
||||
│ ├── ai_chat/ # AI 聊天集成
|
||||
│ ├── app_ingeek_mdk/ # 车钥匙 MDK 集成
|
||||
│ ├── bloc/ # 状态管理(BLoC)
|
||||
│ ├── car_animation/ # 车辆动画效果
|
||||
│ ├── car_charging_center/ # 充电中心功能
|
||||
│ ├── car_charging_profiles/# 充电配置文件
|
||||
│ ├── car_climatisation/ # 空调控制
|
||||
│ ├── car_climatisation_50/ # 空调控制(5.0版本)
|
||||
│ ├── car_common_widget/ # 车辆通用组件
|
||||
│ ├── car_digital_key_renewal/# 数字钥匙更新
|
||||
│ ├── car_enum/ # 车辆相关枚举
|
||||
│ ├── car_finder_card/ # 车辆查找卡片
|
||||
│ ├── car_health_status/ # 车辆健康状态
|
||||
│ ├── car_lock_unlock/ # 车门锁控制
|
||||
│ ├── car_vehicle_status/ # 车辆状态管理
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── dbr_card/ # DBR 卡片组件
|
||||
│ ├── models/ # 数据模型
|
||||
│ ├── pages/ # 页面组件
|
||||
│ ├── res/ # 资源文件
|
||||
│ ├── utils/ # 工具类
|
||||
│ ├── common_import.dart # 通用导入
|
||||
│ ├── route_dp.dart # 路由配置
|
||||
│ └── route_export.dart # 路由导出
|
||||
├── assets/ # 静态资源
|
||||
├── pubspec.yaml # 依赖配置
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 核心功能模块
|
||||
|
||||
### 1. 车辆控制核心 (Vehicle Control Core)
|
||||
|
||||
基于真实的OneApp项目实现,使用统一的Vehicle服务和BLoC状态管理。
|
||||
|
||||
#### 远程车辆状态管理 (`bloc/home/bloc_rvs.dart`)
|
||||
```dart
|
||||
// 实际的远程车辆状态BLoC
|
||||
class RemoteVehicleStateBloc
|
||||
extends Bloc<RemoteVehicleStateEvent, RemoteVehicleState> {
|
||||
|
||||
RemoteVehicleStateBloc(
|
||||
RvsService rvs,
|
||||
ClimatizationService climatization,
|
||||
int index,
|
||||
String? noticeVin,
|
||||
BuildContext? context,
|
||||
) : super(
|
||||
RemoteVehicleState(
|
||||
rvs: rvs,
|
||||
climatization: climatization,
|
||||
index: index,
|
||||
isRefreshing: false,
|
||||
),
|
||||
) {
|
||||
on<EnterManualRefreshEvent>(_onEnterManualRefreshEvent);
|
||||
on<ExecuteManualRefreshEvent>(_onExecuteManualRefreshEvent);
|
||||
on<ConditionerEvent>(_conditionerEvent);
|
||||
on<LockEvent>(_lockEvent);
|
||||
on<UnlockEvent>(_unlockEvent);
|
||||
on<VehicleOverallStatusEvent>(_vehicleOverallStatusEvent);
|
||||
|
||||
// 检查权限
|
||||
checkPermission();
|
||||
|
||||
// 首次进来的时候获取默认车辆信息更新到Vehicle
|
||||
Vehicle.updateUserVehicleInfo(VehicleUtils.assembleDefaultVehicleLocal());
|
||||
|
||||
// 拉取页面数据
|
||||
refreshHomeData(RvsAction.refresh);
|
||||
}
|
||||
}
|
||||
|
||||
// 实际的远程车辆状态数据模型
|
||||
@freezed
|
||||
class RemoteVehicleState with _$RemoteVehicleState {
|
||||
const factory RemoteVehicleState({
|
||||
required RvsService rvs,
|
||||
required ClimatizationService climatization,
|
||||
required int index,
|
||||
required bool isRefreshing,
|
||||
VehicleRemoteStatus? status,
|
||||
double? temperature,
|
||||
ClimatisationStatus? climatisationStatus,
|
||||
ClimatizationParameter? cParameter,
|
||||
bool? actionStart,
|
||||
bool? actionStop,
|
||||
bool? actionSetting,
|
||||
bool? actionLock,
|
||||
RluLockState? lockState,
|
||||
CfMessage? cfMessage,
|
||||
bool? locationPermission,
|
||||
bool? isLocationOpen,
|
||||
double? distance,
|
||||
String? searchGeocode,
|
||||
VhrWarningListMessage? primitiveVhrWarningListMessage,
|
||||
List<HealthStatus>? vhrWarningListMessage,
|
||||
List<VehicleDto>? vehicleDtos,
|
||||
}) = _RemoteVehicleState;
|
||||
}
|
||||
```
|
||||
|
||||
#### 车辆服务观察者模式
|
||||
```dart
|
||||
// 实际的车辆服务监听机制
|
||||
class Vehicle {
|
||||
/// 添加服务观察者
|
||||
static ObserverClient addServiceObserver(
|
||||
ServiceType serviceType,
|
||||
Function(UpdateEvent event, ConnectorAction action, dynamic value) callback,
|
||||
) {
|
||||
return ServiceUtils.getServiceByType(serviceType)?.addObserver(callback);
|
||||
}
|
||||
|
||||
/// 更新用户车辆信息
|
||||
static void updateUserVehicleInfo(VehicleDto? vehicleDto) {
|
||||
if (vehicleDto != null) {
|
||||
_currentVehicle = vehicleDto;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 车辆状态管理 (`car_vehicle_status/`)
|
||||
|
||||
#### 实时状态监控
|
||||
```dart
|
||||
// 车辆状态管理器
|
||||
class VehicleStatusManager {
|
||||
Stream<VehicleStatus> get statusStream => _statusController.stream;
|
||||
|
||||
final StreamController<VehicleStatus> _statusController =
|
||||
StreamController.broadcast();
|
||||
|
||||
// 启动状态监控
|
||||
void startStatusMonitoring() {
|
||||
_statusTimer = Timer.periodic(
|
||||
Duration(seconds: 30),
|
||||
(_) => _fetchVehicleStatus(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _fetchVehicleStatus() async {
|
||||
try {
|
||||
final status = await _vehicleConnector.getVehicleStatus();
|
||||
status.fold(
|
||||
(failure) => _handleStatusError(failure),
|
||||
(vehicleStatus) => _statusController.add(vehicleStatus),
|
||||
);
|
||||
} catch (e) {
|
||||
_handleStatusError(VehicleFailure.networkError(e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 车辆健康状态 (`car_health_status/`)
|
||||
```dart
|
||||
// 车辆健康状态模型
|
||||
class VehicleHealthStatus {
|
||||
final BatteryHealth batteryHealth;
|
||||
final EngineHealth engineHealth;
|
||||
final List<MaintenanceAlert> maintenanceAlerts;
|
||||
final List<DiagnosticCode> diagnosticCodes;
|
||||
final DateTime lastCheckTime;
|
||||
|
||||
const VehicleHealthStatus({
|
||||
required this.batteryHealth,
|
||||
required this.engineHealth,
|
||||
required this.maintenanceAlerts,
|
||||
required this.diagnosticCodes,
|
||||
required this.lastCheckTime,
|
||||
});
|
||||
|
||||
// 获取整体健康评分
|
||||
HealthScore get overallScore {
|
||||
final scores = [
|
||||
batteryHealth.score,
|
||||
engineHealth.score,
|
||||
];
|
||||
final average = scores.reduce((a, b) => a + b) / scores.length;
|
||||
return HealthScore.fromValue(average);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 充电管理 (`car_charging_center/`, `car_charging_profiles/`)
|
||||
|
||||
基于真实项目的充电管理实现,使用Vehicle服务和ChargingOverall状态模型。
|
||||
|
||||
#### 充电中心控制 (`car_charging_center_bloc.dart`)
|
||||
```dart
|
||||
// 实际的充电中心BLoC
|
||||
class CarChargingCenterBloc
|
||||
extends Bloc<CarChargingCenterEvent, CarChargingCenterState> {
|
||||
|
||||
CarChargingCenterBloc() : super(const CarChargingCenterState()) {
|
||||
on<RefreshChargingEvent>(_refreshChargingEvent);
|
||||
on<CarChargingCenterClearEvent>(_chargingCenterClearEvent);
|
||||
|
||||
// 注册充电服务
|
||||
chargingService();
|
||||
|
||||
// 先获取内存中的值进行显示
|
||||
final cService = ServiceUtils.getChargingService();
|
||||
final ChargingOverall? cs =
|
||||
cService.status == null ? null : cService.status as ChargingOverall;
|
||||
emit(state.copyWith(chargingOverall: cs));
|
||||
|
||||
// 刷新充电数据
|
||||
add(const CarChargingCenterEvent.refreshCharging());
|
||||
}
|
||||
|
||||
/// 充电服务观察者
|
||||
ObserverClient? chargingClient;
|
||||
|
||||
/// 充电服务监听
|
||||
void chargingService() {
|
||||
chargingClient = Vehicle.addServiceObserver(
|
||||
ServiceType.remoteCharging,
|
||||
(UpdateEvent event, ConnectorAction action, dynamic value) {
|
||||
if (event == UpdateEvent.onStatusChange) {
|
||||
if (value != null) {
|
||||
final chargingOverall = value as ChargingOverall;
|
||||
emit(state.copyWith(chargingOverall: chargingOverall));
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 实际的充电状态模型
|
||||
@freezed
|
||||
class CarChargingCenterState with _$CarChargingCenterState {
|
||||
const factory CarChargingCenterState({
|
||||
ChargingOverall? chargingOverall,
|
||||
bool? isRefreshing,
|
||||
}) = _CarChargingCenterState;
|
||||
}
|
||||
```
|
||||
|
||||
#### 充电配置文件管理 (`car_charging_profiles_bloc.dart`)
|
||||
```dart
|
||||
// 实际的充电配置BLoC
|
||||
class CarChargingProfilesBloc
|
||||
extends Bloc<CarChargingProfilesEvent, CarChargingProfilesState> {
|
||||
|
||||
CarChargingProfilesBloc() : super(const CarChargingProfilesState()) {
|
||||
on<CarChargingProfilesRefreshEvent>(_refreshEvent);
|
||||
on<CarChargingProfilesDeleteEvent>(_deleteEvent);
|
||||
|
||||
// 注册服务监听
|
||||
chargingProfilesService();
|
||||
|
||||
// 首次加载配置文件列表
|
||||
add(const CarChargingProfilesEvent.refreshEvent());
|
||||
}
|
||||
|
||||
/// 充电配置服务
|
||||
void chargingProfilesService() {
|
||||
chargingClient = Vehicle.addServiceObserver(
|
||||
ServiceType.remoteCharging,
|
||||
(UpdateEvent event, ConnectorAction action, dynamic value) {
|
||||
if (event == UpdateEvent.onStatusChange) {
|
||||
// 处理充电配置状态变更
|
||||
_handleChargingProfilesUpdate(value);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 数字钥匙管理 (`car_digital_key_renewal/`, `app_ingeek_mdk/`)
|
||||
|
||||
#### 数字钥匙服务
|
||||
```dart
|
||||
// 数字钥匙管理服务
|
||||
class DigitalKeyService {
|
||||
// 数字钥匙续期
|
||||
Future<Result<void>> renewDigitalKey() async {
|
||||
try {
|
||||
final result = await _ingeekMdk.renewKey();
|
||||
if (result.isSuccess) {
|
||||
await _updateLocalKeyInfo(result.keyInfo);
|
||||
return Right(unit);
|
||||
} else {
|
||||
return Left(DigitalKeyFailure.renewalFailed(result.error));
|
||||
}
|
||||
} catch (e) {
|
||||
return Left(DigitalKeyFailure.networkError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// 检查钥匙状态
|
||||
Future<Result<DigitalKeyStatus>> checkKeyStatus() async {
|
||||
try {
|
||||
final keyInfo = await _ingeekMdk.getKeyInfo();
|
||||
return Right(DigitalKeyStatus.fromKeyInfo(keyInfo));
|
||||
} catch (e) {
|
||||
return Left(DigitalKeyFailure.statusCheckFailed(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// 激活数字钥匙
|
||||
Future<Result<void>> activateDigitalKey(String activationCode) async {
|
||||
return await _ingeekMdk.activateKey(activationCode);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 车辆查找功能 (`car_finder_card/`)
|
||||
|
||||
#### 车辆定位服务
|
||||
```dart
|
||||
// 车辆查找服务
|
||||
class CarFinderService {
|
||||
// 获取车辆位置
|
||||
Future<Result<VehicleLocation>> getVehicleLocation() async {
|
||||
return await _vehicleConnector.getVehicleLocation();
|
||||
}
|
||||
|
||||
// 闪灯鸣笛
|
||||
Future<Result<void>> flashAndHonk() async {
|
||||
return await _vehicleConnector.sendCommand(
|
||||
VehicleCommand.flashAndHonk(),
|
||||
);
|
||||
}
|
||||
|
||||
// 计算到车辆的距离
|
||||
Future<Result<Distance>> calculateDistanceToVehicle(
|
||||
UserLocation userLocation,
|
||||
) async {
|
||||
final vehicleLocationResult = await getVehicleLocation();
|
||||
return vehicleLocationResult.map((vehicleLocation) {
|
||||
return Distance.calculate(userLocation, vehicleLocation.coordinates);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 状态管理架构 (`bloc/`)
|
||||
|
||||
基于真实项目的BLoC架构和Flutter Modular依赖注入框架。
|
||||
|
||||
### 模块化架构实现
|
||||
```dart
|
||||
// 实际的车辆控制模块(app_car.dart)
|
||||
class CarControlModule extends Module with RouteObjProvider {
|
||||
@override
|
||||
List<Module> get imports => [];
|
||||
|
||||
@override
|
||||
List<Bind> get binds => [
|
||||
Bind<CarBloc>((i) => CarBloc(), export: true),
|
||||
];
|
||||
|
||||
@override
|
||||
List<ModularRoute> get routes {
|
||||
final r1 = RouteCenterAPI.routeMetaBy(CarControlRouteExport.keyHome);
|
||||
final r2 = RouteCenterAPI.routeMetaBy(CarControlRouteExport.keyClimatization);
|
||||
final r3 = RouteCenterAPI.routeMetaBy(CarControlRouteExport.keyCharging);
|
||||
final r4 = RouteCenterAPI.routeMetaBy(CarControlRouteExport.keyChargingProfile);
|
||||
// ... 更多路由配置
|
||||
|
||||
return [
|
||||
ChildRoute(r1.path, child: (_, args) => r1.provider(args).as()),
|
||||
ChildRoute(r2.path, child: (_, args) => r2.provider(args).as()),
|
||||
ChildRoute(r3.path, child: (_, args) => r3.provider(args).as()),
|
||||
ChildRoute(r4.path, child: (_, args) => r4.provider(args).as()),
|
||||
// ... 更多路由实现
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 实际的CarBloc实现
|
||||
class CarBloc extends Bloc<CarEvent, CarState> {
|
||||
CarBloc() : super(CarState().getInstance()) {
|
||||
on<CarEvent>((event, emit) {
|
||||
// 处理车辆相关事件
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 车辆状态BLoC实现
|
||||
```dart
|
||||
// 实际的车辆状态管理BLoC
|
||||
class CarVehicleBloc extends Bloc<CarVehicleEvent, CarVehicleState> {
|
||||
CarVehicleBloc() : super(const CarVehicleState()) {
|
||||
on<CarVehicleInitEvent>(_initEvent);
|
||||
on<CarVehicleRefreshEvent>(_refreshEvent);
|
||||
|
||||
// 初始化车辆服务
|
||||
initVehicleService();
|
||||
}
|
||||
|
||||
void initVehicleService() {
|
||||
// 注册车辆状态观察者
|
||||
Vehicle.addServiceObserver(
|
||||
ServiceType.remoteVehicleStatus,
|
||||
(UpdateEvent event, ConnectorAction action, dynamic value) {
|
||||
if (event == UpdateEvent.onStatusChange) {
|
||||
final status = value as VehicleRemoteStatus;
|
||||
emit(state.copyWith(vehicleStatus: status));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 数据模型 (`models/`)
|
||||
|
||||
### 车辆状态模型
|
||||
```dart
|
||||
// 车辆状态模型
|
||||
class VehicleStatus {
|
||||
final String vehicleId;
|
||||
final LockStatus lockStatus;
|
||||
final BatteryStatus batteryStatus;
|
||||
final ClimatisationStatus climatisationStatus;
|
||||
final ChargingStatus chargingStatus;
|
||||
final VehicleLocation? location;
|
||||
final DateTime lastUpdated;
|
||||
|
||||
const VehicleStatus({
|
||||
required this.vehicleId,
|
||||
required this.lockStatus,
|
||||
required this.batteryStatus,
|
||||
required this.climatisationStatus,
|
||||
required this.chargingStatus,
|
||||
this.location,
|
||||
required this.lastUpdated,
|
||||
});
|
||||
|
||||
factory VehicleStatus.fromJson(Map<String, dynamic> json) {
|
||||
return VehicleStatus(
|
||||
vehicleId: json['vehicle_id'],
|
||||
lockStatus: LockStatus.fromString(json['lock_status']),
|
||||
batteryStatus: BatteryStatus.fromJson(json['battery_status']),
|
||||
climatisationStatus: ClimatisationStatus.fromJson(json['climatisation_status']),
|
||||
chargingStatus: ChargingStatus.fromJson(json['charging_status']),
|
||||
location: json['location'] != null
|
||||
? VehicleLocation.fromJson(json['location'])
|
||||
: null,
|
||||
lastUpdated: DateTime.parse(json['last_updated']),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 车辆控制命令模型
|
||||
```dart
|
||||
// 车辆控制命令
|
||||
abstract class VehicleCommand {
|
||||
const VehicleCommand();
|
||||
|
||||
// 车门锁命令
|
||||
factory VehicleCommand.lock() = LockCommand;
|
||||
factory VehicleCommand.unlock() = UnlockCommand;
|
||||
|
||||
// 空调命令
|
||||
factory VehicleCommand.startClimatisation({
|
||||
required double temperature,
|
||||
AirConditioningMode mode,
|
||||
}) = StartClimatisationCommand;
|
||||
|
||||
factory VehicleCommand.stopClimatisation() = StopClimatisationCommand;
|
||||
|
||||
// 充电命令
|
||||
factory VehicleCommand.startCharging({
|
||||
ChargingProfile? profile,
|
||||
}) = StartChargingCommand;
|
||||
|
||||
factory VehicleCommand.stopCharging() = StopChargingCommand;
|
||||
|
||||
// 车辆查找命令
|
||||
factory VehicleCommand.flashAndHonk() = FlashAndHonkCommand;
|
||||
}
|
||||
```
|
||||
|
||||
## 枚举定义 (`car_enum/`)
|
||||
|
||||
### 车辆状态枚举
|
||||
```dart
|
||||
// 车门锁状态
|
||||
enum LockStatus {
|
||||
locked,
|
||||
unlocked,
|
||||
unknown;
|
||||
|
||||
static LockStatus fromString(String value) {
|
||||
switch (value.toLowerCase()) {
|
||||
case 'locked':
|
||||
return LockStatus.locked;
|
||||
case 'unlocked':
|
||||
return LockStatus.unlocked;
|
||||
default:
|
||||
return LockStatus.unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 充电状态
|
||||
enum ChargingStatus {
|
||||
notConnected,
|
||||
connected,
|
||||
charging,
|
||||
chargingComplete,
|
||||
chargingError;
|
||||
|
||||
bool get isCharging => this == ChargingStatus.charging;
|
||||
bool get isConnected => this != ChargingStatus.notConnected;
|
||||
}
|
||||
|
||||
// 空调模式
|
||||
enum AirConditioningMode {
|
||||
auto,
|
||||
heat,
|
||||
cool,
|
||||
ventilation,
|
||||
defrost;
|
||||
|
||||
String get displayName {
|
||||
switch (this) {
|
||||
case AirConditioningMode.auto:
|
||||
return '自动';
|
||||
case AirConditioningMode.heat:
|
||||
return '制热';
|
||||
case AirConditioningMode.cool:
|
||||
return '制冷';
|
||||
case AirConditioningMode.ventilation:
|
||||
return '通风';
|
||||
case AirConditioningMode.defrost:
|
||||
return '除霜';
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## UI 组件 (`car_common_widget/`)
|
||||
|
||||
### 车辆状态卡片
|
||||
```dart
|
||||
// 车辆状态卡片组件
|
||||
class VehicleStatusCard extends StatelessWidget {
|
||||
final VehicleStatus status;
|
||||
final VoidCallback? onRefresh;
|
||||
|
||||
const VehicleStatusCard({
|
||||
Key? key,
|
||||
required this.status,
|
||||
this.onRefresh,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(),
|
||||
SizedBox(height: 16),
|
||||
_buildStatusGrid(),
|
||||
SizedBox(height: 16),
|
||||
_buildActionButtons(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusGrid() {
|
||||
return GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 2,
|
||||
children: [
|
||||
_buildStatusItem('车门', status.lockStatus.displayName),
|
||||
_buildStatusItem('电量', '${status.batteryStatus.percentage}%'),
|
||||
_buildStatusItem('空调', status.climatisationStatus.displayName),
|
||||
_buildStatusItem('充电', status.chargingStatus.displayName),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 车辆控制面板
|
||||
```dart
|
||||
// 车辆控制面板
|
||||
class VehicleControlPanel extends StatelessWidget {
|
||||
final VehicleStatus status;
|
||||
final Function(VehicleCommand) onCommand;
|
||||
|
||||
const VehicleControlPanel({
|
||||
Key? key,
|
||||
required this.status,
|
||||
required this.onCommand,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
_buildLockControls(),
|
||||
SizedBox(height: 16),
|
||||
_buildClimatisationControls(),
|
||||
SizedBox(height: 16),
|
||||
_buildChargingControls(),
|
||||
SizedBox(height: 16),
|
||||
_buildFinderControls(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLockControls() {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: status.lockStatus == LockStatus.unlocked
|
||||
? () => onCommand(VehicleCommand.lock())
|
||||
: null,
|
||||
icon: Icon(Icons.lock),
|
||||
label: Text('上锁'),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: status.lockStatus == LockStatus.locked
|
||||
? () => onCommand(VehicleCommand.unlock())
|
||||
: null,
|
||||
icon: Icon(Icons.lock_open),
|
||||
label: Text('解锁'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 动画效果 (`car_animation/`)
|
||||
|
||||
### 车辆控制动画
|
||||
```dart
|
||||
// 车辆控制动画控制器
|
||||
class VehicleAnimationController extends ChangeNotifier {
|
||||
late AnimationController _lockAnimationController;
|
||||
late AnimationController _chargingAnimationController;
|
||||
|
||||
Animation<double> get lockAnimation => _lockAnimationController;
|
||||
Animation<double> get chargingAnimation => _chargingAnimationController;
|
||||
|
||||
void initialize(TickerProvider vsync) {
|
||||
_lockAnimationController = AnimationController(
|
||||
duration: Duration(milliseconds: 500),
|
||||
vsync: vsync,
|
||||
);
|
||||
|
||||
_chargingAnimationController = AnimationController(
|
||||
duration: Duration(milliseconds: 1500),
|
||||
vsync: vsync,
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
void playLockAnimation() {
|
||||
_lockAnimationController.forward().then((_) {
|
||||
_lockAnimationController.reverse();
|
||||
});
|
||||
}
|
||||
|
||||
void startChargingAnimation() {
|
||||
_chargingAnimationController.repeat();
|
||||
}
|
||||
|
||||
void stopChargingAnimation() {
|
||||
_chargingAnimationController.stop();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## AI 聊天集成 (`ai_chat/`)
|
||||
|
||||
### AI 聊天车辆控制
|
||||
```dart
|
||||
// AI 聊天车辆控制集成
|
||||
class AIChatVehicleIntegration {
|
||||
final VehicleControlRepository _vehicleRepository;
|
||||
final AIChatAssistant _aiAssistant;
|
||||
|
||||
AIChatVehicleIntegration(this._vehicleRepository, this._aiAssistant);
|
||||
|
||||
// 处理车辆控制语音命令
|
||||
Future<AIChatResponse> handleVehicleCommand(String command) async {
|
||||
final intent = await _aiAssistant.parseIntent(command);
|
||||
|
||||
switch (intent.type) {
|
||||
case VehicleIntentType.lock:
|
||||
return await _handleLockCommand();
|
||||
case VehicleIntentType.unlock:
|
||||
return await _handleUnlockCommand();
|
||||
case VehicleIntentType.startAC:
|
||||
return await _handleStartACCommand(intent.parameters);
|
||||
case VehicleIntentType.stopAC:
|
||||
return await _handleStopACCommand();
|
||||
default:
|
||||
return AIChatResponse.error('未识别的车辆控制命令');
|
||||
}
|
||||
}
|
||||
|
||||
Future<AIChatResponse> _handleLockCommand() async {
|
||||
final result = await _vehicleRepository.lockVehicle();
|
||||
return result.fold(
|
||||
(failure) => AIChatResponse.error('车辆上锁失败:${failure.message}'),
|
||||
(_) => AIChatResponse.success('车辆已成功上锁'),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖管理
|
||||
|
||||
基于实际的pubspec.yaml配置,展示真实的项目依赖关系。
|
||||
|
||||
### 核心依赖
|
||||
```yaml
|
||||
# 车辆连接和服务依赖
|
||||
dependencies:
|
||||
car_connector: ^0.4.11 # 车联网连接服务
|
||||
car_vehicle: ^0.6.4+1 # 车辆基础服务
|
||||
car_vur: ^0.1.12 # 车辆更新记录
|
||||
flutter_ingeek_carkey: 1.6.2 # 数字钥匙 SDK
|
||||
|
||||
# 框架依赖
|
||||
basic_modular: ^0.2.3 # 模块化框架
|
||||
basic_modular_route: ^0.2.1 # 路由管理
|
||||
basic_intl: ^0.2.0 # 国际化支持
|
||||
basic_storage: ^0.2.2 # 本地存储
|
||||
|
||||
# 业务服务依赖
|
||||
clr_mno: ^0.2.2 # MNO 服务
|
||||
clr_geo: ^0.2.16+1 # 地理位置服务
|
||||
|
||||
# 功能性依赖
|
||||
dartz: ^0.10.1 # 函数式编程支持
|
||||
freezed_annotation: ^2.2.0 # 不可变类生成
|
||||
json_annotation: ^4.9.0 # JSON 序列化
|
||||
|
||||
# AI功能集成
|
||||
ai_chat_assistant: # AI 聊天助手模块
|
||||
path: ../ai_chat_assistant
|
||||
|
||||
# UI组件依赖
|
||||
carousel_slider: ^4.2.1 # 轮播图组件
|
||||
flutter_slidable: ^3.1.2 # 滑动组件
|
||||
overlay_support: ^2.1.0 # 覆盖层支持
|
||||
provider: ^6.0.5 # 状态管理
|
||||
```
|
||||
|
||||
### 模块间依赖关系
|
||||
```dart
|
||||
// 实际的模块依赖结构(基于项目配置)
|
||||
app_car/
|
||||
├── car_connector: 车辆连接服务 (核心通信)
|
||||
├── car_vehicle: 车辆基础服务 (状态管理)
|
||||
├── car_vur: 车辆更新记录 (版本控制)
|
||||
├── flutter_ingeek_carkey: 数字钥匙SDK (安全认证)
|
||||
├── ai_chat_assistant: AI聊天助手 (智能交互)
|
||||
├── clr_mno: MNO服务 (网络运营商)
|
||||
├── clr_geo: 地理位置服务 (定位功能)
|
||||
└── basic_*: 基础框架模块群
|
||||
```
|
||||
|
||||
## 路由配置 (`route_dp.dart`, `route_export.dart`)
|
||||
|
||||
### 路由定义
|
||||
```dart
|
||||
// 车辆模块路由配置
|
||||
class CarRoutes {
|
||||
static const String vehicleStatus = '/car/status';
|
||||
static const String vehicleControl = '/car/control';
|
||||
static const String chargingCenter = '/car/charging';
|
||||
static const String digitalKey = '/car/digital-key';
|
||||
static const String carFinder = '/car/finder';
|
||||
static const String climatisation = '/car/climatisation';
|
||||
|
||||
static List<ModularRoute> get routes => [
|
||||
ChildRoute(
|
||||
vehicleStatus,
|
||||
child: (context, args) => VehicleStatusPage(),
|
||||
),
|
||||
ChildRoute(
|
||||
vehicleControl,
|
||||
child: (context, args) => VehicleControlPage(),
|
||||
),
|
||||
ChildRoute(
|
||||
chargingCenter,
|
||||
child: (context, args) => ChargingCenterPage(),
|
||||
),
|
||||
ChildRoute(
|
||||
digitalKey,
|
||||
child: (context, args) => DigitalKeyPage(),
|
||||
),
|
||||
ChildRoute(
|
||||
carFinder,
|
||||
child: (context, args) => CarFinderPage(),
|
||||
),
|
||||
ChildRoute(
|
||||
climatisation,
|
||||
child: (context, args) => ClimatisationPage(),
|
||||
),
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
## 常量定义 (`constants/`)
|
||||
|
||||
### 车辆常量
|
||||
```dart
|
||||
// 车辆控制常量
|
||||
class CarConstants {
|
||||
// 温度范围
|
||||
static const double minTemperature = 16.0;
|
||||
static const double maxTemperature = 32.0;
|
||||
static const double defaultTemperature = 22.0;
|
||||
|
||||
// 充电相关
|
||||
static const int minChargingTarget = 20;
|
||||
static const int maxChargingTarget = 100;
|
||||
static const int defaultChargingTarget = 80;
|
||||
|
||||
// 动画时长
|
||||
static const Duration lockAnimationDuration = Duration(milliseconds: 500);
|
||||
static const Duration statusUpdateInterval = Duration(seconds: 30);
|
||||
|
||||
// 错误重试
|
||||
static const int maxRetryCount = 3;
|
||||
static const Duration retryDelay = Duration(seconds: 2);
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 车辆特定异常
|
||||
```dart
|
||||
// 车辆操作异常
|
||||
abstract class VehicleFailure {
|
||||
const VehicleFailure();
|
||||
|
||||
factory VehicleFailure.networkError(String message) = NetworkFailure;
|
||||
factory VehicleFailure.authenticationError() = AuthenticationFailure;
|
||||
factory VehicleFailure.vehicleNotFound() = VehicleNotFoundFailure;
|
||||
factory VehicleFailure.commandTimeout() = CommandTimeoutFailure;
|
||||
factory VehicleFailure.vehicleOffline() = VehicleOfflineFailure;
|
||||
factory VehicleFailure.insufficientBattery() = InsufficientBatteryFailure;
|
||||
}
|
||||
|
||||
class NetworkFailure extends VehicleFailure {
|
||||
final String message;
|
||||
const NetworkFailure(this.message);
|
||||
}
|
||||
|
||||
class VehicleOfflineFailure extends VehicleFailure {
|
||||
const VehicleOfflineFailure();
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 状态缓存策略
|
||||
- 车辆状态本地缓存
|
||||
- 智能刷新机制
|
||||
- 后台状态同步
|
||||
|
||||
### 网络优化
|
||||
- 命令队列管理
|
||||
- 批量请求处理
|
||||
- 离线命令缓存
|
||||
|
||||
### UI 优化
|
||||
- 状态变更动画
|
||||
- 加载状态指示
|
||||
- 错误状态处理
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- BLoC 状态管理测试
|
||||
- 服务类功能测试
|
||||
- 模型序列化测试
|
||||
|
||||
### 集成测试
|
||||
- 车联网通信测试
|
||||
- 状态同步测试
|
||||
- 命令执行测试
|
||||
|
||||
### UI 测试
|
||||
- 控制面板交互测试
|
||||
- 状态显示测试
|
||||
- 错误场景测试
|
||||
|
||||
## 总结
|
||||
|
||||
`app_car` 模块是 OneApp 车辆功能的核心,提供了完整的车辆控制和状态管理功能。模块采用 BLoC 模式进行状态管理,具有清晰的分层架构和良好的可扩展性。通过集成 AI 聊天助手和数字钥匙技术,为用户提供了智能化和便捷的车辆操作体验。
|
||||
625
app_car/app_carwatcher.md
Normal file
625
app_car/app_carwatcher.md
Normal file
@@ -0,0 +1,625 @@
|
||||
# App Carwatcher 车辆监控模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_carwatcher` 是 OneApp 车联网生态中的车辆监控模块,负责实时监控车辆状态、位置信息、安全警报等功能。该模块为用户提供全方位的车辆安全监控服务,确保车辆的安全性和用户的使用体验。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_carwatcher
|
||||
- **版本**: 0.1.2
|
||||
- **描述**: 车辆监控应用模块
|
||||
- **Flutter 版本**: >=2.10.5
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **实时车辆监控**
|
||||
- 车辆位置实时追踪
|
||||
- 车辆状态监控(锁车状态、车窗状态等)
|
||||
- 车辆异常报警
|
||||
|
||||
2. **地理围栏管理**
|
||||
- 围栏设置和编辑
|
||||
- 围栏事件监控
|
||||
- POI 地点搜索
|
||||
|
||||
3. **历史报告查看**
|
||||
- 日报详情查看
|
||||
- 事件详情展示
|
||||
- 事件过滤功能
|
||||
|
||||
4. **地图集成**
|
||||
- 车辆位置可视化
|
||||
- 历史轨迹查看
|
||||
- 地理围栏设置
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── app_carwatcher.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── app_carwatcher_module.dart # 模块定义和依赖注入
|
||||
│ ├── route_dp.dart # 路由配置
|
||||
│ ├── route_export.dart # 路由导出
|
||||
│ ├── blocs/ # 状态管理
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── pages/ # 页面组件
|
||||
│ │ ├── home/ # 首页
|
||||
│ │ ├── geo_fence_list/ # 地理围栏列表
|
||||
│ │ ├── geo_fence_detail/ # 地理围栏详情
|
||||
│ │ ├── geo_fence_search_poi/ # POI搜索
|
||||
│ │ ├── daily_report/ # 日报详情
|
||||
│ │ ├── event_detail/ # 事件详情
|
||||
│ │ └── event_filter/ # 事件过滤
|
||||
│ └── utils/ # 工具类
|
||||
├── generated/ # 代码生成文件
|
||||
└── l10n/ # 国际化文件
|
||||
```
|
||||
|
||||
## 核心实现
|
||||
|
||||
### 1. 模块入口文件
|
||||
|
||||
**文件**: `lib/app_carwatcher.dart`
|
||||
|
||||
```dart
|
||||
/// Carwatcher APP
|
||||
library app_carwatcher;
|
||||
|
||||
export 'src/app_carwatcher_module.dart';
|
||||
export 'src/route_dp.dart';
|
||||
export 'src/route_export.dart';
|
||||
```
|
||||
|
||||
### 2. 模块定义与路由配置
|
||||
|
||||
**文件**: `src/app_carwatcher_module.dart`
|
||||
|
||||
```dart
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'package:basic_modular_route/basic_modular_route.dart';
|
||||
|
||||
import 'route_export.dart';
|
||||
|
||||
/// Module负责的页面
|
||||
class AppCarwatcherModule extends Module with RouteObjProvider {
|
||||
@override
|
||||
List<ModularRoute> get routes {
|
||||
final moduleHome = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyModule);
|
||||
final carWatcherHomePage = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyCarWatcherHomePage);
|
||||
final geoFenceListPage = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyGeoFenceListPage);
|
||||
final geoFenceDetailPage = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyGeoFenceDetailPage);
|
||||
final searchPoiPage = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyGeoFenceSearchPOIPage);
|
||||
final dailyReportDetailPage = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyDailyReportPage);
|
||||
final eventFilterPage = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyEventFilterPage);
|
||||
final reportDetailPage = RouteCenterAPI.routeMetaBy(AppCarwatcherRouteExport.keyReportDetailPage);
|
||||
|
||||
return [
|
||||
ChildRoute<dynamic>(moduleHome.path, child: (_, args) => moduleHome.provider(args).as()),
|
||||
ChildRoute<dynamic>(carWatcherHomePage.path, child: (_, args) => carWatcherHomePage.provider(args).as()),
|
||||
ChildRoute<dynamic>(geoFenceListPage.path, child: (_, args) => geoFenceListPage.provider(args).as()),
|
||||
ChildRoute<dynamic>(geoFenceDetailPage.path, child: (_, args) => geoFenceDetailPage.provider(args).as()),
|
||||
ChildRoute<dynamic>(searchPoiPage.path, child: (_, args) => searchPoiPage.provider(args).as()),
|
||||
ChildRoute<dynamic>(dailyReportDetailPage.path, child: (_, args) => dailyReportDetailPage.provider(args).as()),
|
||||
ChildRoute<dynamic>(eventFilterPage.path, child: (_, args) => eventFilterPage.provider(args).as()),
|
||||
ChildRoute<dynamic>(reportDetailPage.path, child: (_, args) => reportDetailPage.provider(args).as()),
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 路由导出管理
|
||||
|
||||
**文件**: `src/route_export.dart`
|
||||
|
||||
```dart
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'package:clr_carwatcher/clr_carwatcher.dart';
|
||||
import 'package:ui_mapview/ui_mapview.dart';
|
||||
|
||||
import 'app_carwatcher_module.dart';
|
||||
import 'pages/daily_report/daily_report_detail_page.dart';
|
||||
import 'pages/event_detail/report_event_detail_page.dart';
|
||||
import 'pages/event_filter/event_filter_page.dart';
|
||||
import 'pages/geo_fence_detail/geo_fence_detail_page.dart';
|
||||
import 'pages/geo_fence_list/geo_fence_list_page.dart';
|
||||
import 'pages/geo_fence_search_poi/geo_fence_search_poi_page.dart';
|
||||
import 'pages/home/car_watcher_home_page.dart';
|
||||
|
||||
/// app_carwatcher的路由管理
|
||||
class AppCarwatcherRouteExport implements RouteExporter {
|
||||
// 路由常量定义
|
||||
static const String keyModule = 'app_carWatcher';
|
||||
static const String keyCarWatcherHomePage = 'app_carWatcher.carWatcher_home';
|
||||
static const String keyGeoFenceListPage = 'app_carWatcher.geoFenceList';
|
||||
static const String keyGeoFenceDetailPage = 'app_carWatcher.geoFenceDetail';
|
||||
static const String keyGeoFenceSearchPOIPage = 'app_carWatcher.poiSearch';
|
||||
static const String keyDailyReportPage = 'app_carWatcher.dailyReport';
|
||||
static const String keyEventFilterPage = 'app_carWatcher.eventFilter';
|
||||
static const String keyReportDetailPage = 'app_carWatcher.reportDetail';
|
||||
|
||||
@override
|
||||
List<RouteMeta> exportRoutes() {
|
||||
final r0 = RouteMeta(keyModule, '/app_carWatcher', (args) => AppCarwatcherModule(), null);
|
||||
|
||||
final r1 = RouteMeta(keyCarWatcherHomePage, '/carWatcher_home',
|
||||
(args) => CarWatcherHomePage(args.data['vin'] as String), r0);
|
||||
|
||||
final r2 = RouteMeta(keyGeoFenceListPage, '/geoFenceList',
|
||||
(args) => GeoFenceListPage(args.data['vin'] as String), r0);
|
||||
|
||||
final r3 = RouteMeta(keyGeoFenceDetailPage, '/geoFenceDetail',
|
||||
(args) => GeoFenceDetailPage(
|
||||
args.data['vin'] as String,
|
||||
args.data['fenceId'] as String?,
|
||||
args.data['fenceOnCount'] as int,
|
||||
), r0);
|
||||
|
||||
final r4 = RouteMeta(keyGeoFenceSearchPOIPage, '/poiSearch',
|
||||
(args) => GeoFenceSearchPOIPage(
|
||||
args.data['province'] as String?,
|
||||
args.data['city'] as String?,
|
||||
args.data['cityCode'] as String?,
|
||||
args.data['fenceLatLng'] as LatLng?,
|
||||
), r0);
|
||||
|
||||
final r5 = RouteMeta(keyDailyReportPage, '/dailyReport',
|
||||
(args) => DailyReportDetailPage(
|
||||
args.data['vin'] as String,
|
||||
args.data['reportId'] as String,
|
||||
), r0);
|
||||
|
||||
final r6 = RouteMeta(keyEventFilterPage, '/eventFilter',
|
||||
(args) => EventFilterPage(args.data['eventTypes'] as List<EEventType>?), r0);
|
||||
|
||||
final r7 = RouteMeta(keyReportDetailPage, '/reportDetail',
|
||||
(args) => ReportEventDetailPage(
|
||||
args.data['vin'] as String,
|
||||
args.data['eventId'] as String,
|
||||
), r0);
|
||||
|
||||
return [r0, r1, r2, r3, r4, r5, r6, r7];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 核心页面功能
|
||||
|
||||
### 1. 车辆监控首页
|
||||
|
||||
**文件**: `pages/home/car_watcher_home_page.dart`
|
||||
|
||||
```dart
|
||||
import 'package:app_consent/app_consent.dart';
|
||||
import 'package:basic_intl/intl.dart';
|
||||
import 'package:basic_logger/basic_logger.dart';
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ui_basic/pull_to_refresh.dart';
|
||||
import 'package:ui_basic/screen_util.dart';
|
||||
import 'package:ui_basic/ui_basic.dart';
|
||||
|
||||
/// CarWatcher首页
|
||||
class CarWatcherHomePage extends StatefulWidget with RouteObjProvider {
|
||||
const CarWatcherHomePage(this.vin, {Key? key}) : super(key: key);
|
||||
|
||||
/// 车辆vin码
|
||||
final String vin;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _CarWatcherHomeState();
|
||||
}
|
||||
|
||||
class _CarWatcherHomeState extends State<CarWatcherHomePage> {
|
||||
final CarWatcherHomeBloc _bloc = CarWatcherHomeBloc();
|
||||
late List<BannerBean> images = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// 初始化banner数据
|
||||
images.add(BannerBean(
|
||||
imageUrl: 'packages/app_carwatcher/assets/images/icon_banner1.png',
|
||||
title: '车辆监控横幅1',
|
||||
));
|
||||
|
||||
images.add(BannerBean(
|
||||
imageUrl: 'packages/app_carwatcher/assets/images/icon_banner2.png',
|
||||
title: '车辆监控横幅2',
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('车辆监控')),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
_bloc.add(RefreshDataEvent());
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// Banner轮播
|
||||
HomeBannerWidget(images: images),
|
||||
|
||||
// 功能入口区域
|
||||
_buildFunctionEntries(),
|
||||
|
||||
// 车辆状态信息
|
||||
_buildVehicleStatus(),
|
||||
|
||||
// 最近事件列表
|
||||
_buildRecentEvents(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFunctionEntries() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 2,
|
||||
children: [
|
||||
_buildFunctionCard(
|
||||
icon: Icons.location_on,
|
||||
title: '地理围栏',
|
||||
onTap: () => _navigateToGeoFenceList(),
|
||||
),
|
||||
_buildFunctionCard(
|
||||
icon: Icons.event_note,
|
||||
title: '历史报告',
|
||||
onTap: () => _navigateToDailyReport(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFunctionCard({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return Card(
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, size: 48, color: Colors.blue),
|
||||
SizedBox(height: 8),
|
||||
Text(title, style: TextStyle(fontSize: 16)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToGeoFenceList() {
|
||||
Modular.to.pushNamed('/app_carWatcher/geoFenceList', arguments: {'vin': widget.vin});
|
||||
}
|
||||
|
||||
void _navigateToDailyReport() {
|
||||
Modular.to.pushNamed('/app_carWatcher/dailyReport', arguments: {'vin': widget.vin});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 地理围栏功能
|
||||
|
||||
#### 围栏列表页面
|
||||
```dart
|
||||
/// 地理围栏列表页面
|
||||
class GeoFenceListPage extends StatefulWidget {
|
||||
const GeoFenceListPage(this.vin, {Key? key}) : super(key: key);
|
||||
|
||||
final String vin;
|
||||
|
||||
@override
|
||||
State<GeoFenceListPage> createState() => _GeoFenceListPageState();
|
||||
}
|
||||
|
||||
class _GeoFenceListPageState extends State<GeoFenceListPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('地理围栏'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.add),
|
||||
onPressed: () => _navigateToCreateFence(),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: ListView.builder(
|
||||
itemCount: fenceList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final fence = fenceList[index];
|
||||
return ListTile(
|
||||
title: Text(fence.name),
|
||||
subtitle: Text(fence.address),
|
||||
trailing: Switch(
|
||||
value: fence.isEnabled,
|
||||
onChanged: (value) => _toggleFence(fence, value),
|
||||
),
|
||||
onTap: () => _navigateToFenceDetail(fence),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToCreateFence() {
|
||||
Modular.to.pushNamed('/app_carWatcher/geoFenceDetail', arguments: {
|
||||
'vin': widget.vin,
|
||||
'fenceId': null,
|
||||
'fenceOnCount': 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 围栏详情页面
|
||||
```dart
|
||||
/// 地理围栏详情页面
|
||||
class GeoFenceDetailPage extends StatefulWidget {
|
||||
const GeoFenceDetailPage(this.vin, this.fenceId, this.fenceOnCount, {Key? key})
|
||||
: super(key: key);
|
||||
|
||||
final String vin;
|
||||
final String? fenceId;
|
||||
final int fenceOnCount;
|
||||
|
||||
@override
|
||||
State<GeoFenceDetailPage> createState() => _GeoFenceDetailPageState();
|
||||
}
|
||||
|
||||
class _GeoFenceDetailPageState extends State<GeoFenceDetailPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.fenceId == null ? '新建围栏' : '编辑围栏'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: _saveFence,
|
||||
child: Text('保存'),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
// 地图显示区域
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
color: Colors.grey[300],
|
||||
child: Center(child: Text('地图显示区域')),
|
||||
),
|
||||
),
|
||||
|
||||
// 设置区域
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: '围栏名称',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Text('半径(米): '),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
min: 100,
|
||||
max: 5000,
|
||||
value: 500,
|
||||
onChanged: (value) {},
|
||||
),
|
||||
),
|
||||
Text('500'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _saveFence() {
|
||||
// 保存围栏逻辑
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. POI搜索功能
|
||||
|
||||
```dart
|
||||
/// POI搜索页面
|
||||
class GeoFenceSearchPOIPage extends StatefulWidget {
|
||||
const GeoFenceSearchPOIPage(
|
||||
this.province,
|
||||
this.city,
|
||||
this.cityCode,
|
||||
this.fenceLatLng, {
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
final String? province;
|
||||
final String? city;
|
||||
final String? cityCode;
|
||||
final LatLng? fenceLatLng;
|
||||
|
||||
@override
|
||||
State<GeoFenceSearchPOIPage> createState() => _GeoFenceSearchPOIPageState();
|
||||
}
|
||||
|
||||
class _GeoFenceSearchPOIPageState extends State<GeoFenceSearchPOIPage> {
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
List<POIItem> _searchResults = [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: TextField(
|
||||
controller: _searchController,
|
||||
decoration: InputDecoration(
|
||||
hintText: '搜索地点',
|
||||
border: InputBorder.none,
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(Icons.search),
|
||||
onPressed: _performSearch,
|
||||
),
|
||||
),
|
||||
onSubmitted: (_) => _performSearch(),
|
||||
),
|
||||
),
|
||||
body: ListView.builder(
|
||||
itemCount: _searchResults.length,
|
||||
itemBuilder: (context, index) {
|
||||
final poi = _searchResults[index];
|
||||
return ListTile(
|
||||
title: Text(poi.name),
|
||||
subtitle: Text(poi.address),
|
||||
onTap: () => _selectPOI(poi),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _performSearch() {
|
||||
// 执行POI搜索
|
||||
setState(() {
|
||||
_searchResults = [
|
||||
// 模拟搜索结果
|
||||
POIItem(name: '示例地点1', address: '示例地址1'),
|
||||
POIItem(name: '示例地点2', address: '示例地址2'),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
void _selectPOI(POIItem poi) {
|
||||
Navigator.of(context).pop(poi);
|
||||
}
|
||||
}
|
||||
|
||||
class POIItem {
|
||||
final String name;
|
||||
final String address;
|
||||
|
||||
POIItem({required this.name, required this.address});
|
||||
}
|
||||
```
|
||||
|
||||
## 状态管理
|
||||
|
||||
### BLoC状态管理模式
|
||||
```dart
|
||||
// CarWatcher首页状态管理
|
||||
class CarWatcherHomeBloc extends Bloc<CarWatcherHomeEvent, CarWatcherHomeState> {
|
||||
CarWatcherHomeBloc() : super(CarWatcherHomeInitial()) {
|
||||
on<LoadDataEvent>(_onLoadData);
|
||||
on<RefreshDataEvent>(_onRefreshData);
|
||||
}
|
||||
|
||||
Future<void> _onLoadData(LoadDataEvent event, Emitter<CarWatcherHomeState> emit) async {
|
||||
emit(CarWatcherHomeLoading());
|
||||
|
||||
try {
|
||||
// 加载车辆数据
|
||||
final vehicleData = await loadVehicleData(event.vin);
|
||||
emit(CarWatcherHomeLoaded(vehicleData));
|
||||
} catch (e) {
|
||||
emit(CarWatcherHomeError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onRefreshData(RefreshDataEvent event, Emitter<CarWatcherHomeState> emit) async {
|
||||
// 刷新数据逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 事件定义
|
||||
abstract class CarWatcherHomeEvent {}
|
||||
|
||||
class LoadDataEvent extends CarWatcherHomeEvent {
|
||||
final String vin;
|
||||
LoadDataEvent(this.vin);
|
||||
}
|
||||
|
||||
class RefreshDataEvent extends CarWatcherHomeEvent {}
|
||||
|
||||
// 状态定义
|
||||
abstract class CarWatcherHomeState {}
|
||||
|
||||
class CarWatcherHomeInitial extends CarWatcherHomeState {}
|
||||
|
||||
class CarWatcherHomeLoading extends CarWatcherHomeState {}
|
||||
|
||||
class CarWatcherHomeLoaded extends CarWatcherHomeState {
|
||||
final VehicleData data;
|
||||
CarWatcherHomeLoaded(this.data);
|
||||
}
|
||||
|
||||
class CarWatcherHomeError extends CarWatcherHomeState {
|
||||
final String message;
|
||||
CarWatcherHomeError(this.message);
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖管理
|
||||
|
||||
### 核心依赖
|
||||
- **clr_carwatcher**: 车辆监控服务SDK
|
||||
- **ui_mapview**: 地图视图组件
|
||||
- **app_consent**: 用户授权管理
|
||||
|
||||
### 框架依赖
|
||||
- **basic_modular**: 模块化框架
|
||||
- **basic_modular_route**: 路由管理
|
||||
- **basic_intl**: 国际化支持
|
||||
- **basic_logger**: 日志服务
|
||||
|
||||
### UI 组件依赖
|
||||
- **ui_basic**: 基础UI组件
|
||||
- **flutter/material**: Material Design组件
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 代码组织
|
||||
- 按功能模块组织页面和组件
|
||||
- 统一的路由管理和导航
|
||||
- 清晰的状态管理模式
|
||||
|
||||
### 2. 用户体验
|
||||
- 响应式设计适配不同屏幕
|
||||
- 友好的加载和错误提示
|
||||
- 流畅的页面转场
|
||||
|
||||
### 3. 性能优化
|
||||
- 合理的状态管理避免不必要的重建
|
||||
- 地图资源的合理加载和释放
|
||||
- 网络请求的优化和缓存
|
||||
899
app_car/app_charging.md
Normal file
899
app_car/app_charging.md
Normal file
@@ -0,0 +1,899 @@
|
||||
# App Charging - 充电管理模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_charging` 是 OneApp 的充电管理核心模块,提供完整的电动车充电功能,包括充电地图、充电站查找、订单管理、支付结算等全流程充电服务。该模块集成了高德地图服务、BLoC状态管理、路由导航等,为用户提供便捷的充电体验。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_charging
|
||||
- **路径**: oneapp_app_car/app_charging/
|
||||
- **依赖**: car_services, car_vehicle, clr_charging, basic_modular
|
||||
- **主要功能**: 充电地图、充电站搜索、订单管理、智能寻桩
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
app_charging/
|
||||
├── lib/
|
||||
│ ├── app_charging.dart # 主导出文件
|
||||
│ ├── generated/ # 代码生成文件
|
||||
│ ├── l10n/ # 国际化文件
|
||||
│ └── src/ # 源代码目录
|
||||
│ ├── app_charging_module.dart # 充电模块配置
|
||||
│ ├── blocs/ # 状态管理(BLoC)
|
||||
│ ├── carfinder/ # 车辆查找功能
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── pages/ # 页面组件
|
||||
│ │ └── public_charging/ # 公共充电页面
|
||||
│ │ ├── charging_map_home_page/ # 充电地图首页
|
||||
│ │ ├── charging_station_detail_page/ # 充电站详情
|
||||
│ │ ├── charging_query_order_list_page/ # 订单列表
|
||||
│ │ ├── charging_report_page/ # 充电报告
|
||||
│ │ ├── charging_smart_pile_finding_page/ # 智能寻桩
|
||||
│ │ └── ... # 其他充电功能页面
|
||||
│ ├── utils/ # 工具类
|
||||
│ ├── route_dp.dart # 路由配置
|
||||
│ ├── route_export.dart # 路由导出
|
||||
│ └── switch_vehicle.dart # 车辆切换功能
|
||||
├── assets/ # 静态资源
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
# App Charging - 充电管理模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_charging` 是 OneApp 的充电管理核心模块,提供完整的电动车充电功能,包括充电地图、充电站查找、订单管理、支付结算等全流程充电服务。该模块集成了高德地图服务、BLoC状态管理、路由导航等,为用户提供便捷的充电体验。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_charging
|
||||
- **路径**: oneapp_app_car/app_charging/
|
||||
- **依赖**: car_services, car_vehicle, clr_charging, basic_modular
|
||||
- **主要功能**: 充电地图、充电站搜索、订单管理、智能寻桩
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
app_charging/
|
||||
├── lib/
|
||||
│ ├── app_charging.dart # 主导出文件
|
||||
│ ├── generated/ # 代码生成文件
|
||||
│ ├── l10n/ # 国际化文件
|
||||
│ └── src/ # 源代码目录
|
||||
│ ├── app_charging_module.dart # 充电模块配置
|
||||
│ ├── blocs/ # 状态管理(BLoC)
|
||||
│ ├── carfinder/ # 车辆查找功能
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── pages/ # 页面组件
|
||||
│ │ └── public_charging/ # 公共充电页面
|
||||
│ │ ├── charging_map_home_page/ # 充电地图首页
|
||||
│ │ ├── charging_station_detail_page/ # 充电站详情
|
||||
│ │ ├── charging_query_order_list_page/ # 订单列表
|
||||
│ │ ├── charging_report_page/ # 充电报告
|
||||
│ │ ├── charging_smart_pile_finding_page/ # 智能寻桩
|
||||
│ │ ├── charging_coupon_page/ # 充电优惠券
|
||||
│ │ ├── charging_power_monitor_page/ # 功率监控
|
||||
│ │ └── ... # 其他充电功能页面
|
||||
│ ├── utils/ # 工具类
|
||||
│ ├── route_dp.dart # 路由配置
|
||||
│ ├── route_export.dart # 路由导出
|
||||
│ └── switch_vehicle.dart # 车辆切换功能
|
||||
├── assets/ # 静态资源
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 核心实现
|
||||
|
||||
### 1. 模块主导出文件
|
||||
|
||||
**文件**: `lib/app_charging.dart`
|
||||
|
||||
```dart
|
||||
/// charging pages
|
||||
library app_charging;
|
||||
|
||||
export 'package:car_services/services.dart';
|
||||
export 'package:car_vehicle/vehicle.dart';
|
||||
|
||||
export 'src/app_charging_module.dart';
|
||||
export 'src/pages/public_charging/charging_map_card/charging_map_card.dart';
|
||||
export 'src/pages/public_charging/charging_map_home_page/charging_map_home_page.dart';
|
||||
export 'src/pages/public_charging/charging_query_order_list_page/charging_query_order_list_page.dart';
|
||||
|
||||
// 路由键导出
|
||||
export 'src/route_dp.dart' show ChargingReservationRouteKey;
|
||||
export 'src/route_dp.dart' show CarChargingCouponRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingCpoCollectionRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingDetectiveRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingMapHomeNonOwnerRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingMapHomeRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingPowerMonitorResultRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingPowerMonitorRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingPrePaySettingRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingQueryOrderDetailRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingQueryOrderListRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingQueryRatingRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingReportRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingSmartPileFindingRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingStationDetailRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingStationGuideRouteKey;
|
||||
export 'src/route_dp.dart' show ChargingVehicleReportRouteKey;
|
||||
export 'src/route_export.dart';
|
||||
```
|
||||
|
||||
### 2. 模块定义与依赖管理
|
||||
|
||||
**文件**: `src/app_charging_module.dart`
|
||||
|
||||
```dart
|
||||
import 'package:basic_logger/basic_logger.dart';
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'package:basic_modular_route/basic_modular_route.dart';
|
||||
import 'package:clr_account/account.dart';
|
||||
import 'package:clr_charging/clr_charging.dart';
|
||||
import 'package:ui_basic/ui_basic.dart';
|
||||
|
||||
import 'constants/module_constant.dart';
|
||||
import 'route_export.dart';
|
||||
|
||||
/// 充电模块定义
|
||||
class AppChargingModule extends Module with RouteObjProvider, AppLifeCycleListener {
|
||||
@override
|
||||
List<Bind<Object>> get binds => [];
|
||||
|
||||
@override
|
||||
List<Module> get imports => [AccountConModule(), ClrChargingModule()];
|
||||
|
||||
@override
|
||||
List<ModularRoute> get routes {
|
||||
// 模块首页
|
||||
final moduleHome = RouteCenterAPI.routeMetaBy(AppChargingRouteExport.keyModule);
|
||||
|
||||
// 充电地图首页
|
||||
final chargingMapHome = RouteCenterAPI.routeMetaBy(AppChargingRouteExport.keyChargingMapHome);
|
||||
|
||||
// 搜索首页
|
||||
final searchHome = RouteCenterAPI.routeMetaBy(AppChargingRouteExport.keySearchHome);
|
||||
|
||||
// CPO收藏页面
|
||||
final cpoCollection = RouteCenterAPI.routeMetaBy(AppChargingRouteExport.keyChargingCpoCollection);
|
||||
|
||||
// 充电站详情页面
|
||||
final stationDetailPage = RouteCenterAPI.routeMetaBy(AppChargingRouteExport.keyStationDetailPage);
|
||||
|
||||
// 电价页面
|
||||
final electricPricePage = RouteCenterAPI.routeMetaBy(AppChargingRouteExport.keyStationElectricPricePage);
|
||||
|
||||
return [
|
||||
ChildRoute<dynamic>(moduleHome.path, child: (_, args) => moduleHome.provider(args).as()),
|
||||
ChildRoute<dynamic>(chargingMapHome.path, child: (_, args) => chargingMapHome.provider(args).as()),
|
||||
ChildRoute<dynamic>(searchHome.path, child: (_, args) => searchHome.provider(args).as()),
|
||||
ChildRoute<dynamic>(cpoCollection.path, child: (_, args) => cpoCollection.provider(args).as()),
|
||||
ChildRoute<dynamic>(stationDetailPage.path, child: (_, args) => stationDetailPage.provider(args).as()),
|
||||
ChildRoute<dynamic>(electricPricePage.path, child: (_, args) => electricPricePage.provider(args).as()),
|
||||
// 更多路由配置...
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 路由导出管理
|
||||
|
||||
**文件**: `src/route_export.dart`
|
||||
|
||||
```dart
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:amap_flutter_base/amap_flutter_base.dart';
|
||||
import 'package:basic_logger/basic_logger.dart';
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'package:clr_charging/clr_charging.dart';
|
||||
import 'package:clr_geo/clr_geo.dart';
|
||||
|
||||
import 'app_charging_module.dart';
|
||||
import 'pages/public_charging/charging_map_home_page/charging_map_home_page.dart';
|
||||
import 'pages/public_charging/charging_station_detail_page/charging_station_detail_page.dart';
|
||||
import 'pages/public_charging/charging_query_order_list_page/charging_query_order_list_page.dart';
|
||||
import 'pages/public_charging/charging_smart_pile_finding_page/charging_smart_pile_finding_page.dart';
|
||||
// ... 更多页面导入
|
||||
|
||||
/// app_charging的路由管理
|
||||
class AppChargingRouteExport implements RouteExporter {
|
||||
// 路由键常量定义
|
||||
static const String keyModule = 'charging';
|
||||
static const String keyChargingMapHome = 'charging.map_home';
|
||||
static const String keySearchHome = 'charging.search_home';
|
||||
static const String keyChargingCpoCollection = 'charging.cpo_collection';
|
||||
static const String keyStationDetailPage = 'charging.station_detail';
|
||||
static const String keyStationElectricPricePage = 'charging.electric_price';
|
||||
static const String keyQueryOrderListPage = 'charging.order_list';
|
||||
static const String keySmartPileFinding = 'charging.smart_pile_finding';
|
||||
static const String keyChargingReport = 'charging.report';
|
||||
static const String keyPowerMonitor = 'charging.power_monitor';
|
||||
// ... 更多路由键定义
|
||||
|
||||
@override
|
||||
List<RouteMeta> exportRoutes() {
|
||||
// 模块根路由
|
||||
final r0 = RouteMeta(keyModule, '/charging', (args) => AppChargingModule(), null);
|
||||
|
||||
// 充电地图首页
|
||||
final r1 = RouteMeta(
|
||||
keyChargingMapHome,
|
||||
'/map_home',
|
||||
(args) => ChargingMapHomePage(args.data['vin'] as String?),
|
||||
r0,
|
||||
);
|
||||
|
||||
// 充电站详情页面
|
||||
final r2 = RouteMeta(
|
||||
keyStationDetailPage,
|
||||
'/station_detail',
|
||||
(args) => ChargingStationDetailPage(
|
||||
stationID: args.data['stationID'] as String,
|
||||
chargingVin: args.data['chargingVin'] as String?,
|
||||
),
|
||||
r0,
|
||||
);
|
||||
|
||||
// 智能寻桩页面
|
||||
final r3 = RouteMeta(
|
||||
keySmartPileFinding,
|
||||
'/smart_pile_finding',
|
||||
(args) => ChargingSmartPileFindingPage(
|
||||
vin: args.data['vin'] as String,
|
||||
),
|
||||
r0,
|
||||
);
|
||||
|
||||
// 订单列表页面
|
||||
final r4 = RouteMeta(
|
||||
keyQueryOrderListPage,
|
||||
'/order_list',
|
||||
(args) => ChargingQueryOrderListPage(
|
||||
vin: args.data['vin'] as String,
|
||||
),
|
||||
r0,
|
||||
);
|
||||
|
||||
return [r0, r1, r2, r3, r4];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 核心功能模块
|
||||
|
||||
### 1. 充电地图首页
|
||||
|
||||
**文件**: `pages/public_charging/charging_map_home_page/charging_map_home_page.dart`
|
||||
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:amap_flutter_map/amap_flutter_map.dart';
|
||||
import 'package:basic_modular/modular.dart';
|
||||
|
||||
/// 充电地图首页
|
||||
class ChargingMapHomePage extends StatefulWidget {
|
||||
const ChargingMapHomePage(this.vin, {Key? key}) : super(key: key);
|
||||
|
||||
final String? vin;
|
||||
|
||||
@override
|
||||
State<ChargingMapHomePage> createState() => _ChargingMapHomePageState();
|
||||
}
|
||||
|
||||
class _ChargingMapHomePageState extends State<ChargingMapHomePage> {
|
||||
AMapController? _mapController;
|
||||
List<ChargingStation> _chargingStations = [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('充电地图'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.search),
|
||||
onPressed: _openSearch,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.filter_list),
|
||||
onPressed: _openFilter,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
// 地图组件
|
||||
AMapWidget(
|
||||
onMapCreated: _onMapCreated,
|
||||
markers: Set<Marker>.from(_buildMarkers()),
|
||||
),
|
||||
|
||||
// 功能按钮区域
|
||||
Positioned(
|
||||
bottom: 100,
|
||||
right: 16,
|
||||
child: Column(
|
||||
children: [
|
||||
FloatingActionButton(
|
||||
heroTag: "locate",
|
||||
onPressed: _locateUser,
|
||||
child: Icon(Icons.my_location),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
FloatingActionButton(
|
||||
heroTag: "smart_find",
|
||||
onPressed: _smartPileFinding,
|
||||
child: Icon(Icons.electric_bolt),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 底部信息卡片
|
||||
_buildBottomSheet(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onMapCreated(AMapController controller) {
|
||||
_mapController = controller;
|
||||
_loadChargingStations();
|
||||
}
|
||||
|
||||
List<Marker> _buildMarkers() {
|
||||
return _chargingStations.map((station) {
|
||||
return Marker(
|
||||
markerId: MarkerId(station.id),
|
||||
position: LatLng(station.latitude, station.longitude),
|
||||
infoWindow: InfoWindow(title: station.name),
|
||||
onTap: () => _showStationDetail(station),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
void _loadChargingStations() {
|
||||
// 加载充电站数据
|
||||
}
|
||||
|
||||
void _openSearch() {
|
||||
Modular.to.pushNamed('/charging/search_home');
|
||||
}
|
||||
|
||||
void _openFilter() {
|
||||
Modular.to.pushNamed('/charging/filter');
|
||||
}
|
||||
|
||||
void _locateUser() {
|
||||
// 定位到用户位置
|
||||
}
|
||||
|
||||
void _smartPileFinding() {
|
||||
if (widget.vin != null) {
|
||||
Modular.to.pushNamed('/charging/smart_pile_finding', arguments: {
|
||||
'vin': widget.vin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _showStationDetail(ChargingStation station) {
|
||||
Modular.to.pushNamed('/charging/station_detail', arguments: {
|
||||
'stationID': station.id,
|
||||
'chargingVin': widget.vin,
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildBottomSheet() {
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, -2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildBottomAction(Icons.list, '订单', _openOrderList),
|
||||
_buildBottomAction(Icons.assessment, '报告', _openReport),
|
||||
_buildBottomAction(Icons.settings, '设置', _openSettings),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomAction(IconData icon, String label, VoidCallback onTap) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, color: Colors.blue),
|
||||
SizedBox(height: 4),
|
||||
Text(label, style: TextStyle(fontSize: 12)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openOrderList() {
|
||||
if (widget.vin != null) {
|
||||
Modular.to.pushNamed('/charging/order_list', arguments: {
|
||||
'vin': widget.vin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _openReport() {
|
||||
if (widget.vin != null) {
|
||||
Modular.to.pushNamed('/charging/report', arguments: {
|
||||
'vin': widget.vin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _openSettings() {
|
||||
Modular.to.pushNamed('/charging/settings');
|
||||
}
|
||||
}
|
||||
|
||||
// 充电站数据模型
|
||||
class ChargingStation {
|
||||
final String id;
|
||||
final String name;
|
||||
final double latitude;
|
||||
final double longitude;
|
||||
final int totalPiles;
|
||||
final int availablePiles;
|
||||
|
||||
ChargingStation({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.latitude,
|
||||
required this.longitude,
|
||||
required this.totalPiles,
|
||||
required this.availablePiles,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 充电站详情页面
|
||||
|
||||
```dart
|
||||
/// 充电站详情页面
|
||||
class ChargingStationDetailPage extends StatefulWidget {
|
||||
const ChargingStationDetailPage({
|
||||
Key? key,
|
||||
required this.stationID,
|
||||
this.chargingVin,
|
||||
}) : super(key: key);
|
||||
|
||||
final String stationID;
|
||||
final String? chargingVin;
|
||||
|
||||
@override
|
||||
State<ChargingStationDetailPage> createState() => _ChargingStationDetailPageState();
|
||||
}
|
||||
|
||||
class _ChargingStationDetailPageState extends State<ChargingStationDetailPage> {
|
||||
ChargingStationDetail? _stationDetail;
|
||||
bool _isLoading = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadStationDetail();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_isLoading) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('充电站详情')),
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
|
||||
if (_stationDetail == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('充电站详情')),
|
||||
body: Center(child: Text('加载失败')),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_stationDetail!.name),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.share),
|
||||
onPressed: _shareStation,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// 充电站基本信息
|
||||
_buildStationInfo(),
|
||||
|
||||
// 充电桩列表
|
||||
_buildChargingPilesList(),
|
||||
|
||||
// 服务设施
|
||||
_buildFacilities(),
|
||||
|
||||
// 电价信息
|
||||
_buildPriceInfo(),
|
||||
|
||||
// 评价与评论
|
||||
_buildRatingsSection(),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: _navigateToStation,
|
||||
child: Text('导航'),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: _bookChargingPile,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
child: Text('预约充电'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStationInfo() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(_stationDetail!.name, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
|
||||
SizedBox(height: 8),
|
||||
Text(_stationDetail!.address, style: TextStyle(color: Colors.grey[600])),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
_buildInfoChip('总桩数', '${_stationDetail!.totalPiles}'),
|
||||
SizedBox(width: 16),
|
||||
_buildInfoChip('可用桩数', '${_stationDetail!.availablePiles}'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoChip(String label, String value) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text('$label: $value', style: TextStyle(color: Colors.blue)),
|
||||
);
|
||||
}
|
||||
|
||||
void _loadStationDetail() {
|
||||
// 加载充电站详情数据
|
||||
Future.delayed(Duration(seconds: 1), () {
|
||||
setState(() {
|
||||
_stationDetail = ChargingStationDetail(
|
||||
id: widget.stationID,
|
||||
name: '示例充电站',
|
||||
address: '示例地址',
|
||||
totalPiles: 10,
|
||||
availablePiles: 6,
|
||||
);
|
||||
_isLoading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _navigateToStation() {
|
||||
Modular.to.pushNamed('/charging/station_guide', arguments: {
|
||||
'stationID': widget.stationID,
|
||||
});
|
||||
}
|
||||
|
||||
void _bookChargingPile() {
|
||||
Modular.to.pushNamed('/charging/reservation', arguments: {
|
||||
'stationID': widget.stationID,
|
||||
'vin': widget.chargingVin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 充电站详情数据模型
|
||||
class ChargingStationDetail {
|
||||
final String id;
|
||||
final String name;
|
||||
final String address;
|
||||
final int totalPiles;
|
||||
final int availablePiles;
|
||||
|
||||
ChargingStationDetail({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.address,
|
||||
required this.totalPiles,
|
||||
required this.availablePiles,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 智能寻桩页面
|
||||
|
||||
```dart
|
||||
/// 智能寻桩页面
|
||||
class ChargingSmartPileFindingPage extends StatefulWidget {
|
||||
const ChargingSmartPileFindingPage({
|
||||
Key? key,
|
||||
required this.vin,
|
||||
}) : super(key: key);
|
||||
|
||||
final String vin;
|
||||
|
||||
@override
|
||||
State<ChargingSmartPileFindingPage> createState() => _ChargingSmartPileFindingPageState();
|
||||
}
|
||||
|
||||
class _ChargingSmartPileFindingPageState extends State<ChargingSmartPileFindingPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('智能寻桩')),
|
||||
body: Column(
|
||||
children: [
|
||||
// 车辆信息卡片
|
||||
_buildVehicleInfoCard(),
|
||||
|
||||
// 推荐充电站列表
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: _recommendedStations.length,
|
||||
itemBuilder: (context, index) {
|
||||
final station = _recommendedStations[index];
|
||||
return _buildStationRecommendCard(station);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildVehicleInfoCard() {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(16),
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 4)],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('当前车辆', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
|
||||
SizedBox(height: 8),
|
||||
Text('VIN: ${widget.vin}'),
|
||||
Text('当前电量: 30%'),
|
||||
Text('续航里程: 120km'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStationRecommendCard(RecommendedStation station) {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Card(
|
||||
child: ListTile(
|
||||
title: Text(station.name),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('距离: ${station.distance}km'),
|
||||
Text('可用桩数: ${station.availablePiles}'),
|
||||
Text('预计费用: ¥${station.estimatedCost}'),
|
||||
],
|
||||
),
|
||||
trailing: ElevatedButton(
|
||||
onPressed: () => _selectStation(station),
|
||||
child: Text('选择'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _selectStation(RecommendedStation station) {
|
||||
Modular.to.pushNamed('/charging/station_detail', arguments: {
|
||||
'stationID': station.id,
|
||||
'chargingVin': widget.vin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 推荐充电站数据模型
|
||||
class RecommendedStation {
|
||||
final String id;
|
||||
final String name;
|
||||
final double distance;
|
||||
final int availablePiles;
|
||||
final double estimatedCost;
|
||||
|
||||
RecommendedStation({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.distance,
|
||||
required this.availablePiles,
|
||||
required this.estimatedCost,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 状态管理 (BLoC)
|
||||
|
||||
### 充电地图状态管理
|
||||
```dart
|
||||
// 充电地图状态管理
|
||||
class ChargingMapHomeBloc extends Bloc<ChargingMapHomeEvent, ChargingMapHomeState> {
|
||||
final ChargingService _chargingService;
|
||||
|
||||
ChargingMapHomeBloc(this._chargingService) : super(ChargingMapHomeInitial()) {
|
||||
on<LoadChargingStationsEvent>(_onLoadChargingStations);
|
||||
on<FilterStationsEvent>(_onFilterStations);
|
||||
on<SearchStationsEvent>(_onSearchStations);
|
||||
}
|
||||
|
||||
Future<void> _onLoadChargingStations(
|
||||
LoadChargingStationsEvent event,
|
||||
Emitter<ChargingMapHomeState> emit,
|
||||
) async {
|
||||
emit(ChargingMapHomeLoading());
|
||||
|
||||
try {
|
||||
final stations = await _chargingService.getNearbyStations(
|
||||
latitude: event.latitude,
|
||||
longitude: event.longitude,
|
||||
radius: event.radius,
|
||||
);
|
||||
|
||||
emit(ChargingMapHomeLoaded(stations));
|
||||
} catch (e) {
|
||||
emit(ChargingMapHomeError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onFilterStations(
|
||||
FilterStationsEvent event,
|
||||
Emitter<ChargingMapHomeState> emit,
|
||||
) async {
|
||||
if (state is ChargingMapHomeLoaded) {
|
||||
final currentState = state as ChargingMapHomeLoaded;
|
||||
final filteredStations = _applyFilter(currentState.stations, event.filter);
|
||||
emit(ChargingMapHomeLoaded(filteredStations));
|
||||
}
|
||||
}
|
||||
|
||||
List<ChargingStation> _applyFilter(List<ChargingStation> stations, StationFilter filter) {
|
||||
return stations.where((station) {
|
||||
if (filter.onlyAvailable && station.availablePiles == 0) return false;
|
||||
if (filter.maxDistance != null && station.distance > filter.maxDistance!) return false;
|
||||
return true;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
// 事件定义
|
||||
abstract class ChargingMapHomeEvent {}
|
||||
|
||||
class LoadChargingStationsEvent extends ChargingMapHomeEvent {
|
||||
final double latitude;
|
||||
final double longitude;
|
||||
final double radius;
|
||||
|
||||
LoadChargingStationsEvent(this.latitude, this.longitude, this.radius);
|
||||
}
|
||||
|
||||
class FilterStationsEvent extends ChargingMapHomeEvent {
|
||||
final StationFilter filter;
|
||||
FilterStationsEvent(this.filter);
|
||||
}
|
||||
|
||||
// 状态定义
|
||||
abstract class ChargingMapHomeState {}
|
||||
|
||||
class ChargingMapHomeInitial extends ChargingMapHomeState {}
|
||||
|
||||
class ChargingMapHomeLoading extends ChargingMapHomeState {}
|
||||
|
||||
class ChargingMapHomeLoaded extends ChargingMapHomeState {
|
||||
final List<ChargingStation> stations;
|
||||
ChargingMapHomeLoaded(this.stations);
|
||||
}
|
||||
|
||||
class ChargingMapHomeError extends ChargingMapHomeState {
|
||||
final String message;
|
||||
ChargingMapHomeError(this.message);
|
||||
}
|
||||
|
||||
// 过滤器模型
|
||||
class StationFilter {
|
||||
final bool onlyAvailable;
|
||||
final double? maxDistance;
|
||||
final List<String>? supportedConnectors;
|
||||
|
||||
StationFilter({
|
||||
this.onlyAvailable = false,
|
||||
this.maxDistance,
|
||||
this.supportedConnectors,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖管理
|
||||
|
||||
### 核心依赖
|
||||
- **clr_charging**: 充电服务SDK
|
||||
- **car_services**: 车辆服务
|
||||
- **car_vehicle**: 车辆管理
|
||||
- **amap_flutter_map**: 高德地图
|
||||
|
||||
### 框架依赖
|
||||
- **basic_modular**: 模块化框架
|
||||
- **basic_modular_route**: 路由管理
|
||||
- **basic_logger**: 日志服务
|
||||
- **ui_basic**: 基础UI组件
|
||||
|
||||
### 账户与支付
|
||||
- **clr_account**: 账户管理
|
||||
- **clr_geo**: 地理位置服务
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 代码组织
|
||||
- 按业务功能模块化组织
|
||||
- 统一的路由管理和页面导航
|
||||
- 清晰的状态管理模式
|
||||
|
||||
### 2. 用户体验
|
||||
- 地图加载优化和缓存策略
|
||||
- 实时充电桩状态更新
|
||||
- 智能推荐算法
|
||||
|
||||
### 3. 性能优化
|
||||
- 地图资源合理加载释放
|
||||
- 充电站数据分页加载
|
||||
- 网络请求优化和重试机制
|
||||
337
app_car/app_composer.md
Normal file
337
app_car/app_composer.md
Normal file
@@ -0,0 +1,337 @@
|
||||
# App Composer 车辆编排模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_composer` 是 OneApp 车联网生态中的车辆编排模块,负责车辆功能的组合编排、自定义场景设置、智能控制流程等功能。该模块为用户提供个性化的车辆控制体验,通过可视化的方式让用户自定义车辆操作流程。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_composer
|
||||
- **版本**: 0.2.9+21
|
||||
- **描述**: 车辆功能编排应用模块
|
||||
- **Flutter 版本**: >=2.5.0
|
||||
- **Dart 版本**: >=2.17.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **场景编排**
|
||||
- 自定义车辆控制场景
|
||||
- 多步骤操作流程设计
|
||||
- 条件触发逻辑设置
|
||||
- 场景模板管理
|
||||
|
||||
2. **智能控制**
|
||||
- 基于时间的自动控制
|
||||
- 基于位置的触发控制
|
||||
- 基于状态的条件控制
|
||||
- 多设备联动控制
|
||||
|
||||
3. **可视化编辑**
|
||||
- 拖拽式流程设计
|
||||
- 可视化逻辑编排
|
||||
- 实时预览效果
|
||||
- 错误检查提示
|
||||
|
||||
4. **场景执行**
|
||||
- 场景一键执行
|
||||
- 执行状态监控
|
||||
- 执行结果反馈
|
||||
- 异常处理机制
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── app_composer.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── config/ # 配置管理
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── global/ # 全局状态管理
|
||||
│ ├── pages/ # 页面组件
|
||||
│ ├── router/ # 路由配置
|
||||
│ ├── util/ # 工具类
|
||||
│ └── widgets/ # 自定义组件
|
||||
├── const/ # 模块常量
|
||||
├── generated/ # 代码生成文件
|
||||
└── l10n/ # 国际化文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `basic_modular: ^0.2.1` - 模块化框架
|
||||
- `basic_modular_route: ^0.2.0` - 路由管理
|
||||
- `basic_intl: ^0.2.0` - 国际化支持
|
||||
- `basic_logger: ^0.2.0` - 日志系统
|
||||
|
||||
#### 业务依赖
|
||||
- `ui_basic: ^0.2.43+5` - 基础UI组件
|
||||
- `clr_composer: ^0.2.6+7` - 编排服务SDK
|
||||
- `clr_account: ^0.2.8` - 账户服务SDK
|
||||
|
||||
#### 第三方依赖
|
||||
- `json_annotation: ^4.6.0` - JSON序列化
|
||||
- `dartz: ^0.10.1` - 函数式编程
|
||||
- `uuid: ^3.0.7` - UUID生成
|
||||
- `crypto: ^3.0.3` - 加密功能
|
||||
- `path_provider: ^2.0.15` - 文件路径
|
||||
- `bottom_sheet: ^4.0.0` - 底部弹窗
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`app_composer.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 模块对外接口统一导出
|
||||
- 核心组件和服务暴露
|
||||
|
||||
### 2. 配置管理 (`src/config/`)
|
||||
|
||||
**功能职责**:
|
||||
- 编排引擎配置
|
||||
- 场景模板配置
|
||||
- 执行策略配置
|
||||
- 性能参数配置
|
||||
|
||||
**主要配置**:
|
||||
- `ComposerConfig` - 编排引擎配置
|
||||
- `SceneConfig` - 场景配置
|
||||
- `ExecutionConfig` - 执行配置
|
||||
- `TemplateConfig` - 模板配置
|
||||
|
||||
### 3. 常量定义 (`src/constants/`)
|
||||
|
||||
**功能职责**:
|
||||
- 编排常量定义
|
||||
- 操作类型枚举
|
||||
- 状态码定义
|
||||
- 错误消息常量
|
||||
|
||||
**主要常量**:
|
||||
- 操作类型常量
|
||||
- 触发条件常量
|
||||
- 执行状态常量
|
||||
- UI配置常量
|
||||
|
||||
### 4. 全局状态管理 (`src/global/`)
|
||||
|
||||
**功能职责**:
|
||||
- 编排状态全局管理
|
||||
- 场景数据缓存
|
||||
- 执行状态监控
|
||||
- 数据同步协调
|
||||
|
||||
**主要状态**:
|
||||
- `ComposerState` - 编排器状态
|
||||
- `SceneState` - 场景状态
|
||||
- `ExecutionState` - 执行状态
|
||||
- `TemplateState` - 模板状态
|
||||
|
||||
### 5. 页面组件 (`src/pages/`)
|
||||
|
||||
**功能职责**:
|
||||
- 用户界面展示
|
||||
- 用户交互处理
|
||||
- 编排操作界面
|
||||
|
||||
**主要页面**:
|
||||
- `ComposerHomePage` - 编排主页
|
||||
- `SceneEditorPage` - 场景编辑页
|
||||
- `SceneListPage` - 场景列表页
|
||||
- `ExecutionMonitorPage` - 执行监控页
|
||||
- `TemplateGalleryPage` - 模板库页面
|
||||
|
||||
### 6. 路由配置 (`src/router/`)
|
||||
|
||||
**功能职责**:
|
||||
- 模块内部路由定义
|
||||
- 页面导航管理
|
||||
- 路由参数传递
|
||||
- 导航守卫设置
|
||||
|
||||
### 7. 工具类 (`src/util/`)
|
||||
|
||||
**功能职责**:
|
||||
- 编排逻辑工具
|
||||
- 数据处理辅助
|
||||
- 文件操作工具
|
||||
- 加密解密工具
|
||||
|
||||
**主要工具**:
|
||||
- `SceneBuilder` - 场景构建器
|
||||
- `ExecutionEngine` - 执行引擎
|
||||
- `DataConverter` - 数据转换器
|
||||
- `FileManager` - 文件管理器
|
||||
|
||||
### 8. 自定义组件 (`src/widgets/`)
|
||||
|
||||
**功能职责**:
|
||||
- 编排专用UI组件
|
||||
- 可视化编辑组件
|
||||
- 交互控制组件
|
||||
- 状态展示组件
|
||||
|
||||
**主要组件**:
|
||||
- `FlowChart` - 流程图组件
|
||||
- `NodeEditor` - 节点编辑器
|
||||
- `ConditionBuilder` - 条件构建器
|
||||
- `ExecutionProgress` - 执行进度组件
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 场景编排流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[创建场景] --> B[选择模板]
|
||||
B --> C[添加操作节点]
|
||||
C --> D[设置节点参数]
|
||||
D --> E[配置触发条件]
|
||||
E --> F[连接节点关系]
|
||||
F --> G[预览场景流程]
|
||||
G --> H{验证是否通过}
|
||||
H -->|是| I[保存场景]
|
||||
H -->|否| J[修正错误]
|
||||
J --> F
|
||||
I --> K[场景测试]
|
||||
K --> L{测试是否通过}
|
||||
L -->|是| M[发布场景]
|
||||
L -->|否| N[调试修改]
|
||||
N --> G
|
||||
```
|
||||
|
||||
### 场景执行流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[触发场景] --> B[验证执行条件]
|
||||
B --> C{条件是否满足}
|
||||
C -->|是| D[开始执行]
|
||||
C -->|否| E[等待或跳过]
|
||||
D --> F[执行当前节点]
|
||||
F --> G[检查执行结果]
|
||||
G --> H{是否成功}
|
||||
H -->|是| I[执行下一节点]
|
||||
H -->|否| J[执行错误处理]
|
||||
J --> K{是否继续}
|
||||
K -->|是| I
|
||||
K -->|否| L[终止执行]
|
||||
I --> M{是否还有节点}
|
||||
M -->|是| F
|
||||
M -->|否| N[执行完成]
|
||||
E --> O[记录日志]
|
||||
L --> O
|
||||
N --> O
|
||||
```
|
||||
|
||||
## 编排引擎设计
|
||||
|
||||
### 节点类型
|
||||
1. **控制节点**
|
||||
- 车辆解锁/上锁
|
||||
- 车窗控制
|
||||
- 空调控制
|
||||
- 灯光控制
|
||||
|
||||
2. **条件节点**
|
||||
- 时间条件
|
||||
- 位置条件
|
||||
- 状态条件
|
||||
- 传感器条件
|
||||
|
||||
3. **逻辑节点**
|
||||
- 分支判断
|
||||
- 循环控制
|
||||
- 延时等待
|
||||
- 并行执行
|
||||
|
||||
4. **通知节点**
|
||||
- 推送通知
|
||||
- 短信通知
|
||||
- 邮件通知
|
||||
- 语音提醒
|
||||
|
||||
### 执行策略
|
||||
- **串行执行**: 按顺序逐个执行
|
||||
- **并行执行**: 同时执行多个操作
|
||||
- **条件执行**: 基于条件判断执行
|
||||
- **循环执行**: 重复执行指定次数
|
||||
|
||||
## 安全特性
|
||||
|
||||
### 权限控制
|
||||
- 操作权限验证
|
||||
- 用户身份认证
|
||||
- 设备授权检查
|
||||
- 场景访问控制
|
||||
|
||||
### 数据安全
|
||||
- 场景数据加密
|
||||
- 执行日志保护
|
||||
- 敏感信息脱敏
|
||||
- 数据传输安全
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 执行优化
|
||||
- 节点缓存机制
|
||||
- 批量操作优化
|
||||
- 异步执行策略
|
||||
- 资源复用设计
|
||||
|
||||
### 内存管理
|
||||
- 场景数据懒加载
|
||||
- 执行上下文管理
|
||||
- 内存泄漏防护
|
||||
- 大场景分片处理
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 插件化架构
|
||||
- 自定义节点插件
|
||||
- 第三方服务集成
|
||||
- 扩展操作类型
|
||||
- 自定义触发器
|
||||
|
||||
### 模板系统
|
||||
- 预设场景模板
|
||||
- 用户自定义模板
|
||||
- 模板分享机制
|
||||
- 模板版本管理
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- 节点逻辑测试
|
||||
- 执行引擎测试
|
||||
- 数据模型测试
|
||||
- 工具类测试
|
||||
|
||||
### 集成测试
|
||||
- 场景执行测试
|
||||
- 服务集成测试
|
||||
- 数据流测试
|
||||
- 权限流程测试
|
||||
|
||||
### 场景测试
|
||||
- 复杂场景测试
|
||||
- 异常场景测试
|
||||
- 性能压力测试
|
||||
- 用户体验测试
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 配置管理
|
||||
- 环境配置分离
|
||||
- 功能开关控制
|
||||
- 性能参数调优
|
||||
- 错误恢复策略
|
||||
|
||||
### 监控指标
|
||||
- 场景执行成功率
|
||||
- 执行响应时间
|
||||
- 用户使用频率
|
||||
- 异常错误统计
|
||||
|
||||
## 总结
|
||||
|
||||
`app_composer` 模块作为 OneApp 的智能编排中心,为用户提供了强大的车辆功能定制能力。通过可视化的编排界面、灵活的执行引擎和丰富的节点类型,用户可以创建个性化的车辆控制场景,提升用车体验的智能化水平。模块具有良好的扩展性和可维护性,能够适应不断变化的智能车联网需求。
|
||||
423
app_car/app_maintenance.md
Normal file
423
app_car/app_maintenance.md
Normal file
@@ -0,0 +1,423 @@
|
||||
# App Maintenance - 维护保养模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_maintenance` 是 OneApp 车辆模块群中的维护保养核心模块,提供车辆保养预约管理、经销商选择、时间预约、历史记录查询等功能。该模块集成了地图服务、经销商查询、预约管理等,为用户提供完整的车辆维护保养预约体验。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_maintenance
|
||||
- **路径**: oneapp_app_car/app_maintenance/
|
||||
- **依赖**: clr_maintenance, basic_modular, basic_modular_route
|
||||
- **主要功能**: 维保预约、经销商选择、时间管理、历史记录
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
app_maintenance/
|
||||
├── lib/
|
||||
│ ├── app_maintenance.dart # 主导出文件
|
||||
│ └── src/ # 源代码目录
|
||||
│ ├── pages/ # 维护保养页面
|
||||
│ │ ├── maintenance_home_page/ # 维保信息首页
|
||||
│ │ ├── appointment_create_page/ # 创建预约页面
|
||||
│ │ ├── appointment_detail_page/ # 预约详情页面
|
||||
│ │ ├── appointment_history_page/ # 预约历史页面
|
||||
│ │ ├── dealer_select_page/ # 经销商选择页面
|
||||
│ │ ├── time_select_page/ # 时间选择页面
|
||||
│ │ └── carPlate_binding_page/ # 车牌绑定页面
|
||||
│ ├── blocs/ # 状态管理(BLoC)
|
||||
│ ├── model/ # 数据模型
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── route_dp.dart # 路由配置
|
||||
│ └── route_export.dart # 路由导出
|
||||
├── assets/ # 静态资源
|
||||
├── uml.puml/svg # UML 设计图
|
||||
├── pubspec.yaml # 依赖配置
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 核心功能模块
|
||||
|
||||
### 1. 主控制模块
|
||||
|
||||
```dart
|
||||
library app_maintenance;
|
||||
|
||||
import 'package:basic_logger/basic_logger.dart';
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'package:basic_modular_route/basic_modular_route.dart';
|
||||
|
||||
import 'src/route_export.dart';
|
||||
|
||||
export 'src/route_dp.dart';
|
||||
export 'src/route_export.dart';
|
||||
|
||||
/// 维护保养控制模块
|
||||
class MaintenanceControlModule extends Module with RouteObjProvider {
|
||||
@override
|
||||
List<ModularRoute> get routes {
|
||||
// 维保模块主页
|
||||
final RouteMeta maintenance =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keyModule);
|
||||
// 维保信息首页Route
|
||||
final RouteMeta maintenanceHome =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keyMaintenanceHome);
|
||||
// 预约详情页Route
|
||||
final RouteMeta appointmentDetail =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keyAppointmentDetail);
|
||||
// 绑定车牌页Route
|
||||
final RouteMeta bindingPlateNo =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keyBindingPlateNo);
|
||||
// 创建预约Route
|
||||
final RouteMeta createAppointment =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keyAppointmentCreate);
|
||||
// 经销商选择页Route
|
||||
final RouteMeta selectDealerList =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keySelectDealerList);
|
||||
// 选择时间页Route
|
||||
final RouteMeta selectTime =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keySelectTime);
|
||||
// 预约历史页Route
|
||||
final RouteMeta appointmentHistory = RouteCenterAPI.routeMetaBy(
|
||||
MaintenanceRouteExport.keyAppointmentHistory,
|
||||
);
|
||||
// 选择时间_更多页Route
|
||||
final RouteMeta selectTimeMore =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keySelectTimeMore);
|
||||
// 搜索经销商
|
||||
final RouteMeta searchDealerList =
|
||||
RouteCenterAPI.routeMetaBy(MaintenanceRouteExport.keySearchDealerList);
|
||||
|
||||
return [
|
||||
// 维保模块主页
|
||||
ChildRoute<dynamic>(
|
||||
maintenance.path,
|
||||
child: (_, args) => maintenance.provider(args).as(),
|
||||
),
|
||||
// 维保信息首页
|
||||
ChildRoute<dynamic>(
|
||||
maintenanceHome.path,
|
||||
child: (_, args) => maintenanceHome.provider(args).as(),
|
||||
),
|
||||
// 维保详情页
|
||||
ChildRoute<dynamic>(
|
||||
appointmentDetail.path,
|
||||
child: (_, args) => appointmentDetail.provider(args).as(),
|
||||
),
|
||||
// 车牌设置页
|
||||
ChildRoute<dynamic>(
|
||||
bindingPlateNo.path,
|
||||
child: (_, args) => bindingPlateNo.provider(args).as(),
|
||||
),
|
||||
// 创建预约页
|
||||
ChildRoute<dynamic>(
|
||||
createAppointment.path,
|
||||
child: (_, args) => createAppointment.provider(args).as(),
|
||||
),
|
||||
// 选择经销商页
|
||||
ChildRoute<dynamic>(
|
||||
selectDealerList.path,
|
||||
child: (_, args) => selectDealerList.provider(args).as(),
|
||||
),
|
||||
// 选择时间页
|
||||
ChildRoute<dynamic>(
|
||||
selectTime.path,
|
||||
child: (_, args) => selectTime.provider(args).as(),
|
||||
),
|
||||
// 预约历史页
|
||||
ChildRoute<dynamic>(
|
||||
appointmentHistory.path,
|
||||
child: (_, args) => appointmentHistory.provider(args).as(),
|
||||
),
|
||||
// 选择时间_更多页
|
||||
ChildRoute<dynamic>(
|
||||
selectTimeMore.path,
|
||||
child: (_, args) => selectTimeMore.provider(args).as(),
|
||||
),
|
||||
// 搜索经销商
|
||||
ChildRoute<dynamic>(
|
||||
searchDealerList.path,
|
||||
child: (_, args) => searchDealerList.provider(args).as(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Logger.i('AppMaintenance dispose');
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 路由导出配置
|
||||
|
||||
实际的维保模块路由配置:
|
||||
|
||||
```dart
|
||||
/// 维保页面路由
|
||||
class MaintenanceRouteExport implements RouteExporter {
|
||||
/// 模块主页
|
||||
static const String keyModule = 'maintenance';
|
||||
/// 维保首页
|
||||
static const String keyMaintenanceHome = 'maintenance.home';
|
||||
/// 详情页
|
||||
static const String keyAppointmentDetail = 'maintenance.appointmentDetail';
|
||||
/// 绑定/修改车牌页
|
||||
static const String keyBindingPlateNo = 'maintenance.bindingPlateNo';
|
||||
/// 创建维修保养页
|
||||
static const String keyAppointmentCreate = 'maintenance.appointmentCreate';
|
||||
/// 选择经销商列表页
|
||||
static const String keySelectDealerList = 'maintenance.selectDealerList';
|
||||
/// 搜索经销商列表页
|
||||
static const String keySearchDealerList = 'maintenance.keySearchDealerList';
|
||||
/// 选择时间
|
||||
static const String keySelectTime = 'maintenance.selectTime';
|
||||
/// 选择时间更多
|
||||
static const String keySelectTimeMore = 'maintenance.selectTimeMore';
|
||||
/// 预约历史
|
||||
static const String keyAppointmentHistory = 'maintenance.appointmentHistory';
|
||||
|
||||
@override
|
||||
List<RouteMeta> exportRoutes() {
|
||||
// 各种路由配置...包括维保首页、预约创建、经销商选择等
|
||||
return [r1, r2, r3, r4, r5, r6, r7, r8, r9, r10];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 维保信息首页
|
||||
|
||||
```dart
|
||||
/// 维保信息页
|
||||
class MaintenanceHomePage extends StatelessWidget with RouteObjProvider {
|
||||
/// 初始化
|
||||
/// [vin] 页面相关车辆vin码
|
||||
MaintenanceHomePage({
|
||||
required this.vin,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// vin null时请求会取默认车辆vin码
|
||||
String? vin;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocProvider(
|
||||
create: (context) =>
|
||||
MaintenanceHomeBloc()..add(const MaintenanceHomeEvent.init()),
|
||||
child: BlocConsumer<MaintenanceHomeBloc, MaintenanceHomeState>(
|
||||
builder: _buildLayout,
|
||||
listener: (context, state) {},
|
||||
),
|
||||
);
|
||||
|
||||
/// 标题栏
|
||||
CommonTitleBar titleBar(BuildContext context, MaintenanceHomeState state) =>
|
||||
CommonTitleBar(
|
||||
titleText: homePage_titleWidget_title,
|
||||
backgroundColor: OneColors.bgc,
|
||||
actions: [
|
||||
Container(
|
||||
color: OneColors.bgc,
|
||||
width: (16 * 2 + 20).w,
|
||||
child: Center(
|
||||
child: OneIcons.iconHistory(20.r),
|
||||
),
|
||||
).withOnTap(() async {
|
||||
Logger.i('点击预约历史');
|
||||
// 获取车牌
|
||||
String? plateNo;
|
||||
if (state.maintenanceDetailLast == null &&
|
||||
state.maintenanceInFoModel == null) {
|
||||
// 详情与最后一个预约记录全部为null
|
||||
plateNo = null;
|
||||
} else {
|
||||
// 预约详情车牌权重比最后一次高,因为用户可能会更新
|
||||
// 最后一个预约有车牌
|
||||
if (state.maintenanceDetailLast != null) {
|
||||
plateNo = state.maintenanceDetailLast?.plateNo;
|
||||
}
|
||||
// 预约详情有车牌
|
||||
if (state.maintenanceInFoModel != null) {
|
||||
plateNo = null;
|
||||
plateNo = state.maintenanceInFoModel?.vehicleHealth.plateNo;
|
||||
}
|
||||
}
|
||||
|
||||
// 前往历史列表页面
|
||||
final res = await Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(
|
||||
const AppointmentHistoryPageRouteKey(),
|
||||
),
|
||||
arguments: {
|
||||
// 当前是否存在预约
|
||||
'isExistAppointmen': state.isAppointment,
|
||||
// vin
|
||||
'vin': vin ??
|
||||
Modular.get<IGarageFacade>().getDefaultVehicleVin() ??
|
||||
'',
|
||||
// 车牌
|
||||
'plateNo': plateNo,
|
||||
},
|
||||
);
|
||||
// 预约历史页面返回刷新数据
|
||||
if (res is bool && res) {
|
||||
Logger.i('预约历史页面返回刷新数据');
|
||||
context
|
||||
.read<MaintenanceHomeBloc>()
|
||||
.add(const MaintenanceHomeEvent.init());
|
||||
}
|
||||
}),
|
||||
],
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 主要功能页面
|
||||
|
||||
#### 4.1 预约创建页面
|
||||
支持多种预约创建场景:
|
||||
- **安装预约** (`isInstallAppointmen`) - 从安装服务跳转创建预约
|
||||
- **创建预约** (`isCreateAppointmen`) - 普通维保预约创建
|
||||
- **再次预约** (`isAgainAppointmen`) - 基于历史记录再次预约
|
||||
- **修改预约** (`isAmendAppointmen`) - 修改现有预约信息
|
||||
|
||||
```dart
|
||||
AppointmentCreatePage(
|
||||
vin: args.data['vin'] as String?,
|
||||
isCreateAppointmen: true,
|
||||
plateNo: args.data['plateNo'] as String?,
|
||||
detailModel: args.data['model'] as MaintenanceDetailModel?,
|
||||
);
|
||||
```
|
||||
|
||||
#### 4.2 经销商选择页面
|
||||
- **经销商列表页** (`DealerSelectListPage`) - 显示附近经销商列表
|
||||
- **经销商搜索页** (`DealerSearchListPage`) - 支持按地理位置搜索经销商
|
||||
|
||||
#### 4.3 时间选择页面
|
||||
- **时间选择页** (`TimeSelectPage`) - 选择预约时间段
|
||||
- **时间选择更多页** (`TimeSelectMorePage`) - 更多可选时间段展示
|
||||
|
||||
#### 4.4 预约管理页面
|
||||
- **预约详情页** (`AppointmentDetailPage`) - 查看预约详细信息
|
||||
- **预约历史页** (`AppointmentHistoryPage`) - 历史预约记录管理
|
||||
- **车牌绑定页** (`LicensePlatePage`) - 车牌号码设置和修改
|
||||
|
||||
### 5. 核心功能特性
|
||||
|
||||
#### 5.1 预约流程管理
|
||||
- 支持根据VIN码和车牌号创建预约
|
||||
- 提供预约修改、再次预约等功能
|
||||
- 集成经销商信息和时间选择功能
|
||||
- 支持预约历史记录查询
|
||||
|
||||
#### 5.2 经销商服务
|
||||
- 基于地理位置的经销商推荐
|
||||
- 经销商详细信息展示(联系方式、地址等)
|
||||
- 支持经销商搜索和筛选功能
|
||||
|
||||
#### 5.3 时间预约系统
|
||||
- 经销商可用时间段查询
|
||||
- 支持多时间段选择
|
||||
- 提供更多时间选项扩展功能
|
||||
|
||||
```dart
|
||||
// 导航到维保首页
|
||||
Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(MaintenanceRouteExport.keyMaintenanceHome),
|
||||
arguments: {
|
||||
'vin': vehicleVin, // 车辆VIN码
|
||||
},
|
||||
);
|
||||
|
||||
// 创建新预约
|
||||
Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(MaintenanceRouteExport.keyAppointmentCreate),
|
||||
arguments: {
|
||||
'isCreateAppointmen': true,
|
||||
'vin': vehicleVin,
|
||||
'plateNo': plateNumber,
|
||||
'model': previousDetailModel, // 携带上一次预约信息
|
||||
},
|
||||
);
|
||||
|
||||
// 修改现有预约
|
||||
Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(MaintenanceRouteExport.keyAppointmentCreate),
|
||||
arguments: {
|
||||
'isAmendAppointmen': true,
|
||||
'plateNo': plateNumber,
|
||||
'model': currentDetailModel,
|
||||
},
|
||||
);
|
||||
|
||||
// 查看预约详情
|
||||
Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(MaintenanceRouteExport.keyAppointmentDetail),
|
||||
arguments: {
|
||||
'number': appointmentNumber,
|
||||
'vin': vehicleVin,
|
||||
'isExistAppointmen': true,
|
||||
'model': detailModel,
|
||||
},
|
||||
);
|
||||
|
||||
// 选择经销商
|
||||
Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(MaintenanceRouteExport.keySelectDealerList),
|
||||
);
|
||||
|
||||
// 选择预约时间
|
||||
Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(MaintenanceRouteExport.keySelectTime),
|
||||
arguments: {
|
||||
'dealerCode': selectedDealerCode,
|
||||
},
|
||||
);
|
||||
|
||||
// 查看预约历史
|
||||
Modular.to.pushNamed(
|
||||
RouteCenterAPI.getRoutePathBy(MaintenanceRouteExport.keyAppointmentHistory),
|
||||
arguments: {
|
||||
'tabKey': 'hasAppointment', // 或 'noAppointment'
|
||||
'plateNo': plateNumber,
|
||||
},
|
||||
);
|
||||
|
||||
// 安装服务预约(deeplink支持)
|
||||
// oneapp://dssomobile/launch?routePath=/maintenance/createAppointment&isInstallAppointmen=1&vin=$vin&dealer=$dealer&dealerCode=$dealerCode&dealerPhone=$dealerPhone
|
||||
```
|
||||
|
||||
## 依赖关系
|
||||
|
||||
该模块依赖以下包:
|
||||
- `clr_maintenance` - 维保业务逻辑核心
|
||||
- `basic_modular` - 模块化架构支持
|
||||
- `basic_modular_route` - 路由管理
|
||||
- `basic_logger` - 日志记录
|
||||
- `basic_intl` - 国际化支持
|
||||
- `basic_track` - 埋点追踪
|
||||
- `clr_account` - 账户管理
|
||||
- `ui_basic` - 基础UI组件
|
||||
- `app_car` - 车辆相关功能
|
||||
|
||||
## 总结
|
||||
|
||||
app_maintenance 模块是 OneApp 维保功能的核心实现,提供了完整的维保预约管理体验:
|
||||
|
||||
### 主要特性
|
||||
1. **多场景预约支持** - 支持创建预约、修改预约、再次预约、安装服务预约等多种业务场景
|
||||
2. **完整预约流程** - 从经销商选择到时间预约的完整用户体验
|
||||
3. **历史记录管理** - 提供预约历史查询和管理功能
|
||||
4. **车辆信息管理** - 支持车牌绑定和车辆信息管理
|
||||
5. **地理位置集成** - 基于位置的经销商推荐和搜索功能
|
||||
|
||||
### 技术架构
|
||||
- **BLoC状态管理** - 使用BLoC模式管理复杂的预约业务状态
|
||||
- **模块化路由** - 采用基于路由中心的模块化架构设计
|
||||
- **参数传递机制** - 灵活的路由参数传递支持各种业务场景
|
||||
- **业务逻辑分离** - 依赖clr_maintenance提供核心业务逻辑
|
||||
|
||||
### 业务价值
|
||||
该模块通过标准化的维保预约流程,为用户提供便捷的维保服务体验,同时支持经销商管理和时间调度等复杂业务需求。
|
||||
597
app_car/app_order.md
Normal file
597
app_car/app_order.md
Normal file
@@ -0,0 +1,597 @@
|
||||
# App Order - 订单管理模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_order` 是 OneApp 车辆模块群中的订单管理核心模块,提供完整的订单生命周期管理,包括订单详情查看、发票管理、退款处理、订单历史等功能。该模块与支付系统、账户系统深度集成,为用户提供统一的订单管理体验。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_order
|
||||
- **路径**: oneapp_app_car/app_order/
|
||||
- **依赖**: clr_order, basic_modular, basic_modular_route, ui_basic
|
||||
- **主要功能**: 订单详情、发票管理、退款处理、订单中心
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
app_order/
|
||||
├── lib/
|
||||
│ ├── app_order.dart # 主导出文件
|
||||
│ └── src/ # 源代码目录
|
||||
│ ├── pages/ # 订单页面
|
||||
│ │ ├── order_center_page.dart # 订单中心页面
|
||||
│ │ ├── orderdetail/ # 订单详情页面
|
||||
│ │ ├── orderlist/ # 订单列表页面
|
||||
│ │ ├── invoice/ # 发票相关页面
|
||||
│ │ │ ├── invoiceChooseManagePage/ # 发票选择管理
|
||||
│ │ │ ├── invoiceDetailsPage/ # 发票详情
|
||||
│ │ │ ├── invoiceHistoryCenterPage/ # 发票历史
|
||||
│ │ │ └── ... # 其他发票功能
|
||||
│ │ └── refunddetail/ # 退款详情页面
|
||||
│ ├── bloc/ # 状态管理(BLoC)
|
||||
│ ├── models/ # 数据模型
|
||||
│ ├── utils/ # 工具类
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── order_module.dart # 订单模块配置
|
||||
│ ├── route_dp.dart # 路由配置
|
||||
│ └── route_export.dart # 路由导出
|
||||
├── assets/ # 静态资源
|
||||
├── uml.puml/png/svg # UML 设计图
|
||||
├── pubspec.yaml # 依赖配置
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 核心功能模块
|
||||
|
||||
### 1. 主导出模块
|
||||
|
||||
**文件**: `lib/app_order.dart`
|
||||
|
||||
```dart
|
||||
library app_order;
|
||||
|
||||
// 页面导出
|
||||
export 'src/pages/order_center_page.dart';
|
||||
export 'src/pages/orderdetail/orderdetail_page.dart';
|
||||
export 'src/pages/orderlist/orderlist_page.dart';
|
||||
export 'src/pages/invoice/invoiceChooseManagePage/invoiceChooseManage_page.dart';
|
||||
export 'src/pages/invoice/invoiceDetailsPage/invoiceDetails_page.dart';
|
||||
export 'src/pages/invoice/invoiceHistoryCenterPage/invoiceHistoryCenter_page.dart';
|
||||
export 'src/pages/refunddetail/refunddetail_page.dart';
|
||||
|
||||
// 模块配置导出
|
||||
export 'src/order_module.dart';
|
||||
export 'src/route_dp.dart';
|
||||
export 'src/route_export.dart';
|
||||
```
|
||||
|
||||
### 2. 订单模块配置
|
||||
|
||||
**文件**: `src/order_module.dart`
|
||||
|
||||
```dart
|
||||
import 'package:basic_modular/basic_modular.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'route_dp.dart';
|
||||
|
||||
/// App Order 模块定义
|
||||
class AppOrderModule extends Module {
|
||||
@override
|
||||
String get name => "app_order";
|
||||
|
||||
@override
|
||||
List<Bind> get binds => [];
|
||||
|
||||
@override
|
||||
List<ModularRoute> get routes => OrderRouteController.routes;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 路由导出管理
|
||||
|
||||
**文件**: `src/route_export.dart`
|
||||
|
||||
```dart
|
||||
import 'package:basic_modular_route/basic_modular_route.dart';
|
||||
|
||||
class AppOrderRouteExport {
|
||||
/// 订单中心路径
|
||||
static const String orderCenter = "/order-center";
|
||||
|
||||
/// 订单详情路径
|
||||
static const String orderDetail = "/order-detail";
|
||||
|
||||
/// 订单列表路径
|
||||
static const String orderList = "/order-list";
|
||||
|
||||
/// 发票管理路径
|
||||
static const String invoiceManage = "/invoice-manage";
|
||||
|
||||
/// 发票详情路径
|
||||
static const String invoiceDetail = "/invoice-detail";
|
||||
|
||||
/// 发票历史中心路径
|
||||
static const String invoiceHistoryCenter = "/invoice-history-center";
|
||||
|
||||
/// 退款详情路径
|
||||
static const String refundDetail = "/refund-detail";
|
||||
|
||||
/// 跳转到订单中心
|
||||
static Future<T?> gotoOrderCenter<T extends Object?>(
|
||||
ModularRouteInformation information,
|
||||
) {
|
||||
return information.pushNamed<T>(orderCenter);
|
||||
}
|
||||
|
||||
/// 跳转到订单详情
|
||||
static Future<T?> gotoOrderDetail<T extends Object?>(
|
||||
ModularRouteInformation information, {
|
||||
required String orderId,
|
||||
}) {
|
||||
return information.pushNamed<T>(
|
||||
orderDetail,
|
||||
arguments: {'orderId': orderId},
|
||||
);
|
||||
}
|
||||
|
||||
/// 跳转到发票管理页面
|
||||
static Future<T?> gotoInvoiceManage<T extends Object?>(
|
||||
ModularRouteInformation information,
|
||||
) {
|
||||
return information.pushNamed<T>(invoiceManage);
|
||||
}
|
||||
|
||||
/// 跳转到发票详情页面
|
||||
static Future<T?> gotoInvoiceDetail<T extends Object?>(
|
||||
ModularRouteInformation information, {
|
||||
required String invoiceId,
|
||||
}) {
|
||||
return information.pushNamed<T>(
|
||||
invoiceDetail,
|
||||
arguments: {'invoiceId': invoiceId},
|
||||
);
|
||||
}
|
||||
|
||||
/// 跳转到退款详情页面
|
||||
static Future<T?> gotoRefundDetail<T extends Object?>(
|
||||
ModularRouteInformation information, {
|
||||
required String refundId,
|
||||
}) {
|
||||
return information.pushNamed<T>(
|
||||
refundDetail,
|
||||
arguments: {'refundId': refundId},
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 订单中心页面
|
||||
|
||||
**文件**: `src/pages/order_center_page.dart`
|
||||
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:basic_modular_route/basic_modular_route.dart';
|
||||
import 'package:ui_basic/ui_basic.dart';
|
||||
import '../bloc/order_center_bloc.dart';
|
||||
|
||||
class OrderCenterPage extends StatefulWidget {
|
||||
@override
|
||||
_OrderCenterPageState createState() => _OrderCenterPageState();
|
||||
}
|
||||
|
||||
class _OrderCenterPageState extends State<OrderCenterPage>
|
||||
with TickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
int _currentIndex = 0;
|
||||
|
||||
final List<String> _tabTitles = [
|
||||
'全部订单',
|
||||
'待付款',
|
||||
'已付款',
|
||||
'已完成',
|
||||
'已取消',
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_tabController = TabController(
|
||||
length: _tabTitles.length,
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_tabController.addListener(() {
|
||||
if (!_tabController.indexIsChanging) {
|
||||
setState(() {
|
||||
_currentIndex = _tabController.index;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('订单中心'),
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0.5,
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
tabs: _tabTitles.map((title) => Tab(text: title)).toList(),
|
||||
indicatorColor: Theme.of(context).primaryColor,
|
||||
labelColor: Theme.of(context).primaryColor,
|
||||
unselectedLabelColor: Colors.grey,
|
||||
isScrollable: false,
|
||||
),
|
||||
),
|
||||
body: TabBarView(
|
||||
controller: _tabController,
|
||||
children: _tabTitles.map((title) => _buildOrderList(title)).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOrderList(String tabTitle) {
|
||||
return Container(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
// 刷新订单列表
|
||||
await _refreshOrderList(tabTitle);
|
||||
},
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.all(16),
|
||||
itemBuilder: (context, index) => _buildOrderCard(index),
|
||||
itemCount: 10, // 示例数量
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOrderCard(int index) {
|
||||
return Card(
|
||||
margin: EdgeInsets.only(bottom: 12),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'订单号:20231201${(index + 1000)}',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'已付款',
|
||||
style: TextStyle(
|
||||
color: Colors.green,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'服务内容:车辆充电服务',
|
||||
style: TextStyle(color: Colors.grey[600]),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'金额:¥${(index * 50 + 100)}.00',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'下单时间:2023-12-0${index % 9 + 1} 14:30',
|
||||
style: TextStyle(
|
||||
color: Colors.grey[500],
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () => _viewOrderDetail(index),
|
||||
child: Text('查看详情'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => _manageInvoice(index),
|
||||
child: Text('发票管理'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _refreshOrderList(String tabTitle) async {
|
||||
// 模拟刷新延时
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
}
|
||||
|
||||
void _viewOrderDetail(int index) {
|
||||
ModularRouteInformation.of(context).pushNamed('/order-detail',
|
||||
arguments: {'orderId': '20231201${(index + 1000)}'});
|
||||
}
|
||||
|
||||
void _manageInvoice(int index) {
|
||||
ModularRouteInformation.of(context).pushNamed('/invoice-manage',
|
||||
arguments: {'orderId': '20231201${(index + 1000)}'});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 路由配置系统
|
||||
|
||||
**文件**: `src/route_dp.dart`
|
||||
|
||||
```dart
|
||||
import 'package:basic_modular/modular.dart';
|
||||
import 'route_export.dart';
|
||||
|
||||
/// 订单中心页面路由key
|
||||
class OrderCenterRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const OrderCenterRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyOrderCenter;
|
||||
}
|
||||
|
||||
/// 订单详情页面路由key
|
||||
class OrderDetailRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const OrderDetailRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyOrderDetail;
|
||||
}
|
||||
|
||||
/// 订单退款详情页面路由key
|
||||
class RefundDetailRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const RefundDetailRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyRefundDetail;
|
||||
}
|
||||
|
||||
/// 发票抬头选择管理页路由key
|
||||
class InvoiceTitleCMRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const InvoiceTitleCMRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyInvoiceCM;
|
||||
}
|
||||
|
||||
/// 开具发票抬头提交页/发票抬头详情页
|
||||
class InvoiceTitleDetailsRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const InvoiceTitleDetailsRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyInvoiceTitleDetails;
|
||||
}
|
||||
|
||||
/// 发票历史
|
||||
class InvoiceHistoryRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const InvoiceHistoryRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyInvoiceHistory;
|
||||
}
|
||||
|
||||
/// 发票详情页
|
||||
class InvoiceDetailsRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const InvoiceDetailsRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyInvoiceDetails;
|
||||
}
|
||||
|
||||
/// 可开发票列表页
|
||||
class OpenInvoiceOrderChooseRouteKey implements RouteKey {
|
||||
/// 默认构造器
|
||||
const OpenInvoiceOrderChooseRouteKey();
|
||||
|
||||
@override
|
||||
String get routeKey => AppOrderRouteExport.keyOpneInvoiceOrderChoose;
|
||||
}
|
||||
```
|
||||
|
||||
## 实际项目集成
|
||||
|
||||
### 依赖配置
|
||||
|
||||
**文件**: `pubspec.yaml`
|
||||
|
||||
```yaml
|
||||
name: app_order
|
||||
description: OneApp 订单管理模块
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
# 基础依赖
|
||||
basic_modular:
|
||||
path: ../../oneapp_basic_utils/base_mvvm
|
||||
basic_modular_route:
|
||||
path: ../../oneapp_basic_utils/basic_modular_route
|
||||
ui_basic:
|
||||
path: ../../oneapp_basic_uis/ui_basic
|
||||
|
||||
# 订单核心依赖
|
||||
clr_order:
|
||||
path: ../clr_order
|
||||
|
||||
# 其他依赖
|
||||
flutter_bloc: ^8.1.3
|
||||
equatable: ^2.0.5
|
||||
dio: ^5.3.2
|
||||
cached_network_image: ^3.3.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/images/
|
||||
- assets/icons/
|
||||
```
|
||||
|
||||
### 模块集成流程
|
||||
|
||||
#### 1. 模块注册
|
||||
|
||||
在主应用中注册订单模块:
|
||||
|
||||
```dart
|
||||
// main_app 集成代码
|
||||
import 'package:app_order/app_order.dart';
|
||||
|
||||
void setupOrderModule() {
|
||||
// 注册订单模块
|
||||
Modular.bindModule(AppOrderModule());
|
||||
|
||||
// 配置路由
|
||||
Get.routing.add(
|
||||
AppOrderRouteExport.keyOrderCenter,
|
||||
page: () => OrderCenterPage(),
|
||||
binding: OrderCenterBinding(),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 功能特性
|
||||
|
||||
- **多状态订单管理**: 支持待付款、已付款、已完成、已取消等多种状态
|
||||
- **发票系统集成**: 完整的发票申请、管理、历史查看功能
|
||||
- **退款处理**: 订单退款申请和详情查看
|
||||
- **实时状态更新**: TabController 实现的多 Tab 订单分类浏览
|
||||
- **响应式设计**: 支持刷新和分页加载的订单列表
|
||||
- **模块化架构**: 基于 basic_modular 的标准化模块设计
|
||||
|
||||
#### 3. 与其他模块的集成
|
||||
|
||||
```dart
|
||||
// 与其他车辆服务模块的集成示例
|
||||
class OrderIntegrationService {
|
||||
// 从充电模块创建订单
|
||||
Future<void> createChargingOrder(ChargingSession session) async {
|
||||
await AppOrderRouteExport.gotoOrderCenter(
|
||||
ModularRouteInformation.current(),
|
||||
);
|
||||
}
|
||||
|
||||
// 从维保模块创建订单
|
||||
Future<void> createMaintenanceOrder(MaintenanceAppointment appointment) async {
|
||||
await AppOrderRouteExport.gotoOrderDetail(
|
||||
ModularRouteInformation.current(),
|
||||
orderId: appointment.orderId,
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 技术架构与设计模式
|
||||
|
||||
### 1. 模块化架构
|
||||
|
||||
app_order 模块采用标准的 OneApp 模块化架构:
|
||||
|
||||
- **模块定义**: `AppOrderModule` 继承自 `basic_modular.Module`
|
||||
- **路由管理**: 通过 `AppOrderRouteExport` 统一管理所有路由
|
||||
- **依赖注入**: 使用 basic_modular 的依赖注入机制
|
||||
- **状态管理**: 基于 BLoC 模式的响应式状态管理
|
||||
|
||||
### 2. 核心功能实现
|
||||
|
||||
#### 订单中心页面特性
|
||||
- **TabController**: 5个标签页(全部、待付款、已付款、已完成、已取消)
|
||||
- **响应式设计**: 支持下拉刷新的 RefreshIndicator
|
||||
- **卡片列表**: 每个订单展示为 Card 组件
|
||||
- **导航集成**: 与订单详情页和发票管理页面的路由跳转
|
||||
|
||||
#### 发票管理系统
|
||||
- **发票选择管理**: `invoiceChooseManagePage`
|
||||
- **发票详情页面**: `invoiceDetailsPage`
|
||||
- **发票历史中心**: `invoiceHistoryCenterPage`
|
||||
- **发票抬头管理**: 支持个人和企业发票抬头
|
||||
|
||||
#### 退款处理流程
|
||||
- **退款详情页**: `refunddetail_page.dart`
|
||||
- **退款状态跟踪**: 支持退款进度查看
|
||||
- **退款原因记录**: 详细的退款申请理由
|
||||
|
||||
### 3. 与其他模块集成
|
||||
|
||||
```dart
|
||||
// 集成示例 - 从其他模块跳转到订单相关页面
|
||||
class OrderNavigationHelper {
|
||||
// 从充电模块跳转到订单中心
|
||||
static void gotoOrderCenterFromCharging() {
|
||||
AppOrderRouteExport.gotoOrderCenter(
|
||||
ModularRouteInformation.current(),
|
||||
);
|
||||
}
|
||||
|
||||
// 从维保模块跳转到具体订单详情
|
||||
static void gotoOrderDetailFromMaintenance(String orderId) {
|
||||
AppOrderRouteExport.gotoOrderDetail(
|
||||
ModularRouteInformation.current(),
|
||||
orderId: orderId,
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践与规范
|
||||
|
||||
### 1. 代码组织
|
||||
- 页面文件统一放在 `src/pages/` 目录
|
||||
- 按功能模块分别组织(订单、发票、退款)
|
||||
- 共享组件复用,减少代码重复
|
||||
|
||||
### 2. 状态管理
|
||||
- 采用 BLoC 模式管理复杂状态
|
||||
- TabController 管理标签页切换状态
|
||||
- RefreshIndicator 处理列表刷新状态
|
||||
|
||||
### 3. 用户体验优化
|
||||
- 支持下拉刷新和上拉加载
|
||||
- 响应式布局适配不同屏幕尺寸
|
||||
- 错误状态友好提示
|
||||
|
||||
### 4. 性能优化
|
||||
- 列表项懒加载,避免一次性加载过多数据
|
||||
- 图片缓存和占位符处理
|
||||
- 合理的状态更新频率控制
|
||||
350
app_car/app_rpa.md
Normal file
350
app_car/app_rpa.md
Normal file
@@ -0,0 +1,350 @@
|
||||
# App RPA 自动化模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_rpa` 是 OneApp 车联网生态中的 RPA(Robotic Process Automation)自动化模块,负责车辆操作的自动化流程、智能任务调度、批量操作处理等功能。该模块通过自动化技术提升用户的车辆管理效率,减少重复性操作。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_rpa
|
||||
- **版本**: 0.1.7
|
||||
- **描述**: RPA自动化应用模块
|
||||
- **Flutter 版本**: >=2.10.5
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **自动化任务**
|
||||
- 定时任务调度
|
||||
- 批量操作执行
|
||||
- 条件触发自动化
|
||||
- 智能任务优化
|
||||
|
||||
2. **流程自动化**
|
||||
- 车辆状态自动检查
|
||||
- 维护提醒自动化
|
||||
- 数据同步自动化
|
||||
- 报告生成自动化
|
||||
|
||||
3. **智能调度**
|
||||
- 任务优先级管理
|
||||
- 资源冲突解决
|
||||
- 执行时间优化
|
||||
- 失败重试机制
|
||||
|
||||
4. **监控管理**
|
||||
- 任务执行监控
|
||||
- 性能指标统计
|
||||
- 异常告警处理
|
||||
- 日志记录分析
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── app_rpa.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── automation/ # 自动化引擎
|
||||
│ ├── scheduler/ # 任务调度器
|
||||
│ ├── tasks/ # 任务定义
|
||||
│ ├── monitors/ # 监控组件
|
||||
│ ├── pages/ # 页面组件
|
||||
│ ├── models/ # 数据模型
|
||||
│ └── utils/ # 工具类
|
||||
├── generated/ # 代码生成文件
|
||||
└── l10n/ # 国际化文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `basic_modular: ^0.2.3` - 模块化框架
|
||||
- `basic_modular_route: ^0.2.1` - 路由管理
|
||||
- `basic_intl: ^0.2.0` - 国际化支持
|
||||
- `basic_theme: ^0.2.5` - 主题系统
|
||||
- `basic_track: ^0.1.3` - 数据埋点
|
||||
|
||||
#### 业务依赖
|
||||
- `car_rpa: ^0.1.5` - RPA服务SDK
|
||||
- `location_service_check: ^1.0.1` - 位置服务检查
|
||||
- `amap_flutter_location: ^3.0.3` - 高德定位服务
|
||||
|
||||
#### 第三方依赖
|
||||
- `json_annotation: ^4.8.1` - JSON序列化
|
||||
- `dartz: ^0.10.1` - 函数式编程
|
||||
- `shared_preferences: ^2.2.2` - 本地存储
|
||||
- `flutter_constraintlayout: ^1.7.0-stable` - 约束布局
|
||||
- `url_launcher: ^6.1.11` - URL启动
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`app_rpa.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 模块对外接口统一导出
|
||||
- RPA服务初始化
|
||||
- 自动化引擎启动
|
||||
|
||||
### 2. 自动化引擎 (`src/automation/`)
|
||||
|
||||
**功能职责**:
|
||||
- 自动化任务执行引擎
|
||||
- 流程控制逻辑
|
||||
- 条件判断处理
|
||||
- 异常恢复机制
|
||||
|
||||
**主要组件**:
|
||||
- `AutomationEngine` - 自动化引擎核心
|
||||
- `ProcessController` - 流程控制器
|
||||
- `ConditionEvaluator` - 条件评估器
|
||||
- `ErrorHandler` - 错误处理器
|
||||
|
||||
### 3. 任务调度器 (`src/scheduler/`)
|
||||
|
||||
**功能职责**:
|
||||
- 任务时间调度
|
||||
- 优先级队列管理
|
||||
- 资源分配控制
|
||||
- 并发执行协调
|
||||
|
||||
**主要组件**:
|
||||
- `TaskScheduler` - 任务调度器
|
||||
- `PriorityQueue` - 优先级队列
|
||||
- `ResourceManager` - 资源管理器
|
||||
- `ConcurrencyController` - 并发控制器
|
||||
|
||||
### 4. 任务定义 (`src/tasks/`)
|
||||
|
||||
**功能职责**:
|
||||
- 预定义任务模板
|
||||
- 自定义任务创建
|
||||
- 任务参数配置
|
||||
- 任务生命周期管理
|
||||
|
||||
**主要任务类型**:
|
||||
- `VehicleCheckTask` - 车辆状态检查任务
|
||||
- `MaintenanceReminderTask` - 维护提醒任务
|
||||
- `DataSyncTask` - 数据同步任务
|
||||
- `ReportGenerationTask` - 报告生成任务
|
||||
|
||||
### 5. 监控组件 (`src/monitors/`)
|
||||
|
||||
**功能职责**:
|
||||
- 任务执行监控
|
||||
- 性能指标收集
|
||||
- 异常检测告警
|
||||
- 统计数据分析
|
||||
|
||||
**主要监控器**:
|
||||
- `ExecutionMonitor` - 执行监控器
|
||||
- `PerformanceMonitor` - 性能监控器
|
||||
- `ExceptionMonitor` - 异常监控器
|
||||
- `StatisticsCollector` - 统计收集器
|
||||
|
||||
### 6. 页面组件 (`src/pages/`)
|
||||
|
||||
**功能职责**:
|
||||
- 用户界面展示
|
||||
- 任务管理界面
|
||||
- 监控仪表板
|
||||
- 配置设置页面
|
||||
|
||||
**主要页面**:
|
||||
- `RPAHomePage` - RPA主页
|
||||
- `TaskManagementPage` - 任务管理页
|
||||
- `MonitorDashboardPage` - 监控仪表板
|
||||
- `AutomationConfigPage` - 自动化配置页
|
||||
|
||||
### 7. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 任务数据模型
|
||||
- 执行结果模型
|
||||
- 配置参数模型
|
||||
- 统计数据模型
|
||||
|
||||
**主要模型**:
|
||||
- `Task` - 任务模型
|
||||
- `ExecutionResult` - 执行结果模型
|
||||
- `AutomationConfig` - 自动化配置模型
|
||||
- `MonitoringData` - 监控数据模型
|
||||
|
||||
### 8. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- RPA工具方法
|
||||
- 数据处理辅助
|
||||
- 时间计算工具
|
||||
- 配置解析工具
|
||||
|
||||
**主要工具**:
|
||||
- `TaskBuilder` - 任务构建器
|
||||
- `CronParser` - 定时表达式解析器
|
||||
- `DataProcessor` - 数据处理器
|
||||
- `ConfigValidator` - 配置验证器
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 任务调度流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[创建任务] --> B[任务验证]
|
||||
B --> C{验证是否通过}
|
||||
C -->|是| D[添加到调度队列]
|
||||
C -->|否| E[返回错误信息]
|
||||
D --> F[等待调度执行]
|
||||
F --> G[检查执行条件]
|
||||
G --> H{条件是否满足}
|
||||
H -->|是| I[开始执行任务]
|
||||
H -->|否| J[延迟或跳过]
|
||||
I --> K[监控执行过程]
|
||||
K --> L{执行是否成功}
|
||||
L -->|是| M[记录成功结果]
|
||||
L -->|否| N[执行重试逻辑]
|
||||
N --> O{重试次数是否超限}
|
||||
O -->|是| P[标记为失败]
|
||||
O -->|否| I
|
||||
J --> Q[更新任务状态]
|
||||
M --> Q
|
||||
P --> Q
|
||||
Q --> R[通知结果]
|
||||
```
|
||||
|
||||
### 自动化执行流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[触发自动化] --> B[加载任务配置]
|
||||
B --> C[初始化执行环境]
|
||||
C --> D[开始执行步骤]
|
||||
D --> E[执行当前步骤]
|
||||
E --> F[检查步骤结果]
|
||||
F --> G{是否成功}
|
||||
G -->|是| H[执行下一步骤]
|
||||
G -->|否| I[执行错误处理]
|
||||
I --> J{是否可恢复}
|
||||
J -->|是| K[尝试恢复]
|
||||
J -->|否| L[终止执行]
|
||||
K --> M{恢复是否成功}
|
||||
M -->|是| H
|
||||
M -->|否| L
|
||||
H --> N{是否还有步骤}
|
||||
N -->|是| E
|
||||
N -->|否| O[执行完成]
|
||||
L --> P[清理资源]
|
||||
O --> P
|
||||
P --> Q[生成执行报告]
|
||||
```
|
||||
|
||||
## RPA引擎设计
|
||||
|
||||
### 任务类型
|
||||
1. **定时任务**
|
||||
- 周期性检查任务
|
||||
- 定时报告生成
|
||||
- 数据备份任务
|
||||
- 清理维护任务
|
||||
|
||||
2. **事件驱动任务**
|
||||
- 状态变化触发
|
||||
- 异常检测触发
|
||||
- 用户操作触发
|
||||
- 外部系统触发
|
||||
|
||||
3. **条件任务**
|
||||
- 基于位置的任务
|
||||
- 基于时间的任务
|
||||
- 基于状态的任务
|
||||
- 基于数据的任务
|
||||
|
||||
4. **流程任务**
|
||||
- 多步骤流程
|
||||
- 分支判断流程
|
||||
- 循环执行流程
|
||||
- 并行处理流程
|
||||
|
||||
### 执行策略
|
||||
- **立即执行**: 任务创建后立即执行
|
||||
- **延迟执行**: 指定时间后执行
|
||||
- **周期执行**: 按周期重复执行
|
||||
- **条件执行**: 满足条件时执行
|
||||
|
||||
## 安全特性
|
||||
|
||||
### 权限控制
|
||||
- 任务执行权限验证
|
||||
- 敏感操作授权检查
|
||||
- 用户身份认证
|
||||
- 操作审计日志
|
||||
|
||||
### 数据安全
|
||||
- 任务配置加密存储
|
||||
- 执行日志安全保护
|
||||
- 敏感数据脱敏处理
|
||||
- 传输数据加密
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 执行优化
|
||||
- 任务批量处理
|
||||
- 并发执行控制
|
||||
- 资源池管理
|
||||
- 缓存机制优化
|
||||
|
||||
### 内存管理
|
||||
- 任务数据懒加载
|
||||
- 执行上下文清理
|
||||
- 大数据分片处理
|
||||
- 内存泄漏监控
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 插件化架构
|
||||
- 自定义任务插件
|
||||
- 第三方服务集成
|
||||
- 扩展触发器类型
|
||||
- 自定义执行器
|
||||
|
||||
### 配置化管理
|
||||
- 任务模板可配置
|
||||
- 执行策略可调整
|
||||
- 监控规则可定制
|
||||
- 告警机制可配置
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- 任务执行逻辑测试
|
||||
- 调度器功能测试
|
||||
- 数据模型测试
|
||||
- 工具类方法测试
|
||||
|
||||
### 集成测试
|
||||
- 端到端任务执行测试
|
||||
- 服务集成测试
|
||||
- 数据流测试
|
||||
- 异常场景测试
|
||||
|
||||
### 性能测试
|
||||
- 并发执行压力测试
|
||||
- 长时间运行稳定性测试
|
||||
- 内存使用测试
|
||||
- 响应时间测试
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 配置管理
|
||||
- 环境配置分离
|
||||
- 任务参数配置
|
||||
- 性能调优参数
|
||||
- 监控阈值配置
|
||||
|
||||
### 监控指标
|
||||
- 任务执行成功率
|
||||
- 平均执行时间
|
||||
- 系统资源使用率
|
||||
- 异常错误统计
|
||||
|
||||
## 总结
|
||||
|
||||
`app_rpa` 模块作为 OneApp 的自动化中枢,为用户提供了强大的车辆管理自动化能力。通过智能的任务调度、可靠的执行引擎和完善的监控机制,用户可以实现车辆管理的自动化和智能化,显著提升管理效率。模块具有良好的扩展性和可维护性,能够适应不断变化的自动化需求。
|
||||
380
app_car/app_touchgo.md
Normal file
380
app_car/app_touchgo.md
Normal file
@@ -0,0 +1,380 @@
|
||||
# App TouchGo 触控交互模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_touchgo` 是 OneApp 车联网生态中的触控交互模块,负责车辆的触控操作、手势识别、快捷操作等功能。该模块为用户提供直观便捷的车辆交互体验,通过手势和触控操作简化车辆控制流程。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_touchgo
|
||||
- **版本**: 0.1.5
|
||||
- **描述**: 触控交互应用模块
|
||||
- **Flutter 版本**: >=2.5.0
|
||||
- **Dart 版本**: >=2.16.2 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **触控交互**
|
||||
- 多点触控识别
|
||||
- 手势操作识别
|
||||
- 快捷操作设置
|
||||
- 触控反馈优化
|
||||
|
||||
2. **桌面小组件**
|
||||
- 车辆状态小组件
|
||||
- 快捷控制小组件
|
||||
- 信息展示小组件
|
||||
- 自定义小组件
|
||||
|
||||
3. **地理位置集成**
|
||||
- 基于位置的操作
|
||||
- 地理围栏触发
|
||||
- 位置相关提醒
|
||||
- 地图触控交互
|
||||
|
||||
4. **车辆服务集成**
|
||||
- 车辆控制接口
|
||||
- 状态信息获取
|
||||
- 服务调用优化
|
||||
- 实时数据同步
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── app_touchgo.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── gestures/ # 手势识别
|
||||
│ ├── widgets/ # 桌面小组件
|
||||
│ ├── controllers/ # 控制器
|
||||
│ ├── services/ # 服务层
|
||||
│ ├── pages/ # 页面组件
|
||||
│ ├── models/ # 数据模型
|
||||
│ └── utils/ # 工具类
|
||||
├── generated/ # 代码生成文件
|
||||
└── l10n/ # 国际化文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `basic_modular: ^0.2.3` - 模块化框架
|
||||
- `basic_modular_route: ^0.2.1` - 路由管理
|
||||
- `basic_intl_flutter: ^0.2.2+1` - 国际化Flutter支持
|
||||
- `basic_intl: ^0.2.0` - 国际化基础
|
||||
- `basic_logger: ^0.2.2` - 日志系统
|
||||
|
||||
#### 业务依赖
|
||||
- `ui_basic: ^0.2.17` - 基础UI组件
|
||||
- `car_services: ^0.6.1` - 车辆服务
|
||||
- `car_vehicle: ^0.6.4+1` - 车辆控制
|
||||
- `clr_geo: ^0.2.16+1` - 地理位置服务
|
||||
- `clr_touchgo: ^0.1.3` - 触控服务SDK
|
||||
|
||||
#### 第三方依赖
|
||||
- `json_annotation: ^4.8.1` - JSON序列化
|
||||
- `dartz: ^0.10.1` - 函数式编程
|
||||
- `home_widget: ^0.6.0` - 桌面小组件
|
||||
- `amap_flutter_base: ^3.0.4` - 高德地图基础
|
||||
- `amap_flutter_search: ^0.0.17` - 高德地图搜索
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`app_touchgo.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 模块对外接口统一导出
|
||||
- 触控服务初始化
|
||||
- 手势识别引擎启动
|
||||
|
||||
### 2. 手势识别 (`src/gestures/`)
|
||||
|
||||
**功能职责**:
|
||||
- 多点触控处理
|
||||
- 手势模式识别
|
||||
- 自定义手势定义
|
||||
- 手势事件分发
|
||||
|
||||
**主要组件**:
|
||||
- `GestureDetector` - 手势检测器
|
||||
- `TouchProcessor` - 触控处理器
|
||||
- `GestureRecognizer` - 手势识别器
|
||||
- `CustomGestureBuilder` - 自定义手势构建器
|
||||
|
||||
**支持的手势类型**:
|
||||
- 单击/双击
|
||||
- 长按操作
|
||||
- 滑动手势
|
||||
- 缩放手势
|
||||
- 旋转手势
|
||||
- 多指操作
|
||||
|
||||
### 3. 桌面小组件 (`src/widgets/`)
|
||||
|
||||
**功能职责**:
|
||||
- 原生桌面小组件
|
||||
- 车辆信息展示
|
||||
- 快捷操作入口
|
||||
- 实时数据更新
|
||||
|
||||
**主要小组件**:
|
||||
- `VehicleStatusWidget` - 车辆状态小组件
|
||||
- `QuickControlWidget` - 快捷控制小组件
|
||||
- `LocationWidget` - 位置信息小组件
|
||||
- `BatteryWidget` - 电池状态小组件
|
||||
|
||||
### 4. 控制器 (`src/controllers/`)
|
||||
|
||||
**功能职责**:
|
||||
- 触控事件处理
|
||||
- 车辆操作控制
|
||||
- 状态管理协调
|
||||
- 数据流控制
|
||||
|
||||
**主要控制器**:
|
||||
- `TouchController` - 触控控制器
|
||||
- `VehicleController` - 车辆控制器
|
||||
- `WidgetController` - 小组件控制器
|
||||
- `GestureController` - 手势控制器
|
||||
|
||||
### 5. 服务层 (`src/services/`)
|
||||
|
||||
**功能职责**:
|
||||
- 车辆服务接口
|
||||
- 地理位置服务
|
||||
- 小组件数据服务
|
||||
- 触控数据处理
|
||||
|
||||
**主要服务**:
|
||||
- `VehicleService` - 车辆服务
|
||||
- `LocationService` - 位置服务
|
||||
- `WidgetDataService` - 小组件数据服务
|
||||
- `TouchDataService` - 触控数据服务
|
||||
|
||||
### 6. 页面组件 (`src/pages/`)
|
||||
|
||||
**功能职责**:
|
||||
- 用户界面展示
|
||||
- 交互配置页面
|
||||
- 手势设置页面
|
||||
- 小组件管理页面
|
||||
|
||||
**主要页面**:
|
||||
- `TouchGoHomePage` - 触控主页
|
||||
- `GestureConfigPage` - 手势配置页
|
||||
- `WidgetManagementPage` - 小组件管理页
|
||||
- `TouchSettingsPage` - 触控设置页
|
||||
|
||||
### 7. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 触控数据模型
|
||||
- 手势配置模型
|
||||
- 小组件数据模型
|
||||
- 车辆状态模型
|
||||
|
||||
**主要模型**:
|
||||
- `TouchEvent` - 触控事件模型
|
||||
- `GestureConfig` - 手势配置模型
|
||||
- `WidgetData` - 小组件数据模型
|
||||
- `VehicleStatus` - 车辆状态模型
|
||||
|
||||
### 8. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- 触控工具方法
|
||||
- 手势计算工具
|
||||
- 数据转换工具
|
||||
- 性能优化工具
|
||||
|
||||
**主要工具**:
|
||||
- `TouchCalculator` - 触控计算器
|
||||
- `GestureAnalyzer` - 手势分析器
|
||||
- `WidgetRenderer` - 小组件渲染器
|
||||
- `PerformanceOptimizer` - 性能优化器
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 手势识别流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[接收触控事件] --> B[预处理触控数据]
|
||||
B --> C[分析触控模式]
|
||||
C --> D{是否为已知手势}
|
||||
D -->|是| E[匹配手势类型]
|
||||
D -->|否| F[记录未知模式]
|
||||
E --> G[执行对应操作]
|
||||
G --> H[提供触觉反馈]
|
||||
H --> I[记录操作日志]
|
||||
F --> J[学习新手势]
|
||||
J --> K{是否需要用户确认}
|
||||
K -->|是| L[请求用户确认]
|
||||
K -->|否| M[自动学习]
|
||||
L --> N{用户是否确认}
|
||||
N -->|是| O[保存新手势]
|
||||
N -->|否| P[丢弃手势]
|
||||
M --> O
|
||||
O --> Q[更新手势库]
|
||||
P --> R[结束处理]
|
||||
I --> R
|
||||
Q --> R
|
||||
```
|
||||
|
||||
### 小组件更新流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[数据变化事件] --> B[检查小组件订阅]
|
||||
B --> C{是否有订阅小组件}
|
||||
C -->|是| D[获取最新数据]
|
||||
C -->|否| E[忽略更新]
|
||||
D --> F[格式化数据]
|
||||
F --> G[渲染小组件]
|
||||
G --> H[更新系统桌面]
|
||||
H --> I[验证更新结果]
|
||||
I --> J{更新是否成功}
|
||||
J -->|是| K[记录成功日志]
|
||||
J -->|否| L[执行重试机制]
|
||||
L --> M{重试次数是否超限}
|
||||
M -->|是| N[记录失败日志]
|
||||
M -->|否| G
|
||||
K --> O[通知订阅者]
|
||||
N --> P[发送错误报告]
|
||||
O --> Q[结束更新]
|
||||
P --> Q
|
||||
E --> Q
|
||||
```
|
||||
|
||||
## 触控交互设计
|
||||
|
||||
### 手势类型
|
||||
1. **基础手势**
|
||||
- 单击:快速操作
|
||||
- 双击:确认操作
|
||||
- 长按:菜单操作
|
||||
- 滑动:切换操作
|
||||
|
||||
2. **复合手势**
|
||||
- 双指缩放:调整参数
|
||||
- 三指滑动:切换模式
|
||||
- 多指点击:组合操作
|
||||
- 自定义手势:个性化操作
|
||||
|
||||
3. **上下文手势**
|
||||
- 基于位置的手势
|
||||
- 基于时间的手势
|
||||
- 基于状态的手势
|
||||
- 基于场景的手势
|
||||
|
||||
### 反馈机制
|
||||
- **触觉反馈**: 震动反馈
|
||||
- **视觉反馈**: 动画效果
|
||||
- **听觉反馈**: 提示音效
|
||||
- **语音反馈**: 语音确认
|
||||
|
||||
## 小组件设计
|
||||
|
||||
### 小组件类型
|
||||
1. **信息展示类**
|
||||
- 车辆状态展示
|
||||
- 电池电量显示
|
||||
- 位置信息显示
|
||||
- 天气信息显示
|
||||
|
||||
2. **快捷操作类**
|
||||
- 一键锁车/解锁
|
||||
- 空调控制
|
||||
- 充电控制
|
||||
- 导航启动
|
||||
|
||||
3. **监控类**
|
||||
- 安全状态监控
|
||||
- 异常告警显示
|
||||
- 维护提醒
|
||||
- 服务通知
|
||||
|
||||
### 更新策略
|
||||
- **实时更新**: 关键状态信息
|
||||
- **定时更新**: 定期刷新数据
|
||||
- **事件更新**: 状态变化触发
|
||||
- **手动更新**: 用户主动刷新
|
||||
|
||||
## 安全特性
|
||||
|
||||
### 权限控制
|
||||
- 触控操作权限验证
|
||||
- 敏感功能授权检查
|
||||
- 用户身份认证
|
||||
- 操作审计记录
|
||||
|
||||
### 数据保护
|
||||
- 触控数据加密存储
|
||||
- 手势模式隐私保护
|
||||
- 敏感操作二次确认
|
||||
- 数据传输安全
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 触控优化
|
||||
- 触控事件去抖动
|
||||
- 手势识别算法优化
|
||||
- 响应时间优化
|
||||
- 内存使用优化
|
||||
|
||||
### 小组件优化
|
||||
- 数据缓存机制
|
||||
- 增量更新策略
|
||||
- 渲染性能优化
|
||||
- 电池续航优化
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 插件化架构
|
||||
- 自定义手势插件
|
||||
- 第三方小组件集成
|
||||
- 扩展触控功能
|
||||
- 自定义反馈机制
|
||||
|
||||
### 配置化管理
|
||||
- 手势灵敏度配置
|
||||
- 反馈强度设置
|
||||
- 小组件布局配置
|
||||
- 个性化定制
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- 手势识别算法测试
|
||||
- 触控事件处理测试
|
||||
- 数据模型测试
|
||||
- 工具类方法测试
|
||||
|
||||
### 集成测试
|
||||
- 车辆服务集成测试
|
||||
- 小组件功能测试
|
||||
- 地理位置集成测试
|
||||
- 完整交互流程测试
|
||||
|
||||
### 用户体验测试
|
||||
- 手势响应速度测试
|
||||
- 操作准确性测试
|
||||
- 用户满意度测试
|
||||
- 易用性评估
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 配置管理
|
||||
- 手势库配置
|
||||
- 小组件模板配置
|
||||
- 性能参数调优
|
||||
- 权限策略配置
|
||||
|
||||
### 监控指标
|
||||
- 手势识别准确率
|
||||
- 触控响应时间
|
||||
- 小组件更新成功率
|
||||
- 用户操作频率
|
||||
|
||||
## 总结
|
||||
|
||||
`app_touchgo` 模块作为 OneApp 的触控交互中心,为用户提供了直观便捷的车辆操作体验。通过先进的手势识别技术、丰富的桌面小组件和智能的触控反馈,用户可以更自然地与车辆进行交互。模块具有良好的扩展性和个性化能力,能够适应不同用户的使用习惯和需求。
|
||||
351
app_car/app_vur.md
Normal file
351
app_car/app_vur.md
Normal file
@@ -0,0 +1,351 @@
|
||||
# App VUR 车辆更新记录模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_vur` 是 OneApp 车联网生态中的 VUR(Vehicle Update Record)车辆更新记录模块,负责车辆软件更新、固件升级、系统维护记录等功能。该模块为用户提供完整的车辆更新历史追踪和管理服务。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_vur
|
||||
- **版本**: 0.1.25
|
||||
- **描述**: 车辆更新记录应用模块
|
||||
- **Flutter 版本**: >=2.5.0
|
||||
- **Dart 版本**: >=2.16.2 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **更新记录管理**
|
||||
- 软件更新历史记录
|
||||
- 固件升级跟踪
|
||||
- 系统维护日志
|
||||
- 版本变更记录
|
||||
|
||||
2. **更新进度监控**
|
||||
- 实时更新进度显示
|
||||
- 更新状态跟踪
|
||||
- 错误信息收集
|
||||
- 回滚操作支持
|
||||
|
||||
3. **版本信息展示**
|
||||
- 当前系统版本信息
|
||||
- 可用更新检查
|
||||
- 版本差异对比
|
||||
- 更新说明展示
|
||||
|
||||
4. **分享和导出**
|
||||
- 更新记录分享
|
||||
- 日志文件导出
|
||||
- 报告生成功能
|
||||
- 技术支持数据
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── app_vur.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── records/ # 记录管理
|
||||
│ ├── updates/ # 更新处理
|
||||
│ ├── versions/ # 版本管理
|
||||
│ ├── monitoring/ # 监控组件
|
||||
│ ├── pages/ # 页面组件
|
||||
│ ├── models/ # 数据模型
|
||||
│ └── utils/ # 工具类
|
||||
├── generated/ # 代码生成文件
|
||||
└── l10n/ # 国际化文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `basic_modular: ^0.2.3` - 模块化框架
|
||||
- `basic_modular_route: ^0.2.1` - 路由管理
|
||||
- `basic_intl: ^0.2.0` - 国际化基础
|
||||
- `basic_intl_flutter: ^0.2.2+1` - 国际化Flutter支持
|
||||
|
||||
#### 业务依赖
|
||||
- `car_vur: ^0.1.12` - VUR服务SDK
|
||||
- `basic_webview: ^0.2.4` - WebView组件
|
||||
- `app_consent: ^0.2.19` - 用户同意模块
|
||||
- `basic_consent: ^0.2.17` - 基础同意框架
|
||||
- `basic_share: ^0.2.1` - 基础分享服务
|
||||
- `ui_share: ^0.2.0` - 分享UI组件
|
||||
|
||||
#### 第三方依赖
|
||||
- `json_annotation: ^4.8.1` - JSON序列化
|
||||
- `dartz: ^0.10.1` - 函数式编程
|
||||
- `super_tooltip: ^2.0.8` - 提示框组件
|
||||
- `just_the_tooltip: ^0.0.12` - 轻量级提示框
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`app_vur.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 模块对外接口统一导出
|
||||
- VUR服务初始化
|
||||
- 更新监控启动
|
||||
|
||||
### 2. 记录管理 (`src/records/`)
|
||||
|
||||
**功能职责**:
|
||||
- 更新记录存储和管理
|
||||
- 历史数据查询
|
||||
- 记录分类和筛选
|
||||
- 数据备份和恢复
|
||||
|
||||
**主要组件**:
|
||||
- `RecordManager` - 记录管理器
|
||||
- `RecordStorage` - 记录存储
|
||||
- `RecordQuery` - 记录查询
|
||||
- `RecordBackup` - 记录备份
|
||||
|
||||
### 3. 更新处理 (`src/updates/`)
|
||||
|
||||
**功能职责**:
|
||||
- 更新任务处理
|
||||
- 更新进度跟踪
|
||||
- 更新状态管理
|
||||
- 异常处理和恢复
|
||||
|
||||
**主要组件**:
|
||||
- `UpdateProcessor` - 更新处理器
|
||||
- `ProgressTracker` - 进度跟踪器
|
||||
- `StatusManager` - 状态管理器
|
||||
- `ErrorHandler` - 错误处理器
|
||||
|
||||
### 4. 版本管理 (`src/versions/`)
|
||||
|
||||
**功能职责**:
|
||||
- 版本信息管理
|
||||
- 版本比较和分析
|
||||
- 兼容性检查
|
||||
- 依赖关系处理
|
||||
|
||||
**主要组件**:
|
||||
- `VersionManager` - 版本管理器
|
||||
- `VersionComparator` - 版本比较器
|
||||
- `CompatibilityChecker` - 兼容性检查器
|
||||
- `DependencyResolver` - 依赖解析器
|
||||
|
||||
### 5. 监控组件 (`src/monitoring/`)
|
||||
|
||||
**功能职责**:
|
||||
- 更新过程监控
|
||||
- 性能指标收集
|
||||
- 异常检测和报告
|
||||
- 系统健康状态监控
|
||||
|
||||
**主要监控器**:
|
||||
- `UpdateMonitor` - 更新监控器
|
||||
- `PerformanceCollector` - 性能收集器
|
||||
- `HealthChecker` - 健康检查器
|
||||
- `AlertManager` - 告警管理器
|
||||
|
||||
### 6. 页面组件 (`src/pages/`)
|
||||
|
||||
**功能职责**:
|
||||
- 用户界面展示
|
||||
- 更新记录展示
|
||||
- 版本信息页面
|
||||
- 设置配置页面
|
||||
|
||||
**主要页面**:
|
||||
- `VURHomePage` - VUR主页
|
||||
- `UpdateHistoryPage` - 更新历史页
|
||||
- `VersionInfoPage` - 版本信息页
|
||||
- `UpdateProgressPage` - 更新进度页
|
||||
- `SettingsPage` - 设置页面
|
||||
|
||||
### 7. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 更新记录数据模型
|
||||
- 版本信息模型
|
||||
- 进度状态模型
|
||||
- 配置参数模型
|
||||
|
||||
**主要模型**:
|
||||
- `UpdateRecord` - 更新记录模型
|
||||
- `VersionInfo` - 版本信息模型
|
||||
- `UpdateProgress` - 更新进度模型
|
||||
- `VURConfig` - VUR配置模型
|
||||
|
||||
### 8. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- VUR工具方法
|
||||
- 数据处理辅助
|
||||
- 文件操作工具
|
||||
- 格式化工具
|
||||
|
||||
**主要工具**:
|
||||
- `RecordFormatter` - 记录格式化器
|
||||
- `DataExporter` - 数据导出器
|
||||
- `LogAnalyzer` - 日志分析器
|
||||
- `ReportGenerator` - 报告生成器
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 更新记录流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[检测到更新] --> B[创建更新记录]
|
||||
B --> C[记录初始状态]
|
||||
C --> D[开始更新过程]
|
||||
D --> E[实时记录进度]
|
||||
E --> F[监控更新状态]
|
||||
F --> G{更新是否成功}
|
||||
G -->|是| H[记录成功状态]
|
||||
G -->|否| I[记录失败信息]
|
||||
H --> J[更新版本信息]
|
||||
I --> K[保存错误日志]
|
||||
J --> L[生成更新报告]
|
||||
K --> M[触发异常处理]
|
||||
L --> N[通知用户结果]
|
||||
M --> O[记录恢复操作]
|
||||
N --> P[保存完整记录]
|
||||
O --> P
|
||||
P --> Q[更新历史列表]
|
||||
```
|
||||
|
||||
### 版本检查流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[启动版本检查] --> B[获取当前版本]
|
||||
B --> C[查询可用更新]
|
||||
C --> D{是否有新版本}
|
||||
D -->|是| E[获取版本详情]
|
||||
D -->|否| F[记录检查结果]
|
||||
E --> G[检查兼容性]
|
||||
G --> H{是否兼容}
|
||||
H -->|是| I[显示更新提示]
|
||||
H -->|否| J[记录兼容性问题]
|
||||
I --> K[用户确认更新]
|
||||
K --> L{用户是否同意}
|
||||
L -->|是| M[开始更新流程]
|
||||
L -->|否| N[记录用户拒绝]
|
||||
J --> O[提供解决方案]
|
||||
F --> P[结束检查]
|
||||
M --> P
|
||||
N --> P
|
||||
O --> P
|
||||
```
|
||||
|
||||
## VUR系统设计
|
||||
|
||||
### 记录类型
|
||||
1. **软件更新记录**
|
||||
- 应用程序更新
|
||||
- 系统软件更新
|
||||
- 驱动程序更新
|
||||
- 配置文件更新
|
||||
|
||||
2. **固件升级记录**
|
||||
- ECU固件升级
|
||||
- 传感器固件更新
|
||||
- 通信模块更新
|
||||
- 安全模块升级
|
||||
|
||||
3. **维护记录**
|
||||
- 系统诊断记录
|
||||
- 性能优化记录
|
||||
- 清理维护记录
|
||||
- 配置修改记录
|
||||
|
||||
4. **回滚记录**
|
||||
- 更新回滚操作
|
||||
- 版本降级记录
|
||||
- 恢复操作日志
|
||||
- 紧急修复记录
|
||||
|
||||
### 状态管理
|
||||
- **待更新**: 检测到可用更新
|
||||
- **下载中**: 正在下载更新包
|
||||
- **准备中**: 准备安装更新
|
||||
- **安装中**: 正在安装更新
|
||||
- **验证中**: 验证更新结果
|
||||
- **完成**: 更新成功完成
|
||||
- **失败**: 更新过程失败
|
||||
- **回滚**: 执行回滚操作
|
||||
|
||||
## 安全特性
|
||||
|
||||
### 数据完整性
|
||||
- 更新记录数字签名
|
||||
- 数据校验和验证
|
||||
- 记录篡改检测
|
||||
- 备份数据验证
|
||||
|
||||
### 隐私保护
|
||||
- 敏感信息加密存储
|
||||
- 用户数据脱敏处理
|
||||
- 访问权限控制
|
||||
- 数据传输加密
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 存储优化
|
||||
- 记录数据压缩
|
||||
- 过期数据清理
|
||||
- 索引优化设计
|
||||
- 查询性能优化
|
||||
|
||||
### 内存管理
|
||||
- 大数据分页加载
|
||||
- 缓存机制优化
|
||||
- 内存使用监控
|
||||
- 资源及时释放
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 插件化架构
|
||||
- 自定义记录类型
|
||||
- 第三方更新源集成
|
||||
- 扩展监控功能
|
||||
- 自定义报告格式
|
||||
|
||||
### 配置化管理
|
||||
- 记录保留策略配置
|
||||
- 监控规则可配置
|
||||
- 报告模板定制
|
||||
- 告警阈值设置
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- 记录管理逻辑测试
|
||||
- 版本比较算法测试
|
||||
- 数据模型测试
|
||||
- 工具类方法测试
|
||||
|
||||
### 集成测试
|
||||
- 更新流程端到端测试
|
||||
- 服务集成测试
|
||||
- 数据持久化测试
|
||||
- 异常场景测试
|
||||
|
||||
### 性能测试
|
||||
- 大量记录处理测试
|
||||
- 查询性能测试
|
||||
- 内存使用测试
|
||||
- 并发访问测试
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 配置管理
|
||||
- 记录存储配置
|
||||
- 更新策略配置
|
||||
- 监控参数设置
|
||||
- 性能调优参数
|
||||
|
||||
### 监控指标
|
||||
- 更新成功率
|
||||
- 记录查询响应时间
|
||||
- 存储空间使用率
|
||||
- 异常错误统计
|
||||
|
||||
## 总结
|
||||
|
||||
`app_vur` 模块作为 OneApp 的车辆更新记录中心,为用户提供了完整的车辆软硬件更新历史追踪服务。通过详细的记录管理、实时的进度监控和完善的版本管理,用户可以全面了解车辆的更新状态和历史变更。模块具有良好的数据完整性保障和性能优化设计,能够可靠地记录和管理车辆的各类更新信息。
|
||||
359
app_car/app_wallbox.md
Normal file
359
app_car/app_wallbox.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# App Wallbox 充电墙盒模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`app_wallbox` 是 OneApp 车联网生态中的充电墙盒管理模块,负责家用充电桩(墙盒)的管理、安装、配置和监控等功能。该模块为用户提供完整的家庭充电解决方案管理服务。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: app_wallbox
|
||||
- **版本**: 0.2.29
|
||||
- **描述**: 充电墙盒应用模块
|
||||
- **Flutter 版本**: >=2.10.5
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **墙盒设备管理**
|
||||
- 设备注册和绑定
|
||||
- 设备状态监控
|
||||
- 设备配置管理
|
||||
- 设备固件升级
|
||||
|
||||
2. **安装服务**
|
||||
- 安装预约申请
|
||||
- 安装进度跟踪
|
||||
- 安装城市选择
|
||||
- 安装文件上传
|
||||
|
||||
3. **充电管理**
|
||||
- 远程充电控制
|
||||
- 充电计划设置
|
||||
- 充电记录查看
|
||||
- 电费统计分析
|
||||
|
||||
4. **智能功能**
|
||||
- 智能充电调度
|
||||
- 电网负荷优化
|
||||
- 太阳能集成
|
||||
- 能源管理优化
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── app_wallbox.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── devices/ # 设备管理
|
||||
│ ├── installation/ # 安装服务
|
||||
│ ├── charging/ # 充电控制
|
||||
│ ├── monitoring/ # 监控组件
|
||||
│ ├── smart/ # 智能功能
|
||||
│ ├── pages/ # 页面组件
|
||||
│ ├── models/ # 数据模型
|
||||
│ └── utils/ # 工具类
|
||||
├── generated/ # 代码生成文件
|
||||
└── l10n/ # 国际化文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `basic_modular: ^0.2.3` - 模块化框架
|
||||
- `basic_modular_route: ^0.2.1` - 路由管理
|
||||
- `basic_resource: ^0.2.10` - 资源管理
|
||||
- `basic_intl: ^0.2.0` - 国际化支持
|
||||
- `basic_storage: ^0.2.2` - 本地存储
|
||||
- `basic_network: ^0.2.3+3` - 网络通信
|
||||
- `basic_track: ^0.1.3` - 数据埋点
|
||||
|
||||
#### 业务依赖
|
||||
- `ui_business: ^0.2.23` - 业务UI组件
|
||||
|
||||
#### 第三方依赖
|
||||
- `json_annotation: ^4.6.0` - JSON序列化
|
||||
- `dartz: ^0.10.1` - 函数式编程
|
||||
- `extended_image: ^8.2.3` - 增强图片组件
|
||||
- `url_launcher: ^6.1.4` - URL启动
|
||||
- `collection: ^1.17.1` - 集合工具
|
||||
- `path_provider: ^2.0.15` - 文件路径
|
||||
- `path: ^1.8.3` - 路径操作
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`app_wallbox.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 模块对外接口统一导出
|
||||
- 墙盒服务初始化
|
||||
- 设备管理启动
|
||||
|
||||
### 2. 设备管理 (`src/devices/`)
|
||||
|
||||
**功能职责**:
|
||||
- 墙盒设备注册和绑定
|
||||
- 设备状态实时监控
|
||||
- 设备配置参数管理
|
||||
- 设备固件和软件升级
|
||||
|
||||
**主要组件**:
|
||||
- `DeviceManager` - 设备管理器
|
||||
- `DeviceRegistry` - 设备注册表
|
||||
- `StatusMonitor` - 状态监控器
|
||||
- `ConfigManager` - 配置管理器
|
||||
- `FirmwareUpdater` - 固件升级器
|
||||
|
||||
### 3. 安装服务 (`src/installation/`)
|
||||
|
||||
**功能职责**:
|
||||
- 安装服务预约和申请
|
||||
- 安装进度实时跟踪
|
||||
- 安装城市和地区选择
|
||||
- 安装相关文件上传管理
|
||||
|
||||
**主要组件**:
|
||||
- `InstallationService` - 安装服务
|
||||
- `ProgressTracker` - 进度跟踪器
|
||||
- `CityPicker` - 城市选择器
|
||||
- `UploadManager` - 文件上传管理器
|
||||
- `AppointmentManager` - 预约管理器
|
||||
|
||||
### 4. 充电控制 (`src/charging/`)
|
||||
|
||||
**功能职责**:
|
||||
- 远程充电启停控制
|
||||
- 充电计划和策略设置
|
||||
- 充电过程监控
|
||||
- 充电数据记录和分析
|
||||
|
||||
**主要组件**:
|
||||
- `ChargingController` - 充电控制器
|
||||
- `ScheduleManager` - 计划管理器
|
||||
- `ProcessMonitor` - 过程监控器
|
||||
- `DataRecorder` - 数据记录器
|
||||
|
||||
### 5. 监控组件 (`src/monitoring/`)
|
||||
|
||||
**功能职责**:
|
||||
- 设备运行状态监控
|
||||
- 充电过程实时监控
|
||||
- 异常检测和告警
|
||||
- 性能指标收集
|
||||
|
||||
**主要监控器**:
|
||||
- `DeviceMonitor` - 设备监控器
|
||||
- `ChargingMonitor` - 充电监控器
|
||||
- `AlertManager` - 告警管理器
|
||||
- `MetricsCollector` - 指标收集器
|
||||
|
||||
### 6. 智能功能 (`src/smart/`)
|
||||
|
||||
**功能职责**:
|
||||
- 智能充电调度算法
|
||||
- 电网负荷平衡优化
|
||||
- 可再生能源集成
|
||||
- 能源成本优化
|
||||
|
||||
**主要组件**:
|
||||
- `SmartScheduler` - 智能调度器
|
||||
- `LoadBalancer` - 负荷均衡器
|
||||
- `EnergyOptimizer` - 能源优化器
|
||||
- `GridInterface` - 电网接口
|
||||
|
||||
### 7. 页面组件 (`src/pages/`)
|
||||
|
||||
**功能职责**:
|
||||
- 用户界面展示
|
||||
- 设备管理界面
|
||||
- 充电控制界面
|
||||
- 安装服务界面
|
||||
|
||||
**主要页面**:
|
||||
- `WallboxHomePage` - 墙盒主页
|
||||
- `DeviceManagementPage` - 设备管理页
|
||||
- `ChargingControlPage` - 充电控制页
|
||||
- `InstallationPage` - 安装服务页
|
||||
- `MonitoringDashboard` - 监控仪表板
|
||||
|
||||
### 8. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 设备信息数据模型
|
||||
- 充电数据模型
|
||||
- 安装服务模型
|
||||
- 配置参数模型
|
||||
|
||||
**主要模型**:
|
||||
- `WallboxDevice` - 墙盒设备模型
|
||||
- `ChargingSession` - 充电会话模型
|
||||
- `InstallationOrder` - 安装订单模型
|
||||
- `DeviceConfig` - 设备配置模型
|
||||
|
||||
### 9. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- 墙盒工具方法
|
||||
- 数据处理辅助
|
||||
- 文件操作工具
|
||||
- 计算辅助工具
|
||||
|
||||
**主要工具**:
|
||||
- `PowerCalculator` - 功率计算器
|
||||
- `EnergyAnalyzer` - 能源分析器
|
||||
- `FileUploader` - 文件上传器
|
||||
- `DataFormatter` - 数据格式化器
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 设备安装流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[用户申请安装] --> B[选择安装城市]
|
||||
B --> C[填写安装信息]
|
||||
C --> D[上传相关文件]
|
||||
D --> E[提交安装申请]
|
||||
E --> F[系统审核申请]
|
||||
F --> G{审核是否通过}
|
||||
G -->|是| H[安排安装服务]
|
||||
G -->|否| I[通知修改申请]
|
||||
H --> J[派遣安装团队]
|
||||
J --> K[现场安装施工]
|
||||
K --> L[设备调试测试]
|
||||
L --> M{测试是否通过}
|
||||
M -->|是| N[设备注册绑定]
|
||||
M -->|否| O[问题排查修复]
|
||||
N --> P[安装完成]
|
||||
O --> L
|
||||
I --> C
|
||||
P --> Q[用户验收]
|
||||
```
|
||||
|
||||
### 智能充电流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[用户设置充电需求] --> B[系统分析用电负荷]
|
||||
B --> C[获取电价信息]
|
||||
C --> D[检查电网状态]
|
||||
D --> E[计算最优充电策略]
|
||||
E --> F[生成充电计划]
|
||||
F --> G[用户确认计划]
|
||||
G --> H{用户是否同意}
|
||||
H -->|是| I[执行充电计划]
|
||||
H -->|否| J[调整计划参数]
|
||||
I --> K[监控充电过程]
|
||||
K --> L[动态调整功率]
|
||||
L --> M{是否达到目标}
|
||||
M -->|是| N[充电完成]
|
||||
M -->|否| O[继续充电]
|
||||
J --> E
|
||||
O --> K
|
||||
N --> P[生成充电报告]
|
||||
```
|
||||
|
||||
## 墙盒系统设计
|
||||
|
||||
### 设备类型
|
||||
1. **家用标准墙盒**
|
||||
- 7kW交流充电
|
||||
- 单相/三相供电
|
||||
- WiFi/以太网连接
|
||||
- 基础智能功能
|
||||
|
||||
2. **商用快充墙盒**
|
||||
- 22kW交流快充
|
||||
- 三相供电
|
||||
- 有线网络连接
|
||||
- 高级智能功能
|
||||
|
||||
3. **智能墙盒**
|
||||
- 可变功率充电
|
||||
- 太阳能集成
|
||||
- 储能系统集成
|
||||
- AI优化算法
|
||||
|
||||
### 通信协议
|
||||
- **OCPP**: 开放充电点协议
|
||||
- **Modbus**: 工业通信协议
|
||||
- **HTTP/HTTPS**: Web API通信
|
||||
- **MQTT**: 物联网消息协议
|
||||
|
||||
## 安全特性
|
||||
|
||||
### 设备安全
|
||||
- 设备身份认证
|
||||
- 通信数据加密
|
||||
- 固件签名验证
|
||||
- 安全升级机制
|
||||
|
||||
### 用户安全
|
||||
- 用户身份验证
|
||||
- 操作权限控制
|
||||
- 敏感数据保护
|
||||
- 安全审计日志
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 通信优化
|
||||
- 数据压缩传输
|
||||
- 断线重连机制
|
||||
- 离线数据缓存
|
||||
- 网络自适应
|
||||
|
||||
### 能效优化
|
||||
- 智能功率调节
|
||||
- 负荷均衡算法
|
||||
- 能源损耗最小化
|
||||
- 电网友好充电
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 协议支持
|
||||
- 多种通信协议适配
|
||||
- 标准协议兼容
|
||||
- 自定义协议扩展
|
||||
- 协议版本升级
|
||||
|
||||
### 设备兼容
|
||||
- 多厂商设备支持
|
||||
- 不同型号适配
|
||||
- 新设备快速接入
|
||||
- 设备能力自动识别
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- 充电控制逻辑测试
|
||||
- 设备通信测试
|
||||
- 数据模型测试
|
||||
- 算法功能测试
|
||||
|
||||
### 集成测试
|
||||
- 设备集成测试
|
||||
- 系统端到端测试
|
||||
- 协议兼容性测试
|
||||
- 性能压力测试
|
||||
|
||||
### 现场测试
|
||||
- 实际设备测试
|
||||
- 网络环境测试
|
||||
- 用户场景测试
|
||||
- 长期稳定性测试
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 设备管理
|
||||
- 设备远程配置
|
||||
- 固件OTA升级
|
||||
- 故障远程诊断
|
||||
- 预防性维护
|
||||
|
||||
### 系统监控
|
||||
- 设备在线率监控
|
||||
- 充电成功率统计
|
||||
- 系统性能监控
|
||||
- 用户满意度跟踪
|
||||
|
||||
## 总结
|
||||
|
||||
`app_wallbox` 模块作为 OneApp 的家庭充电解决方案中心,为用户提供了完整的充电墙盒管理服务。通过智能的设备管理、便捷的安装服务和高效的充电控制,用户可以享受到安全、智能、经济的家庭充电体验。模块具有良好的设备兼容性和扩展能力,能够适应不断发展的充电技术和用户需求。
|
||||
374
app_car/car_services.md
Normal file
374
app_car/car_services.md
Normal file
@@ -0,0 +1,374 @@
|
||||
# Car Services 车辆服务模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`car_services` 是 OneApp 车联网生态中的车辆服务模块,负责车辆核心服务的统一接口封装、车辆数据处理、服务调用管理和业务逻辑抽象等功能。该模块为上层应用提供了统一的车辆服务接口。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: car_services
|
||||
- **版本**: 0.6.25
|
||||
- **描述**: 车辆服务统一接口模块
|
||||
- **Flutter 版本**: >=2.10.5
|
||||
- **Dart 版本**: >=3.0.0 <4.0.08
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **服务接口统一**
|
||||
- 车辆控制接口封装
|
||||
- 数据查询接口标准化
|
||||
- 异步调用管理
|
||||
- 错误处理统一
|
||||
|
||||
2. **数据模型管理**
|
||||
- 车辆状态数据模型
|
||||
- 服务请求响应模型
|
||||
- 配置参数模型
|
||||
- 业务实体模型
|
||||
|
||||
3. **服务调用优化**
|
||||
- 请求缓存机制
|
||||
- 批量操作支持
|
||||
- 超时重试机制
|
||||
- 并发控制管理
|
||||
|
||||
4. **业务逻辑抽象**
|
||||
- 领域驱动设计
|
||||
- 服务层解耦
|
||||
- 依赖注入支持
|
||||
- 模块化架构
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── car_services.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── services/ # 服务实现
|
||||
│ ├── models/ # 数据模型
|
||||
│ ├── repositories/ # 数据仓库
|
||||
│ ├── interfaces/ # 接口定义
|
||||
│ ├── utils/ # 工具类
|
||||
│ └── constants/ # 常量定义
|
||||
├── test/ # 测试文件
|
||||
└── generated/ # 代码生成文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心框架依赖
|
||||
- `basic_modular: ^0.2.3` - 模块化框架
|
||||
- `basic_modular_route: ^0.2.1` - 路由管理
|
||||
- `basic_network: ^0.2.3+4` - 网络通信框架
|
||||
- `basic_intl: ^0.2.0` - 国际化支持
|
||||
|
||||
#### 业务依赖
|
||||
- `car_connector: ^0.4.11` - 车联网连接器
|
||||
|
||||
#### 工具依赖
|
||||
- `dartz: ^0.10.1` - 函数式编程
|
||||
- `freezed_annotation: ^2.2.0` - 数据类注解
|
||||
|
||||
#### 开发依赖
|
||||
- `build_runner: ^2.4.9` - 代码生成引擎
|
||||
- `freezed: ^2.4.7` - 不可变类生成
|
||||
- `json_serializable: ^6.7.0` - JSON序列化
|
||||
- `mockito: ^5.4.1` - 测试模拟框架
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`car_services.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 服务模块对外接口导出
|
||||
- 依赖注入配置
|
||||
- 模块初始化管理
|
||||
|
||||
### 2. 服务实现 (`src/services/`)
|
||||
|
||||
**功能职责**:
|
||||
- 车辆控制服务实现
|
||||
- 数据查询服务实现
|
||||
- 状态监控服务实现
|
||||
- 配置管理服务实现
|
||||
|
||||
**主要服务**:
|
||||
- `VehicleControlService` - 车辆控制服务
|
||||
- `VehicleDataService` - 车辆数据服务
|
||||
- `VehicleStatusService` - 车辆状态服务
|
||||
- `VehicleConfigService` - 车辆配置服务
|
||||
- `DiagnosticService` - 诊断服务
|
||||
|
||||
### 3. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 业务数据模型定义
|
||||
- 请求响应模型
|
||||
- 状态信息模型
|
||||
- 配置参数模型
|
||||
|
||||
**主要模型**:
|
||||
- `VehicleInfo` - 车辆信息模型
|
||||
- `VehicleStatus` - 车辆状态模型
|
||||
- `ControlCommand` - 控制命令模型
|
||||
- `ServiceRequest` - 服务请求模型
|
||||
- `ServiceResponse` - 服务响应模型
|
||||
|
||||
### 4. 数据仓库 (`src/repositories/`)
|
||||
|
||||
**功能职责**:
|
||||
- 数据访问层抽象
|
||||
- 本地缓存管理
|
||||
- 远程数据获取
|
||||
- 数据同步控制
|
||||
|
||||
**主要仓库**:
|
||||
- `VehicleRepository` - 车辆数据仓库
|
||||
- `ConfigRepository` - 配置数据仓库
|
||||
- `StatusRepository` - 状态数据仓库
|
||||
- `HistoryRepository` - 历史数据仓库
|
||||
|
||||
### 5. 接口定义 (`src/interfaces/`)
|
||||
|
||||
**功能职责**:
|
||||
- 服务接口抽象定义
|
||||
- 依赖倒置实现
|
||||
- 接口规范约束
|
||||
- 扩展性支持
|
||||
|
||||
**主要接口**:
|
||||
- `IVehicleService` - 车辆服务接口
|
||||
- `IDataRepository` - 数据仓库接口
|
||||
- `IStatusProvider` - 状态提供者接口
|
||||
- `IConfigManager` - 配置管理接口
|
||||
|
||||
### 6. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- 数据转换工具
|
||||
- 验证工具方法
|
||||
- 缓存工具
|
||||
- 网络工具
|
||||
|
||||
**主要工具**:
|
||||
- `DataConverter` - 数据转换器
|
||||
- `Validator` - 数据验证器
|
||||
- `CacheHelper` - 缓存助手
|
||||
- `NetworkHelper` - 网络助手
|
||||
|
||||
### 7. 常量定义 (`src/constants/`)
|
||||
|
||||
**功能职责**:
|
||||
- 服务常量定义
|
||||
- 错误码管理
|
||||
- 配置常量
|
||||
- API端点定义
|
||||
|
||||
**主要常量**:
|
||||
- `ServiceConstants` - 服务常量
|
||||
- `ErrorCodes` - 错误码定义
|
||||
- `ApiEndpoints` - API端点
|
||||
- `ConfigKeys` - 配置键值
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 服务调用流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[应用发起请求] --> B[服务接口层]
|
||||
B --> C[参数验证]
|
||||
C --> D{验证是否通过}
|
||||
D -->|否| E[返回验证错误]
|
||||
D -->|是| F[检查本地缓存]
|
||||
F --> G{缓存是否有效}
|
||||
G -->|是| H[返回缓存数据]
|
||||
G -->|否| I[调用远程服务]
|
||||
I --> J[网络请求]
|
||||
J --> K{请求是否成功}
|
||||
K -->|是| L[处理响应数据]
|
||||
K -->|否| M[错误处理]
|
||||
L --> N[更新本地缓存]
|
||||
N --> O[返回处理结果]
|
||||
M --> P[重试机制]
|
||||
P --> Q{是否需要重试}
|
||||
Q -->|是| I
|
||||
Q -->|否| R[返回错误结果]
|
||||
E --> S[记录日志]
|
||||
H --> S
|
||||
O --> S
|
||||
R --> S
|
||||
```
|
||||
|
||||
### 数据同步流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[触发数据同步] --> B[获取本地数据版本]
|
||||
B --> C[请求远程数据版本]
|
||||
C --> D{版本是否一致}
|
||||
D -->|是| E[无需同步]
|
||||
D -->|否| F[下载增量数据]
|
||||
F --> G[验证数据完整性]
|
||||
G --> H{验证是否通过}
|
||||
H -->|是| I[更新本地数据]
|
||||
H -->|否| J[重新下载]
|
||||
I --> K[更新版本信息]
|
||||
K --> L[触发数据更新事件]
|
||||
J --> M{重试次数是否超限}
|
||||
M -->|否| F
|
||||
M -->|是| N[同步失败]
|
||||
E --> O[同步完成]
|
||||
L --> O
|
||||
N --> P[记录错误日志]
|
||||
```
|
||||
|
||||
## 服务设计模式
|
||||
|
||||
### 领域驱动设计(DDD)
|
||||
1. **实体层(Entity)**
|
||||
- 车辆实体
|
||||
- 用户实体
|
||||
- 订单实体
|
||||
- 配置实体
|
||||
|
||||
2. **值对象层(Value Object)**
|
||||
- 车辆状态
|
||||
- 位置信息
|
||||
- 时间范围
|
||||
- 配置项
|
||||
|
||||
3. **服务层(Service)**
|
||||
- 领域服务
|
||||
- 应用服务
|
||||
- 基础设施服务
|
||||
|
||||
4. **仓库层(Repository)**
|
||||
- 数据访问抽象
|
||||
- 缓存策略
|
||||
- 数据同步
|
||||
|
||||
### 依赖注入模式
|
||||
- **接口抽象**: 定义服务契约
|
||||
- **实现分离**: 具体实现与接口分离
|
||||
- **生命周期管理**: 单例、瞬态、作用域
|
||||
- **配置驱动**: 通过配置控制依赖关系
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### 多级缓存架构
|
||||
1. **内存缓存**
|
||||
- 热点数据缓存
|
||||
- LRU淘汰策略
|
||||
- 容量限制管理
|
||||
- 过期时间控制
|
||||
|
||||
2. **本地存储缓存**
|
||||
- 持久化数据存储
|
||||
- 离线数据支持
|
||||
- 增量更新机制
|
||||
- 数据压缩存储
|
||||
|
||||
3. **远程缓存**
|
||||
- CDN内容分发
|
||||
- 边缘节点缓存
|
||||
- 区域化数据
|
||||
- 负载均衡
|
||||
|
||||
### 缓存一致性
|
||||
- **写通策略**: 同时更新缓存和数据源
|
||||
- **写回策略**: 延迟写入数据源
|
||||
- **失效策略**: 主动失效过期数据
|
||||
- **版本控制**: 数据版本管理
|
||||
|
||||
## 错误处理机制
|
||||
|
||||
### 错误分类
|
||||
1. **网络错误**
|
||||
- 连接超时
|
||||
- 网络不可达
|
||||
- 服务不可用
|
||||
- 限流熔断
|
||||
|
||||
2. **业务错误**
|
||||
- 参数验证失败
|
||||
- 业务规则违反
|
||||
- 权限不足
|
||||
- 数据不存在
|
||||
|
||||
3. **系统错误**
|
||||
- 内存不足
|
||||
- 存储空间不够
|
||||
- 系统异常
|
||||
- 未知错误
|
||||
|
||||
### 处理策略
|
||||
- **重试机制**: 指数退避重试
|
||||
- **熔断保护**: 快速失败机制
|
||||
- **降级处理**: 服务降级策略
|
||||
- **监控告警**: 异常监控报警
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 请求优化
|
||||
- **批量请求**: 减少网络往返
|
||||
- **数据压缩**: 减少传输量
|
||||
- **连接复用**: HTTP连接池
|
||||
- **并发控制**: 限制并发数量
|
||||
|
||||
### 缓存优化
|
||||
- **预加载**: 预测性数据加载
|
||||
- **懒加载**: 按需数据加载
|
||||
- **缓存预热**: 系统启动预热
|
||||
- **缓存穿透保护**: 空值缓存
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 插件化架构
|
||||
- **服务插件**: 自定义服务实现
|
||||
- **数据源插件**: 多数据源支持
|
||||
- **缓存插件**: 自定义缓存策略
|
||||
- **网络插件**: 网络适配器
|
||||
|
||||
### 配置化管理
|
||||
- **服务配置**: 服务参数可配置
|
||||
- **缓存配置**: 缓存策略可调整
|
||||
- **网络配置**: 网络参数可设置
|
||||
- **业务配置**: 业务规则可定制
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- **服务逻辑测试**: 业务逻辑正确性
|
||||
- **数据模型测试**: 序列化反序列化
|
||||
- **工具类测试**: 工具方法功能
|
||||
- **接口测试**: 接口契约验证
|
||||
|
||||
### 集成测试
|
||||
- **服务集成测试**: 端到端流程
|
||||
- **数据库集成测试**: 数据访问层
|
||||
- **网络集成测试**: 网络通信
|
||||
- **缓存集成测试**: 缓存机制
|
||||
|
||||
### 性能测试
|
||||
- **压力测试**: 高并发场景
|
||||
- **负载测试**: 正常负载下性能
|
||||
- **容量测试**: 系统容量极限
|
||||
- **稳定性测试**: 长时间运行
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 配置管理
|
||||
- **环境配置**: 开发、测试、生产
|
||||
- **服务配置**: API地址、超时设置
|
||||
- **缓存配置**: 缓存策略参数
|
||||
- **业务配置**: 业务规则参数
|
||||
|
||||
### 监控指标
|
||||
- **性能指标**: 响应时间、吞吐量
|
||||
- **错误指标**: 错误率、失败次数
|
||||
- **资源指标**: CPU、内存使用率
|
||||
- **业务指标**: 调用次数、成功率
|
||||
|
||||
## 总结
|
||||
|
||||
`car_services` 模块作为 OneApp 的车辆服务统一接口层,通过领域驱动设计和模块化架构,为上层应用提供了稳定、高效、可扩展的车辆服务能力。模块具有完善的缓存机制、错误处理和性能优化策略,能够满足大规模车联网应用的服务需求。
|
||||
372
app_car/clr_avatarcore.md
Normal file
372
app_car/clr_avatarcore.md
Normal file
@@ -0,0 +1,372 @@
|
||||
# CLR AvatarCore 虚拟形象核心服务
|
||||
|
||||
## 模块概述
|
||||
|
||||
`clr_avatarcore` 是 OneApp 车联网生态中的虚拟形象核心服务模块,负责虚拟形象的渲染、动画处理、资源管理和交互控制等核心功能。该模块为车载虚拟助手提供底层的形象生成和控制能力。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: clr_avatarcore
|
||||
- **版本**: 0.4.0+2
|
||||
- **描述**: 虚拟形象核心服务SDK
|
||||
- **Flutter 版本**: >=1.17.0
|
||||
- **Dart 版本**: >=2.16.2 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **形象渲染引擎**
|
||||
- 3D虚拟形象渲染
|
||||
- 实时动画播放
|
||||
- 光照和材质处理
|
||||
- 表情和动作同步
|
||||
|
||||
2. **资源管理系统**
|
||||
- 形象资源下载和缓存
|
||||
- 动画资源压缩和解压
|
||||
- 资源版本管理
|
||||
- 本地存储优化
|
||||
|
||||
3. **动画控制系统**
|
||||
- 表情动画控制
|
||||
- 语音同步动画
|
||||
- 手势和动作驱动
|
||||
- 情绪表达映射
|
||||
|
||||
4. **交互处理**
|
||||
- 语音输入响应
|
||||
- 触控交互处理
|
||||
- 环境感知适配
|
||||
- 智能行为生成
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── clr_avatarcore.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── rendering/ # 渲染引擎
|
||||
│ ├── animation/ # 动画系统
|
||||
│ ├── resources/ # 资源管理
|
||||
│ ├── interaction/ # 交互处理
|
||||
│ ├── models/ # 数据模型
|
||||
│ └── utils/ # 工具类
|
||||
├── assets/ # 资源文件
|
||||
└── native/ # 原生代码接口
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `car_connector: ^0.4.11` - 车联网连接器
|
||||
- `basic_intl: ^0.2.0` - 国际化支持
|
||||
- `basic_logger: ^0.2.0` - 日志系统
|
||||
|
||||
#### 网络和存储
|
||||
- `dio: ^5.2.0` - HTTP客户端
|
||||
- `path_provider: ^2.0.11` - 文件路径
|
||||
- `shared_preferences: ^2.1.1` - 本地存储
|
||||
- `flutter_archive: ^5.0.0` - 文件压缩解压
|
||||
|
||||
#### 工具依赖
|
||||
- `crypto: ^3.0.3` - 加密功能
|
||||
- `fluttertoast: ^8.2.5` - 提示组件
|
||||
- `flutter_screenutil: ^5.9.0` - 屏幕适配
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`clr_avatarcore.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 虚拟形象服务初始化
|
||||
- 渲染引擎启动
|
||||
- 资源管理系统配置
|
||||
|
||||
### 2. 渲染引擎 (`src/rendering/`)
|
||||
|
||||
**功能职责**:
|
||||
- 3D形象渲染管道
|
||||
- 实时画面生成
|
||||
- 性能优化控制
|
||||
- 渲染质量管理
|
||||
|
||||
**主要组件**:
|
||||
- `RenderEngine` - 渲染引擎核心
|
||||
- `SceneManager` - 场景管理器
|
||||
- `MaterialProcessor` - 材质处理器
|
||||
- `LightingSystem` - 光照系统
|
||||
- `CameraController` - 摄像机控制器
|
||||
|
||||
### 3. 动画系统 (`src/animation/`)
|
||||
|
||||
**功能职责**:
|
||||
- 角色动画播放
|
||||
- 表情动画控制
|
||||
- 动作序列管理
|
||||
- 动画混合和过渡
|
||||
|
||||
**主要组件**:
|
||||
- `AnimationController` - 动画控制器
|
||||
- `ExpressionManager` - 表情管理器
|
||||
- `MotionBlender` - 动作混合器
|
||||
- `Timeline` - 时间轴管理
|
||||
- `BehaviorTree` - 行为树系统
|
||||
|
||||
### 4. 资源管理 (`src/resources/`)
|
||||
|
||||
**功能职责**:
|
||||
- 形象资源下载
|
||||
- 文件缓存管理
|
||||
- 资源版本控制
|
||||
- 内存使用优化
|
||||
|
||||
**主要组件**:
|
||||
- `ResourceManager` - 资源管理器
|
||||
- `DownloadManager` - 下载管理器
|
||||
- `CacheManager` - 缓存管理器
|
||||
- `AssetLoader` - 资源加载器
|
||||
- `VersionController` - 版本控制器
|
||||
|
||||
### 5. 交互处理 (`src/interaction/`)
|
||||
|
||||
**功能职责**:
|
||||
- 用户交互响应
|
||||
- 语音输入处理
|
||||
- 手势识别处理
|
||||
- 环境适应控制
|
||||
|
||||
**主要组件**:
|
||||
- `InteractionHandler` - 交互处理器
|
||||
- `VoiceProcessor` - 语音处理器
|
||||
- `GestureRecognizer` - 手势识别器
|
||||
- `EmotionMapper` - 情绪映射器
|
||||
- `BehaviorGenerator` - 行为生成器
|
||||
|
||||
### 6. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 形象数据模型
|
||||
- 动画数据结构
|
||||
- 配置参数模型
|
||||
- 状态信息模型
|
||||
|
||||
**主要模型**:
|
||||
- `AvatarModel` - 虚拟形象模型
|
||||
- `AnimationData` - 动画数据模型
|
||||
- `SceneConfig` - 场景配置模型
|
||||
- `InteractionState` - 交互状态模型
|
||||
|
||||
### 7. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- 数学计算工具
|
||||
- 文件处理工具
|
||||
- 性能监控工具
|
||||
- 调试辅助工具
|
||||
|
||||
**主要工具**:
|
||||
- `MathUtils` - 数学计算工具
|
||||
- `FileUtils` - 文件操作工具
|
||||
- `PerformanceMonitor` - 性能监控器
|
||||
- `DebugUtils` - 调试工具
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 虚拟形象初始化流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[启动形象服务] --> B[检查本地资源]
|
||||
B --> C{资源是否完整}
|
||||
C -->|是| D[加载形象模型]
|
||||
C -->|否| E[下载缺失资源]
|
||||
E --> F[解压资源文件]
|
||||
F --> G[验证资源完整性]
|
||||
G --> H{验证是否通过}
|
||||
H -->|是| D
|
||||
H -->|否| I[重新下载资源]
|
||||
I --> F
|
||||
D --> J[初始化渲染引擎]
|
||||
J --> K[加载动画数据]
|
||||
K --> L[设置默认状态]
|
||||
L --> M[启动交互监听]
|
||||
M --> N[形象准备就绪]
|
||||
```
|
||||
|
||||
### 动画播放流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[接收动画指令] --> B[解析动画类型]
|
||||
B --> C[查找动画资源]
|
||||
C --> D{资源是否存在}
|
||||
D -->|是| E[加载动画数据]
|
||||
D -->|否| F[下载动画资源]
|
||||
F --> E
|
||||
E --> G[计算动画参数]
|
||||
G --> H[开始动画播放]
|
||||
H --> I[实时渲染更新]
|
||||
I --> J{动画是否结束}
|
||||
J -->|否| I
|
||||
J -->|是| K[恢复默认状态]
|
||||
K --> L[释放动画资源]
|
||||
```
|
||||
|
||||
## 渲染系统设计
|
||||
|
||||
### 渲染管道
|
||||
1. **几何处理阶段**
|
||||
- 顶点变换
|
||||
- 骨骼动画
|
||||
- 形变处理
|
||||
- 裁剪优化
|
||||
|
||||
2. **光栅化阶段**
|
||||
- 像素着色
|
||||
- 纹理映射
|
||||
- 光照计算
|
||||
- 阴影处理
|
||||
|
||||
3. **后处理阶段**
|
||||
- 抗锯齿
|
||||
- 色彩校正
|
||||
- 特效合成
|
||||
- 输出优化
|
||||
|
||||
### 性能优化策略
|
||||
- **LOD系统**: 距离层次细节
|
||||
- **遮挡剔除**: 视锥体剔除
|
||||
- **批量渲染**: 减少绘制调用
|
||||
- **纹理压缩**: 内存使用优化
|
||||
|
||||
## 动画系统设计
|
||||
|
||||
### 动画类型
|
||||
1. **骨骼动画**
|
||||
- 关节旋转控制
|
||||
- 骨骼层次结构
|
||||
- 动作混合
|
||||
- 逆向运动学
|
||||
|
||||
2. **表情动画**
|
||||
- 面部肌肉控制
|
||||
- 表情混合
|
||||
- 实时表情捕捉
|
||||
- 情绪表达映射
|
||||
|
||||
3. **程序动画**
|
||||
- 物理模拟
|
||||
- 粒子系统
|
||||
- 布料模拟
|
||||
- 头发动画
|
||||
|
||||
### 动画状态机
|
||||
- **状态定义**: 待机、说话、思考、响应
|
||||
- **状态转换**: 平滑过渡控制
|
||||
- **条件触发**: 基于输入的状态切换
|
||||
- **优先级管理**: 动画播放优先级
|
||||
|
||||
## 资源管理系统
|
||||
|
||||
### 资源类型
|
||||
1. **模型资源**
|
||||
- 3D几何模型
|
||||
- 纹理贴图
|
||||
- 材质定义
|
||||
- 骨骼数据
|
||||
|
||||
2. **动画资源**
|
||||
- 关键帧数据
|
||||
- 动作序列
|
||||
- 表情数据
|
||||
- 音频同步
|
||||
|
||||
3. **配置资源**
|
||||
- 场景配置
|
||||
- 行为定义
|
||||
- 参数设置
|
||||
- 皮肤主题
|
||||
|
||||
### 缓存策略
|
||||
- **多级缓存**: 内存+磁盘缓存
|
||||
- **LRU算法**: 最近最少使用淘汰
|
||||
- **压缩存储**: 减少存储空间
|
||||
- **增量更新**: 仅更新变化部分
|
||||
|
||||
## 安全特性
|
||||
|
||||
### 数据安全
|
||||
- 资源文件加密存储
|
||||
- 传输数据加密
|
||||
- 数字签名验证
|
||||
- 防篡改检测
|
||||
|
||||
### 隐私保护
|
||||
- 本地数据保护
|
||||
- 用户行为数据脱敏
|
||||
- 敏感信息加密
|
||||
- 访问权限控制
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 渲染优化
|
||||
- GPU资源管理
|
||||
- 绘制批次优化
|
||||
- 着色器缓存
|
||||
- 内存池管理
|
||||
|
||||
### 动画优化
|
||||
- 动画数据压缩
|
||||
- 关键帧插值优化
|
||||
- 动画LOD系统
|
||||
- 预计算优化
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 插件化架构
|
||||
- 自定义渲染器
|
||||
- 扩展动画系统
|
||||
- 第三方资源集成
|
||||
- 自定义交互模式
|
||||
|
||||
### 配置化管理
|
||||
- 渲染质量可配置
|
||||
- 动画参数可调节
|
||||
- 资源策略可定制
|
||||
- 性能阈值可设置
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- 渲染算法测试
|
||||
- 动画逻辑测试
|
||||
- 资源管理测试
|
||||
- 数据模型测试
|
||||
|
||||
### 性能测试
|
||||
- 渲染性能测试
|
||||
- 内存使用测试
|
||||
- 电池续航测试
|
||||
- 热量控制测试
|
||||
|
||||
### 兼容性测试
|
||||
- 不同设备测试
|
||||
- 不同分辨率测试
|
||||
- 不同GPU测试
|
||||
- 系统版本兼容测试
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 资源部署
|
||||
- CDN资源分发
|
||||
- 区域化部署
|
||||
- 版本管理
|
||||
- 灰度发布
|
||||
|
||||
### 监控指标
|
||||
- 渲染帧率
|
||||
- 资源加载时间
|
||||
- 内存使用率
|
||||
- 崩溃率统计
|
||||
|
||||
## 总结
|
||||
|
||||
`clr_avatarcore` 模块作为 OneApp 的虚拟形象核心引擎,提供了完整的3D虚拟形象渲染和交互能力。通过高效的渲染管道、智能的动画系统和完善的资源管理,为用户提供了生动逼真的虚拟助手体验。模块具有良好的性能优化和扩展能力,能够适应不同硬件环境和业务需求。
|
||||
704
app_car/clr_order.md
Normal file
704
app_car/clr_order.md
Normal file
@@ -0,0 +1,704 @@
|
||||
# CLR Order - 订单服务 SDK
|
||||
|
||||
## 模块概述
|
||||
|
||||
`clr_order` 是 OneApp 车辆订单管理的核心服务 SDK,提供了完整的订单生命周期管理功能。该模块封装了订单创建、支付、状态跟踪、取消退款等核心业务逻辑,为上层应用模块提供统一的订单服务接口。
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. 订单管理
|
||||
- **订单创建**:支持多种类型订单的创建和初始化
|
||||
- **订单查询**:提供订单详情查询和列表获取功能
|
||||
- **订单更新**:支持订单状态和信息的实时更新
|
||||
- **订单取消**:处理订单取消和退款流程
|
||||
|
||||
### 2. 支付集成
|
||||
- **支付方式管理**:支持多种支付渠道的集成
|
||||
- **支付状态跟踪**:实时监控支付进度和结果
|
||||
- **退款处理**:自动化的退款流程处理
|
||||
- **支付安全**:确保支付过程的安全性和可靠性
|
||||
|
||||
### 3. 订单类型支持
|
||||
- **充电订单**:电动车充电服务订单
|
||||
- **维保订单**:车辆维护保养服务订单
|
||||
- **配件订单**:车辆配件和用品订单
|
||||
- **服务订单**:各类增值服务订单
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 架构设计
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 应用层 │
|
||||
│ (app_order, app_charging, etc.) │
|
||||
├─────────────────────────────────────┤
|
||||
│ CLR Order SDK │
|
||||
│ ┌─────────────┬─────────────────┐ │
|
||||
│ │ 订单管理 │ 支付服务 │ │
|
||||
│ ├─────────────┼─────────────────┤ │
|
||||
│ │ 状态机制 │ 安全认证 │ │
|
||||
│ └─────────────┴─────────────────┘ │
|
||||
├─────────────────────────────────────┤
|
||||
│ 网络层 │
|
||||
│ (RESTful API / GraphQL) │
|
||||
├─────────────────────────────────────┤
|
||||
│ 后端服务 │
|
||||
│ ┌─────────────┬─────────────────┐ │
|
||||
│ │ 订单服务 │ 支付网关 │ │
|
||||
│ └─────────────┴─────────────────┘ │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 核心组件
|
||||
|
||||
#### 1. 订单管理器 (OrderFacade)
|
||||
```dart
|
||||
/// 订单服务接口
|
||||
abstract class IOrderFacade {
|
||||
/// 创建订单
|
||||
Future<Either<OrderError, OrderDetail>> createOrder({
|
||||
required OrderCreateParams params,
|
||||
});
|
||||
|
||||
/// 批量获取订单
|
||||
Future<Either<OrderError, OrderList>> fetchOrders({
|
||||
required int pageIndex,
|
||||
required OrderQueryType orderQueryType,
|
||||
int pageSize = 10,
|
||||
OrderRefundQueryType? orderRefundQueryType,
|
||||
});
|
||||
|
||||
/// 取消订单
|
||||
Future<Either<OrderError, Unit>> cancelOrder(String orderId);
|
||||
|
||||
/// 删除订单
|
||||
Future<Either<OrderError, Unit>> delOrder(String orderId);
|
||||
|
||||
/// 获取订单详情
|
||||
Future<Either<OrderError, OrderDetail>> fetchOrderDetail(
|
||||
String orderId, {
|
||||
bool realTimePull = false,
|
||||
});
|
||||
|
||||
/// 获取退款详情
|
||||
Future<Either<OrderError, RefundDetail>> fetchRefundDetail(String orderId);
|
||||
|
||||
/// 获取待支付的总数
|
||||
Future<Either<OrderError, OrderNum>> fetchAllUnpaidNum();
|
||||
|
||||
/// 获取订单状态
|
||||
Future<Either<OrderError, OrderStatus>> fetchOrderStatus(String orderId);
|
||||
}
|
||||
|
||||
class OrderFacade implements IOrderFacade {
|
||||
final OrderRemoteApi? remoteApi;
|
||||
final String? environment;
|
||||
|
||||
OrderFacade(this.remoteApi, this.environment) {
|
||||
remoteApi ??= OrderRemoteApi(Impl());
|
||||
environment ??= defaultOption.environment;
|
||||
OrderModuleConfig.setUp(environment ?? '');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<OrderError, OrderDetail>> createOrder({
|
||||
required OrderCreateParams params,
|
||||
}) async {
|
||||
try {
|
||||
final orderDetail = await remoteApi!.createOrder(params: params);
|
||||
return right(orderDetail);
|
||||
} catch (e) {
|
||||
return left(OrderError.createOrderError(obj: 'create order failed, $e'));
|
||||
}
|
||||
}
|
||||
|
||||
// 其他方法实现...
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 发票门面 (InvoiceFacade)
|
||||
```dart
|
||||
/// 发票服务接口
|
||||
abstract class IInvoiceFacade {
|
||||
/// 获取发票抬头详情
|
||||
Future<Either<OrderError, InvoiceTitleDetailsDo>> getInvoiceTitleDetails(
|
||||
String titleId,
|
||||
);
|
||||
|
||||
/// 新增/修改发票抬头
|
||||
Future<Either<OrderError, String>> submitInvoiceTitleDetails(
|
||||
InvoiceTitleDetailsDo invoiceTitleDetails,
|
||||
);
|
||||
|
||||
/// 删除发票抬头
|
||||
Future<Either<OrderError, Unit>> delInvoiceTitleDetails(String titleId);
|
||||
|
||||
/// 获取发票抬头列表
|
||||
Future<Either<OrderError, List<InvoiceTitleDetailsDo>>>
|
||||
getInvoiceTitleDetailsList();
|
||||
|
||||
/// 获取发票详情
|
||||
Future<Either<OrderError, InvoiceDetailsDo>> getInvoiceDetails(
|
||||
String invoiceId,
|
||||
);
|
||||
|
||||
/// 获取发票历史列表
|
||||
Future<Either<OrderError, List<InvoiceDetailsDo>>> getInvoiceList({
|
||||
required int pageIndex,
|
||||
required int pageSize,
|
||||
});
|
||||
|
||||
/// 申请开具发票
|
||||
Future<Either<OrderError, Unit>> submitInvoice(InvoiceOptionsDo invoiceOptions);
|
||||
|
||||
/// 获取可开发票的订单列表
|
||||
Future<Either<OrderError, List<NoOpenInvoiceOrderDo>>> getNoOpenInvoiceOrderList({
|
||||
required int pageIndex,
|
||||
required int pageSize,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 订单状态和类型枚举
|
||||
```dart
|
||||
/// 订单状态枚举
|
||||
enum OrderStatus {
|
||||
unpaid, // 未付款
|
||||
paid, // 已付款
|
||||
processing, // 处理中
|
||||
completed, // 已完成
|
||||
cancelled, // 已取消
|
||||
refunding, // 退款中
|
||||
refunded // 已退款
|
||||
}
|
||||
|
||||
/// 订单查询类型
|
||||
enum OrderQueryType {
|
||||
all, // 全部
|
||||
unpaid, // 待付款
|
||||
paid, // 已付款
|
||||
completed, // 已完成
|
||||
cancelled // 已取消
|
||||
}
|
||||
|
||||
/// 订单退款查询类型
|
||||
enum OrderRefundQueryType {
|
||||
refunding, // 退款中
|
||||
refunded, // 已退款
|
||||
refundFailed // 退款失败
|
||||
}
|
||||
```
|
||||
|
||||
## 数据模型
|
||||
|
||||
### 订单模型
|
||||
```dart
|
||||
/// 订单领域模型
|
||||
class Order {
|
||||
/// 订单ID
|
||||
final String id;
|
||||
|
||||
/// 订单价格
|
||||
final double price;
|
||||
|
||||
/// 订单标题
|
||||
final String title;
|
||||
|
||||
/// 创建时间
|
||||
final DateTime createTime;
|
||||
|
||||
/// 订单状态
|
||||
final OrderStatus status;
|
||||
|
||||
/// 支付金额
|
||||
final double payAmount;
|
||||
|
||||
/// 订单来源
|
||||
final OrderSource orderSource;
|
||||
|
||||
/// 订单类型
|
||||
final OrderType orderType;
|
||||
|
||||
/// 折扣金额
|
||||
final double discountAmount;
|
||||
|
||||
/// 订单项总数量
|
||||
final int orderItemTotalQuantity;
|
||||
|
||||
Order({
|
||||
required this.id,
|
||||
required this.price,
|
||||
required this.title,
|
||||
required this.createTime,
|
||||
required this.status,
|
||||
required this.payAmount,
|
||||
required this.orderSource,
|
||||
required this.orderType,
|
||||
required this.discountAmount,
|
||||
required this.orderItemTotalQuantity,
|
||||
});
|
||||
|
||||
/// 从DTO转换为DO
|
||||
factory Order.fromDto(OrderDto dto) => Order(
|
||||
id: dto.orderNo,
|
||||
price: dto.orderAmount,
|
||||
title: dto.title,
|
||||
createTime: DateTime.fromMillisecondsSinceEpoch(dto.orderCreateTime),
|
||||
status: OrderStatusEx.valueFromBackend(dto.orderState),
|
||||
payAmount: dto.payAmount,
|
||||
orderSource: OrderSourceEx.valueFromBackend(dto.orderSource),
|
||||
orderType: OrderSourceTypeEx.valueFromBackend(dto.orderType),
|
||||
discountAmount: dto.discountAmount,
|
||||
orderItemTotalQuantity: dto.orderItemTotalQuantity,
|
||||
);
|
||||
}
|
||||
|
||||
/// 订单详情模型
|
||||
class OrderDetail {
|
||||
final String id;
|
||||
final double orderPrice;
|
||||
final List<Product> products;
|
||||
final DateTime createTime;
|
||||
final OrderStatus status;
|
||||
final double payAmount;
|
||||
final OrderSource orderSource;
|
||||
final OrderType orderType;
|
||||
final double discountAmount;
|
||||
final int orderItemTotalQuantity;
|
||||
|
||||
// 构造方法和工厂方法...
|
||||
}
|
||||
|
||||
/// 产品模型
|
||||
class Product {
|
||||
final String productId;
|
||||
final String productName;
|
||||
final String productImage;
|
||||
final double price;
|
||||
final int quantity;
|
||||
|
||||
// 构造方法...
|
||||
}
|
||||
```
|
||||
|
||||
### 发票模型
|
||||
```dart
|
||||
/// 发票详情模型
|
||||
class InvoiceDetailsDo {
|
||||
final String invoiceId;
|
||||
final String invoiceNumber;
|
||||
final String invoiceTitle;
|
||||
final double invoiceAmount;
|
||||
final DateTime createTime;
|
||||
final InvoiceStatus status;
|
||||
final String downloadUrl;
|
||||
|
||||
// 构造方法和工厂方法...
|
||||
}
|
||||
|
||||
/// 发票抬头模型
|
||||
class InvoiceTitleDetailsDo {
|
||||
final String titleId;
|
||||
final String invoiceTitle;
|
||||
final InvoiceType invoiceType;
|
||||
final String taxNumber;
|
||||
final String address;
|
||||
final String phone;
|
||||
final String bankName;
|
||||
final String bankAccount;
|
||||
|
||||
// 构造方法和工厂方法...
|
||||
}
|
||||
|
||||
/// 发票选项模型
|
||||
class InvoiceOptionsDo {
|
||||
final String orderId;
|
||||
final String titleId;
|
||||
final String invoiceType;
|
||||
final String email;
|
||||
|
||||
// 构造方法...
|
||||
}
|
||||
|
||||
/// 可开发票订单模型
|
||||
class NoOpenInvoiceOrderDo {
|
||||
final String orderId;
|
||||
final String orderTitle;
|
||||
final double amount;
|
||||
final DateTime createTime;
|
||||
final bool canInvoice;
|
||||
|
||||
// 构造方法...
|
||||
}
|
||||
```
|
||||
|
||||
## API 接口
|
||||
|
||||
### 订单接口
|
||||
```dart
|
||||
/// 订单服务接口
|
||||
abstract class IOrderFacade {
|
||||
/// 创建订单
|
||||
/// DSSOMOBILE-ONEAPP-ORDER-3001
|
||||
Future<Either<OrderError, OrderDetail>> createOrder({
|
||||
required OrderCreateParams params,
|
||||
});
|
||||
|
||||
/// 批量获取订单
|
||||
/// DSSOMOBILE-ONEAPP-ORDER-3002
|
||||
Future<Either<OrderError, OrderList>> fetchOrders({
|
||||
required int pageIndex,
|
||||
required OrderQueryType orderQueryType,
|
||||
int pageSize = 10,
|
||||
OrderRefundQueryType? orderRefundQueryType,
|
||||
});
|
||||
|
||||
/// 获取订单详情
|
||||
/// DSSOMOBILE-ONEAPP-ORDER-3003
|
||||
Future<Either<OrderError, OrderDetail>> fetchOrderDetail(
|
||||
String orderId, {
|
||||
bool realTimePull = false,
|
||||
});
|
||||
|
||||
/// 删除订单
|
||||
/// DSSOMOBILE-ONEAPP-ORDER-3004
|
||||
Future<Either<OrderError, Unit>> delOrder(String orderId);
|
||||
|
||||
/// 取消订单
|
||||
/// DSSOMOBILE-ONEAPP-ORDER-3005
|
||||
Future<Either<OrderError, Unit>> cancelOrder(String orderId);
|
||||
|
||||
/// 获取待支付订单数量
|
||||
/// DSSOMOBILE-ONEAPP-ORDER-3006
|
||||
Future<Either<OrderError, OrderNum>> fetchAllUnpaidNum();
|
||||
|
||||
/// 获取订单状态
|
||||
/// DSSOMOBILE-ONEAPP-ORDER-3007
|
||||
Future<Either<OrderError, OrderStatus>> fetchOrderStatus(String orderId);
|
||||
|
||||
/// 获取退款详情
|
||||
Future<Either<OrderError, RefundDetail>> fetchRefundDetail(String orderId);
|
||||
}
|
||||
```
|
||||
|
||||
### 发票接口
|
||||
```dart
|
||||
/// 发票服务接口
|
||||
abstract class IInvoiceFacade {
|
||||
/// 获取发票抬头详情
|
||||
Future<Either<OrderError, InvoiceTitleDetailsDo>> getInvoiceTitleDetails(
|
||||
String titleId,
|
||||
);
|
||||
|
||||
/// 新增/修改发票抬头
|
||||
Future<Either<OrderError, String>> submitInvoiceTitleDetails(
|
||||
InvoiceTitleDetailsDo invoiceTitleDetails,
|
||||
);
|
||||
|
||||
/// 删除发票抬头
|
||||
Future<Either<OrderError, Unit>> delInvoiceTitleDetails(String titleId);
|
||||
|
||||
/// 获取发票抬头列表
|
||||
Future<Either<OrderError, List<InvoiceTitleDetailsDo>>>
|
||||
getInvoiceTitleDetailsList();
|
||||
|
||||
/// 获取发票详情
|
||||
Future<Either<OrderError, InvoiceDetailsDo>> getInvoiceDetails(
|
||||
String invoiceId,
|
||||
);
|
||||
|
||||
/// 获取发票历史列表
|
||||
Future<Either<OrderError, List<InvoiceDetailsDo>>> getInvoiceList({
|
||||
required int pageIndex,
|
||||
required int pageSize,
|
||||
});
|
||||
|
||||
/// 申请开具发票
|
||||
Future<Either<OrderError, Unit>> submitInvoice(InvoiceOptionsDo invoiceOptions);
|
||||
|
||||
/// 获取可开发票的订单列表
|
||||
Future<Either<OrderError, List<NoOpenInvoiceOrderDo>>> getNoOpenInvoiceOrderList({
|
||||
required int pageIndex,
|
||||
required int pageSize,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 环境配置
|
||||
```dart
|
||||
class OrderConfig {
|
||||
static const String baseUrl = String.fromEnvironment('ORDER_API_BASE_URL');
|
||||
static const String apiKey = String.fromEnvironment('ORDER_API_KEY');
|
||||
static const int timeoutSeconds = 30;
|
||||
static const int maxRetries = 3;
|
||||
}
|
||||
```
|
||||
|
||||
### 支付配置
|
||||
```dart
|
||||
class PaymentConfig {
|
||||
static const Map<PaymentMethod, PaymentProviderConfig> providers = {
|
||||
PaymentMethod.creditCard: PaymentProviderConfig(
|
||||
provider: 'stripe',
|
||||
publicKey: 'pk_live_...',
|
||||
),
|
||||
PaymentMethod.digitalWallet: PaymentProviderConfig(
|
||||
provider: 'alipay',
|
||||
appId: 'app_...',
|
||||
),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 订单错误类型
|
||||
```dart
|
||||
enum OrderErrorType {
|
||||
invalidRequest, // 无效请求
|
||||
orderNotFound, // 订单未找到
|
||||
paymentFailed, // 支付失败
|
||||
insufficientStock, // 库存不足
|
||||
orderExpired, // 订单过期
|
||||
unauthorized, // 未授权
|
||||
networkError, // 网络错误
|
||||
serverError // 服务器错误
|
||||
}
|
||||
|
||||
class OrderException implements Exception {
|
||||
final OrderErrorType type;
|
||||
final String message;
|
||||
final Map<String, dynamic>? details;
|
||||
|
||||
const OrderException(this.type, this.message, [this.details]);
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 创建订单
|
||||
```dart
|
||||
final orderFacade = buildOrderFacadeImpl();
|
||||
|
||||
try {
|
||||
final orderCreateParams = OrderCreateParams(
|
||||
products: [
|
||||
OrderProduct(
|
||||
productId: 'charging_session',
|
||||
quantity: 1,
|
||||
price: 25.0,
|
||||
),
|
||||
],
|
||||
deliveryAddress: '北京市朝阳区...',
|
||||
paymentMethod: 'alipay',
|
||||
);
|
||||
|
||||
final result = await orderFacade.createOrder(params: orderCreateParams);
|
||||
|
||||
result.fold(
|
||||
(error) => print('订单创建失败: ${error.message}'),
|
||||
(orderDetail) => print('订单创建成功: ${orderDetail.id}'),
|
||||
);
|
||||
} catch (e) {
|
||||
print('订单创建异常: $e');
|
||||
}
|
||||
```
|
||||
|
||||
### 查询订单列表
|
||||
```dart
|
||||
final orderFacade = buildOrderFacadeImpl();
|
||||
|
||||
try {
|
||||
final result = await orderFacade.fetchOrders(
|
||||
pageIndex: 1,
|
||||
orderQueryType: OrderQueryType.all,
|
||||
pageSize: 20,
|
||||
);
|
||||
|
||||
result.fold(
|
||||
(error) => print('查询订单失败: ${error.message}'),
|
||||
(orderList) {
|
||||
print('查询订单成功,共 ${orderList.orders.length} 条记录');
|
||||
for (final order in orderList.orders) {
|
||||
print('订单: ${order.id} - ${order.title} - ${order.status}');
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
print('查询订单异常: $e');
|
||||
}
|
||||
```
|
||||
|
||||
### 获取订单详情
|
||||
```dart
|
||||
final orderFacade = buildOrderFacadeImpl();
|
||||
|
||||
try {
|
||||
final result = await orderFacade.fetchOrderDetail('order_123');
|
||||
|
||||
result.fold(
|
||||
(error) => print('获取订单详情失败: ${error.message}'),
|
||||
(orderDetail) {
|
||||
print('订单详情获取成功:');
|
||||
print('订单ID: ${orderDetail.id}');
|
||||
print('订单状态: ${orderDetail.status}');
|
||||
print('订单金额: ${orderDetail.orderPrice}');
|
||||
print('产品列表: ${orderDetail.products.map((p) => p.productName).join(', ')}');
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
print('获取订单详情异常: $e');
|
||||
}
|
||||
```
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
```dart
|
||||
group('OrderManager Tests', () {
|
||||
test('should create order successfully', () async {
|
||||
// Given
|
||||
final request = CreateOrderRequest(/* ... */);
|
||||
|
||||
// When
|
||||
final result = await orderManager.createOrder(request);
|
||||
|
||||
// Then
|
||||
expect(result.isSuccess, true);
|
||||
expect(result.data.status, OrderStatus.created);
|
||||
});
|
||||
|
||||
test('should handle payment failure', () async {
|
||||
// Given
|
||||
final request = PaymentRequest(/* invalid data */);
|
||||
|
||||
// When & Then
|
||||
expect(
|
||||
() => paymentProcessor.initiatePayment(request),
|
||||
throwsA(isA<OrderException>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 集成测试
|
||||
```dart
|
||||
group('Order Integration Tests', () {
|
||||
testWidgets('complete order flow', (tester) async {
|
||||
// 1. 创建订单
|
||||
final order = await createTestOrder();
|
||||
|
||||
// 2. 处理支付
|
||||
final payment = await processTestPayment(order.id);
|
||||
|
||||
// 3. 验证订单状态
|
||||
final updatedOrder = await getOrder(order.id);
|
||||
expect(updatedOrder.status, OrderStatus.completed);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 缓存策略
|
||||
- **订单缓存**:本地缓存常用订单信息
|
||||
- **支付状态缓存**:缓存支付状态避免频繁查询
|
||||
- **配置缓存**:缓存支付配置和费率信息
|
||||
|
||||
### 网络优化
|
||||
- **请求合并**:合并多个订单查询请求
|
||||
- **分页加载**:大量订单数据分页获取
|
||||
- **压缩传输**:启用 gzip 压缩减少传输量
|
||||
|
||||
## 安全考虑
|
||||
|
||||
### 数据安全
|
||||
- **敏感信息加密**:支付信息和个人数据加密存储
|
||||
- **传输安全**:使用 HTTPS 和证书绑定
|
||||
- **访问控制**:基于角色的权限控制
|
||||
|
||||
### 支付安全
|
||||
- **PCI DSS 合规**:遵循支付卡行业数据安全标准
|
||||
- **令牌化**:敏感支付信息使用令牌替换
|
||||
- **风险控制**:实时风险评估和欺诈检测
|
||||
|
||||
## 监控和分析
|
||||
|
||||
### 业务指标
|
||||
- **订单转化率**:从创建到完成的转化率
|
||||
- **支付成功率**:支付处理的成功率
|
||||
- **平均订单价值**:订单金额统计分析
|
||||
- **退款率**:退款订单占比
|
||||
|
||||
### 技术指标
|
||||
- **API 响应时间**:接口性能监控
|
||||
- **错误率**:系统错误和异常监控
|
||||
- **可用性**:服务可用性监控
|
||||
- **吞吐量**:系统处理能力监控
|
||||
|
||||
## 版本历史
|
||||
|
||||
### v0.2.6+3 (当前版本)
|
||||
- 新增加密货币支付支持
|
||||
- 优化订单状态机逻辑
|
||||
- 修复支付回调处理问题
|
||||
- 改进错误处理机制
|
||||
|
||||
### v0.2.5
|
||||
- 支持批量订单操作
|
||||
- 新增订单搜索功能
|
||||
- 优化支付流程
|
||||
- 修复已知 bug
|
||||
|
||||
### v0.2.4
|
||||
- 支持多币种订单
|
||||
- 新增订单模板功能
|
||||
- 改进性能和稳定性
|
||||
|
||||
## 依赖关系
|
||||
|
||||
### 内部依赖
|
||||
- `basic_network`: 网络请求基础库
|
||||
- `basic_storage`: 本地存储服务
|
||||
- `basic_error`: 错误处理框架
|
||||
- `basic_track`: 埋点统计服务
|
||||
|
||||
### 外部依赖
|
||||
- `dio`: HTTP 客户端
|
||||
- `json_annotation`: JSON 序列化
|
||||
- `rxdart`: 响应式编程支持
|
||||
|
||||
## 部署说明
|
||||
|
||||
### 环境变量
|
||||
```bash
|
||||
ORDER_API_BASE_URL=https://api.oneapp.com/order
|
||||
ORDER_API_KEY=your_api_key_here
|
||||
PAYMENT_PROVIDER_STRIPE_KEY=pk_live_...
|
||||
PAYMENT_PROVIDER_ALIPAY_APP_ID=app_...
|
||||
```
|
||||
|
||||
### 配置文件
|
||||
```yaml
|
||||
order:
|
||||
timeout: 30s
|
||||
retry_count: 3
|
||||
cache_ttl: 300s
|
||||
|
||||
payment:
|
||||
providers:
|
||||
- stripe
|
||||
- alipay
|
||||
- wechat_pay
|
||||
security:
|
||||
encryption: aes256
|
||||
signature: hmac_sha256
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
`clr_order` 作为订单服务的核心 SDK,提供了完整的订单生命周期管理能力。通过统一的接口设计、可靠的支付处理、完善的错误处理和安全保障,为 OneApp 的各个业务模块提供了稳定高效的订单服务支持。
|
||||
|
||||
该模块在设计上充分考虑了可扩展性、安全性和性能要求,能够很好地支撑车辆相关的各种订单业务场景,是 OneApp 电商和服务体系的重要基础设施。
|
||||
533
app_car/clr_touchgo.md
Normal file
533
app_car/clr_touchgo.md
Normal file
@@ -0,0 +1,533 @@
|
||||
# CLR TouchGo - Touch&Go 服务 SDK
|
||||
|
||||
## 模块概述
|
||||
|
||||
`clr_touchgo` 是 OneApp Touch&Go 智能交互功能的核心服务 SDK,提供了免接触式车辆操作和智能感知服务。该模块集成了先进的传感器技术、手势识别、语音控制等多种交互方式,为用户提供更便捷、更智能的车辆控制体验。
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. 手势控制
|
||||
- **手势识别**:支持多种手势的实时识别和响应
|
||||
- **动作映射**:将手势动作映射到具体的车辆控制指令
|
||||
- **精度优化**:高精度的手势识别算法
|
||||
- **自定义手势**:支持用户自定义手势指令
|
||||
|
||||
### 2. 语音交互
|
||||
- **语音识别**:高精度的语音识别引擎
|
||||
- **语义理解**:智能理解用户意图和指令
|
||||
- **语音合成**:自然流畅的语音反馈
|
||||
- **多语言支持**:支持多种语言的语音交互
|
||||
|
||||
### 3. 智能感知
|
||||
- **环境感知**:感知车辆周围环境状态
|
||||
- **用户识别**:识别和认证授权用户
|
||||
- **行为预测**:基于历史数据预测用户行为
|
||||
- **场景适配**:根据不同场景自动调整交互方式
|
||||
|
||||
### 4. 免接触操作
|
||||
- **远程控制**:支持远距离的车辆控制
|
||||
- **自动执行**:基于条件自动执行预设操作
|
||||
- **安全验证**:多重安全验证确保操作安全
|
||||
- **实时反馈**:操作结果的实时反馈
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 架构设计
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 应用层 │
|
||||
│ (app_touchgo, app_car) │
|
||||
├─────────────────────────────────────┤
|
||||
│ CLR TouchGo SDK │
|
||||
│ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ 手势识别 │ 语音控制 │ 智能感知 │ │
|
||||
│ ├──────────┼──────────┼──────────┤ │
|
||||
│ │ 传感器 │ AI引擎 │ 安全模块 │ │
|
||||
│ └──────────┴──────────┴──────────┘ │
|
||||
├─────────────────────────────────────┤
|
||||
│ 硬件抽象层 │
|
||||
│ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ 摄像头 │ 麦克风 │ 距离传感 │ │
|
||||
│ └──────────┴──────────┴──────────┘ │
|
||||
├─────────────────────────────────────┤
|
||||
│ 车载系统 │
|
||||
│ (CAN Bus, ECU, etc.) │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 核心组件
|
||||
|
||||
#### 1. 手势识别引擎 (GestureEngine)
|
||||
```dart
|
||||
class GestureEngine {
|
||||
// 初始化手势识别
|
||||
Future<bool> initialize();
|
||||
|
||||
// 开始手势检测
|
||||
Future<void> startDetection();
|
||||
|
||||
// 停止手势检测
|
||||
Future<void> stopDetection();
|
||||
|
||||
// 注册手势处理器
|
||||
void registerGestureHandler(GestureType type, GestureHandler handler);
|
||||
|
||||
// 校准手势识别
|
||||
Future<bool> calibrateGesture(GestureType type);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 语音控制引擎 (VoiceEngine)
|
||||
```dart
|
||||
class VoiceEngine {
|
||||
// 初始化语音引擎
|
||||
Future<bool> initialize(VoiceConfig config);
|
||||
|
||||
// 开始语音监听
|
||||
Future<void> startListening();
|
||||
|
||||
// 停止语音监听
|
||||
Future<void> stopListening();
|
||||
|
||||
// 语音合成
|
||||
Future<void> speak(String text, VoiceSettings settings);
|
||||
|
||||
// 设置语音识别语言
|
||||
Future<void> setLanguage(String languageCode);
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 智能感知管理器 (SensingManager)
|
||||
```dart
|
||||
class SensingManager {
|
||||
// 开始环境感知
|
||||
Future<void> startEnvironmentSensing();
|
||||
|
||||
// 用户身份识别
|
||||
Future<UserIdentity> identifyUser();
|
||||
|
||||
// 获取环境状态
|
||||
Future<EnvironmentState> getEnvironmentState();
|
||||
|
||||
// 预测用户行为
|
||||
Future<List<PredictedAction>> predictUserActions();
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 安全验证模块 (SecurityModule)
|
||||
```dart
|
||||
class SecurityModule {
|
||||
// 生物特征验证
|
||||
Future<bool> verifyBiometrics(BiometricData data);
|
||||
|
||||
// 多因子认证
|
||||
Future<bool> multiFactorAuth(List<AuthFactor> factors);
|
||||
|
||||
// 操作权限检查
|
||||
Future<bool> checkPermission(String userId, Operation operation);
|
||||
|
||||
// 安全日志记录
|
||||
Future<void> logSecurityEvent(SecurityEvent event);
|
||||
}
|
||||
```
|
||||
|
||||
## 数据模型
|
||||
|
||||
### 手势模型
|
||||
```dart
|
||||
enum GestureType {
|
||||
swipeLeft, // 左滑
|
||||
swipeRight, // 右滑
|
||||
swipeUp, // 上滑
|
||||
swipeDown, // 下滑
|
||||
pinch, // 捏合
|
||||
spread, // 展开
|
||||
tap, // 点击
|
||||
longPress, // 长按
|
||||
circle, // 画圈
|
||||
custom // 自定义
|
||||
}
|
||||
|
||||
class Gesture {
|
||||
final GestureType type;
|
||||
final List<Point> trajectory;
|
||||
final double confidence;
|
||||
final DateTime timestamp;
|
||||
final Map<String, dynamic> metadata;
|
||||
}
|
||||
```
|
||||
|
||||
### 语音模型
|
||||
```dart
|
||||
class VoiceCommand {
|
||||
final String text;
|
||||
final String intent;
|
||||
final Map<String, String> entities;
|
||||
final double confidence;
|
||||
final String languageCode;
|
||||
final DateTime timestamp;
|
||||
}
|
||||
|
||||
class VoiceResponse {
|
||||
final String text;
|
||||
final VoiceSettings settings;
|
||||
final Duration duration;
|
||||
final AudioFormat format;
|
||||
}
|
||||
```
|
||||
|
||||
### 感知模型
|
||||
```dart
|
||||
class EnvironmentState {
|
||||
final double lighting;
|
||||
final double noise;
|
||||
final double temperature;
|
||||
final List<DetectedObject> objects;
|
||||
final List<DetectedPerson> persons;
|
||||
final DateTime timestamp;
|
||||
}
|
||||
|
||||
class UserIdentity {
|
||||
final String userId;
|
||||
final String name;
|
||||
final double confidence;
|
||||
final BiometricData biometrics;
|
||||
final List<String> permissions;
|
||||
}
|
||||
```
|
||||
|
||||
## API 接口
|
||||
|
||||
### 手势控制接口
|
||||
```dart
|
||||
abstract class GestureService {
|
||||
// 配置手势识别
|
||||
Future<ApiResponse<bool>> configureGesture(GestureConfig config);
|
||||
|
||||
// 执行手势指令
|
||||
Future<ApiResponse<CommandResult>> executeGestureCommand(GestureCommand command);
|
||||
|
||||
// 获取支持的手势列表
|
||||
Future<ApiResponse<List<GestureType>>> getSupportedGestures();
|
||||
|
||||
// 训练自定义手势
|
||||
Future<ApiResponse<bool>> trainCustomGesture(CustomGestureData data);
|
||||
}
|
||||
```
|
||||
|
||||
### 语音控制接口
|
||||
```dart
|
||||
abstract class VoiceService {
|
||||
// 处理语音指令
|
||||
Future<ApiResponse<CommandResult>> processVoiceCommand(VoiceCommand command);
|
||||
|
||||
// 获取语音配置
|
||||
Future<ApiResponse<VoiceConfig>> getVoiceConfig();
|
||||
|
||||
// 更新语音设置
|
||||
Future<ApiResponse<bool>> updateVoiceSettings(VoiceSettings settings);
|
||||
|
||||
// 获取支持的语言
|
||||
Future<ApiResponse<List<Language>>> getSupportedLanguages();
|
||||
}
|
||||
```
|
||||
|
||||
### 智能感知接口
|
||||
```dart
|
||||
abstract class SensingService {
|
||||
// 获取环境状态
|
||||
Future<ApiResponse<EnvironmentState>> getEnvironmentState();
|
||||
|
||||
// 识别用户身份
|
||||
Future<ApiResponse<UserIdentity>> identifyUser(BiometricData data);
|
||||
|
||||
// 获取行为预测
|
||||
Future<ApiResponse<List<PredictedAction>>> getPredictedActions(String userId);
|
||||
|
||||
// 更新感知配置
|
||||
Future<ApiResponse<bool>> updateSensingConfig(SensingConfig config);
|
||||
}
|
||||
```
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 手势配置
|
||||
```dart
|
||||
class GestureConfig {
|
||||
final double sensitivity;
|
||||
final double timeoutMs;
|
||||
final bool enableCustomGestures;
|
||||
final Map<GestureType, GestureSettings> gestureSettings;
|
||||
|
||||
static const GestureConfig defaultConfig = GestureConfig(
|
||||
sensitivity: 0.8,
|
||||
timeoutMs: 3000,
|
||||
enableCustomGestures: true,
|
||||
gestureSettings: {
|
||||
GestureType.swipeLeft: GestureSettings(threshold: 50.0),
|
||||
GestureType.swipeRight: GestureSettings(threshold: 50.0),
|
||||
// ... other gestures
|
||||
},
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 语音配置
|
||||
```dart
|
||||
class VoiceConfig {
|
||||
final String languageCode;
|
||||
final double noiseReduction;
|
||||
final bool continuousListening;
|
||||
final VoiceModel model;
|
||||
final Map<String, dynamic> customSettings;
|
||||
|
||||
static const VoiceConfig defaultConfig = VoiceConfig(
|
||||
languageCode: 'zh-CN',
|
||||
noiseReduction: 0.7,
|
||||
continuousListening: false,
|
||||
model: VoiceModel.enhanced,
|
||||
customSettings: {},
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 算法和模型
|
||||
|
||||
### 手势识别算法
|
||||
```dart
|
||||
class GestureRecognitionAlgorithm {
|
||||
// 特征提取
|
||||
List<Feature> extractFeatures(List<Point> trajectory);
|
||||
|
||||
// 模式匹配
|
||||
GestureMatch matchPattern(List<Feature> features);
|
||||
|
||||
// 置信度计算
|
||||
double calculateConfidence(GestureMatch match);
|
||||
|
||||
// 模型训练
|
||||
Future<bool> trainModel(List<TrainingData> data);
|
||||
}
|
||||
```
|
||||
|
||||
### 语音识别模型
|
||||
```dart
|
||||
class VoiceRecognitionModel {
|
||||
// 音频预处理
|
||||
AudioFeatures preprocessAudio(AudioData audio);
|
||||
|
||||
// 语音转文本
|
||||
String speechToText(AudioFeatures features);
|
||||
|
||||
// 意图识别
|
||||
Intent recognizeIntent(String text);
|
||||
|
||||
// 实体抽取
|
||||
Map<String, String> extractEntities(String text);
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 手势控制示例
|
||||
```dart
|
||||
// 初始化手势引擎
|
||||
final gestureEngine = GestureEngine.instance;
|
||||
await gestureEngine.initialize();
|
||||
|
||||
// 注册手势处理器
|
||||
gestureEngine.registerGestureHandler(
|
||||
GestureType.swipeLeft,
|
||||
(gesture) async {
|
||||
// 执行左滑操作:打开车门
|
||||
await CarController.instance.openDoor(DoorPosition.driver);
|
||||
},
|
||||
);
|
||||
|
||||
// 开始手势检测
|
||||
await gestureEngine.startDetection();
|
||||
```
|
||||
|
||||
### 语音控制示例
|
||||
```dart
|
||||
// 初始化语音引擎
|
||||
final voiceEngine = VoiceEngine.instance;
|
||||
await voiceEngine.initialize(VoiceConfig.defaultConfig);
|
||||
|
||||
// 设置语音指令处理器
|
||||
voiceEngine.onVoiceCommand.listen((command) async {
|
||||
switch (command.intent) {
|
||||
case 'start_engine':
|
||||
await CarController.instance.startEngine();
|
||||
await voiceEngine.speak('引擎已启动');
|
||||
break;
|
||||
case 'open_window':
|
||||
await CarController.instance.openWindow();
|
||||
await voiceEngine.speak('车窗已打开');
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 开始语音监听
|
||||
await voiceEngine.startListening();
|
||||
```
|
||||
|
||||
### 智能感知示例
|
||||
```dart
|
||||
// 初始化感知管理器
|
||||
final sensingManager = SensingManager.instance;
|
||||
|
||||
// 开始环境感知
|
||||
await sensingManager.startEnvironmentSensing();
|
||||
|
||||
// 监听用户接近事件
|
||||
sensingManager.onUserApproaching.listen((user) async {
|
||||
// 用户接近时自动解锁车辆
|
||||
if (user.isAuthorized) {
|
||||
await CarController.instance.unlockVehicle();
|
||||
|
||||
// 根据用户偏好调整车内环境
|
||||
final preferences = await getUserPreferences(user.id);
|
||||
await CarController.instance.applyPreferences(preferences);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
```dart
|
||||
group('GestureEngine Tests', () {
|
||||
test('should recognize swipe left gesture', () async {
|
||||
// Given
|
||||
final trajectory = [
|
||||
Point(100, 50),
|
||||
Point(80, 50),
|
||||
Point(60, 50),
|
||||
Point(40, 50),
|
||||
Point(20, 50),
|
||||
];
|
||||
|
||||
// When
|
||||
final gesture = await gestureEngine.recognizeGesture(trajectory);
|
||||
|
||||
// Then
|
||||
expect(gesture.type, GestureType.swipeLeft);
|
||||
expect(gesture.confidence, greaterThan(0.8));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 集成测试
|
||||
```dart
|
||||
group('TouchGo Integration Tests', () {
|
||||
testWidgets('complete gesture control flow', (tester) async {
|
||||
// 1. 初始化系统
|
||||
await TouchGoService.initialize();
|
||||
|
||||
// 2. 模拟手势输入
|
||||
await tester.simulateGesture(GestureType.swipeLeft);
|
||||
|
||||
// 3. 验证车辆响应
|
||||
verify(mockCarController.openDoor(DoorPosition.driver));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 算法优化
|
||||
- **特征缓存**:缓存常用的特征计算结果
|
||||
- **模型压缩**:使用轻量级的识别模型
|
||||
- **并行处理**:多线程处理音视频数据
|
||||
- **增量学习**:在线学习优化识别精度
|
||||
|
||||
### 资源管理
|
||||
- **内存管理**:及时释放不需要的音视频数据
|
||||
- **CPU调度**:智能调度 AI 计算任务
|
||||
- **电池优化**:根据电量自动调整功能
|
||||
- **热量控制**:防止长时间运行过热
|
||||
|
||||
## 安全和隐私
|
||||
|
||||
### 数据安全
|
||||
- **本地处理**:敏感数据本地处理,不上传云端
|
||||
- **数据加密**:生物特征数据加密存储
|
||||
- **访问控制**:严格的权限控制机制
|
||||
- **审计日志**:完整的操作审计记录
|
||||
|
||||
### 隐私保护
|
||||
- **数据最小化**:只收集必要的数据
|
||||
- **用户授权**:明确的用户授权机制
|
||||
- **数据销毁**:及时删除过期数据
|
||||
- **匿名化**:敏感数据匿名化处理
|
||||
|
||||
## 监控和诊断
|
||||
|
||||
### 性能监控
|
||||
- **识别精度**:手势和语音识别的准确率
|
||||
- **响应时间**:从输入到执行的延迟
|
||||
- **资源使用**:CPU、内存、电池使用情况
|
||||
- **错误率**:系统错误和异常统计
|
||||
|
||||
### 用户体验监控
|
||||
- **使用频率**:各功能的使用频率统计
|
||||
- **用户满意度**:用户反馈和评分
|
||||
- **学习效果**:个性化学习的改进效果
|
||||
- **场景适配**:不同场景下的表现
|
||||
|
||||
## 版本历史
|
||||
|
||||
### v0.2.6+7 (当前版本)
|
||||
- 新增多语言语音支持
|
||||
- 优化手势识别算法
|
||||
- 改进低光环境下的识别能力
|
||||
- 修复已知稳定性问题
|
||||
|
||||
### v0.2.5
|
||||
- 支持自定义手势训练
|
||||
- 新增语音情感识别
|
||||
- 优化电池使用效率
|
||||
- 改进安全验证流程
|
||||
|
||||
### v0.2.4
|
||||
- 支持离线语音识别
|
||||
- 新增环境自适应功能
|
||||
- 优化识别精度
|
||||
- 修复兼容性问题
|
||||
|
||||
## 依赖关系
|
||||
|
||||
### 内部依赖
|
||||
- `basic_platform`: 平台抽象层
|
||||
- `basic_error`: 错误处理框架
|
||||
- `basic_storage`: 本地存储服务
|
||||
- `kit_native_uikit`: 原生 UI 组件
|
||||
|
||||
### 外部依赖
|
||||
- `camera`: 摄像头访问
|
||||
- `microphone`: 麦克风访问
|
||||
- `sensors_plus`: 传感器数据
|
||||
- `tflite_flutter`: TensorFlow Lite 模型
|
||||
|
||||
## 硬件要求
|
||||
|
||||
### 最低要求
|
||||
- **摄像头**: 前置摄像头,分辨率 ≥ 720p
|
||||
- **麦克风**: 数字麦克风,降噪支持
|
||||
- **处理器**: ARM64 架构,≥ 1.5GHz
|
||||
- **内存**: ≥ 2GB RAM
|
||||
- **存储**: ≥ 500MB 可用空间
|
||||
|
||||
### 推荐配置
|
||||
- **摄像头**: 1080p 前置摄像头,红外夜视
|
||||
- **麦克风**: 阵列麦克风,回声消除
|
||||
- **处理器**: ≥ 2.0GHz 多核处理器
|
||||
- **内存**: ≥ 4GB RAM
|
||||
- **传感器**: 距离传感器、环境光传感器
|
||||
|
||||
## 总结
|
||||
|
||||
`clr_touchgo` 作为 Touch&Go 智能交互的核心 SDK,通过集成先进的 AI 技术和传感器融合,为用户提供了自然、便捷、安全的车辆交互体验。该模块不仅支持传统的手势和语音控制,还具备智能感知和预测能力,能够主动为用户提供个性化的服务。
|
||||
|
||||
通过持续的算法优化和用户体验改进,TouchGo 技术将继续引领车辆智能交互的发展方向,为 OneApp 用户带来更加智能化的出行体验。
|
||||
364
app_car/clr_wallbox.md
Normal file
364
app_car/clr_wallbox.md
Normal file
@@ -0,0 +1,364 @@
|
||||
# CLR Wallbox 充电墙盒服务SDK
|
||||
|
||||
## 模块概述
|
||||
|
||||
`clr_wallbox` 是 OneApp 车联网生态中的充电墙盒服务SDK,负责充电墙盒设备的通信协议、数据处理、状态管理和业务逻辑封装等功能。该模块为充电墙盒应用提供底层的设备控制和数据服务能力。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: clr_wallbox
|
||||
- **版本**: 0.2.14
|
||||
- **描述**: 充电墙盒服务SDK
|
||||
- **Flutter 版本**: >=2.10.5
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **设备通信协议**
|
||||
- OCPP协议支持
|
||||
- Modbus通信协议
|
||||
- WebSocket实时通信
|
||||
- HTTP RESTful API
|
||||
|
||||
2. **数据处理服务**
|
||||
- 充电数据解析
|
||||
- 设备状态处理
|
||||
- 配置参数管理
|
||||
- 历史数据存储
|
||||
|
||||
3. **业务逻辑封装**
|
||||
- 充电会话管理
|
||||
- 计费逻辑处理
|
||||
- 安全验证机制
|
||||
- 异常处理流程
|
||||
|
||||
4. **状态监控系统**
|
||||
- 实时状态监控
|
||||
- 健康状态检查
|
||||
- 异常告警处理
|
||||
- 性能指标统计
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── clr_wallbox.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── protocols/ # 通信协议
|
||||
│ ├── services/ # 业务服务
|
||||
│ ├── models/ # 数据模型
|
||||
│ ├── repositories/ # 数据仓库
|
||||
│ ├── processors/ # 数据处理器
|
||||
│ └── utils/ # 工具类
|
||||
├── test/ # 测试文件
|
||||
└── generated/ # 代码生成文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心框架依赖
|
||||
- `basic_modular: ^0.2.3` - 模块化框架
|
||||
- `basic_network: ^0.2.3+4` - 网络通信框架
|
||||
- `basic_storage: ^0.2.2` - 本地存储框架
|
||||
- `basic_track: ^0.1.3` - 数据埋点
|
||||
|
||||
#### 工具依赖
|
||||
- `json_annotation: ^4.6.0` - JSON序列化
|
||||
- `dartz: ^0.10.1` - 函数式编程
|
||||
- `freezed_annotation: ^2.0.3` - 数据类注解
|
||||
- `path_provider: ^2.1.3` - 文件路径
|
||||
- `charset_converter: ^2.1.1` - 字符编码转换
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`clr_wallbox.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- SDK对外接口导出
|
||||
- 服务初始化配置
|
||||
- 依赖注入管理
|
||||
|
||||
### 2. 通信协议 (`src/protocols/`)
|
||||
|
||||
**功能职责**:
|
||||
- 充电设备通信协议实现
|
||||
- 消息编码解码处理
|
||||
- 协议版本管理
|
||||
- 连接状态维护
|
||||
|
||||
**主要协议**:
|
||||
- `OCPPProtocol` - OCPP充电协议
|
||||
- `ModbusProtocol` - Modbus工业协议
|
||||
- `WebSocketProtocol` - WebSocket实时协议
|
||||
- `HTTPProtocol` - HTTP REST协议
|
||||
|
||||
**协议特性**:
|
||||
- **OCPP 1.6/2.0**: 开放充电点协议
|
||||
- **Modbus RTU/TCP**: 工业标准协议
|
||||
- **自定义协议**: 厂商特定协议
|
||||
- **协议适配**: 多协议统一接口
|
||||
|
||||
### 3. 业务服务 (`src/services/`)
|
||||
|
||||
**功能职责**:
|
||||
- 充电业务逻辑封装
|
||||
- 设备管理服务
|
||||
- 用户认证服务
|
||||
- 计费结算服务
|
||||
|
||||
**主要服务**:
|
||||
- `ChargingService` - 充电服务
|
||||
- `DeviceService` - 设备服务
|
||||
- `AuthService` - 认证服务
|
||||
- `BillingService` - 计费服务
|
||||
- `MonitoringService` - 监控服务
|
||||
|
||||
### 4. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 充电设备数据模型
|
||||
- 协议消息模型
|
||||
- 业务实体模型
|
||||
- 配置参数模型
|
||||
|
||||
**主要模型**:
|
||||
- `WallboxDevice` - 墙盒设备模型
|
||||
- `ChargingSession` - 充电会话模型
|
||||
- `OCPPMessage` - OCPP消息模型
|
||||
- `DeviceStatus` - 设备状态模型
|
||||
- `ChargingConfig` - 充电配置模型
|
||||
|
||||
### 5. 数据仓库 (`src/repositories/`)
|
||||
|
||||
**功能职责**:
|
||||
- 设备数据持久化
|
||||
- 充电记录存储
|
||||
- 配置信息管理
|
||||
- 缓存数据处理
|
||||
|
||||
**主要仓库**:
|
||||
- `DeviceRepository` - 设备数据仓库
|
||||
- `SessionRepository` - 会话数据仓库
|
||||
- `ConfigRepository` - 配置数据仓库
|
||||
- `LogRepository` - 日志数据仓库
|
||||
|
||||
### 6. 数据处理器 (`src/processors/`)
|
||||
|
||||
**功能职责**:
|
||||
- 协议数据解析
|
||||
- 业务数据转换
|
||||
- 状态数据处理
|
||||
- 异常数据过滤
|
||||
|
||||
**主要处理器**:
|
||||
- `MessageProcessor` - 消息处理器
|
||||
- `StatusProcessor` - 状态处理器
|
||||
- `DataConverter` - 数据转换器
|
||||
- `ExceptionHandler` - 异常处理器
|
||||
|
||||
### 7. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- 协议工具方法
|
||||
- 数据验证工具
|
||||
- 加密解密工具
|
||||
- 时间处理工具
|
||||
|
||||
**主要工具**:
|
||||
- `ProtocolUtils` - 协议工具
|
||||
- `CryptoUtils` - 加密工具
|
||||
- `ValidationUtils` - 验证工具
|
||||
- `TimeUtils` - 时间工具
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 充电启动流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[用户请求充电] --> B[设备状态检查]
|
||||
B --> C{设备是否可用}
|
||||
C -->|否| D[返回设备不可用]
|
||||
C -->|是| E[用户身份验证]
|
||||
E --> F{验证是否通过}
|
||||
F -->|否| G[返回认证失败]
|
||||
F -->|是| H[发送充电启动指令]
|
||||
H --> I[设备响应处理]
|
||||
I --> J{启动是否成功}
|
||||
J -->|是| K[创建充电会话]
|
||||
J -->|否| L[返回启动失败]
|
||||
K --> M[开始充电监控]
|
||||
M --> N[记录充电数据]
|
||||
N --> O[更新充电状态]
|
||||
O --> P{充电是否完成}
|
||||
P -->|否| N
|
||||
P -->|是| Q[结束充电会话]
|
||||
Q --> R[生成充电报告]
|
||||
```
|
||||
|
||||
### OCPP消息处理流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[接收OCPP消息] --> B[消息格式验证]
|
||||
B --> C{格式是否正确}
|
||||
C -->|否| D[返回格式错误]
|
||||
C -->|是| E[解析消息内容]
|
||||
E --> F[识别消息类型]
|
||||
F --> G[路由到对应处理器]
|
||||
G --> H[执行业务逻辑]
|
||||
H --> I[生成响应消息]
|
||||
I --> J[序列化响应]
|
||||
J --> K[发送响应消息]
|
||||
K --> L[记录处理日志]
|
||||
```
|
||||
|
||||
## OCPP协议设计
|
||||
|
||||
### 消息类型
|
||||
1. **核心消息**
|
||||
- `Authorize` - 授权验证
|
||||
- `StartTransaction` - 开始充电
|
||||
- `StopTransaction` - 停止充电
|
||||
- `Heartbeat` - 心跳消息
|
||||
|
||||
2. **状态消息**
|
||||
- `StatusNotification` - 状态通知
|
||||
- `MeterValues` - 电表数值
|
||||
- `BootNotification` - 启动通知
|
||||
- `DataTransfer` - 数据传输
|
||||
|
||||
3. **配置消息**
|
||||
- `ChangeConfiguration` - 修改配置
|
||||
- `GetConfiguration` - 获取配置
|
||||
- `Reset` - 重置设备
|
||||
- `UnlockConnector` - 解锁连接器
|
||||
|
||||
### 消息结构
|
||||
```json
|
||||
{
|
||||
"messageTypeId": 2,
|
||||
"uniqueId": "19223201",
|
||||
"action": "Heartbeat",
|
||||
"payload": {}
|
||||
}
|
||||
```
|
||||
|
||||
## 数据存储设计
|
||||
|
||||
### 本地存储
|
||||
1. **设备配置**
|
||||
- 设备基本信息
|
||||
- 通信参数
|
||||
- 充电参数
|
||||
- 安全配置
|
||||
|
||||
2. **充电记录**
|
||||
- 充电会话数据
|
||||
- 电量消耗记录
|
||||
- 时间戳信息
|
||||
- 用户信息
|
||||
|
||||
3. **状态数据**
|
||||
- 设备当前状态
|
||||
- 错误信息
|
||||
- 性能指标
|
||||
- 诊断数据
|
||||
|
||||
### 数据同步
|
||||
- **增量同步**: 仅同步变化数据
|
||||
- **全量同步**: 定期全量同步
|
||||
- **冲突解决**: 数据冲突处理策略
|
||||
- **版本控制**: 数据版本管理
|
||||
|
||||
## 安全机制
|
||||
|
||||
### 通信安全
|
||||
- **TLS加密**: 传输层安全
|
||||
- **证书验证**: 设备身份验证
|
||||
- **消息签名**: 消息完整性验证
|
||||
- **防重放**: 防止重放攻击
|
||||
|
||||
### 数据安全
|
||||
- **敏感数据加密**: 本地数据加密
|
||||
- **访问控制**: 数据访问权限
|
||||
- **审计日志**: 操作审计记录
|
||||
- **安全擦除**: 数据安全删除
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 通信优化
|
||||
- **连接池**: 复用网络连接
|
||||
- **消息批处理**: 批量处理消息
|
||||
- **压缩传输**: 数据压缩传输
|
||||
- **异步处理**: 非阻塞消息处理
|
||||
|
||||
### 存储优化
|
||||
- **数据压缩**: 存储空间优化
|
||||
- **索引优化**: 查询性能优化
|
||||
- **缓存策略**: 热点数据缓存
|
||||
- **清理机制**: 过期数据清理
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 错误分类
|
||||
1. **通信错误**
|
||||
- 网络连接失败
|
||||
- 协议解析错误
|
||||
- 超时错误
|
||||
- 服务不可用
|
||||
|
||||
2. **业务错误**
|
||||
- 认证失败
|
||||
- 参数无效
|
||||
- 状态冲突
|
||||
- 资源不足
|
||||
|
||||
3. **系统错误**
|
||||
- 内存不足
|
||||
- 存储空间不够
|
||||
- 系统异常
|
||||
- 硬件故障
|
||||
|
||||
### 处理策略
|
||||
- **重试机制**: 自动重试失败操作
|
||||
- **降级处理**: 服务降级策略
|
||||
- **补偿机制**: 事务补偿处理
|
||||
- **告警通知**: 异常情况告警
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- **协议解析测试**: 消息编解码
|
||||
- **业务逻辑测试**: 充电流程
|
||||
- **数据模型测试**: 序列化反序列化
|
||||
- **工具类测试**: 工具方法功能
|
||||
|
||||
### 集成测试
|
||||
- **协议集成测试**: 设备通信
|
||||
- **数据库集成测试**: 数据持久化
|
||||
- **服务集成测试**: 端到端流程
|
||||
- **第三方集成测试**: 外部系统
|
||||
|
||||
### 兼容性测试
|
||||
- **设备兼容性**: 不同厂商设备
|
||||
- **协议版本**: OCPP不同版本
|
||||
- **网络环境**: 不同网络条件
|
||||
- **并发测试**: 多设备并发
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 配置管理
|
||||
- **环境配置**: 开发、测试、生产
|
||||
- **协议配置**: 协议参数设置
|
||||
- **安全配置**: 证书和密钥管理
|
||||
- **性能配置**: 性能调优参数
|
||||
|
||||
### 监控指标
|
||||
- **设备在线率**: 设备连接状态
|
||||
- **消息处理量**: 消息吞吐量
|
||||
- **错误率**: 错误发生频率
|
||||
- **响应时间**: 消息处理延迟
|
||||
|
||||
## 总结
|
||||
|
||||
`clr_wallbox` 模块作为 OneApp 的充电墙盒服务SDK,提供了完整的充电设备通信和管理能力。通过标准化的协议支持、稳定的数据处理和完善的安全机制,为充电基础设施的数字化管理提供了可靠的技术支撑。模块具有良好的扩展性和兼容性,能够适应不同厂商的充电设备和多样化的部署环境。
|
||||
391
app_car/kit_rpa_plugin.md
Normal file
391
app_car/kit_rpa_plugin.md
Normal file
@@ -0,0 +1,391 @@
|
||||
# Kit RPA Plugin RPA自动化插件
|
||||
|
||||
## 模块概述
|
||||
|
||||
`kit_rpa_plugin` 是 OneApp 车联网生态中的 RPA(Robotic Process Automation)原生插件,负责为 Flutter 应用提供原生平台的自动化操作能力。该插件通过平台通道实现 Flutter 与 Android/iOS 原生代码的交互,为 RPA 自动化任务提供底层支持。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: kit_rpa_plugin
|
||||
- **版本**: 0.1.8+1
|
||||
- **类型**: Flutter Plugin(原生插件)
|
||||
- **Flutter 版本**: >=2.10.5
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **原生自动化操作**
|
||||
- 屏幕点击模拟
|
||||
- 键盘输入模拟
|
||||
- 手势操作模拟
|
||||
- 应用启动控制
|
||||
|
||||
2. **系统信息获取**
|
||||
- 设备信息查询
|
||||
- 应用状态监控
|
||||
- 系统资源获取
|
||||
- 权限状态检查
|
||||
|
||||
3. **文件系统操作**
|
||||
- 文件读写操作
|
||||
- 目录遍历
|
||||
- 权限管理
|
||||
- 路径解析
|
||||
|
||||
4. **网络状态监控**
|
||||
- 网络连接状态
|
||||
- 网络类型检测
|
||||
- 流量使用统计
|
||||
- 连接质量评估
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
kit_rpa_plugin/
|
||||
├── lib/ # Dart代码
|
||||
│ ├── kit_rpa_plugin.dart # 插件入口
|
||||
│ ├── src/ # 源代码
|
||||
│ │ ├── platform_interface.dart # 平台接口定义
|
||||
│ │ ├── method_channel.dart # 方法通道实现
|
||||
│ │ └── models/ # 数据模型
|
||||
│ └── kit_rpa_plugin_platform_interface.dart
|
||||
├── android/ # Android原生代码
|
||||
│ ├── src/main/kotlin/
|
||||
│ │ └── com/oneapp/kit_rpa_plugin/
|
||||
│ │ ├── KitRpaPlugin.kt # 主插件类
|
||||
│ │ ├── AutomationHandler.kt # 自动化处理器
|
||||
│ │ ├── SystemInfoProvider.kt # 系统信息提供者
|
||||
│ │ └── FileOperationHandler.kt # 文件操作处理器
|
||||
│ └── build.gradle
|
||||
├── ios/ # iOS原生代码
|
||||
│ ├── Classes/
|
||||
│ │ ├── KitRpaPlugin.swift # 主插件类
|
||||
│ │ ├── AutomationHandler.swift # 自动化处理器
|
||||
│ │ ├── SystemInfoProvider.swift # 系统信息提供者
|
||||
│ │ └── FileOperationHandler.swift # 文件操作处理器
|
||||
│ └── kit_rpa_plugin.podspec
|
||||
├── example/ # 示例应用
|
||||
└── test/ # 测试文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `plugin_platform_interface: ^2.0.2` - 插件平台接口
|
||||
- `device_info_plus: ^9.1.1` - 设备信息获取
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. Flutter端实现
|
||||
|
||||
#### 插件入口 (`lib/kit_rpa_plugin.dart`)
|
||||
**功能职责**:
|
||||
- 插件对外API导出
|
||||
- 平台通道初始化
|
||||
- 方法调用封装
|
||||
|
||||
#### 平台接口 (`lib/src/platform_interface.dart`)
|
||||
**功能职责**:
|
||||
- 定义插件抽象接口
|
||||
- 规范方法签名
|
||||
- 支持多平台实现
|
||||
|
||||
#### 方法通道 (`lib/src/method_channel.dart`)
|
||||
**功能职责**:
|
||||
- 实现平台通道通信
|
||||
- 处理异步方法调用
|
||||
- 管理回调和异常
|
||||
|
||||
### 2. Android端实现
|
||||
|
||||
#### 主插件类 (`KitRpaPlugin.kt`)
|
||||
```kotlin
|
||||
class KitRpaPlugin: FlutterPlugin, MethodCallHandler {
|
||||
private lateinit var channel: MethodChannel
|
||||
private lateinit var context: Context
|
||||
private lateinit var automationHandler: AutomationHandler
|
||||
private lateinit var systemInfoProvider: SystemInfoProvider
|
||||
private lateinit var fileOperationHandler: FileOperationHandler
|
||||
|
||||
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
channel = MethodChannel(binding.binaryMessenger, "kit_rpa_plugin")
|
||||
context = binding.applicationContext
|
||||
initializeHandlers()
|
||||
channel.setMethodCallHandler(this)
|
||||
}
|
||||
|
||||
override fun onMethodCall(call: MethodCall, result: Result) {
|
||||
when (call.method) {
|
||||
"simulateClick" -> automationHandler.simulateClick(call, result)
|
||||
"getSystemInfo" -> systemInfoProvider.getSystemInfo(call, result)
|
||||
"performFileOperation" -> fileOperationHandler.performOperation(call, result)
|
||||
else -> result.notImplemented()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 自动化处理器 (`AutomationHandler.kt`)
|
||||
**功能职责**:
|
||||
- 屏幕点击模拟
|
||||
- 键盘输入模拟
|
||||
- 手势操作模拟
|
||||
- 无障碍服务集成
|
||||
|
||||
**主要方法**:
|
||||
- `simulateClick(x: Float, y: Float)` - 模拟屏幕点击
|
||||
- `simulateKeyInput(text: String)` - 模拟键盘输入
|
||||
- `simulateSwipe(startX: Float, startY: Float, endX: Float, endY: Float)` - 模拟滑动
|
||||
- `simulateLongPress(x: Float, y: Float, duration: Long)` - 模拟长按
|
||||
|
||||
#### 系统信息提供者 (`SystemInfoProvider.kt`)
|
||||
**功能职责**:
|
||||
- 设备硬件信息获取
|
||||
- 系统版本信息
|
||||
- 应用状态监控
|
||||
- 权限状态检查
|
||||
|
||||
**主要方法**:
|
||||
- `getDeviceInfo()` - 获取设备信息
|
||||
- `getSystemVersion()` - 获取系统版本
|
||||
- `getInstalledApps()` - 获取已安装应用
|
||||
- `checkPermissions()` - 检查权限状态
|
||||
|
||||
#### 文件操作处理器 (`FileOperationHandler.kt`)
|
||||
**功能职责**:
|
||||
- 文件系统访问
|
||||
- 文件读写操作
|
||||
- 目录管理
|
||||
- 存储权限处理
|
||||
|
||||
**主要方法**:
|
||||
- `readFile(path: String)` - 读取文件
|
||||
- `writeFile(path: String, content: String)` - 写入文件
|
||||
- `listDirectory(path: String)` - 列出目录内容
|
||||
- `createDirectory(path: String)` - 创建目录
|
||||
|
||||
### 3. iOS端实现
|
||||
|
||||
#### 主插件类 (`KitRpaPlugin.swift`)
|
||||
```swift
|
||||
public class KitRpaPlugin: NSObject, FlutterPlugin {
|
||||
private var automationHandler: AutomationHandler!
|
||||
private var systemInfoProvider: SystemInfoProvider!
|
||||
private var fileOperationHandler: FileOperationHandler!
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "kit_rpa_plugin",
|
||||
binaryMessenger: registrar.messenger())
|
||||
let instance = KitRpaPlugin()
|
||||
instance.initializeHandlers()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
}
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "simulateClick":
|
||||
automationHandler.simulateClick(call: call, result: result)
|
||||
case "getSystemInfo":
|
||||
systemInfoProvider.getSystemInfo(call: call, result: result)
|
||||
case "performFileOperation":
|
||||
fileOperationHandler.performOperation(call: call, result: result)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 自动化处理器 (`AutomationHandler.swift`)
|
||||
**功能职责**:
|
||||
- 利用 UIKit 进行界面操作
|
||||
- 集成 Accessibility 框架
|
||||
- 手势识别和模拟
|
||||
- 应用控制操作
|
||||
|
||||
#### 系统信息提供者 (`SystemInfoProvider.swift`)
|
||||
**功能职责**:
|
||||
- 利用 UIDevice 获取设备信息
|
||||
- 系统版本和硬件信息
|
||||
- 应用状态监控
|
||||
- 权限状态查询
|
||||
|
||||
#### 文件操作处理器 (`FileOperationHandler.swift`)
|
||||
**功能职责**:
|
||||
- 文件系统访问
|
||||
- 沙盒目录操作
|
||||
- 文档目录管理
|
||||
- 安全文件操作
|
||||
|
||||
## 业务流程
|
||||
|
||||
### 自动化操作流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Flutter发起自动化请求] --> B[方法通道传递参数]
|
||||
B --> C[原生端接收调用]
|
||||
C --> D{判断操作类型}
|
||||
D -->|点击操作| E[屏幕点击处理]
|
||||
D -->|输入操作| F[键盘输入处理]
|
||||
D -->|手势操作| G[手势模拟处理]
|
||||
E --> H[执行原生操作]
|
||||
F --> H
|
||||
G --> H
|
||||
H --> I{操作是否成功}
|
||||
I -->|是| J[返回成功结果]
|
||||
I -->|否| K[返回错误信息]
|
||||
J --> L[Flutter端接收结果]
|
||||
K --> L
|
||||
L --> M[更新UI状态]
|
||||
```
|
||||
|
||||
### 权限检查流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[检查操作权限] --> B{是否需要特殊权限}
|
||||
B -->|否| C[直接执行操作]
|
||||
B -->|是| D[检查权限状态]
|
||||
D --> E{权限是否已授予}
|
||||
E -->|是| C
|
||||
E -->|否| F[请求用户授权]
|
||||
F --> G{用户是否同意}
|
||||
G -->|是| H[获得权限]
|
||||
G -->|否| I[权限被拒绝]
|
||||
H --> C
|
||||
I --> J[返回权限错误]
|
||||
C --> K[执行自动化操作]
|
||||
```
|
||||
|
||||
## 平台特性实现
|
||||
|
||||
### Android特性
|
||||
1. **无障碍服务(Accessibility Service)**
|
||||
- 应用界面元素访问
|
||||
- 自动化操作执行
|
||||
- 界面变化监听
|
||||
- 全局手势模拟
|
||||
|
||||
2. **系统权限管理**
|
||||
- 动态权限申请
|
||||
- 特殊权限处理
|
||||
- 权限状态监控
|
||||
- 权限组管理
|
||||
|
||||
3. **文件系统访问**
|
||||
- 外部存储访问
|
||||
- 应用私有目录
|
||||
- 分区存储适配
|
||||
- 文件提供者集成
|
||||
|
||||
### iOS特性
|
||||
1. **Accessibility框架**
|
||||
- UI元素识别
|
||||
- 辅助功能集成
|
||||
- 自动化测试支持
|
||||
- 界面操作模拟
|
||||
|
||||
2. **沙盒安全机制**
|
||||
- 应用沙盒限制
|
||||
- 文件访问权限
|
||||
- 数据保护机制
|
||||
- 隐私权限管理
|
||||
|
||||
3. **系统集成**
|
||||
- UIKit框架集成
|
||||
- Core Foundation使用
|
||||
- 系统服务调用
|
||||
- 设备信息获取
|
||||
|
||||
## 安全考虑
|
||||
|
||||
### 权限控制
|
||||
- **最小权限原则**: 仅申请必要权限
|
||||
- **动态权限**: 运行时权限申请
|
||||
- **权限说明**: 清晰的权限使用说明
|
||||
- **权限回收**: 不需要时释放权限
|
||||
|
||||
### 数据安全
|
||||
- **敏感数据保护**: 避免记录敏感信息
|
||||
- **数据传输安全**: 加密敏感数据传输
|
||||
- **本地存储安全**: 安全的本地数据存储
|
||||
- **隐私合规**: 遵守隐私保护法规
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 操作效率
|
||||
- **批量操作**: 减少方法通道调用次数
|
||||
- **异步处理**: 避免阻塞主线程
|
||||
- **操作缓存**: 缓存重复操作结果
|
||||
- **资源复用**: 复用系统资源
|
||||
|
||||
### 内存管理
|
||||
- **及时释放**: 及时释放不需要的资源
|
||||
- **内存监控**: 监控内存使用情况
|
||||
- **垃圾回收**: 配合系统垃圾回收
|
||||
- **循环引用避免**: 避免内存泄漏
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 异常类型
|
||||
1. **权限异常**
|
||||
- 权限未授予
|
||||
- 权限被撤销
|
||||
- 系统权限限制
|
||||
- 特殊权限要求
|
||||
|
||||
2. **操作异常**
|
||||
- 目标元素不存在
|
||||
- 操作被系统阻止
|
||||
- 界面状态异常
|
||||
- 硬件功能不支持
|
||||
|
||||
3. **系统异常**
|
||||
- 系统版本不兼容
|
||||
- 硬件功能缺失
|
||||
- 资源不足
|
||||
- 系统服务异常
|
||||
|
||||
### 处理策略
|
||||
- **优雅降级**: 功能不可用时的替代方案
|
||||
- **错误重试**: 临时错误的重试机制
|
||||
- **用户提示**: 清晰的错误信息提示
|
||||
- **日志记录**: 详细的错误日志记录
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- **方法通道测试**: 通信接口测试
|
||||
- **数据模型测试**: 序列化反序列化
|
||||
- **工具类测试**: 辅助功能测试
|
||||
- **异常处理测试**: 错误场景测试
|
||||
|
||||
### 集成测试
|
||||
- **平台集成测试**: 原生功能集成
|
||||
- **权限流程测试**: 权限申请流程
|
||||
- **文件操作测试**: 文件系统操作
|
||||
- **自动化功能测试**: 自动化操作验证
|
||||
|
||||
### 兼容性测试
|
||||
- **设备兼容性**: 不同设备型号
|
||||
- **系统版本**: 不同操作系统版本
|
||||
- **权限策略**: 不同权限策略
|
||||
- **性能表现**: 不同性能水平设备
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 版本管理
|
||||
- **API版本控制**: 兼容不同版本
|
||||
- **功能开关**: 新功能渐进式发布
|
||||
- **回滚机制**: 问题版本快速回滚
|
||||
- **升级策略**: 平滑升级路径
|
||||
|
||||
### 监控指标
|
||||
- **调用成功率**: 方法调用成功率
|
||||
- **响应时间**: 操作响应延迟
|
||||
- **错误率**: 异常发生频率
|
||||
- **权限授予率**: 用户权限授予情况
|
||||
|
||||
## 总结
|
||||
|
||||
`kit_rpa_plugin` 作为 OneApp 的RPA自动化原生插件,为Flutter应用提供了强大的原生平台自动化操作能力。通过平台通道机制,实现了Flutter与Android/iOS原生代码的无缝集成,为RPA自动化任务提供了可靠的底层支持。插件设计考虑了安全性、性能和兼容性,能够在保证用户隐私和系统安全的前提下,提供高效的自动化操作能力。
|
||||
527
app_car/one_app_cache_plugin.md
Normal file
527
app_car/one_app_cache_plugin.md
Normal file
@@ -0,0 +1,527 @@
|
||||
# OneApp Cache Plugin 缓存插件
|
||||
|
||||
## 模块概述
|
||||
|
||||
`one_app_cache_plugin` 是 OneApp 车联网生态中的原生缓存插件,负责为 Flutter 应用提供高效的原生缓存能力。该插件通过平台通道实现 Flutter 与 Android/iOS 原生缓存系统的交互,为应用数据缓存提供底层支持。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: one_app_cache_plugin
|
||||
- **版本**: 0.0.4
|
||||
- **类型**: Flutter Plugin(原生插件)
|
||||
- **Flutter 版本**: >=3.3.0
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **多级缓存系统**
|
||||
- 内存缓存(L1 Cache)
|
||||
- 磁盘缓存(L2 Cache)
|
||||
- 网络缓存(L3 Cache)
|
||||
- 分布式缓存支持
|
||||
|
||||
2. **缓存策略管理**
|
||||
- LRU(最近最少使用)淘汰
|
||||
- LFU(最少使用频率)淘汰
|
||||
- TTL(生存时间)过期
|
||||
- 自定义淘汰策略
|
||||
|
||||
3. **数据类型支持**
|
||||
- 字符串数据缓存
|
||||
- 二进制数据缓存
|
||||
- JSON对象缓存
|
||||
- 文件资源缓存
|
||||
|
||||
4. **性能优化**
|
||||
- 异步操作支持
|
||||
- 批量操作优化
|
||||
- 预加载机制
|
||||
- 智能压缩存储
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
one_app_cache_plugin/
|
||||
├── lib/ # Dart代码
|
||||
│ ├── one_app_cache_plugin.dart # 插件入口
|
||||
│ ├── src/ # 源代码
|
||||
│ │ ├── cache_manager.dart # 缓存管理器
|
||||
│ │ ├── cache_strategy.dart # 缓存策略
|
||||
│ │ ├── cache_models.dart # 数据模型
|
||||
│ │ └── platform_interface.dart # 平台接口
|
||||
│ └── one_app_cache_plugin_platform_interface.dart
|
||||
├── android/ # Android原生代码
|
||||
│ ├── src/main/kotlin/
|
||||
│ │ └── com/oneapp/cache/
|
||||
│ │ ├── OneAppCachePlugin.kt # 主插件类
|
||||
│ │ ├── MemoryCache.kt # 内存缓存
|
||||
│ │ ├── DiskCache.kt # 磁盘缓存
|
||||
│ │ ├── CacheStrategy.kt # 缓存策略
|
||||
│ │ └── CacheUtils.kt # 缓存工具
|
||||
│ └── build.gradle
|
||||
├── ios/ # iOS原生代码
|
||||
│ ├── Classes/
|
||||
│ │ ├── OneAppCachePlugin.swift # 主插件类
|
||||
│ │ ├── MemoryCache.swift # 内存缓存
|
||||
│ │ ├── DiskCache.swift # 磁盘缓存
|
||||
│ │ ├── CacheStrategy.swift # 缓存策略
|
||||
│ │ └── CacheUtils.swift # 缓存工具
|
||||
│ └── one_app_cache_plugin.podspec
|
||||
├── example/ # 示例应用
|
||||
└── test/ # 测试文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `plugin_platform_interface: ^2.0.2` - 插件平台接口
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. Flutter端实现
|
||||
|
||||
#### 插件入口 (`lib/one_app_cache_plugin.dart`)
|
||||
```dart
|
||||
class OneAppCachePlugin {
|
||||
static const MethodChannel _channel = MethodChannel('one_app_cache_plugin');
|
||||
|
||||
/// 获取缓存数据
|
||||
static Future<String?> get(String key) async {
|
||||
return await _channel.invokeMethod('get', {'key': key});
|
||||
}
|
||||
|
||||
/// 设置缓存数据
|
||||
static Future<bool> set(String key, String value, {Duration? ttl}) async {
|
||||
final result = await _channel.invokeMethod('set', {
|
||||
'key': key,
|
||||
'value': value,
|
||||
'ttl': ttl?.inMilliseconds,
|
||||
});
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
/// 删除缓存数据
|
||||
static Future<bool> delete(String key) async {
|
||||
final result = await _channel.invokeMethod('delete', {'key': key});
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
/// 清空所有缓存
|
||||
static Future<bool> clear() async {
|
||||
final result = await _channel.invokeMethod('clear');
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
/// 获取缓存统计信息
|
||||
static Future<CacheStats> getStats() async {
|
||||
final result = await _channel.invokeMethod('getStats');
|
||||
return CacheStats.fromMap(result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 缓存管理器 (`lib/src/cache_manager.dart`)
|
||||
```dart
|
||||
class CacheManager {
|
||||
static final CacheManager _instance = CacheManager._internal();
|
||||
factory CacheManager() => _instance;
|
||||
CacheManager._internal();
|
||||
|
||||
/// 配置缓存策略
|
||||
Future<void> configure(CacheConfig config) async {
|
||||
await OneAppCachePlugin.configure(config);
|
||||
}
|
||||
|
||||
/// 智能缓存获取
|
||||
Future<T?> getOrSet<T>(
|
||||
String key,
|
||||
Future<T> Function() valueFactory, {
|
||||
Duration? ttl,
|
||||
CacheLevel level = CacheLevel.all,
|
||||
}) async {
|
||||
// 先尝试从缓存获取
|
||||
final cached = await get<T>(key, level: level);
|
||||
if (cached != null) return cached;
|
||||
|
||||
// 缓存未命中,获取新值并缓存
|
||||
final value = await valueFactory();
|
||||
await set(key, value, ttl: ttl, level: level);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// 批量操作
|
||||
Future<Map<String, T?>> getBatch<T>(List<String> keys) async {
|
||||
return await OneAppCachePlugin.getBatch(keys);
|
||||
}
|
||||
|
||||
/// 预热缓存
|
||||
Future<void> preload(Map<String, dynamic> data) async {
|
||||
await OneAppCachePlugin.preload(data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Android端实现
|
||||
|
||||
#### 主插件类 (`OneAppCachePlugin.kt`)
|
||||
```kotlin
|
||||
class OneAppCachePlugin: FlutterPlugin, MethodCallHandler {
|
||||
private lateinit var context: Context
|
||||
private lateinit var memoryCache: MemoryCache
|
||||
private lateinit var diskCache: DiskCache
|
||||
private lateinit var cacheStrategy: CacheStrategy
|
||||
|
||||
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
context = binding.applicationContext
|
||||
initializeCaches()
|
||||
|
||||
val channel = MethodChannel(binding.binaryMessenger, "one_app_cache_plugin")
|
||||
channel.setMethodCallHandler(this)
|
||||
}
|
||||
|
||||
private fun initializeCaches() {
|
||||
memoryCache = MemoryCache(context)
|
||||
diskCache = DiskCache(context)
|
||||
cacheStrategy = CacheStrategy()
|
||||
}
|
||||
|
||||
override fun onMethodCall(call: MethodCall, result: Result) {
|
||||
when (call.method) {
|
||||
"get" -> handleGet(call, result)
|
||||
"set" -> handleSet(call, result)
|
||||
"delete" -> handleDelete(call, result)
|
||||
"clear" -> handleClear(call, result)
|
||||
"getStats" -> handleGetStats(call, result)
|
||||
"configure" -> handleConfigure(call, result)
|
||||
else -> result.notImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleGet(call: MethodCall, result: Result) {
|
||||
val key = call.argument<String>("key")
|
||||
if (key == null) {
|
||||
result.error("INVALID_ARGUMENT", "Key cannot be null", null)
|
||||
return
|
||||
}
|
||||
|
||||
// 多级缓存查找
|
||||
var value = memoryCache.get(key)
|
||||
if (value == null) {
|
||||
value = diskCache.get(key)
|
||||
if (value != null) {
|
||||
// 将磁盘缓存的数据提升到内存缓存
|
||||
memoryCache.set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
result.success(value)
|
||||
}
|
||||
|
||||
private fun handleSet(call: MethodCall, result: Result) {
|
||||
val key = call.argument<String>("key")
|
||||
val value = call.argument<String>("value")
|
||||
val ttl = call.argument<Long>("ttl")
|
||||
|
||||
if (key == null || value == null) {
|
||||
result.error("INVALID_ARGUMENT", "Key and value cannot be null", null)
|
||||
return
|
||||
}
|
||||
|
||||
val success = try {
|
||||
memoryCache.set(key, value, ttl)
|
||||
diskCache.set(key, value, ttl)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
result.success(success)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 内存缓存 (`MemoryCache.kt`)
|
||||
```kotlin
|
||||
class MemoryCache(private val context: Context) {
|
||||
private val cache = LruCache<String, CacheEntry>(getMaxMemoryCacheSize())
|
||||
|
||||
fun get(key: String): String? {
|
||||
val entry = cache.get(key) ?: return null
|
||||
|
||||
// 检查是否过期
|
||||
if (entry.isExpired()) {
|
||||
cache.remove(key)
|
||||
return null
|
||||
}
|
||||
|
||||
return entry.value
|
||||
}
|
||||
|
||||
fun set(key: String, value: String, ttl: Long? = null) {
|
||||
val expiryTime = ttl?.let { System.currentTimeMillis() + it }
|
||||
val entry = CacheEntry(value, expiryTime)
|
||||
cache.put(key, entry)
|
||||
}
|
||||
|
||||
private fun getMaxMemoryCacheSize(): Int {
|
||||
val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
|
||||
return maxMemory / 8 // 使用最大内存的1/8作为缓存大小
|
||||
}
|
||||
}
|
||||
|
||||
data class CacheEntry(
|
||||
val value: String,
|
||||
val expiryTime: Long? = null
|
||||
) {
|
||||
fun isExpired(): Boolean {
|
||||
return expiryTime?.let { System.currentTimeMillis() > it } ?: false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 磁盘缓存 (`DiskCache.kt`)
|
||||
```kotlin
|
||||
class DiskCache(private val context: Context) {
|
||||
private val cacheDir = File(context.cacheDir, "one_app_cache")
|
||||
private val metadataFile = File(cacheDir, "metadata.json")
|
||||
private val metadata = mutableMapOf<String, CacheMetadata>()
|
||||
|
||||
init {
|
||||
if (!cacheDir.exists()) {
|
||||
cacheDir.mkdirs()
|
||||
}
|
||||
loadMetadata()
|
||||
}
|
||||
|
||||
fun get(key: String): String? {
|
||||
val meta = metadata[key] ?: return null
|
||||
|
||||
// 检查是否过期
|
||||
if (meta.isExpired()) {
|
||||
delete(key)
|
||||
return null
|
||||
}
|
||||
|
||||
val file = File(cacheDir, meta.filename)
|
||||
return if (file.exists()) {
|
||||
try {
|
||||
file.readText()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
} else null
|
||||
}
|
||||
|
||||
fun set(key: String, value: String, ttl: Long? = null) {
|
||||
val filename = generateFilename(key)
|
||||
val file = File(cacheDir, filename)
|
||||
|
||||
try {
|
||||
file.writeText(value)
|
||||
val expiryTime = ttl?.let { System.currentTimeMillis() + it }
|
||||
metadata[key] = CacheMetadata(filename, expiryTime, System.currentTimeMillis())
|
||||
saveMetadata()
|
||||
} catch (e: Exception) {
|
||||
// 处理写入错误
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateFilename(key: String): String {
|
||||
return key.hashCode().toString() + ".cache"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. iOS端实现
|
||||
|
||||
#### 主插件类 (`OneAppCachePlugin.swift`)
|
||||
```swift
|
||||
public class OneAppCachePlugin: NSObject, FlutterPlugin {
|
||||
private var memoryCache: MemoryCache!
|
||||
private var diskCache: DiskCache!
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "one_app_cache_plugin",
|
||||
binaryMessenger: registrar.messenger())
|
||||
let instance = OneAppCachePlugin()
|
||||
instance.initializeCaches()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
}
|
||||
|
||||
private func initializeCaches() {
|
||||
memoryCache = MemoryCache()
|
||||
diskCache = DiskCache()
|
||||
}
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "get":
|
||||
handleGet(call: call, result: result)
|
||||
case "set":
|
||||
handleSet(call: call, result: result)
|
||||
case "delete":
|
||||
handleDelete(call: call, result: result)
|
||||
case "clear":
|
||||
handleClear(call: call, result: result)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
private func handleGet(call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
guard let args = call.arguments as? [String: Any],
|
||||
let key = args["key"] as? String else {
|
||||
result(FlutterError(code: "INVALID_ARGUMENT",
|
||||
message: "Key is required",
|
||||
details: nil))
|
||||
return
|
||||
}
|
||||
|
||||
// 多级缓存查找
|
||||
if let value = memoryCache.get(key: key) {
|
||||
result(value)
|
||||
return
|
||||
}
|
||||
|
||||
if let value = diskCache.get(key: key) {
|
||||
// 提升到内存缓存
|
||||
memoryCache.set(key: key, value: value)
|
||||
result(value)
|
||||
return
|
||||
}
|
||||
|
||||
result(nil)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 缓存策略设计
|
||||
|
||||
### 淘汰策略
|
||||
1. **LRU (Least Recently Used)**
|
||||
- 淘汰最近最少使用的数据
|
||||
- 适用于访问模式相对稳定的场景
|
||||
- 实现简单,性能良好
|
||||
|
||||
2. **LFU (Least Frequently Used)**
|
||||
- 淘汰使用频率最低的数据
|
||||
- 适用于热点数据明显的场景
|
||||
- 需要维护访问频率统计
|
||||
|
||||
3. **TTL (Time To Live)**
|
||||
- 基于时间的自动过期
|
||||
- 适用于时效性数据
|
||||
- 可与其他策略组合使用
|
||||
|
||||
4. **FIFO (First In First Out)**
|
||||
- 先进先出的简单策略
|
||||
- 实现简单但效果有限
|
||||
- 适用于对缓存效果要求不高的场景
|
||||
|
||||
### 多级缓存架构
|
||||
```
|
||||
应用层
|
||||
↓
|
||||
Flutter缓存管理器
|
||||
↓
|
||||
L1: 内存缓存 (NSCache/LruCache)
|
||||
↓
|
||||
L2: 磁盘缓存 (本地文件系统)
|
||||
↓
|
||||
L3: 网络缓存 (HTTP缓存/CDN)
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 内存优化
|
||||
- **智能大小调整**: 根据可用内存动态调整缓存大小
|
||||
- **内存压力监控**: 监听系统内存压力事件
|
||||
- **延迟加载**: 按需加载缓存数据
|
||||
- **压缩存储**: 对大数据进行压缩存储
|
||||
|
||||
### 磁盘优化
|
||||
- **异步I/O**: 所有磁盘操作异步执行
|
||||
- **批量操作**: 批量读写减少I/O次数
|
||||
- **文件压缩**: 压缩存储节省空间
|
||||
- **定期清理**: 定期清理过期和无效文件
|
||||
|
||||
### 网络优化
|
||||
- **预加载**: 预测性数据预加载
|
||||
- **增量更新**: 仅传输变化数据
|
||||
- **并发控制**: 限制并发网络请求
|
||||
- **断点续传**: 支持大文件断点续传
|
||||
|
||||
## 数据安全
|
||||
|
||||
### 加密存储
|
||||
- **敏感数据加密**: 对敏感缓存数据进行加密
|
||||
- **密钥管理**: 安全的密钥存储和管理
|
||||
- **完整性验证**: 数据完整性校验
|
||||
- **安全擦除**: 安全删除敏感数据
|
||||
|
||||
### 权限控制
|
||||
- **访问控制**: 基于权限的缓存访问
|
||||
- **沙盒隔离**: 应用间缓存数据隔离
|
||||
- **审计日志**: 缓存访问审计记录
|
||||
- **异常监控**: 异常访问行为监控
|
||||
|
||||
## 监控和诊断
|
||||
|
||||
### 性能指标
|
||||
```dart
|
||||
class CacheStats {
|
||||
final int hitCount; // 命中次数
|
||||
final int missCount; // 未命中次数
|
||||
final int evictionCount; // 淘汰次数
|
||||
final double hitRate; // 命中率
|
||||
final int size; // 当前大小
|
||||
final int maxSize; // 最大大小
|
||||
|
||||
double get hitRate => hitCount / (hitCount + missCount);
|
||||
}
|
||||
```
|
||||
|
||||
### 诊断工具
|
||||
- **缓存命中率监控**: 实时监控缓存效果
|
||||
- **内存使用分析**: 分析内存使用模式
|
||||
- **性能分析器**: 分析缓存操作性能
|
||||
- **调试界面**: 可视化缓存状态
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- **缓存操作测试**: 基本CRUD操作
|
||||
- **过期策略测试**: TTL和淘汰策略
|
||||
- **并发安全测试**: 多线程访问安全
|
||||
- **边界条件测试**: 极限情况处理
|
||||
|
||||
### 集成测试
|
||||
- **平台集成测试**: 原生平台功能
|
||||
- **性能测试**: 大数据量性能
|
||||
- **稳定性测试**: 长时间运行稳定性
|
||||
- **兼容性测试**: 不同设备和系统版本
|
||||
|
||||
### 压力测试
|
||||
- **高并发测试**: 大量并发访问
|
||||
- **大数据测试**: 大容量数据处理
|
||||
- **内存压力测试**: 低内存环境测试
|
||||
- **存储压力测试**: 存储空间不足测试
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 使用建议
|
||||
1. **合理设置TTL**: 根据数据特性设置合适的过期时间
|
||||
2. **选择合适策略**: 根据访问模式选择淘汰策略
|
||||
3. **监控缓存效果**: 定期检查命中率和性能指标
|
||||
4. **控制缓存大小**: 避免缓存过大影响性能
|
||||
|
||||
### 性能优化建议
|
||||
1. **预加载热点数据**: 应用启动时预加载重要数据
|
||||
2. **批量操作**: 尽量使用批量API减少开销
|
||||
3. **异步操作**: 避免阻塞主线程
|
||||
4. **合理清理**: 定期清理过期和不需要的缓存
|
||||
|
||||
## 总结
|
||||
|
||||
`one_app_cache_plugin` 作为 OneApp 的原生缓存插件,为Flutter应用提供了高效、可靠的多级缓存能力。通过智能的缓存策略、完善的性能优化和安全的数据保护,显著提升了应用的数据访问性能和用户体验。插件设计考虑了跨平台兼容性和可扩展性,能够适应不同的应用场景和性能要求。
|
||||
446
app_car/ui_avatarx.md
Normal file
446
app_car/ui_avatarx.md
Normal file
@@ -0,0 +1,446 @@
|
||||
# UI AvatarX 虚拟形象UI组件
|
||||
|
||||
## 模块概述
|
||||
|
||||
`ui_avatarx` 是 OneApp 车联网生态中的虚拟形象UI组件库,负责虚拟形象的界面展示、交互控制、动画效果和用户体验优化等功能。该模块为虚拟助手提供了丰富的UI组件和交互体验。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: ui_avatarx
|
||||
- **版本**: 0.4.7+3
|
||||
- **描述**: 虚拟形象UI组件库
|
||||
- **Flutter 版本**: >=2.5.0
|
||||
- **Dart 版本**: >=2.16.2 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **虚拟形象展示**
|
||||
- 3D虚拟形象渲染
|
||||
- 2D头像展示
|
||||
- 表情动画播放
|
||||
- 状态指示器
|
||||
|
||||
2. **交互组件**
|
||||
- 语音交互界面
|
||||
- 手势控制组件
|
||||
- 触控反馈效果
|
||||
- 情绪表达控件
|
||||
|
||||
3. **动画效果**
|
||||
- 流畅的转场动画
|
||||
- 表情切换动画
|
||||
- 状态变化动画
|
||||
- 自定义动画序列
|
||||
|
||||
4. **主题定制**
|
||||
- 多种形象主题
|
||||
- 可定制外观
|
||||
- 响应式布局
|
||||
- 暗黑模式支持
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── ui_avatarx.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── widgets/ # UI组件
|
||||
│ ├── animations/ # 动画效果
|
||||
│ ├── themes/ # 主题配置
|
||||
│ ├── controllers/ # 控制器
|
||||
│ ├── models/ # 数据模型
|
||||
│ └── utils/ # 工具类
|
||||
├── assets/ # 资源文件
|
||||
└── examples/ # 示例代码
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### 核心依赖
|
||||
- `basic_logger` - 日志系统(本地路径依赖)
|
||||
|
||||
#### Flutter框架
|
||||
- `flutter` - Flutter SDK
|
||||
|
||||
## 核心模块分析
|
||||
|
||||
### 1. 模块入口 (`ui_avatarx.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- UI组件对外接口导出
|
||||
- 主题配置初始化
|
||||
- 组件注册管理
|
||||
|
||||
### 2. UI组件 (`src/widgets/`)
|
||||
|
||||
**功能职责**:
|
||||
- 虚拟形象展示组件
|
||||
- 交互控制组件
|
||||
- 状态指示组件
|
||||
- 自定义装饰组件
|
||||
|
||||
**主要组件**:
|
||||
- `AvatarXWidget` - 主虚拟形象组件
|
||||
- `AvatarXHead` - 头像组件
|
||||
- `ExpressionPanel` - 表情控制面板
|
||||
- `VoiceIndicator` - 语音指示器
|
||||
- `EmotionSelector` - 情绪选择器
|
||||
- `AvatarXContainer` - 形象容器
|
||||
- `InteractionOverlay` - 交互覆盖层
|
||||
|
||||
### 3. 动画效果 (`src/animations/`)
|
||||
|
||||
**功能职责**:
|
||||
- 表情动画控制
|
||||
- 转场动画实现
|
||||
- 自定义动画序列
|
||||
- 动画状态管理
|
||||
|
||||
**主要动画**:
|
||||
- `ExpressionAnimation` - 表情动画
|
||||
- `TransitionAnimation` - 转场动画
|
||||
- `IdleAnimation` - 待机动画
|
||||
- `InteractionAnimation` - 交互动画
|
||||
- `EmotionAnimation` - 情绪动画
|
||||
|
||||
### 4. 主题配置 (`src/themes/`)
|
||||
|
||||
**功能职责**:
|
||||
- 主题样式定义
|
||||
- 颜色配置管理
|
||||
- 尺寸规范设置
|
||||
- 响应式配置
|
||||
|
||||
**主要主题**:
|
||||
- `DefaultAvatarTheme` - 默认主题
|
||||
- `DarkAvatarTheme` - 暗黑主题
|
||||
- `CustomAvatarTheme` - 自定义主题
|
||||
- `ResponsiveTheme` - 响应式主题
|
||||
|
||||
### 5. 控制器 (`src/controllers/`)
|
||||
|
||||
**功能职责**:
|
||||
- 虚拟形象状态控制
|
||||
- 动画播放控制
|
||||
- 交互事件处理
|
||||
- 生命周期管理
|
||||
|
||||
**主要控制器**:
|
||||
- `AvatarXController` - 主控制器
|
||||
- `AnimationController` - 动画控制器
|
||||
- `InteractionController` - 交互控制器
|
||||
- `ThemeController` - 主题控制器
|
||||
|
||||
### 6. 数据模型 (`src/models/`)
|
||||
|
||||
**功能职责**:
|
||||
- 虚拟形象数据模型
|
||||
- 动画配置模型
|
||||
- 主题配置模型
|
||||
- 状态信息模型
|
||||
|
||||
**主要模型**:
|
||||
- `AvatarXModel` - 虚拟形象模型
|
||||
- `ExpressionModel` - 表情模型
|
||||
- `AnimationConfig` - 动画配置模型
|
||||
- `ThemeConfig` - 主题配置模型
|
||||
- `InteractionState` - 交互状态模型
|
||||
|
||||
### 7. 工具类 (`src/utils/`)
|
||||
|
||||
**功能职责**:
|
||||
- 动画工具方法
|
||||
- 主题工具函数
|
||||
- 布局计算工具
|
||||
- 性能优化工具
|
||||
|
||||
**主要工具**:
|
||||
- `AnimationUtils` - 动画工具
|
||||
- `ThemeUtils` - 主题工具
|
||||
- `LayoutUtils` - 布局工具
|
||||
- `PerformanceUtils` - 性能工具
|
||||
|
||||
## 组件设计
|
||||
|
||||
### 核心组件详解
|
||||
|
||||
#### AvatarXWidget
|
||||
```dart
|
||||
class AvatarXWidget extends StatefulWidget {
|
||||
final AvatarXModel avatar;
|
||||
final AvatarXController? controller;
|
||||
final AvatarTheme? theme;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final bool enableInteraction;
|
||||
final VoidCallback? onTap;
|
||||
final Function(String)? onExpressionChanged;
|
||||
|
||||
const AvatarXWidget({
|
||||
Key? key,
|
||||
required this.avatar,
|
||||
this.controller,
|
||||
this.theme,
|
||||
this.width,
|
||||
this.height,
|
||||
this.enableInteraction = true,
|
||||
this.onTap,
|
||||
this.onExpressionChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AvatarXWidget> createState() => _AvatarXWidgetState();
|
||||
}
|
||||
```
|
||||
|
||||
**主要功能**:
|
||||
- 虚拟形象渲染展示
|
||||
- 交互事件处理
|
||||
- 动画状态管理
|
||||
- 主题样式应用
|
||||
|
||||
#### ExpressionPanel
|
||||
```dart
|
||||
class ExpressionPanel extends StatelessWidget {
|
||||
final List<String> expressions;
|
||||
final String? currentExpression;
|
||||
final Function(String) onExpressionSelected;
|
||||
final bool showLabels;
|
||||
final Axis direction;
|
||||
|
||||
const ExpressionPanel({
|
||||
Key? key,
|
||||
required this.expressions,
|
||||
this.currentExpression,
|
||||
required this.onExpressionSelected,
|
||||
this.showLabels = true,
|
||||
this.direction = Axis.horizontal,
|
||||
}) : super(key: key);
|
||||
}
|
||||
```
|
||||
|
||||
**主要功能**:
|
||||
- 表情选择界面
|
||||
- 表情预览功能
|
||||
- 选择状态指示
|
||||
- 可定制布局方向
|
||||
|
||||
#### VoiceIndicator
|
||||
```dart
|
||||
class VoiceIndicator extends StatefulWidget {
|
||||
final bool isListening;
|
||||
final bool isSpeaking;
|
||||
final double amplitude;
|
||||
final Color? color;
|
||||
final double size;
|
||||
final VoiceIndicatorStyle style;
|
||||
|
||||
const VoiceIndicator({
|
||||
Key? key,
|
||||
this.isListening = false,
|
||||
this.isSpeaking = false,
|
||||
this.amplitude = 0.0,
|
||||
this.color,
|
||||
this.size = 60.0,
|
||||
this.style = VoiceIndicatorStyle.wave,
|
||||
}) : super(key: key);
|
||||
}
|
||||
```
|
||||
|
||||
**主要功能**:
|
||||
- 语音状态可视化
|
||||
- 音频波形显示
|
||||
- 实时振幅反映
|
||||
- 多种视觉样式
|
||||
|
||||
## 动画系统
|
||||
|
||||
### 动画类型
|
||||
1. **表情动画**
|
||||
- 面部表情切换
|
||||
- 眼部动作
|
||||
- 嘴部动作
|
||||
- 眉毛表情
|
||||
|
||||
2. **身体动画**
|
||||
- 头部转动
|
||||
- 肩膀动作
|
||||
- 手势动作
|
||||
- 姿态变化
|
||||
|
||||
3. **交互动画**
|
||||
- 点击反馈
|
||||
- 悬停效果
|
||||
- 拖拽响应
|
||||
- 状态转换
|
||||
|
||||
4. **环境动画**
|
||||
- 背景变化
|
||||
- 光照效果
|
||||
- 粒子效果
|
||||
- 氛围营造
|
||||
|
||||
### 动画控制
|
||||
```dart
|
||||
class AnimationController {
|
||||
Future<void> playExpression(String expression, {
|
||||
Duration duration = const Duration(milliseconds: 500),
|
||||
Curve curve = Curves.easeInOut,
|
||||
});
|
||||
|
||||
Future<void> playSequence(List<AnimationStep> steps);
|
||||
|
||||
void pauseAnimation();
|
||||
void resumeAnimation();
|
||||
void stopAnimation();
|
||||
|
||||
Stream<AnimationState> get animationState;
|
||||
}
|
||||
```
|
||||
|
||||
## 主题系统
|
||||
|
||||
### 主题配置
|
||||
```dart
|
||||
class AvatarTheme {
|
||||
final Color primaryColor;
|
||||
final Color secondaryColor;
|
||||
final Color backgroundColor;
|
||||
final TextStyle labelStyle;
|
||||
final EdgeInsets padding;
|
||||
final BorderRadius borderRadius;
|
||||
final BoxShadow? shadow;
|
||||
final AvatarSize size;
|
||||
|
||||
const AvatarTheme({
|
||||
required this.primaryColor,
|
||||
required this.secondaryColor,
|
||||
required this.backgroundColor,
|
||||
required this.labelStyle,
|
||||
this.padding = const EdgeInsets.all(8.0),
|
||||
this.borderRadius = const BorderRadius.all(Radius.circular(8.0)),
|
||||
this.shadow,
|
||||
this.size = AvatarSize.medium,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 响应式设计
|
||||
- **屏幕尺寸适配**: 自动调整组件大小
|
||||
- **密度适配**: 支持不同像素密度
|
||||
- **方向适配**: 横竖屏自适应
|
||||
- **平台适配**: iOS/Android样式适配
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 渲染优化
|
||||
- **组件缓存**: 缓存渲染结果
|
||||
- **差分更新**: 仅更新变化部分
|
||||
- **懒加载**: 按需加载资源
|
||||
- **预加载**: 预测性资源加载
|
||||
|
||||
### 内存管理
|
||||
- **资源释放**: 及时释放不需要的资源
|
||||
- **内存池**: 复用对象减少GC
|
||||
- **弱引用**: 避免内存泄漏
|
||||
- **监控告警**: 内存使用监控
|
||||
|
||||
### 动画优化
|
||||
- **硬件加速**: 利用GPU加速
|
||||
- **帧率控制**: 智能帧率调节
|
||||
- **插值优化**: 高效插值算法
|
||||
- **批量更新**: 批量处理动画更新
|
||||
|
||||
## 交互设计
|
||||
|
||||
### 手势支持
|
||||
1. **点击手势**
|
||||
- 单击激活
|
||||
- 双击特殊功能
|
||||
- 长按菜单
|
||||
- 多点触控
|
||||
|
||||
2. **滑动手势**
|
||||
- 水平滑动切换
|
||||
- 垂直滑动控制
|
||||
- 旋转手势
|
||||
- 缩放手势
|
||||
|
||||
3. **自定义手势**
|
||||
- 手势识别器
|
||||
- 手势回调
|
||||
- 手势反馈
|
||||
- 手势组合
|
||||
|
||||
### 反馈机制
|
||||
- **视觉反馈**: 动画和颜色变化
|
||||
- **触觉反馈**: 震动反馈
|
||||
- **听觉反馈**: 音效提示
|
||||
- **语音反馈**: 语音确认
|
||||
|
||||
## 可访问性
|
||||
|
||||
### 无障碍支持
|
||||
- **语义标签**: 为屏幕阅读器提供标签
|
||||
- **焦点管理**: 键盘导航支持
|
||||
- **对比度**: 高对比度模式
|
||||
- **字体缩放**: 支持系统字体缩放
|
||||
|
||||
### 国际化支持
|
||||
- **多语言**: 支持多语言界面
|
||||
- **RTL布局**: 从右到左文字支持
|
||||
- **文化适配**: 不同文化的视觉适配
|
||||
- **时区处理**: 时间显示本地化
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
- **组件渲染测试**: Widget渲染正确性
|
||||
- **动画逻辑测试**: 动画状态转换
|
||||
- **主题应用测试**: 主题配置正确性
|
||||
- **工具类测试**: 工具方法功能
|
||||
|
||||
### Widget测试
|
||||
- **交互测试**: 用户交互响应
|
||||
- **状态测试**: 组件状态变化
|
||||
- **布局测试**: 响应式布局
|
||||
- **性能测试**: 渲染性能
|
||||
|
||||
### 集成测试
|
||||
- **端到端测试**: 完整用户流程
|
||||
- **兼容性测试**: 不同设备适配
|
||||
- **性能测试**: 真实设备性能
|
||||
- **可访问性测试**: 无障碍功能
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 版本管理
|
||||
- **API稳定性**: 向后兼容保证
|
||||
- **渐进式升级**: 平滑版本升级
|
||||
- **功能开关**: 新功能渐进发布
|
||||
- **回滚策略**: 问题版本快速回滚
|
||||
|
||||
### 监控指标
|
||||
- **组件使用率**: 各组件使用频率
|
||||
- **性能指标**: 渲染性能和内存使用
|
||||
- **用户体验**: 交互响应时间
|
||||
- **错误率**: 组件异常发生率
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 开发建议
|
||||
1. **组件复用**: 优先使用现有组件
|
||||
2. **主题一致**: 遵循设计系统
|
||||
3. **性能考虑**: 避免过度渲染
|
||||
4. **可测试性**: 编写可测试代码
|
||||
|
||||
### 使用指南
|
||||
1. **合理选择**: 根据场景选择合适组件
|
||||
2. **配置优化**: 合理配置组件参数
|
||||
3. **资源管理**: 注意资源生命周期
|
||||
4. **用户体验**: 关注用户交互体验
|
||||
|
||||
## 总结
|
||||
|
||||
`ui_avatarx` 模块作为 OneApp 的虚拟形象UI组件库,提供了丰富的虚拟形象展示和交互能力。通过模块化的组件设计、灵活的主题系统和流畅的动画效果,为用户提供了优秀的虚拟助手交互体验。模块具有良好的性能优化和可访问性支持,能够适应不同的设备和使用场景。
|
||||
Reference in New Issue
Block a user