Flutter + 开源鸿蒙实战|城市智慧停车管理系统 Day3 车场详情+车位预约+计时计费算法+路线导航+常用车场缓存持久化
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
html
<!-- Schema.org 结构化数据 -->
<script type="application/ld+json">
{
"@context":"https://schema.org",
"type":"BlogPosting",
"headline":"Flutter+开源鸿蒙实战 城市智慧停车管理系统Day3 车场详情+车位预约+计时计费+路线导航+本地缓存",
"author":{"type":"Person","name":"鸿蒙跨端开发者"},
"publisher":{"type":"Organization","name":"开源鸿蒙技术社区"},
"datePublished":"2026-05-09",
"description":"商业级非校园实战项目Day3,基于Day2地图定位基础,实现车场详情页完整布局、车位预约功能、阶梯式停车计费算法、地图路线导航、常用车场本地缓存持久化、预约弹窗交互优化,适配鸿蒙手机平板,第三方库深度整合,毕设高分硬核业务落地",
"keywords":"Flutter,开源鸿蒙,OpenHarmony,智慧停车,车场详情,车位预约,计时计费,高德导航,本地缓存,GetX"
}
</script>
一、前言
哈喽小伙伴们,我们继续推进城市智慧停车管理系统实战开发,全程聚焦城市市政、商业综合体、小区真实停车业务,无任何校园场景,功能硬核、技术密集,毕设、作品集、面试项目竞争力极强。
快速复盘 Day1--Day2 完整进度:
- Day1:项目初始化、企业级分层架构、高德地图/定位/权限/缓存等全套第三方库集成、GetX全局状态、底部导航、页面骨架搭建;
- Day2:高德地图全屏展示、实时定位、车场点位标注、搜索筛选、车场卡片、全局路由配置,完成地图+定位+车场查询核心底座。
来到 Day3 ,我们正式落地智慧停车最核心的商业业务闭环 :
用户查看车场详情 → 预约空闲车位 → 开始停车计时 → 阶梯计费 → 导航前往车场 → 缓存常用车场。
今天所有功能均为真实停车系统必备逻辑,包含计费算法、预约逻辑、路线规划、本地持久化,技术含金量极高。
本文严格沿用你固定的写作规范:口语化叙事、代码精简5--6行、分点清晰、鸿蒙全端适配、文末配套4张实景配图说明,格式风格和前序完全统一。
今日 Day3 核心开发任务(逐项落地)
- 开发车场详情页完整布局,展示车场全量信息、车位实时状态;
- 封装单个车位组件,区分空闲/占用/已预约三种状态;
- 实现车位预约功能,预约后锁定车位,禁止重复预约;
- 编写阶梯式停车计时计费算法,区分普通用户/会员折扣;
- 集成高德地图路线规划,实现实时导航前往车场;
- 接入 SharedPreferences,实现常用车场本地缓存持久化;
- 封装预约确认弹窗、计费提示弹窗,优化交互体验;
- 完善 GetX 控制器预约、计时、缓存业务逻辑;
- 适配鸿蒙手机/平板多端布局,修复滑动、溢出、定位异常;
- 整理 Day3 高频问题与避坑方案。
二、版块1:车场详情页面完整布局搭建
文字讲解
通过路由传参接收车场实体数据,详情页分为:车场基础信息区、收费规则区、车位网格区、导航预约操作区,整体采用上中下结构,适配鸿蒙屏幕。
dart
class ParkDetailPage extends GetView<ParkController> {
const ParkDetailPage({super.key});
final ParkModel park = Get.arguments;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(park.name),
body: SingleChildScrollView(
padding: EdgeInsets.all(AppStyle.padding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildInfoPanel(),
SizedBox(height: 15.h),
buildFeePanel(),
SizedBox(height: 15.h),
buildParkingGrid(),
SizedBox(height: 20.h),
buildBottomBtn(),
],
),
),
);
}
}
三、版块2:车位实体与状态枚举定义
文字讲解
定义车位三种状态:空闲、已占用、已预约,用于UI颜色区分和预约逻辑判断,为网格布局提供数据支撑。
dart
enum ParkStatus { free, used, booked }
class SlotModel {
final int id;
final ParkStatus status;
SlotModel({required this.id, required this.status});
}
四、版块3:车位网格布局+单个车位组件封装
文字讲解
使用 GridView 实现车位矩阵,空闲绿色、占用灰色、预约蓝色,点击空闲车位触发预约弹窗,样式统一可复用。
dart
Widget buildSlotItem(SlotModel slot, VoidCallback onTap) {
Color color = slot.status == ParkStatus.free
? Colors.green[300]!
: slot.status == ParkStatus.booked
? Colors.blue[300]!
: Colors.grey[400]!;
return InkWell(
onTap: slot.status == ParkStatus.free ? onTap : null,
child: Container(
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(8.r)),
child: Center(child: Text("${slot.id}号")),
),
);
}
五、版块4:车位预约核心逻辑实现
文字讲解
用户点击空闲车位,弹出预约确认弹窗,确认后修改车位状态为已预约,控制器更新数据,UI实时刷新;同时禁止重复预约、占用车位不可预约。
dart
// 控制器预约车位
void bookSlot(int slotId, String parkName) {
var slot = slotList.firstWhere((e) => e.id == slotId);
if (slot.status != ParkStatus.free) return;
slot.status = ParkStatus.booked;
slotList.refresh();
saveRecentPark(parkName); // 保存常用车场
Get.back();
ToastUtil.show("预约成功,请尽快前往停车");
}
dart
// 预约弹窗
void showBookDialog(int slotId, String parkName) {
Get.dialog(AlertDialog(
title: const Text("车位预约确认"),
content: Text("确认预约${slotId}号车位?"),
actions: [
TextButton(onPressed: () => Get.back(), child: const Text("取消")),
TextButton(onPressed: () => controller.bookSlot(slotId, parkName), child: const Text("确认预约")),
],
));
}

