样式交互修改

This commit is contained in:
2026-01-06 17:57:56 +08:00
parent 6cc123f272
commit c57c849073
4 changed files with 131 additions and 76 deletions

View File

@@ -8,6 +8,7 @@ class AppTheme {
static const Color themeColor = Color(0xFF0c83c3); static const Color themeColor = Color(0xFF0c83c3);
//http://192.168.110.222:8080/ //http://192.168.110.222:8080/
//http://192.168.110.44:8080/
static const String test_service_url = "https://beta-esg.api.lnh2e.com/"; static const String test_service_url = "https://beta-esg.api.lnh2e.com/";
static const String release_service_url = ""; static const String release_service_url = "";

View File

@@ -41,10 +41,10 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
final DateTime _now = DateTime.now(); final DateTime _now = DateTime.now();
// 计算当前时间属于哪个小时区间 // 计算当前时间属于哪个1小时区间
late final TimeOfDay _initialStartTime = _calculateInitialStartTime(_now); late final TimeOfDay _initialStartTime = _calculateInitialStartTime(_now);
late final TimeOfDay _initialEndTime = TimeOfDay.fromDateTime( 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<DateTime> selectedDate = DateTime(_now.year, _now.month, _now.day).obs;
late final Rx<TimeOfDay> startTime = _initialStartTime.obs; late final Rx<TimeOfDay> startTime = _initialStartTime.obs;
@@ -52,13 +52,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
/// 静态辅助方法,用于计算初始的开始时间 /// 静态辅助方法,用于计算初始的开始时间
static TimeOfDay _calculateInitialStartTime(DateTime now) { static TimeOfDay _calculateInitialStartTime(DateTime now) {
if (now.minute < 30) {
// 如果当前分钟小于30则开始时间为当前小时的0分
return TimeOfDay(hour: now.hour, minute: 0); return TimeOfDay(hour: now.hour, minute: 0);
} else {
// 如果当前分钟大于等于30则开始时间为当前小时的30分
return TimeOfDay(hour: now.hour, minute: 30);
}
} }
/// 静态辅助方法将TimeOfDay转换为DateTime /// 静态辅助方法将TimeOfDay转换为DateTime
@@ -186,7 +180,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
} }
} }
///30 分钟为间隔 时间选择器 ///60 分钟为间隔 时间选择器
void pickTime(BuildContext context) { void pickTime(BuildContext context) {
final now = DateTime.now(); final now = DateTime.now();
final isToday = final isToday =
@@ -195,21 +189,15 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
selectedDate.value.day == now.day; selectedDate.value.day == now.day;
final List<TimeSlot> availableSlots = []; final List<TimeSlot> availableSlots = [];
for (int i = 0; i < 48; i++) { for (int i = 0; i < 24; i++) {
final startMinutes = i * 30; // 每次增加 60 分钟
final endMinutes = startMinutes + 30; final startMinutes = i * 60;
final endMinutes = startMinutes + 60;
final startTime = TimeOfDay(hour: startMinutes ~/ 60, minute: 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 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) { if (!isToday) {
availableSlots.add(TimeSlot(startTime, endTime)); availableSlots.add(TimeSlot(startTime, endTime));
@@ -224,8 +212,16 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
endTime.minute, 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)); availableSlots.add(TimeSlot(startTime, endTime));
} }
} }
@@ -236,13 +232,11 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
return; return;
} }
// 查找当前选中的时间对应的新列表中的索引
int initialItem = availableSlots.indexWhere( int initialItem = availableSlots.indexWhere(
(slot) => (slot) => slot.start.hour == startTime.value.hour,
slot.start.hour == startTime.value.hour &&
(startTime.value.minute < 30
? slot.start.minute == 0
: slot.start.minute == 30),
); );
if (initialItem == -1) { if (initialItem == -1) {
initialItem = 0; initialItem = 0;
} }

View File

