调整预约时间格式

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

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width"> <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>导航规划</title> <title>路径规划</title>
<style> <style>
html, body, #container { width: 100%; height: 100%; margin: 0; } html, body, #container { width: 100%; height: 100%; margin: 0; }

View File

@@ -45,8 +45,6 @@ class B_BaseWidgetsPage extends GetView<B_BaseWidgetsController> {
label: '加氢预约', label: '加氢预约',
icon: AntdIcon.orderedlist, icon: AntdIcon.orderedlist,
selectedIcon: AntdIcon.calendar_fill, selectedIcon: AntdIcon.calendar_fill,
badge: '99+',
dot: true,
), ),
NavigationItemModel( NavigationItemModel(
label: '站点信息', label: '站点信息',

View File

@@ -71,7 +71,7 @@ class ReservationPage extends GetView<ReservationController> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
_buildHeaderStat(controller.costPrice, '氢气价格'), _buildHeaderStat(controller.customerPrice, '氢气价格'),
_buildHeaderStat(controller.timeStr, '营业时间'), _buildHeaderStat(controller.timeStr, '营业时间'),
_buildHeaderStat('98%', '设备状态'), _buildHeaderStat('98%', '设备状态'),
], ],
@@ -119,7 +119,7 @@ class ReservationPage extends GetView<ReservationController> {
// --- 价格信息 --- // --- 价格信息 ---
_buildSectionTitle('价格信息'), _buildSectionTitle('价格信息'),
_buildDisplayField(label: '氢气价格 (元/kg)', value: controller.costPrice), // _buildDisplayField(label: '氢气价格 (元/kg)', value: controller.costPrice),
_buildDisplayField(label: '官方价格 (元/kg)', value: controller.customerPrice), _buildDisplayField(label: '官方价格 (元/kg)', value: controller.customerPrice),
const SizedBox(height: 16), const SizedBox(height: 16),

View File

@@ -51,14 +51,11 @@ class BaseWidgetsPage extends GetView<BaseWidgetsController> {
label: '地图', label: '地图',
icon: AntdIcon.location, icon: AntdIcon.location,
selectedIcon: AntdIcon.location_fill, selectedIcon: AntdIcon.location_fill,
dot: false,
), ),
NavigationItemModel( NavigationItemModel(
label: '加氢预约', label: '加氢预约',
icon: AntdIcon.orderedlist, icon: AntdIcon.orderedlist,
selectedIcon: AntdIcon.calendar_fill, selectedIcon: AntdIcon.calendar_fill,
badge: '99+',
dot: true,
), ),
NavigationItemModel( NavigationItemModel(
label: '车辆信息', label: '车辆信息',

View File

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