六、版块5:阶梯式停车计时计费算法(项目核心亮点)
文字讲解
真实商业计费规则:0--2小时基础价,2--8小时加价,8小时以上按天封顶;会员8折优惠。算法独立封装,后期修改价格只需改一处,毕设核心加分项。
dart
double calcParkingFee(int hour, bool isVip) {
double base;
if (hour <= 2) base = 4;
else if (hour <= 8) base = 8;
else base = 15;
return isVip ? base * 0.8 : base;
}
七、版块6:高德地图路线规划与导航功能
文字讲解
集成高德路线规划API,从用户当前位置到目标车场生成路线,支持驾车导航,适配鸿蒙定位,一键跳转地图导航。
dart
void startNav(LatLng parkLatLng) async {
await AMapFlutterNavi.startNavi(NaviParams(
destination: parkLatLng,
startPoint: controller.currentLocation.value,
naviType: NaviType.driving,
));
}
八、版块7:常用车场本地缓存持久化
文字讲解
用户预约/进入车场详情,自动保存车场名称、地址、经纬度到本地;重启APP不丢失,首页可展示常用车场列表,提升用户体验。
dart
Future<void> saveRecentPark(String parkName) async {
final sp = await SharedPreferences.getInstance();
List<String> list = sp.getStringList("recent_park") ?? [];
if (!list.contains(parkName)) list.add(parkName);
await sp.setStringList("recent_park", list);
}
九、版块8:底部操作按钮栏(导航+开始停车)
文字讲解
详情页底部固定两个核心按钮:一键导航、开始停车;点击开始停车后开启计时,实时计算费用,为Day4订单缴费做准备。
dart
Widget buildBottomBtn() {
return Row(
children: [
Expanded(child: buildPrimaryBtn("一键导航", ()=>controller.startNav(park.location))),
SizedBox(width: 10.w),
Expanded(child: buildPrimaryBtn("开始停车", ()=>controller.startTimer(park))),
],
);
}
十、版块9:停车计时实时更新逻辑
文字讲解
使用 Dart Timer 实现停车时长实时累加,每秒更新时长与费用,UI自动刷新;停止停车时生成停车记录。
dart
void startTimer(ParkModel park) {
parkingHour = 0;
timer = Timer.periodic(const Duration(seconds: 3600), (t) {
parkingHour++;
fee.value = calcParkingFee(parkingHour, authController.isVip.value);
});
}

十一、版块10:Day3 新手高频问题详解
问题1:车位点击无反应、状态不切换?
解答:必须用 RxList 管理车位数据;UI 外层用 Obx 包裹;空闲状态判断条件不能写错。
问题2:导航无法启动、定位跳转失败?
解答:高德导航Key和地图Key一致;鸿蒙真机开启定位权限;模拟器不支持导航,必须真机测试。
问题3:计费算法金额计算异常?
解答:小时类型统一用 int;会员状态从全局 AuthController 获取;阶梯判断顺序不可颠倒。
问题4:本地缓存车场重复保存?
解答:保存前判断是否已存在;key 名称统一;异步方法必须加 await。
问题5:GridView车位布局平板错乱?
解答:使用 MediaQuery 动态设置列数;开启 shrinkWrap、禁止内部滚动冲突。
十二、Day3 开发总结
今天 Day3 完成智慧停车系统核心商业业务闭环,从简单地图浏览升级为完整停车服务:
- 完成车场详情页全量布局,信息层级清晰、多端适配;
- 实现车位网格、三种状态区分、预约锁定逻辑;
- 编写阶梯式停车计费算法,区分普通/会员,硬核业务亮点;
- 集成高德路线规划,实现一键导航前往车场;
- 实现常用车场本地缓存持久化,提升用户体验;
- 完成停车计时、实时费用计算,为订单缴费铺路;
- 优化弹窗交互、全局UI样式,适配鸿蒙全终端;
- 汇总高频问题,提供可直接落地的解决方案。
项目至此已具备定位→查询→详情→预约→计时→计费→导航→缓存 完整链路,完全对标真实商用停车APP,无校园同质化,毕设含金量极高。

十三、下期 Day4 预告
Day4 将开发:停车订单自动生成、订单多状态管理、在线缴费逻辑、我的订单页面、会员中心UI、个人中心完善、退出登录与缓存清理。
