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 99e931f..30ed0a4 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/controller.dart @@ -14,6 +14,20 @@ import 'package:ln_jq_app/storage_service.dart'; import '../../../common/styles/theme.dart'; +/// Helper class for managing time slots +class TimeSlot { + final TimeOfDay start; + final TimeOfDay end; + + 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')}'; + return '$startStr - $endStr'; + } +} + class C_ReservationController extends GetxController with BaseControllerMixin { @override String get builderId => 'reservation'; @@ -28,7 +42,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin { TextEditingController plateNumberController = TextEditingController(); final RxList stationOptions = [].obs; - final Rxn selectedStationId = Rxn(); // 用 ID 来选择 + final Rxn selectedStationId = Rxn(); String get formattedDate => DateFormat('yyyy-MM-dd').format(selectedDate.value); @@ -59,23 +73,14 @@ 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)), ), ], ), @@ -84,27 +89,8 @@ class C_ReservationController extends GetxController with BaseControllerMixin { Expanded( child: CupertinoDatePicker( mode: CupertinoDatePickerMode.date, - initialDateTime: - selectedDate.value.isBefore( - DateTime( - DateTime.now().year, - DateTime.now().month, - DateTime.now().day, - ), - ) - ? DateTime( - DateTime.now().year, - DateTime.now().month, - DateTime.now().day, - ) - : selectedDate.value, - - // 设置最小可选日期为“今天凌晨0点” - minimumDate: DateTime( - DateTime.now().year, - DateTime.now().month, - DateTime.now().day, - ), + initialDateTime: selectedDate.value, + minimumDate: DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day), maximumDate: DateTime.now().add(const Duration(days: 365)), onDateTimeChanged: (DateTime newDate) { tempDate = newDate; @@ -118,52 +104,50 @@ class C_ReservationController extends GetxController with BaseControllerMixin { ); } - void pickTime(BuildContext context, bool isStartTime) { - // 1. 确定当前操作的时间和初始值 - TimeOfDay initialTime = isStartTime ? startTime.value : endTime.value; - DateTime now = DateTime.now(); + ///30 分钟为间隔 时间选择器 + void pickTime(BuildContext context) { + final now = DateTime.now(); + final isToday = selectedDate.value.year == now.year && + selectedDate.value.month == now.month && + selectedDate.value.day == now.day; - // 2. 准备小时和分钟的数据源 - List hours = List.generate(24, (index) => index); - List minutes = [0, 30]; + final List availableSlots = []; + for (int i = 0; i < 48; i++) { + final startMinutes = i * 30; + final endMinutes = startMinutes + 30; - // 3. 计算初始选中的索引 - int initialHour = initialTime.hour; - // 将初始分钟校准到0或30,并找到对应的索引 - int initialMinute = initialTime.minute; - int minuteIndex = initialMinute < 30 ? 0 : 1; - initialMinute = minutes[minuteIndex]; // 校准后的分钟 + final startTime = TimeOfDay(hour: startMinutes ~/ 60, minute: startMinutes % 60); + final endTime = TimeOfDay(hour: (endMinutes ~/ 60) % 24, minute: endMinutes % 60); - // 如果校准后导致时间早于当前时间,需要向上调整 - final selectedDay = DateTime(selectedDate.value.year, selectedDate.value.month, selectedDate.value.day); - final today = DateTime(now.year, now.month, now.day); - if (selectedDay.isAtSameMomentAs(today)) { - if (initialHour < now.hour || (initialHour == now.hour && initialMinute < now.minute)) { - initialHour = now.hour; - if (now.minute > 30) { - // 如果当前分钟>30, 则进位到下一小时的0分 - initialHour = (now.hour + 1) % 24; - initialMinute = 0; - } else { - // 否则,取30分 - initialMinute = 30; - } + final slotStartDateTime = DateTime( + selectedDate.value.year, + selectedDate.value.month, + selectedDate.value.day, + startTime.hour, + startTime.minute, + ); + + if (!isToday || slotStartDateTime.isAfter(now)) { + availableSlots.add(TimeSlot(startTime, endTime)); } } - // 重新获取校准后的索引 - minuteIndex = minutes.indexOf(initialMinute); + if (availableSlots.isEmpty) { + showToast('今天已没有可预约的时间段'); + return; + } + 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; + } - // 4. 创建 FixedExtentScrollController 来控制滚轮的初始位置 - final FixedExtentScrollController hourController = - FixedExtentScrollController(initialItem: hours.indexOf(initialHour)); - final FixedExtentScrollController minuteController = - FixedExtentScrollController(initialItem: minuteIndex); + TimeSlot tempSlot = availableSlots[initialItem]; - // 5. 存储临时选择的值 - int tempHour = initialHour; - int tempMinute = initialMinute; + final FixedExtentScrollController scrollController = + FixedExtentScrollController(initialItem: initialItem); Get.bottomSheet( Container( @@ -188,88 +172,25 @@ class C_ReservationController extends GetxController with BaseControllerMixin { ), CupertinoButton( onPressed: () { - final pickedTempTime = TimeOfDay(hour: tempHour, minute: tempMinute); - final now = DateTime.now(); - - // --- 合并和简化校验逻辑 --- - final selectedDateTime = DateTime( - selectedDate.value.year, - selectedDate.value.month, - selectedDate.value.day, - pickedTempTime.hour, - pickedTempTime.minute, - ); - - // 验证1: 不能选择过去的时间(留出一分钟缓冲) - if (selectedDateTime.isBefore(now.subtract(const Duration(minutes: 1)))) { - showToast('不能选择过去的时间'); - return; - } - - // 验证2: 结束时间必须晚于开始时间 - if (isStartTime) { - startTime.value = pickedTempTime; - final startInMinutes = pickedTempTime.hour * 60 + pickedTempTime.minute; - final endInMinutes = endTime.value.hour * 60 + endTime.value.minute; - - // 如果新的开始时间大于等于结束时间,自动将结束时间设置为开始时间+30分钟 - if (startInMinutes >= endInMinutes) { - final newEndDateTime = selectedDateTime.add(const Duration(minutes: 30)); - endTime.value = TimeOfDay.fromDateTime(newEndDateTime); - } - } else { // 正在设置结束时间 - final startInMinutes = startTime.value.hour * 60 + startTime.value.minute; - final endInMinutes = pickedTempTime.hour * 60 + pickedTempTime.minute; - - if (endInMinutes <= startInMinutes) { - showToast('结束时间必须晚于开始时间'); - return; - } - endTime.value = pickedTempTime; - } - + startTime.value = tempSlot.start; + 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)), ), ], ), ), const Divider(height: 1, color: Color(0xFFE5E5E5)), Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // 小时选择器 - Expanded( - child: CupertinoPicker( - scrollController: hourController, - itemExtent: 32.0, - onSelectedItemChanged: (index) { - tempHour = hours[index]; - }, - children: hours - .map((h) => Center(child: Text(h.toString().padLeft(2, '0')))) - .toList(), - ), - ), - // 分钟选择器 - Expanded( - child: CupertinoPicker( - scrollController: minuteController, - itemExtent: 32.0, - onSelectedItemChanged: (index) { - tempMinute = minutes[index]; - }, - children: minutes - .map((m) => Center(child: Text(m.toString().padLeft(2, '0')))) - .toList(), - ), - ), - ], + child: CupertinoPicker( + scrollController: scrollController, + itemExtent: 40.0, + onSelectedItemChanged: (index) { + tempSlot = availableSlots[index]; + }, + children: + availableSlots.map((slot) => Center(child: Text(slot.display))).toList(), ), ), ], 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 7b8bfb9..ec4986b 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/view.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/view.dart @@ -258,16 +258,10 @@ class ReservationPage extends GetView { onTap: () => controller.pickDate(context), ), _buildPickerRow( - label: '开始时间', + label: '预约时间', value: controller.formattedStartTime, icon: Icons.access_time_outlined, - onTap: () => controller.pickTime(context, true), - ), - _buildPickerRow( - label: '结束时间', - value: controller.formattedEndTime, - icon: Icons.access_time_outlined, - onTap: () => controller.pickTime(context, false), + onTap: () => controller.pickTime(context), ), _buildTextField( label: '预约氢量(KG)',