Flutter车辆保养记录器:智能管理车辆保养全流程
项目简介
车辆保养记录器是一款专业的Flutter应用,帮助车主记录和管理车辆保养信息。通过智能提醒功能,确保按时保养,延长车辆使用寿命。应用支持多车辆管理、费用统计、保养提醒等实用功能。
运行效果图




核心功能
- 保养记录管理:添加、编辑、删除保养记录
- 13种保养项目:机油、机滤、空滤、刹车片等常见项目
- 多车辆支持:管理多辆车的保养记录
- 智能提醒:提前7天提醒下次保养
- 双重提醒:支持日期和里程数双重提醒
- 费用统计:按项目统计保养费用
- 数据持久化:本地保存所有记录
- Tab切换:全部记录和保养提醒分页显示
技术特点
- Material Design 3设计风格
- TabBar多页面切换
- Badge徽章提醒
- 紧急提醒颜色区分
- 响应式卡片布局
- SharedPreferences数据持久化
- 完整的表单验证
核心代码实现
1. 保养记录数据模型
dart
class MaintenanceRecord {
String id;
String vehicleName; // 车辆名称
String project; // 保养项目
DateTime date; // 保养日期
double cost; // 费用
int mileage; // 当前里程
DateTime? nextReminder; // 下次保养日期
int? nextMileage; // 下次保养里程
String location; // 保养地点
String notes; // 备注
bool get needsReminder {
if (nextReminder == null) return false;
return DateTime.now().isAfter(
nextReminder!.subtract(const Duration(days: 7))
);
}
int get daysUntilReminder {
if (nextReminder == null) return -1;
return nextReminder!.difference(DateTime.now()).inDays;
}
}
模型字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | String | 唯一标识符 |
| vehicleName | String | 车辆名称(如:本田雅阁) |
| project | String | 保养项目(如:机油更换) |
| date | DateTime | 保养日期 |
| cost | double | 保养费用 |
| mileage | int | 当前里程数 |
| nextReminder | DateTime? | 下次保养提醒日期 |
| nextMileage | int? | 下次保养里程数 |
| location | String | 保养地点 |
| notes | String | 备注信息 |
计算属性:
needsReminder:是否需要提醒(提前7天)daysUntilReminder:距离下次保养天数
2. TabBar多页面布局
dart
class _MaintenanceListPageState extends State<MaintenanceListPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('车辆保养记录器'),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(text: '全部记录', icon: Icon(Icons.list)),
Tab(text: '保养提醒', icon: Icon(Icons.alarm)),
],
),
),
body: TabBarView(
controller: _tabController,
children: [
_buildAllRecordsTab(),
_buildReminderTab(),
],
),
);
}
}
TabBar要点:
- 使用
SingleTickerProviderStateMixin提供动画支持 TabController管理Tab状态TabBar显示标签页TabBarView显示对应内容- 记得在
dispose中释放TabController
3. 智能提醒系统
dart
// 提醒判断逻辑
bool get needsReminder {
if (nextReminder == null) return false;
// 提前7天开始提醒
return DateTime.now().isAfter(
nextReminder!.subtract(const Duration(days: 7))
);
}
// 获取提醒记录
List<MaintenanceRecord> get _reminderRecords {
return _records.where((r) => r.needsReminder).toList()
..sort((a, b) => a.nextReminder!.compareTo(b.nextReminder!));
}
// Badge徽章显示
final reminderCount = _reminderRecords.length;
if (reminderCount > 0)
IconButton(
icon: Badge(
label: Text('$reminderCount'),
child: const Icon(Icons.notifications),
),
onPressed: () {
_tabController.animateTo(1); // 跳转到提醒页面
},
),
4. 紧急提醒卡片
dart
Widget _buildReminderCard(MaintenanceRecord record) {
final daysLeft = record.daysUntilReminder;
final isUrgent = daysLeft <= 3; // 3天内为紧急
return Card(
color: isUrgent ? Colors.red[50] : Colors.orange[50],
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(
isUrgent ? Icons.error : Icons.warning,
color: isUrgent ? Colors.red : Colors.orange,
size: 32,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(record.project),
Text(record.vehicleName),
],
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: isUrgent ? Colors.red : Colors.orange,
borderRadius: BorderRadius.circular(20),
),
child: Text(
daysLeft <= 0 ? '今天' : '$daysLeft天后',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
);
}
提醒级别:
- 🔴 紧急(3天内):红色背景 + error图标
- 🟠 普通(7天内):橙色背景 + warning图标
5. 费用统计功能
dart
void _showStatistics() {
// 按项目统计费用
final projectStats = <String, double>{};
for (var record in _records) {
projectStats[record.project] =
(projectStats[record.project] ?? 0) + record.cost;
}
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('保养统计'),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('总记录数: ${_allRecords.length}'),
Text(
'总费用: ¥${_totalCost.toStringAsFixed(2)}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
const Divider(),
const Text('各项目费用统计:'),
...projectStats.entries.map((entry) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(entry.key),
Text('¥${entry.value.toStringAsFixed(2)}'),
],
)),
],
),
),
),
);
}
6. 多车辆筛选
dart
// 获取所有车辆列表
List<String> get _vehicles {
final vehicles = _records.map((r) => r.vehicleName).toSet().toList();
return ['全部', ...vehicles];
}
// 筛选逻辑
List<MaintenanceRecord> get _allRecords {
var filtered = _records;
if (_filterVehicle != '全部') {
filtered = filtered.where((r) => r.vehicleName == _filterVehicle).toList();
}
filtered.sort((a, b) => b.date.compareTo(a.date));
return filtered;
}
// 筛选UI
Widget _buildVehicleFilter() {
return Container(
height: 60,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _vehicles.length,
itemBuilder: (context, index) {
final vehicle = _vehicles[index];
return FilterChip(
label: Text(vehicle),
selected: _filterVehicle == vehicle,
onSelected: (selected) {
setState(() {
_filterVehicle = vehicle;
});
},
);
},
),
);
}
7. 双重提醒设置
dart
// 日期提醒
Card(
child: ListTile(
leading: const Icon(Icons.alarm),
title: const Text('下次保养日期'),
subtitle: Text(
_nextReminder != null
? '${_nextReminder!.year}-${_nextReminder!.month.toString().padLeft(2, '0')}-${_nextReminder!.day.toString().padLeft(2, '0')}'
: '未设置',
),
onTap: () async {
final picked = await showDatePicker(
context: context,
initialDate: _nextReminder ?? _date.add(const Duration(days: 180)),
firstDate: _date,
lastDate: DateTime.now().add(const Duration(days: 3650)),
);
if (picked != null) {
setState(() {
_nextReminder = picked;
});
}
},
),
),
// 里程提醒
TextFormField(
controller: _nextMileageController,
decoration: const InputDecoration(
labelText: '下次保养里程(km)',
hintText: '例如:55000',
prefixIcon: Icon(Icons.speed),
),
keyboardType: TextInputType.number,
),
技术要点详解
TabController生命周期
TabController需要正确管理生命周期:
dart
class _MyPageState extends State<MyPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
_tabController.dispose(); // 必须释放
super.dispose();
}
}
Set去重技巧
使用Set快速去重:
dart
// 从记录中提取所有车辆名称并去重
final vehicles = _records.map((r) => r.vehicleName).toSet().toList();
// 等价于
final vehicleSet = <String>{};
for (var record in _records) {
vehicleSet.add(record.vehicleName);
}
final vehicles = vehicleSet.toList();
Map统计技巧
使用Map进行分组统计:
dart
final projectStats = <String, double>{};
for (var record in _records) {
// 如果key不存在,使用0作为默认值
projectStats[record.project] =
(projectStats[record.project] ?? 0) + record.cost;
}
DateTime计算
常用的日期计算方法:
dart
// 加减天数
final tomorrow = DateTime.now().add(const Duration(days: 1));
final yesterday = DateTime.now().subtract(const Duration(days: 1));
// 计算天数差
final days = date2.difference(date1).inDays;
// 判断日期先后
if (date1.isAfter(date2)) { }
if (date1.isBefore(date2)) { }
// 格式化日期
final formatted = '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
保养项目说明
常见保养项目及周期
| 项目 | 建议周期 | 参考费用 |
|---|---|---|
| 机油更换 | 5000-10000km | 200-500元 |
| 机滤更换 | 5000-10000km | 50-100元 |
| 空滤更换 | 10000-20000km | 50-150元 |
| 空调滤芯 | 10000-20000km | 50-200元 |
| 刹车片 | 30000-50000km | 300-800元 |
| 轮胎 | 50000-80000km | 400-1000元/条 |
| 火花塞 | 30000-60000km | 100-300元 |
| 变速箱油 | 40000-60000km | 500-1500元 |
| 防冻液 | 2年 | 100-300元 |
| 电瓶 | 3-5年 | 300-800元 |
| 年检 | 1年 | 200-300元 |
| 保险 | 1年 | 3000-8000元 |
保养提醒算法
是
否
是
否
是
否
保养记录
设置了下次保养?
计算距离天数
不提醒
距离<=7天?
显示提醒
不提醒
距离<=3天?
紧急提醒-红色
普通提醒-橙色
功能扩展建议
1. 本地通知
集成flutter_local_notifications实现定时提醒:
dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class NotificationService {
final FlutterLocalNotificationsPlugin _notifications =
FlutterLocalNotificationsPlugin();
Future<void> scheduleReminder(MaintenanceRecord record) async {
if (record.nextReminder == null) return;
await _notifications.zonedSchedule(
record.id.hashCode,
'保养提醒',
'${record.vehicleName}的${record.project}即将到期',
tz.TZDateTime.from(
record.nextReminder!.subtract(const Duration(days: 7)),
tz.local,
),
const NotificationDetails(
android: AndroidNotificationDetails(
'maintenance_channel',
'保养提醒',
importance: Importance.high,
),
),
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
);
}
}
2. 数据导出
导出保养记录为Excel:
dart
import 'package:excel/excel.dart';
import 'package:path_provider/path_provider.dart';
Future<void> exportToExcel(List<MaintenanceRecord> records) async {
var excel = Excel.createExcel();
Sheet sheet = excel['保养记录'];
// 表头
sheet.appendRow([
'车辆名称',
'保养项目',
'保养日期',
'费用',
'里程',
'下次保养',
'地点',
'备注'
]);
// 数据行
for (var record in records) {
sheet.appendRow([
record.vehicleName,
record.project,
'${record.date.year}-${record.date.month}-${record.date.day}',
record.cost,
record.mileage,
record.nextReminder != null
? '${record.nextReminder!.year}-${record.nextReminder!.month}-${record.nextReminder!.day}'
: '',
record.location,
record.notes,
]);
}
// 保存文件
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/保养记录.xlsx');
await file.writeAsBytes(excel.encode()!);
}
3. 照片记录
添加保养照片功能:
dart
class MaintenanceRecord {
// ... 其他字段
List<String> photos; // 照片路径列表
}
// 拍照功能
Future<void> _takePhoto() async {
final picker = ImagePicker();
final pickedFile = await picker.pickImage(source: ImageSource.camera);
if (pickedFile != null) {
setState(() {
_photos.add(pickedFile.path);
});
}
}
// 显示照片
GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemCount: record.photos.length,
itemBuilder: (context, index) {
return Image.file(File(record.photos[index]));
},
)
4. 保养计划
预设保养计划模板:
dart
class MaintenancePlan {
String name;
List<MaintenanceItem> items;
}
class MaintenanceItem {
String project;
int intervalDays;
int intervalMileage;
}
// 预设计划
final plans = [
MaintenancePlan(
name: '标准保养计划',
items: [
MaintenanceItem(project: '机油更换', intervalDays: 180, intervalMileage: 5000),
MaintenanceItem(project: '机滤更换', intervalDays: 180, intervalMileage: 5000),
MaintenanceItem(project: '空滤更换', intervalDays: 365, intervalMileage: 10000),
],
),
];
5. 保养店管理
记录常用保养店信息:
dart
class MaintenanceShop {
String id;
String name;
String address;
String phone;
double rating;
List<String> services;
}
// 选择保养店
Future<MaintenanceShop?> _selectShop() async {
return await showDialog<MaintenanceShop>(
context: context,
builder: (context) => AlertDialog(
title: const Text('选择保养店'),
content: ListView.builder(
itemCount: _shops.length,
itemBuilder: (context, index) {
final shop = _shops[index];
return ListTile(
title: Text(shop.name),
subtitle: Text(shop.address),
trailing: Text('⭐ ${shop.rating}'),
onTap: () => Navigator.pop(context, shop),
);
},
),
),
);
}
6. 图表统计
使用fl_chart显示费用趋势:
dart
import 'package:fl_chart/fl_chart.dart';
Widget _buildCostChart() {
// 按月统计费用
final monthlyData = <int, double>{};
for (var record in _records) {
final month = record.date.month;
monthlyData[month] = (monthlyData[month] ?? 0) + record.cost;
}
return LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
spots: monthlyData.entries
.map((e) => FlSpot(e.key.toDouble(), e.value))
.toList(),
isCurved: true,
color: Colors.blue,
),
],
),
);
}
常见问题解答
Q1: 如何批量导入保养记录?
A: 可以通过CSV文件导入:
dart
import 'package:csv/csv.dart';
Future<void> importFromCSV(String filePath) async {
final file = File(filePath);
final csvString = await file.readAsString();
final rows = const CsvToListConverter().convert(csvString);
for (var i = 1; i < rows.length; i++) { // 跳过表头
final row = rows[i];
final record = MaintenanceRecord(
id: DateTime.now().millisecondsSinceEpoch.toString(),
vehicleName: row[0],
project: row[1],
date: DateTime.parse(row[2]),
cost: double.parse(row[3].toString()),
mileage: int.parse(row[4].toString()),
location: row[5],
notes: row[6],
);
_records.add(record);
}
_saveRecords();
}
Q2: 如何设置不同的提醒时间?
A: 添加提醒天数设置:
dart
class MaintenanceRecord {
// ... 其他字段
int reminderDays; // 提前提醒天数
bool get needsReminder {
if (nextReminder == null) return false;
return DateTime.now().isAfter(
nextReminder!.subtract(Duration(days: reminderDays))
);
}
}
// 在添加页面添加选择器
DropdownButton<int>(
value: _reminderDays,
items: [3, 7, 14, 30].map((days) {
return DropdownMenuItem(
value: days,
child: Text('提前$days天'),
);
}).toList(),
onChanged: (value) {
setState(() {
_reminderDays = value!;
});
},
)
Q3: 如何实现保养历史对比?
A: 添加历史对比功能:
dart
Widget _buildHistoryComparison(String project) {
final projectRecords = _records
.where((r) => r.project == project)
.toList()
..sort((a, b) => a.date.compareTo(b.date));
return ListView.builder(
itemCount: projectRecords.length,
itemBuilder: (context, index) {
final record = projectRecords[index];
final previous = index > 0 ? projectRecords[index - 1] : null;
return ListTile(
title: Text('${record.date.year}-${record.date.month}-${record.date.day}'),
subtitle: Text('¥${record.cost} | ${record.mileage}km'),
trailing: previous != null
? Column(
children: [
Text('间隔: ${record.date.difference(previous.date).inDays}天'),
Text('里程: ${record.mileage - previous.mileage}km'),
],
)
: null,
);
},
);
}
Q4: 如何添加保养提醒推送?
A: 集成推送服务:
dart
// 使用Firebase Cloud Messaging
import 'package:firebase_messaging/firebase_messaging.dart';
class PushNotificationService {
final FirebaseMessaging _fcm = FirebaseMessaging.instance;
Future<void> initialize() async {
await _fcm.requestPermission();
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
// 处理前台消息
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(message.notification?.title ?? ''),
content: Text(message.notification?.body ?? ''),
),
);
});
}
Future<void> scheduleReminder(MaintenanceRecord record) async {
// 调用后端API设置定时推送
await http.post(
Uri.parse('https://your-api.com/schedule'),
body: jsonEncode({
'token': await _fcm.getToken(),
'time': record.nextReminder?.toIso8601String(),
'title': '保养提醒',
'body': '${record.vehicleName}的${record.project}即将到期',
}),
);
}
}
项目总结
实现的功能
✅ 保养记录管理(增删改查)
✅ 13种常见保养项目
✅ 多车辆支持与筛选
✅ 智能提醒系统(提前7天)
✅ 双重提醒(日期+里程)
✅ 紧急提醒标识(3天内)
✅ 费用统计分析
✅ Tab分页显示
✅ Badge徽章提醒
✅ 数据本地持久化
技术亮点
- TabBar架构:清晰的多页面布局
- 智能提醒:提前7天自动提醒
- 紧急标识:3天内红色警告
- 双重提醒:日期和里程双重保障
- 费用统计:按项目分类统计
- 多车管理:支持多辆车记录
- 数据持久化:完整的JSON序列化
应用场景
- 🚗 个人车辆保养管理
- 🚕 家庭多车管理
- 🚙 车队保养记录
- 🔧 汽修店客户管理
- 📊 保养费用分析
- ⏰ 保养时间提醒
数据流程图
添加记录
保存到内存
JSON序列化
SharedPreferences
本地存储
启动应用
读取数据
JSON反序列化
加载到内存
显示界面
提醒逻辑流程
否
是
否
是
是
否
检查记录
有下次保养日期?
不提醒
计算剩余天数
剩余天数<=7?
不提醒
剩余天数<=3?
紧急提醒-红色
普通提醒-橙色
显示在提醒页
Badge徽章显示数量
车辆保养记录器是一款实用的车辆管理应用,通过智能提醒和详细记录,帮助车主科学管理车辆保养,延长车辆使用寿命,降低维护成本。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net