调整预约时间格式

This commit is contained in:
2025-11-26 17:33:04 +08:00
parent 26a24efeb8
commit b854d295f9
5 changed files with 94 additions and 109 deletions

View File

@@ -119,68 +119,55 @@ 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();
// 计算最小可选时间
DateTime? minimumDateTime; // 默认为 null即可选任意时间
// 2. 准备小时和分钟的数据源
List<int> hours = List<int>.generate(24, (index) => index);
List<int> minutes = [0, 30];
// 获取当前选择的日期(年月日)
final selectedDay = DateTime(
selectedDate.value.year,
selectedDate.value.month,
selectedDate.value.day,
);
// 3. 计算初始选中的索引
int initialHour = initialTime.hour;
// 将初始分钟校准到0或30并找到对应的索引
int initialMinute = initialTime.minute;
int minuteIndex = initialMinute < 30 ? 0 : 1;
initialMinute = minutes[minuteIndex]; // 校准后的分钟
// 获取今天的日期(年月日)
// 如果校准后导致时间早于当前时间,需要向上调整
final selectedDay = DateTime(selectedDate.value.year, selectedDate.value.month, selectedDate.value.day);
final today = DateTime(now.year, now.month, now.day);
if (isStartTime) {
// 如果是选择开始时间并且日期是 今天
if (selectedDay.isAtSameMomentAs(today)) {
minimumDateTime = now; // 最小可选时间就是现在
}
} else {
// 如果是选择结束时间
// 将开始时间转换为 DateTime 对象
final startDateTime = DateTime(
selectedDate.value.year,
selectedDate.value.month,
selectedDate.value.day,
startTime.value.hour,
startTime.value.minute,
);
// 结束时间的最小值必须晚于开始时间
minimumDateTime = startDateTime;
// 如果日期是今天,并且开始时间早于现在,那么结束时间的最小值也应该是现在
if (selectedDay.isAtSameMomentAs(today) && startDateTime.isBefore(now)) {
minimumDateTime = now;
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;
}
}
}
// 初始显示时间
DateTime initialDateTime = DateTime(
selectedDate.value.year,
selectedDate.value.month,
selectedDate.value.day,
initialTime.hour,
initialTime.minute,
);
// 重新获取校准后的索引
minuteIndex = minutes.indexOf(initialMinute);
// 确保初始时间不早于最小时间
if (minimumDateTime != null && initialDateTime.isBefore(minimumDateTime)) {
initialDateTime = minimumDateTime;
}
DateTime tempTime = initialDateTime;
// 4. 创建 FixedExtentScrollController 来控制滚轮的初始位置
final FixedExtentScrollController hourController =
FixedExtentScrollController(initialItem: hours.indexOf(initialHour));
final FixedExtentScrollController minuteController =
FixedExtentScrollController(initialItem: minuteIndex);
// 5. 存储临时选择的值
int tempHour = initialHour;
int tempMinute = initialMinute;
Get.bottomSheet(
Container(
height: 300,
padding: const EdgeInsets.only(top: 6.0),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
@@ -197,75 +184,55 @@ 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: () {
final pickedTempTime = TimeOfDay.fromDateTime(tempTime);
final pickedTempTime = TimeOfDay(hour: tempHour, minute: tempMinute);
final now = DateTime.now();
// 验证条件1不能选择过去的时间
// 这个验证只在选择【今天】的【开始时间】或【结束时间】时有意义
final selectedDay = DateTime(
// --- 合并和简化校验逻辑 ---
final selectedDateTime = DateTime(
selectedDate.value.year,
selectedDate.value.month,
selectedDate.value.day,
);
final today = DateTime(
DateTime.now().year,
DateTime.now().month,
DateTime.now().day,
pickedTempTime.hour,
pickedTempTime.minute,
);
if (selectedDay.isAtSameMomentAs(today) &&
tempTime.isBefore(DateTime.now())) {
// 验证1: 不能选择过去的时间(留出一分钟缓冲)
if (selectedDateTime.isBefore(now.subtract(const Duration(minutes: 1)))) {
showToast('不能选择过去的时间');
return; // 中断执行,不关闭弹窗
return;
}
//结束时间必须晚于开始时间
// 验证2: 结束时间必须晚于开始时间
if (isStartTime) {
// 已有的结束时间 比较
final pickedStartInMinutes =
pickedTempTime.hour * 60 + pickedTempTime.minute;
final endInMinutes =
endTime.value.hour * 60 + endTime.value.minute;
startTime.value = pickedTempTime;
final startInMinutes = pickedTempTime.hour * 60 + pickedTempTime.minute;
final endInMinutes = endTime.value.hour * 60 + endTime.value.minute;
if (pickedStartInMinutes >= endInMinutes) {
// 整结束时间
startTime.value = pickedTempTime;
final newEndDateTime = tempTime.add(
const Duration(minutes: 30),
);
// 如果新的开始时间大于等于结束时间,自动将结束时间设置为开始时间+30分钟
if (startInMinutes >= endInMinutes) {
final newEndDateTime = selectedDateTime.add(const Duration(minutes: 30));
endTime.value = TimeOfDay.fromDateTime(newEndDateTime);
} else {
//设置开始时间
startTime.value = pickedTempTime;
}
} else {
// 如果当前正在设置结束时间,我们来和已有的开始时间比较
final pickedEndInMinutes =
pickedTempTime.hour * 60 + pickedTempTime.minute;
final startInMinutes =
startTime.value.hour * 60 + startTime.value.minute;
} else { // 正在设置结束时间
final startInMinutes = startTime.value.hour * 60 + startTime.value.minute;
final endInMinutes = pickedTempTime.hour * 60 + pickedTempTime.minute;
if (pickedEndInMinutes <= startInMinutes) {
if (endInMinutes <= startInMinutes) {
showToast('结束时间必须晚于开始时间');
return; // 中断执行,不关闭弹窗
} else {
endTime.value = pickedTempTime;
return;
}
endTime.value = pickedTempTime;
}
Get.back();
},
child: const Text(
'确认',
style: TextStyle(
color: AppTheme.themeColor,
fontWeight: FontWeight.bold,
),
style: TextStyle(color: AppTheme.themeColor, fontWeight: FontWeight.bold),
),
),
],
@@ -273,14 +240,36 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
),
const Divider(height: 1, color: Color(0xFFE5E5E5)),
Expanded(
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.time,
use24hFormat: true,
initialDateTime: initialDateTime,
minimumDate: minimumDateTime,
onDateTimeChanged: (DateTime newTime) {
tempTime = newTime;
},
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(),
),
),
],
),
),
],
@@ -290,6 +279,8 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
);
}
// 用于存储上一次成功预约的信息
ReservationModel? lastSuccessfulReservation;
@@ -323,7 +314,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
final startTimeStr = '$dateStr ${formattedStartTime}:00';
if (lastSuccessfulReservation != null &&
lastSuccessfulReservation!.id == selectedStationId.value &&
lastSuccessfulReservation!.hydAmount == ampuntStr &&
lastSuccessfulReservation!.startTime == startTimeStr) {
showToast("请勿重复提交相同的预约");
return;