first commit

This commit is contained in:
2025-09-24 14:08:54 +08:00
commit 40784642cf
83 changed files with 37832 additions and 0 deletions

899
app_car/app_charging.md Normal file
View 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. 性能优化
- 地图资源合理加载释放
- 充电站数据分页加载
- 网络请求优化和重试机制