diff --git a/ln_jq_app/lib/pages/c_page/reservation/controller.dart b/ln_jq_app/lib/pages/c_page/reservation/controller.dart index 30ed0a4..ac5e510 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/controller.dart @@ -22,8 +22,10 @@ class TimeSlot { TimeSlot(this.start, this.end); String get display { - final startStr = '${start.hour.toString().padLeft(2, '0')}:${start.minute.toString().padLeft(2, '0')}'; - final endStr = '${end.hour.toString().padLeft(2, '0')}:${end.minute.toString().padLeft(2, '0')}'; + final startStr = + '${start.hour.toString().padLeft(2, '0')}:${start.minute.toString().padLeft(2, '0')}'; + final endStr = + '${end.hour.toString().padLeft(2, '0')}:${end.minute.toString().padLeft(2, '0')}'; return '$startStr - $endStr'; } } @@ -32,11 +34,33 @@ class C_ReservationController extends GetxController with BaseControllerMixin { @override String get builderId => 'reservation'; - final Rx selectedDate = DateTime.now().obs; - final Rx startTime = TimeOfDay.now().obs; - final Rx endTime = TimeOfDay.fromDateTime( - DateTime.now().add(const Duration(minutes: 30)), - ).obs; + final DateTime _now = DateTime.now(); + + // 计算当前时间属于哪个半小时区间 + late final TimeOfDay _initialStartTime = _calculateInitialStartTime(_now); + late final TimeOfDay _initialEndTime = TimeOfDay.fromDateTime( + _getDateTimeFromTimeOfDay(_initialStartTime).add(const Duration(minutes: 30)), + ); + late final Rx selectedDate = DateTime(_now.year, _now.month, _now.day).obs; + late final Rx startTime = _initialStartTime.obs; + late final Rx endTime = _initialEndTime.obs; + + /// 静态辅助方法,用于计算初始的开始时间 + static TimeOfDay _calculateInitialStartTime(DateTime now) { + if (now.minute < 30) { + // 如果当前分钟小于30,则开始时间为当前小时的0分 + return TimeOfDay(hour: now.hour, minute: 0); + } else { + // 如果当前分钟大于等于30,则开始时间为当前小时的30分 + return TimeOfDay(hour: now.hour, minute: 30); + } + } + + /// 静态辅助方法,将TimeOfDay转换为DateTime + static DateTime _getDateTimeFromTimeOfDay(TimeOfDay time) { + final now = DateTime.now(); + return DateTime(now.year, now.month, now.day, time.hour, time.minute); + } final TextEditingController amountController = TextEditingController(); TextEditingController plateNumberController = TextEditingController(); @@ -46,9 +70,9 @@ class C_ReservationController extends GetxController with BaseControllerMixin { String get formattedDate => DateFormat('yyyy-MM-dd').format(selectedDate.value); - String get formattedStartTime => _formatTimeOfDay(startTime.value); - - String get formattedEndTime => _formatTimeOfDay(endTime.value); + /// 时间段 + String get formattedTimeSlot => + '${_formatTimeOfDay(startTime.value)} - ${_formatTimeOfDay(endTime.value)}'; void pickDate(BuildContext context) { DateTime tempDate = selectedDate.value; @@ -73,14 +97,23 @@ class C_ReservationController extends GetxController with BaseControllerMixin { children: [ CupertinoButton( onPressed: () => Get.back(), - child: const Text('取消', style: TextStyle(color: CupertinoColors.systemGrey)), + child: const Text( + '取消', + style: TextStyle(color: CupertinoColors.systemGrey), + ), ), CupertinoButton( onPressed: () { selectedDate.value = tempDate; Get.back(); }, - child: const Text('确认', style: TextStyle(color: AppTheme.themeColor, fontWeight: FontWeight.bold)), + child: const Text( + '确认', + style: TextStyle( + color: AppTheme.themeColor, + fontWeight: FontWeight.bold, + ), + ), ), ], ), @@ -90,7 +123,11 @@ class C_ReservationController extends GetxController with BaseControllerMixin { child: CupertinoDatePicker( mode: CupertinoDatePickerMode.date, initialDateTime: selectedDate.value, - minimumDate: DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day), + minimumDate: DateTime( + DateTime.now().year, + DateTime.now().month, + DateTime.now().day, + ), maximumDate: DateTime.now().add(const Duration(days: 365)), onDateTimeChanged: (DateTime newDate) { tempDate = newDate; @@ -107,7 +144,8 @@ class C_ReservationController extends GetxController with BaseControllerMixin { ///30 分钟为间隔 时间选择器 void pickTime(BuildContext context) { final now = DateTime.now(); - final isToday = selectedDate.value.year == now.year && + final isToday = + selectedDate.value.year == now.year && selectedDate.value.month == now.month && selectedDate.value.day == now.day; @@ -127,8 +165,24 @@ class C_ReservationController extends GetxController with BaseControllerMixin { startTime.minute, ); - if (!isToday || slotStartDateTime.isAfter(now)) { + // 如果不是今天,所有时间段都有效 + if (!isToday) { availableSlots.add(TimeSlot(startTime, endTime)); + } else { + // 如果是今天,需要判断该时间段是否可选 + // 创建时间段的结束时间对象 + final slotEndDateTime = DateTime( + selectedDate.value.year, + selectedDate.value.month, + selectedDate.value.day, + endTime.hour, + endTime.minute, + ); + + // 只要时间段的结束时间晚于当前时间,这个时间段就是可预约的 + if (slotEndDateTime.isAfter(now)) { + availableSlots.add(TimeSlot(startTime, endTime)); + } } } @@ -137,17 +191,22 @@ class C_ReservationController extends GetxController with BaseControllerMixin { return; } - int initialItem = availableSlots.indexWhere((slot) => - slot.start.hour == startTime.value.hour && - (startTime.value.minute < 30 ? slot.start.minute == 0 : slot.start.minute == 30)); + int initialItem = availableSlots.indexWhere( + (slot) => + slot.start.hour == startTime.value.hour && + (startTime.value.minute < 30 + ? slot.start.minute == 0 + : slot.start.minute == 30), + ); if (initialItem == -1) { initialItem = 0; } TimeSlot tempSlot = availableSlots[initialItem]; - final FixedExtentScrollController scrollController = - FixedExtentScrollController(initialItem: initialItem); + final FixedExtentScrollController scrollController = FixedExtentScrollController( + initialItem: initialItem, + ); Get.bottomSheet( Container( @@ -168,7 +227,10 @@ class C_ReservationController extends GetxController with BaseControllerMixin { children: [ CupertinoButton( onPressed: () => Get.back(), - child: const Text('取消', style: TextStyle(color: CupertinoColors.systemGrey)), + child: const Text( + '取消', + style: TextStyle(color: CupertinoColors.systemGrey), + ), ), CupertinoButton( onPressed: () { @@ -176,7 +238,13 @@ class C_ReservationController extends GetxController with BaseControllerMixin { endTime.value = tempSlot.end; Get.back(); }, - child: const Text('确认', style: TextStyle(color: AppTheme.themeColor, fontWeight: FontWeight.bold)), + child: const Text( + '确认', + style: TextStyle( + color: AppTheme.themeColor, + fontWeight: FontWeight.bold, + ), + ), ), ], ), @@ -189,8 +257,9 @@ class C_ReservationController extends GetxController with BaseControllerMixin { onSelectedItemChanged: (index) { tempSlot = availableSlots[index]; }, - children: - availableSlots.map((slot) => Center(child: Text(slot.display))).toList(), + children: availableSlots + .map((slot) => Center(child: Text(slot.display))) + .toList(), ), ), ], @@ -200,8 +269,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin { ); } - - // 用于存储上一次成功预约的信息 ReservationModel? lastSuccessfulReservation; @@ -232,7 +299,9 @@ class C_ReservationController extends GetxController with BaseControllerMixin { } final dateStr = formattedDate; - final startTimeStr = '$dateStr ${formattedStartTime}:00'; + final startTimeStr = + '$dateStr ${_formatTimeOfDay(startTime.value)}:00'; // Use helper directly + if (lastSuccessfulReservation != null && lastSuccessfulReservation!.id == selectedStationId.value && lastSuccessfulReservation!.startTime == startTimeStr) { @@ -240,35 +309,36 @@ class C_ReservationController extends GetxController with BaseControllerMixin { return; } - // 将选择的日期和时间组合成一个完整的 DateTime 对象 - final reservationStartDateTime = DateTime( + final reservationEndDateTime = DateTime( selectedDate.value.year, selectedDate.value.month, selectedDate.value.day, - startTime.value.hour, - startTime.value.minute, + endTime.value.hour, + endTime.value.minute, ); - // 检查预约时间是否在当前时间之前 - if (reservationStartDateTime.isBefore(DateTime.now())) { - showToast("不可预约过去的时间"); + //判断预约区间的结束时间是否早于当前时间(留出1分钟缓冲) + if (reservationEndDateTime.isBefore( + DateTime.now().subtract(const Duration(minutes: 1)), + )) { + showToast("无法预约已过去的时间段"); return; } + try { final selectedStation = stationOptions.firstWhere( - (s) => s.hydrogenId == selectedStationId.value, + (s) => s.hydrogenId == selectedStationId.value, ); - if(selectedStation.siteStatusName != "营运中"){ + if (selectedStation.siteStatusName != "营运中") { showToast("该站点${selectedStation.siteStatusName},暂无法预约"); return; } showLoading("提交中"); - final dateStr = formattedDate; // "yyyy-MM-dd" - final startTimeStr = '$dateStr ${formattedStartTime}:00'; // "yyyy-MM-dd HH:mm:ss" - final endTimeStr = '$dateStr ${formattedEndTime}:00'; + final endTimeStr = + '$dateStr ${_formatTimeOfDay(endTime.value)}:00'; // Use helper directly var responseData = await HttpService.to.post( 'appointment/orderAddHyd/saveOrUpdate', @@ -296,7 +366,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin { if (result.code == 0) { showSuccessToast("预约成功"); - // 预约成功后,保存当前预约信息 lastSuccessfulReservation = ReservationModel( id: selectedStationId.value!, hydAmount: ampuntStr, diff --git a/ln_jq_app/lib/pages/c_page/reservation/view.dart b/ln_jq_app/lib/pages/c_page/reservation/view.dart index ec4986b..c3842d4 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/view.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/view.dart @@ -259,7 +259,7 @@ class ReservationPage extends GetView { ), _buildPickerRow( label: '预约时间', - value: controller.formattedStartTime, + value: controller.formattedTimeSlot, icon: Icons.access_time_outlined, onTap: () => controller.pickTime(context), ),