修改选择器
This commit is contained in:
@@ -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<StationModel> stationOptions = <StationModel>[].obs;
|
||||
final Rxn<String> selectedStationId = Rxn<String>(); // 用 ID 来选择
|
||||
final Rxn<String> selectedStationId = Rxn<String>();
|
||||
|
||||
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<int> hours = List<int>.generate(24, (index) => index);
|
||||
List<int> minutes = [0, 30];
|
||||
final List<TimeSlot> 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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -258,16 +258,10 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
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)',
|
||||
|
||||
Reference in New Issue
Block a user