@@ -13,15 +13,12 @@ import 'reservation_list_bottomsheet.dart';
class ReservationPage extends GetView<C_ReservationController> { class ReservationPage extends GetView<C_ReservationController> {
ReservationPage({super.key}); ReservationPage({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GetBuilder<C_ReservationController>( return GetBuilder<C_ReservationController>(
init: C_ReservationController(), init: C_ReservationController(),
id: 'reservation', id: 'reservation',
builder: (_) { builder: (_) {
return Scaffold( return Scaffold(
backgroundColor: Colors.grey[100], backgroundColor: Colors.grey[100],
body: GestureDetector( body: GestureDetector(
@@ -273,12 +270,12 @@ class ReservationPage extends GetView<C_ReservationController> {
hint: '当前最大可预约氢量${controller.difference}(KG)', hint: '当前最大可预约氢量${controller.difference}(KG)',
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
), ),
_buildTextField( /*_buildTextField(
label: '车牌号', label: '车牌号',
controller: controller.plateNumberController, controller: controller.plateNumberController,
hint: '请输入车牌号', // 修改提示文案 hint: '请输入车牌号', // 修改提示文案
enabled: false, // 设置为不可编辑 enabled: false, // 设置为不可编辑
), ),*/
_buildStationSelector(), _buildStationSelector(),
const SizedBox(height: 20), const SizedBox(height: 20),
Row( Row(
@@ -332,8 +329,6 @@ class ReservationPage extends GetView<C_ReservationController> {
); );
} }
// 表单中的可点击行 (用于日期和时间选择) // 表单中的可点击行 (用于日期和时间选择)
Widget _buildPickerRow({ Widget _buildPickerRow({
required String label, required String label,
@@ -378,6 +373,7 @@ class ReservationPage extends GetView<C_ReservationController> {
TextInputType? keyboardType, TextInputType? keyboardType,
bool enabled = true, bool enabled = true,
}) { }) {
bool showCounter = keyboardType == TextInputType.number;
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 12.0), padding: const EdgeInsets.only(bottom: 12.0),
child: Column( child: Column(
@@ -401,6 +397,25 @@ class ReservationPage extends GetView<C_ReservationController> {
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
filled: !enabled, filled: !enabled,
fillColor: Colors.grey[100], 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() { Widget _buildStationSelector() {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -78,28 +78,41 @@ class ReservationEditController extends GetxController with BaseControllerMixin
selectedDate.value.day == now.day; selectedDate.value.day == now.day;
final List<TimeSlot> availableSlots = []; final List<TimeSlot> availableSlots = [];
for (int i = 0; i < 48; i++) { for (int i = 0; i < 24; i++) {
final startMinutes = i * 30; // 每次增加 60 分钟
final endMinutes = startMinutes + 30; final startMinutes = i * 60;
final slotStartTime = TimeOfDay( final endMinutes = startMinutes + 60;
hour: startMinutes ~/ 60,
minute: startMinutes % 60,
);
final slotEndTime = TimeOfDay(
hour: (endMinutes ~/ 60) % 24,
minute: endMinutes % 60,
);
final slotStartDateTime = DateTime( final startTime = TimeOfDay(hour: startMinutes ~/ 60, minute: startMinutes % 60);
// 注意endMinutes % 60 始终为 0因为间隔是整小时
final endTime = TimeOfDay(hour: (endMinutes ~/ 60) % 24, minute: endMinutes % 60);
// 如果不是今天,所有时间段都有效
if (!isToday) {
availableSlots.add(TimeSlot(startTime, endTime));
} else {
// 如果是今天,需要判断该时间段是否可选
// 创建时间段的结束时间对象
final slotEndDateTime = DateTime(
selectedDate.value.year, selectedDate.value.year,
selectedDate.value.month, selectedDate.value.month,
selectedDate.value.day, selectedDate.value.day,
slotStartTime.hour, endTime.hour,
slotStartTime.minute, endTime.minute,
); );
if (!isToday || slotStartDateTime.isAfter(now)) { // 注意:如果是跨天的 00:00 (例如 23:00 - 00:00),需要将日期加一天,否则 isAfter 判断会出错
availableSlots.add(TimeSlot(slotStartTime, slotEndTime)); // 但由于我们用的是 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; return;
} }
// 查找当前选中的时间对应的新列表中的索引
int initialItem = availableSlots.indexWhere( int initialItem = availableSlots.indexWhere(
(slot) => (slot) => slot.start.hour == startTime.value.hour,
slot.start.hour == startTime.value.hour &&
(startTime.value.minute < 30
? slot.start.minute == 0
: slot.start.minute == 30),
); );
if (initialItem == -1) initialItem = 0;
if (initialItem == -1) {
initialItem = 0;
}
TimeSlot tempSlot = availableSlots[initialItem]; TimeSlot tempSlot = availableSlots[initialItem];
Get.bottomSheet( Get.bottomSheet(
Container( Container(
height: 300, height: 300,