900 lines
27 KiB
Markdown
900 lines
27 KiB
Markdown
# 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. 性能优化
|
||
- 地图资源合理加载释放
|
||
- 充电站数据分页加载
|
||
- 网络请求优化和重试机制
|