样式交互修改
This commit is contained in:
@@ -41,10 +41,10 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
||||
|
||||
final DateTime _now = DateTime.now();
|
||||
|
||||
// 计算当前时间属于哪个半小时区间
|
||||
// 计算当前时间属于哪个1小时区间
|
||||
late final TimeOfDay _initialStartTime = _calculateInitialStartTime(_now);
|
||||
late final TimeOfDay _initialEndTime = TimeOfDay.fromDateTime(
|
||||
_getDateTimeFromTimeOfDay(_initialStartTime).add(const Duration(minutes: 30)),
|
||||
_getDateTimeFromTimeOfDay(_initialStartTime).add(const Duration(minutes: 60)),
|
||||
);
|
||||
late final Rx<DateTime> selectedDate = DateTime(_now.year, _now.month, _now.day).obs;
|
||||
late final Rx<TimeOfDay> startTime = _initialStartTime.obs;
|
||||
@@ -52,13 +52,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
||||
|
||||
/// 静态辅助方法,用于计算初始的开始时间
|
||||
static TimeOfDay _calculateInitialStartTime(DateTime now) {
|
||||
if (now.minute < 30) {
|
||||
// 如果当前分钟小于30,则开始时间为当前小时的0分
|
||||
return TimeOfDay(hour: now.hour, minute: 0);
|
||||
} else {
|
||||
// 如果当前分钟大于等于30,则开始时间为当前小时的30分
|
||||
return TimeOfDay(hour: now.hour, minute: 30);
|
||||
}
|
||||
return TimeOfDay(hour: now.hour, minute: 0);
|
||||
}
|
||||
|
||||
/// 静态辅助方法,将TimeOfDay转换为DateTime
|
||||
@@ -186,30 +180,24 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
||||
}
|
||||
}
|
||||
|
||||
///30 分钟为间隔 时间选择器
|
||||
///60 分钟为间隔 时间选择器
|
||||
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;
|
||||
selectedDate.value.month == now.month &&
|
||||
selectedDate.value.day == now.day;
|
||||
|
||||
final List<TimeSlot> availableSlots = [];
|
||||
for (int i = 0; i < 48; i++) {
|
||||
final startMinutes = i * 30;
|
||||
final endMinutes = startMinutes + 30;
|
||||
for (int i = 0; i < 24; i++) {
|
||||
// 每次增加 60 分钟
|
||||
final startMinutes = i * 60;
|
||||
final endMinutes = startMinutes + 60;
|
||||
|
||||
final startTime = TimeOfDay(hour: startMinutes ~/ 60, minute: startMinutes % 60);
|
||||
// 注意:endMinutes % 60 始终为 0,因为间隔是整小时
|
||||
final endTime = TimeOfDay(hour: (endMinutes ~/ 60) % 24, minute: endMinutes % 60);
|
||||
|
||||
final slotStartDateTime = DateTime(
|
||||
selectedDate.value.year,
|
||||
selectedDate.value.month,
|
||||
selectedDate.value.day,
|
||||
startTime.hour,
|
||||
startTime.minute,
|
||||
);
|
||||
|
||||
// 如果不是今天,所有时间段都有效
|
||||
if (!isToday) {
|
||||
availableSlots.add(TimeSlot(startTime, endTime));
|
||||
@@ -224,8 +212,16 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
||||
endTime.minute,
|
||||
);
|
||||
|
||||
// 注意:如果是跨天的 00:00 (例如 23:00 - 00:00),需要将日期加一天,否则 isAfter 判断会出错
|
||||
// 但由于我们用的是 endTime.hour % 24,当变成 0 时,日期还是 selectedDate
|
||||
// 这里做一个特殊处理:如果 endTime 是 00:00,意味着它实际上是明天的开始
|
||||
DateTime realEndDateTime = slotEndDateTime;
|
||||
if (endTime.hour == 0 && endTime.minute == 0) {
|
||||
realEndDateTime = slotEndDateTime.add(const Duration(days: 1));
|
||||
}
|
||||
|
||||
// 只要时间段的结束时间晚于当前时间,这个时间段就是可预约的
|
||||
if (slotEndDateTime.isAfter(now)) {
|
||||
if (realEndDateTime.isAfter(now)) {
|
||||
availableSlots.add(TimeSlot(startTime, endTime));
|
||||
}
|
||||
}
|
||||
@@ -236,13 +232,11 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找当前选中的时间对应的新列表中的索引
|
||||
int initialItem = availableSlots.indexWhere(
|
||||
(slot) =>
|
||||
slot.start.hour == startTime.value.hour &&
|
||||
(startTime.value.minute < 30
|
||||
? slot.start.minute == 0
|
||||
: slot.start.minute == 30),
|
||||
(slot) => slot.start.hour == startTime.value.hour,
|
||||
);
|
||||
|
||||
if (initialItem == -1) {
|
||||
initialItem = 0;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,12 @@ import 'reservation_list_bottomsheet.dart';
|
||||
class ReservationPage extends GetView<C_ReservationController> {
|
||||
ReservationPage({super.key});
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<C_ReservationController>(
|
||||
init: C_ReservationController(),
|
||||
id: 'reservation',
|
||||
builder: (_) {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.grey[100],
|
||||
body: GestureDetector(
|
||||
@@ -273,12 +270,12 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
hint: '当前最大可预约氢量${controller.difference}(KG)',
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
_buildTextField(
|
||||
/*_buildTextField(
|
||||
label: '车牌号',
|
||||
controller: controller.plateNumberController,
|
||||
hint: '请输入车牌号', // 修改提示文案
|
||||
enabled: false, // 设置为不可编辑
|
||||
),
|
||||
),*/
|
||||
_buildStationSelector(),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
@@ -332,8 +329,6 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 表单中的可点击行 (用于日期和时间选择)
|
||||
Widget _buildPickerRow({
|
||||
required String label,
|
||||
@@ -378,6 +373,7 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
TextInputType? keyboardType,
|
||||
bool enabled = true,
|
||||
}) {
|
||||
bool showCounter = keyboardType == TextInputType.number;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12.0),
|
||||
child: Column(
|
||||
@@ -401,6 +397,25 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
filled: !enabled,
|
||||
fillColor: Colors.grey[100],
|
||||
// 左侧减号按钮
|
||||
prefixIcon: showCounter
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.remove, color: Colors.blue),
|
||||
onPressed: () => _updateAmount(-1),
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 40, minHeight: 40),
|
||||
)
|
||||
: null,
|
||||
|
||||
// 右侧加号按钮
|
||||
suffixIcon: showCounter
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.add, color: Colors.blue),
|
||||
onPressed: () => _updateAmount(1),
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 40, minHeight: 40),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -408,6 +423,37 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
);
|
||||
}
|
||||
|
||||
// :更新氢量逻辑
|
||||
void _updateAmount(int change) {
|
||||
// 获取当前输入框的值,默认为 0
|
||||
double currentAmount = double.tryParse(controller.amountController.text) ?? 0;
|
||||
|
||||
// 获取最大值,注意处理 difference 可能为空或非数字的情况
|
||||
double maxAmount = double.tryParse(controller.difference.toString()) ?? 9999;
|
||||
|
||||
// 计算新值
|
||||
double newAmount = currentAmount + change;
|
||||
|
||||
// 边界检查
|
||||
if (newAmount < 1) {
|
||||
newAmount = 1; // 最小不能小于 1
|
||||
} else if (newAmount > maxAmount) {
|
||||
newAmount = maxAmount; // 最大不能超过 difference
|
||||
}
|
||||
|
||||
// 如果是整数,去掉小数点显示
|
||||
if (newAmount == newAmount.toInt()) {
|
||||
controller.amountController.text = newAmount.toInt().toString();
|
||||
} else {
|
||||
controller.amountController.text = newAmount.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
// 移动光标到末尾,防止光标跳到前面
|
||||
controller.amountController.selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: controller.amountController.text.length),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStationSelector() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -428,7 +474,7 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => DropdownButtonHideUnderline(
|
||||
() => DropdownButtonHideUnderline(
|
||||
child: DropdownButton2<String>(
|
||||
isExpanded: true,
|
||||
hint: const Text(
|
||||
@@ -439,15 +485,15 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
items: controller.stationOptions
|
||||
.map(
|
||||
(station) => DropdownMenuItem<String>(
|
||||
value: station.hydrogenId, // value 是站点的唯一ID
|
||||
enabled: station.isSelect == 1,
|
||||
child: _buildDropdownItem(station), // child 是自定义的 Widget
|
||||
),
|
||||
)
|
||||
value: station.hydrogenId, // value 是站点的唯一ID
|
||||
enabled: station.isSelect == 1,
|
||||
child: _buildDropdownItem(station), // child 是自定义的 Widget
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
value:
|
||||
// 当前的站点 处理默认
|
||||
controller.selectedStationId.value ??
|
||||
// 当前的站点 处理默认
|
||||
controller.selectedStationId.value ??
|
||||
(controller.stationOptions.isNotEmpty
|
||||
? controller.stationOptions.first.hydrogenId
|
||||
: null),
|
||||
@@ -460,15 +506,15 @@ class ReservationPage extends GetView<C_ReservationController> {
|
||||
customButton: Obx(() {
|
||||
// 优先从已选中的 ID 查找
|
||||
var selectedStation = controller.stationOptions.firstWhereOrNull(
|
||||
(s) => s.hydrogenId == controller.selectedStationId.value,
|
||||
(s) => s.hydrogenId == controller.selectedStationId.value,
|
||||
);
|
||||
|
||||
// 如果找不到已选中的(比如 ID 为空或列表里没有),并且列表不为空,则取第一个作为默认
|
||||
final stationToShow =
|
||||
selectedStation ??
|
||||
(controller.stationOptions.isNotEmpty
|
||||
? controller.stationOptions.first
|
||||
: null);
|
||||
(controller.stationOptions.isNotEmpty
|
||||
? controller.stationOptions.first
|
||||
: null);
|
||||
|
||||
// 如果有要显示的站点,就构建按钮
|
||||
if (stationToShow != null) {
|
||||
|
||||
@@ -74,32 +74,45 @@ class ReservationEditController extends GetxController with BaseControllerMixin
|
||||
final now = DateTime.now();
|
||||
final isToday =
|
||||
selectedDate.value.year == now.year &&
|
||||
selectedDate.value.month == now.month &&
|
||||
selectedDate.value.day == now.day;
|
||||
selectedDate.value.month == now.month &&
|
||||
selectedDate.value.day == now.day;
|
||||
|
||||
final List<TimeSlot> availableSlots = [];
|
||||
for (int i = 0; i < 48; i++) {
|
||||
final startMinutes = i * 30;
|
||||
final endMinutes = startMinutes + 30;
|
||||
final slotStartTime = TimeOfDay(
|
||||
hour: startMinutes ~/ 60,
|
||||
minute: startMinutes % 60,
|
||||
);
|
||||
final slotEndTime = TimeOfDay(
|
||||
hour: (endMinutes ~/ 60) % 24,
|
||||
minute: endMinutes % 60,
|
||||
);
|
||||
for (int i = 0; i < 24; i++) {
|
||||
// 每次增加 60 分钟
|
||||
final startMinutes = i * 60;
|
||||
final endMinutes = startMinutes + 60;
|
||||
|
||||
final slotStartDateTime = DateTime(
|
||||
selectedDate.value.year,
|
||||
selectedDate.value.month,
|
||||
selectedDate.value.day,
|
||||
slotStartTime.hour,
|
||||
slotStartTime.minute,
|
||||
);
|
||||
final startTime = TimeOfDay(hour: startMinutes ~/ 60, minute: startMinutes % 60);
|
||||
// 注意:endMinutes % 60 始终为 0,因为间隔是整小时
|
||||
final endTime = TimeOfDay(hour: (endMinutes ~/ 60) % 24, minute: endMinutes % 60);
|
||||
|
||||
if (!isToday || slotStartDateTime.isAfter(now)) {
|
||||
availableSlots.add(TimeSlot(slotStartTime, slotEndTime));
|
||||
// 如果不是今天,所有时间段都有效
|
||||
if (!isToday) {
|
||||
availableSlots.add(TimeSlot(startTime, endTime));
|
||||
} else {
|
||||
// 如果是今天,需要判断该时间段是否可选
|
||||
// 创建时间段的结束时间对象
|
||||
final slotEndDateTime = DateTime(
|
||||
selectedDate.value.year,
|
||||
selectedDate.value.month,
|
||||
selectedDate.value.day,
|
||||
endTime.hour,
|
||||
endTime.minute,
|
||||
);
|
||||
|
||||
// 注意:如果是跨天的 00:00 (例如 23:00 - 00:00),需要将日期加一天,否则 isAfter 判断会出错
|
||||
// 但由于我们用的是 endTime.hour % 24,当变成 0 时,日期还是 selectedDate
|
||||
// 这里做一个特殊处理:如果 endTime 是 00:00,意味着它实际上是明天的开始
|
||||
DateTime realEndDateTime = slotEndDateTime;
|
||||
if (endTime.hour == 0 && endTime.minute == 0) {
|
||||
realEndDateTime = slotEndDateTime.add(const Duration(days: 1));
|
||||
}
|
||||
|
||||
// 只要时间段的结束时间晚于当前时间,这个时间段就是可预约的
|
||||
if (realEndDateTime.isAfter(now)) {
|
||||
availableSlots.add(TimeSlot(startTime, endTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,17 +121,18 @@ class ReservationEditController extends GetxController with BaseControllerMixin
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找当前选中的时间对应的新列表中的索引
|
||||
int initialItem = availableSlots.indexWhere(
|
||||
(slot) =>
|
||||
slot.start.hour == startTime.value.hour &&
|
||||
(startTime.value.minute < 30
|
||||
? slot.start.minute == 0
|
||||
: slot.start.minute == 30),
|
||||
(slot) => slot.start.hour == startTime.value.hour,
|
||||
);
|
||||
if (initialItem == -1) initialItem = 0;
|
||||
|
||||
if (initialItem == -1) {
|
||||
initialItem = 0;
|
||||
}
|
||||
|
||||
TimeSlot tempSlot = availableSlots[initialItem];
|
||||
|
||||
|
||||
Get.bottomSheet(
|
||||
Container(
|
||||
height: 300,
|
||||
|
||||
Reference in New Issue
Block a user