first commit
This commit is contained in:
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. 性能优化
|
||||
- 合理的状态管理避免不必要的重建
|
||||
- 地图资源的合理加载和释放
|
||||
- 网络请求的优化和缓存
|
||||
Reference in New Issue
Block a user