# 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 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(moduleHome.path, child: (_, args) => moduleHome.provider(args).as()), ChildRoute(carWatcherHomePage.path, child: (_, args) => carWatcherHomePage.provider(args).as()), ChildRoute(geoFenceListPage.path, child: (_, args) => geoFenceListPage.provider(args).as()), ChildRoute(geoFenceDetailPage.path, child: (_, args) => geoFenceDetailPage.provider(args).as()), ChildRoute(searchPoiPage.path, child: (_, args) => searchPoiPage.provider(args).as()), ChildRoute(dailyReportDetailPage.path, child: (_, args) => dailyReportDetailPage.provider(args).as()), ChildRoute(eventFilterPage.path, child: (_, args) => eventFilterPage.provider(args).as()), ChildRoute(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 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?), 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 createState() => _CarWatcherHomeState(); } class _CarWatcherHomeState extends State { final CarWatcherHomeBloc _bloc = CarWatcherHomeBloc(); late List 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 createState() => _GeoFenceListPageState(); } class _GeoFenceListPageState extends State { @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 createState() => _GeoFenceDetailPageState(); } class _GeoFenceDetailPageState extends State { @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 createState() => _GeoFenceSearchPOIPageState(); } class _GeoFenceSearchPOIPageState extends State { final TextEditingController _searchController = TextEditingController(); List _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 { CarWatcherHomeBloc() : super(CarWatcherHomeInitial()) { on(_onLoadData); on(_onRefreshData); } Future _onLoadData(LoadDataEvent event, Emitter emit) async { emit(CarWatcherHomeLoading()); try { // 加载车辆数据 final vehicleData = await loadVehicleData(event.vin); emit(CarWatcherHomeLoaded(vehicleData)); } catch (e) { emit(CarWatcherHomeError(e.toString())); } } Future _onRefreshData(RefreshDataEvent event, Emitter 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. 性能优化 - 合理的状态管理避免不必要的重建 - 地图资源的合理加载和释放 - 网络请求的优化和缓存