修改选择器
This commit is contained in:
@@ -14,6 +14,20 @@ import 'package:ln_jq_app/storage_service.dart';
|
|||||||
|
|
||||||
import '../../../common/styles/theme.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 {
|
class C_ReservationController extends GetxController with BaseControllerMixin {
|
||||||
@override
|
@override
|
||||||
String get builderId => 'reservation';
|
String get builderId => 'reservation';
|
||||||
@@ -28,7 +42,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
TextEditingController plateNumberController = TextEditingController();
|
TextEditingController plateNumberController = TextEditingController();
|
||||||
|
|
||||||
final RxList<StationModel> stationOptions = <StationModel>[].obs;
|
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);
|
String get formattedDate => DateFormat('yyyy-MM-dd').format(selectedDate.value);
|
||||||
|
|
||||||
@@ -59,23 +73,14 @@ 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: () {
|
||||||
selectedDate.value = tempDate;
|
selectedDate.value = tempDate;
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text('确认', style: TextStyle(color: AppTheme.themeColor, fontWeight: FontWeight.bold)),
|
||||||
'确认',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.themeColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -84,27 +89,8 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: CupertinoDatePicker(
|
child: CupertinoDatePicker(
|
||||||
mode: CupertinoDatePickerMode.date,
|
mode: CupertinoDatePickerMode.date,
|
||||||
initialDateTime:
|
initialDateTime: selectedDate.value,
|
||||||
selectedDate.value.isBefore(
|
minimumDate: DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day),
|
||||||
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,
|
|
||||||
),
|
|
||||||
maximumDate: DateTime.now().add(const Duration(days: 365)),
|
maximumDate: DateTime.now().add(const Duration(days: 365)),
|
||||||
onDateTimeChanged: (DateTime newDate) {
|
onDateTimeChanged: (DateTime newDate) {
|
||||||
tempDate = newDate;
|
tempDate = newDate;
|
||||||
@@ -118,52 +104,50 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pickTime(BuildContext context, bool isStartTime) {
|
///30 分钟为间隔 时间选择器
|
||||||
// 1. 确定当前操作的时间和初始值
|
void pickTime(BuildContext context) {
|
||||||
TimeOfDay initialTime = isStartTime ? startTime.value : endTime.value;
|
final now = DateTime.now();
|
||||||
DateTime now = DateTime.now();
|
final isToday = selectedDate.value.year == now.year &&
|
||||||
|
selectedDate.value.month == now.month &&
|
||||||
|
selectedDate.value.day == now.day;
|
||||||
|
|
||||||
// 2. 准备小时和分钟的数据源
|
final List<TimeSlot> availableSlots = [];
|
||||||
List<int> hours = List<int>.generate(24, (index) => index);
|
for (int i = 0; i < 48; i++) {
|
||||||
List<int> minutes = [0, 30];
|
final startMinutes = i * 30;
|
||||||
|
final endMinutes = startMinutes + 30;
|
||||||
|
|
||||||
// 3. 计算初始选中的索引
|
final startTime = TimeOfDay(hour: startMinutes ~/ 60, minute: startMinutes % 60);
|
||||||
int initialHour = initialTime.hour;
|
final endTime = TimeOfDay(hour: (endMinutes ~/ 60) % 24, minute: endMinutes % 60);
|
||||||
// 将初始分钟校准到0或30,并找到对应的索引
|
|
||||||
int initialMinute = initialTime.minute;
|
|
||||||
int minuteIndex = initialMinute < 30 ? 0 : 1;
|
|
||||||
initialMinute = minutes[minuteIndex]; // 校准后的分钟
|
|
||||||
|
|
||||||
// 如果校准后导致时间早于当前时间,需要向上调整
|
final slotStartDateTime = DateTime(
|
||||||
final selectedDay = DateTime(selectedDate.value.year, selectedDate.value.month, selectedDate.value.day);
|
selectedDate.value.year,
|
||||||
final today = DateTime(now.year, now.month, now.day);
|
selectedDate.value.month,
|
||||||
if (selectedDay.isAtSameMomentAs(today)) {
|
selectedDate.value.day,
|
||||||
if (initialHour < now.hour || (initialHour == now.hour && initialMinute < now.minute)) {
|
startTime.hour,
|
||||||
initialHour = now.hour;
|
startTime.minute,
|
||||||
if (now.minute > 30) {
|
);
|
||||||
// 如果当前分钟>30, 则进位到下一小时的0分
|
|
||||||
initialHour = (now.hour + 1) % 24;
|
if (!isToday || slotStartDateTime.isAfter(now)) {
|
||||||
initialMinute = 0;
|
availableSlots.add(TimeSlot(startTime, endTime));
|
||||||
} else {
|
|
||||||
// 否则,取30分
|
|
||||||
initialMinute = 30;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (availableSlots.isEmpty) {
|
||||||
|
showToast('今天已没有可预约的时间段');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新获取校准后的索引
|
int initialItem = availableSlots.indexWhere((slot) =>
|
||||||
minuteIndex = minutes.indexOf(initialMinute);
|
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];
|
||||||
|
|
||||||
// 4. 创建 FixedExtentScrollController 来控制滚轮的初始位置
|
final FixedExtentScrollController scrollController =
|
||||||
final FixedExtentScrollController hourController =
|
FixedExtentScrollController(initialItem: initialItem);
|
||||||
FixedExtentScrollController(initialItem: hours.indexOf(initialHour));
|
|
||||||
final FixedExtentScrollController minuteController =
|
|
||||||
FixedExtentScrollController(initialItem: minuteIndex);
|
|
||||||
|
|
||||||
// 5. 存储临时选择的值
|
|
||||||
int tempHour = initialHour;
|
|
||||||
int tempMinute = initialMinute;
|
|
||||||
|
|
||||||
Get.bottomSheet(
|
Get.bottomSheet(
|
||||||
Container(
|
Container(
|
||||||
@@ -188,88 +172,25 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
),
|
),
|
||||||
CupertinoButton(
|
CupertinoButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final pickedTempTime = TimeOfDay(hour: tempHour, minute: tempMinute);
|
startTime.value = tempSlot.start;
|
||||||
final now = DateTime.now();
|
endTime.value = tempSlot.end;
|
||||||
|
|
||||||
// --- 合并和简化校验逻辑 ---
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text('确认', style: TextStyle(color: AppTheme.themeColor, fontWeight: FontWeight.bold)),
|
||||||
'确认',
|
|
||||||
style: TextStyle(color: AppTheme.themeColor, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(height: 1, color: Color(0xFFE5E5E5)),
|
const Divider(height: 1, color: Color(0xFFE5E5E5)),
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
// 小时选择器
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: CupertinoPicker(
|
child: CupertinoPicker(
|
||||||
scrollController: hourController,
|
scrollController: scrollController,
|
||||||
itemExtent: 32.0,
|
itemExtent: 40.0,
|
||||||
onSelectedItemChanged: (index) {
|
onSelectedItemChanged: (index) {
|
||||||
tempHour = hours[index];
|
tempSlot = availableSlots[index];
|
||||||
},
|
},
|
||||||
children: hours
|
children:
|
||||||
.map((h) => Center(child: Text(h.toString().padLeft(2, '0'))))
|
availableSlots.map((slot) => Center(child: Text(slot.display))).toList(),
|
||||||
.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(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -258,16 +258,10 @@ class ReservationPage extends GetView<C_ReservationController> {
|
|||||||
onTap: () => controller.pickDate(context),
|
onTap: () => controller.pickDate(context),
|
||||||
),
|
),
|
||||||
_buildPickerRow(
|
_buildPickerRow(
|
||||||
label: '开始时间',
|
label: '预约时间',
|
||||||
value: controller.formattedStartTime,
|
value: controller.formattedStartTime,
|
||||||
icon: Icons.access_time_outlined,
|
icon: Icons.access_time_outlined,
|
||||||
onTap: () => controller.pickTime(context, true),
|
onTap: () => controller.pickTime(context),
|
||||||
),
|
|
||||||
_buildPickerRow(
|
|
||||||
label: '结束时间',
|
|
||||||
value: controller.formattedEndTime,
|
|
||||||
icon: Icons.access_time_outlined,
|
|
||||||
onTap: () => controller.pickTime(context, false),
|
|
||||||
),
|
),
|
||||||
_buildTextField(
|
_buildTextField(
|
||||||
label: '预约氢量(KG)',
|
label: '预约氢量(KG)',
|
||||||
|
|||||||
Reference in New Issue
Block a user