司机 预约 样式修改

This commit is contained in:
2026-01-27 17:35:37 +08:00
parent 18c04272e2
commit f8a8ecb0ed
4 changed files with 495 additions and 283 deletions

View File

@@ -24,6 +24,10 @@ class CarInfoController extends GetxController with BaseControllerMixin {
final RxList<String> operationAttachments = <String>[].obs;
final RxList<String> hydrogenationAttachments = <String>[].obs;
final RxList<String> registerAttachments = <String>[].obs;
String color = "";
String hydrogenCapacity = "";
String rentFromCompany = "";
String address = "";
bool isNotice = false;
@override
@@ -127,6 +131,12 @@ class CarInfoController extends GetxController with BaseControllerMixin {
...hydrogenationAttachments,
...registerAttachments,
];
color = data['color'].toString();
hydrogenCapacity = data['hydrogenCapacity'].toString();
rentFromCompany = data['rentFromCompany'].toString();
address = data['address'].toString();
loadAllPdfs();
}
}

View File

@@ -339,7 +339,7 @@ class CarInfoPage extends GetView<CarInfoController> {
tabs: const [
Tab(text: '行驶证'),
Tab(text: '营运证'),
Tab(text: '加氢资格'),
Tab(text: '加氢证'),
Tab(text: '登记证'),
],
),
@@ -379,8 +379,8 @@ class CarInfoPage extends GetView<CarInfoController> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildCertDetailItem('所属公司', '上海羚牛氢运物联网科技有限公司', isFull: true),
_buildCertDetailItem('运营城市', controller.vin),
_buildCertDetailItem('所属公司', controller.rentFromCompany, isFull: true),
_buildCertDetailItem('运营城市', controller.address),
],
),
const SizedBox(height: 16),
@@ -389,10 +389,10 @@ class CarInfoPage extends GetView<CarInfoController> {
children: [
_buildCertDetailItem(
'车辆颜色',
'2028-08-14',
controller.color,
valueColor: const Color(0xFF52C41A),
),
_buildCertDetailItem('氢瓶容量', '货运'),
_buildCertDetailItem('氢瓶容量', controller.hydrogenCapacity),
],
),
const SizedBox(height: 16),

View File

@@ -689,6 +689,18 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
} finally {
HttpService.to.setBaseUrl(AppTheme.test_service_url);
}
renderSliderTheme();
}
double current = 0.0;
double maxVal = 0.0;
void renderSliderTheme() {
current = double.tryParse(amountController.text) ?? 0.0;
maxVal = double.tryParse(difference) ?? 100.0;
if (maxVal <= 0) maxVal = 100.0;
updateUi();
}
void getSiteList() async {

View File

@@ -1,6 +1,7 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:getx_scaffold/getx_scaffold.dart';
import 'package:ln_jq_app/common/login_util.dart';
import 'package:ln_jq_app/common/model/station_model.dart';
@@ -25,29 +26,24 @@ class ReservationPage extends GetView<C_ReservationController> {
return Scaffold(
backgroundColor: Color.fromRGBO(247, 249, 251, 1),
body: GestureDetector(
onTap: () {
hideKeyboard();
},
onTap: () => unfocus(),
child: Stack(
children: [
Positioned(
left: 0,
right: 0,
bottom: 10.h,
top: 0,
Positioned.fill(
child: SingleChildScrollView(
child: Column(
children: [
_buildUserInfoCard(),
Padding(
padding: EdgeInsets.only(left: 20.w, right: 20.w),
padding: EdgeInsets.symmetric(horizontal: 18.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: 16.h),
_buildCarInfoCard(),
SizedBox(height: 32.h),
SizedBox(height: 24.h),
_buildReservationFormCard(context),
SizedBox(height: 180.h),
],
),
),
@@ -58,7 +54,7 @@ class ReservationPage extends GetView<C_ReservationController> {
Positioned(
left: 20.w,
right: 20.w,
bottom: 90.h,
bottom: 110.h,
child: _buildReservationItem(context),
),
],
@@ -156,13 +152,7 @@ class ReservationPage extends GetView<C_ReservationController> {
),
),
IconButton(
onPressed: () {
Get.to(() => const MessagePage());
},
style: IconButton.styleFrom(
backgroundColor: Colors.grey[100],
padding: const EdgeInsets.all(8),
),
onPressed: () => Get.to(() => const MessagePage()),
icon: Badge(
smallSize: 8,
backgroundColor: controller.isNotice
@@ -196,9 +186,6 @@ class ReservationPage extends GetView<C_ReservationController> {
);
}
Widget _buildModernStatItem(String title, String subtitle, String value, String unit) {
return Expanded(
child: Container(
@@ -241,7 +228,6 @@ class ReservationPage extends GetView<C_ReservationController> {
);
}
/// 构建车辆信息卡片
Widget _buildCarInfoCard() {
return Card(
elevation: 2,
@@ -251,13 +237,8 @@ class ReservationPage extends GetView<C_ReservationController> {
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
// 左侧:车辆图片
Expanded(
flex: 4,
child: LoginUtil.getAssImg('ic_car_bg@2x'),
),
Expanded(flex: 4, child: LoginUtil.getAssImg('ic_car_bg@2x')),
const SizedBox(width: 16),
// 右侧:信息与进度条
Expanded(
flex: 6,
child: Column(
@@ -268,7 +249,6 @@ class ReservationPage extends GetView<C_ReservationController> {
const SizedBox(height: 8),
_buildCarDataItem('百公里氢耗', '${controller.workEfficiency}Kg'),
const SizedBox(height: 12),
// 进度条部分
Column(
children: [
ClipRRect(
@@ -276,16 +256,32 @@ class ReservationPage extends GetView<C_ReservationController> {
child: LinearProgressIndicator(
value: controller.progressValue,
minHeight: 6,
backgroundColor: Color(0xFFF0F2F5),
valueColor: AlwaysStoppedAnimation<Color>(Color(0xFF006633)),
backgroundColor: const Color(0xFFF0F2F5),
valueColor: const AlwaysStoppedAnimation<Color>(
Color(0xFF006633),
),
),
),
const SizedBox(height: 4),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text("剩余氢量", style: TextStyle(fontSize: 10, color: Colors.grey)),
Text("${controller.leftHydrogen}Kg", style: const TextStyle(fontSize: 10, color: Color(0xFF006633), fontWeight: FontWeight.bold)),
const Text(
"剩余氢量",
style: TextStyle(
fontSize: 10,
color: Colors.grey,
fontWeight: FontWeight.w400,
),
),
Text(
"${controller.leftHydrogen}Kg",
style: const TextStyle(
fontSize: 10,
color: Color(0xFF006633),
fontWeight: FontWeight.w600,
),
),
],
),
],
@@ -304,196 +300,440 @@ class ReservationPage extends GetView<C_ReservationController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(fontSize: 12, color: Colors.grey)),
Text(value, style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: Colors.black87)),
Text(
value,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
],
);
}
/// 构建预约表单卡片
/// --- 构建预约表单卡片---
Widget _buildReservationFormCard(BuildContext context) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
return Column(
children: [
// 1. 顶部:日期与时间选择
Card(
elevation: 0,
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Obx(
() => Column(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildPickerRow(
label: '日期',
value: controller.formattedDate,
icon: Icons.calendar_today_outlined,
onTap: () => controller.pickDate(context),
const Text(
"预约日期与时间",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
_buildPickerRow(
label: '预约时间',
value: controller.formattedTimeSlot,
icon: Icons.access_time_outlined,
onTap: () => controller.pickTime(context),
),
_buildTextField(
label: '预约氢量(KG)',
controller: controller.amountController,
hint: '当前最大可预约氢量${controller.difference}(KG)',
keyboardType: TextInputType.number,
),
/*_buildTextField(
label: '车牌号',
controller: controller.plateNumberController,
hint: '请输入车牌号', // 修改提示文案
enabled: false, // 设置为不可编辑
),*/
_buildStationSelector(),
const SizedBox(height: 20),
_buildHorizontalDateSelector(),
const SizedBox(height: 32),
_buildTimeSlider(context),
],
),
),
),
const SizedBox(height: 12),
// 2. 底部:氢量与站点
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: _buildAmountSliderSection()),
const SizedBox(width: 12),
Expanded(child: _buildStationCardSection(context)),
],
),
],
);
}
Widget _buildReservationItem(BuildContext context) {
return Row(
children: [
Expanded(
flex: 1,
child: OutlinedButton(
onPressed: () {
controller.getReservationList(showPopup: true, addStatus: '');
},
style: OutlinedButton.styleFrom(
minimumSize: Size(double.infinity, 40.h), // 高度与另一个按钮保持一致
side: const BorderSide(color: Color.fromRGBO(226, 232, 240, 1)),
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
/// 水平日期选择器
Widget _buildHorizontalDateSelector() {
final DateTime today = DateTime(
DateTime.now().year,
DateTime.now().month,
DateTime.now().day,
);
final DateTime tomorrow = today.add(const Duration(days: 1));
final List<DateTime> dates = List.generate(
5,
(index) => today.add(Duration(days: index)),
);
const List<String> weekMap = ['', '', '', '', '', '', ''];
return SizedBox(
height: 75,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: dates.length,
itemBuilder: (context, index) {
DateTime date = dates[index];
bool isSelectable =
date.isAtSameMomentAs(today) || date.isAtSameMomentAs(tomorrow);
bool isSelected =
controller.selectedDate.value.year == date.year &&
controller.selectedDate.value.month == date.month &&
controller.selectedDate.value.day == date.day;
return GestureDetector(
onTap: isSelectable
? () {
controller.selectedDate.value = date;
controller.resetTimeForSelectedDate();
controller.updateUi();
}
: null,
child: Container(
width: 58,
margin: const EdgeInsets.only(right: 12),
decoration: BoxDecoration(
color: isSelected ? const Color(0xFF006633) : const Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(14),
),
child: const Text(
'查看预约',
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
weekMap[date.weekday % 7],
style: TextStyle(
color: Color.fromRGBO(119, 119, 119, 1),
fontSize: 12,
color: isSelected
? Colors.white70
: (isSelectable ? Colors.grey : Colors.grey[300]),
),
),
const SizedBox(height: 6),
Text(
"${date.day}",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: isSelected
? Colors.white
: (isSelectable ? Colors.black87 : Colors.grey[300]),
),
),
],
),
),
);
},
),
);
}
/// 时间 Slider 选择器
Widget _buildTimeSlider(BuildContext context) {
return Obx(() {
// 这里的逻辑对应 Controller 中的 24 小时可用 Slot
int currentIdx = controller.startTime.value.hour;
return Column(
children: [
Stack(
alignment: Alignment.topCenter,
clipBehavior: Clip.none,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
color: const Color(0xFFE6F4EA),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.white, width: 2),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Text(
controller.formattedTimeSlot,
style: const TextStyle(
color: Color(0xFF006633),
fontSize: 13,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(width: 16),
Expanded(
flex: 2,
child: ElevatedButton(
onPressed: controller.submitReservation,
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 40.h),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
backgroundColor: AppTheme.themeColor,
foregroundColor: Colors.white,
],
),
child: const Text(
'提交预约',
style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold),
SliderTheme(
data: SliderTheme.of(context).copyWith(
trackHeight: 10,
activeTrackColor: const Color(0xFF006633),
inactiveTrackColor: const Color(0xFFF0F2F5),
thumbColor: Colors.white,
thumbShape: const RoundSliderThumbShape(
enabledThumbRadius: 12,
elevation: 4,
),
overlayColor: const Color(0xFF006633).withOpacity(0.1),
),
child: Slider(
value: currentIdx.toDouble(),
min: 0,
max: 23,
divisions: 23,
onChanged: (val) {
int hour = val.toInt();
// 模拟 Controller 中的 pickTime 逻辑校验
final now = DateTime.now();
final isToday =
controller.selectedDate.value.year == now.year &&
controller.selectedDate.value.month == now.month &&
controller.selectedDate.value.day == now.day;
if (isToday && hour < now.hour) {
// 如果是今天且小时数小于当前,则忽略
return;
}
controller.startTime.value = TimeOfDay(hour: hour, minute: 0);
controller.endTime.value = TimeOfDay(hour: (hour + 1) % 24, minute: 0);
},
),
),
],
);
});
}
// 表单中的可点击行 (用于日期和时间选择)
Widget _buildPickerRow({
required String label,
required String value,
required IconData icon,
required VoidCallback onTap,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
/// 氢量滑块区域
Widget _buildAmountSliderSection() {
return Card(
elevation: 0,
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(13.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 13)),
const SizedBox(height: 8),
InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
const Text(
"预约氢量",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const Text(
"Refuel Amount",
style: TextStyle(fontSize: 10, color: Colors.grey),
),
const SizedBox(height: 24),
Column(
children: [
SliderTheme(
data: SliderTheme.of(Get.context!).copyWith(
trackHeight: 6,
activeTrackColor: const Color(0xFF006633),
inactiveTrackColor: const Color(0xFFF0F2F5),
thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 9),
),
child: Slider(
value: controller.current > controller.maxVal
? controller.maxVal
: controller.current,
min: 0,
max: controller.maxVal,
onChanged: (val) {
final safeVal = val < 1 ? 1 : val; // 最小 1
controller.amountController.text = safeVal.toStringAsFixed(0);
controller.renderSliderTheme();
},
),
),
const SizedBox(height: 12),
Container(
height: 40.h,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey[400]!),
borderRadius: BorderRadius.circular(8),
color: const Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(value, style: const TextStyle(fontSize: 14)),
Icon(icon, color: Colors.grey, size: 20),
],
IconButton(
onPressed: () => _updateAmount(-1),
icon: const Icon(Icons.remove, size: 18, color: Colors.grey),
),
Text(
"${controller.amountController.text} Kg",
style: const TextStyle(fontSize: 14, color: Colors.black87),
),
IconButton(
onPressed: () => _updateAmount(1),
icon: const Icon(Icons.add, size: 18, color: Colors.grey),
),
],
),
),
],
),
],
),
),
);
}
// 表单中的文本输入框
Widget _buildTextField({
required String label,
required TextEditingController controller,
required String hint,
TextInputType? keyboardType,
bool enabled = true,
}) {
bool showCounter = keyboardType == TextInputType.number;
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
/// 站点卡片区域
Widget _buildStationCardSection(BuildContext context) {
return Obx(() {
return DropdownButtonHideUnderline(
child: DropdownButton2<String>(
isExpanded: true,
/// 当前选中值
value: controller.selectedStationId.value,
hint: const Text('请选择加氢站', style: TextStyle(fontSize: 14, color: Colors.grey)),
/// 下拉数据
items: controller.stationOptions
.map(
(station) => DropdownMenuItem<String>(
value: station.hydrogenId,
enabled: station.isSelect == 1,
child: _buildDropdownItem(station),
),
)
.toList(),
/// 选中回调
onChanged: (value) {
if (value != null) {
controller.selectedStationId.value = value;
}
},
///作为 Dropdown 的触发按钮
customButton: _buildStationCard(),
/// 隐藏按钮自身样式
buttonStyleData: const ButtonStyleData(padding: EdgeInsets.zero),
/// 隐藏默认箭头
iconStyleData: const IconStyleData(icon: SizedBox.shrink()),
/// 下拉样式
dropdownStyleData: DropdownStyleData(
maxHeight: 300,
width: MediaQuery.of(context).size.width / 1.3,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
),
/// 下拉项高度
menuItemStyleData: const MenuItemStyleData(height: 60),
),
);
});
}
Widget _buildStationCard() {
final stationId = controller.selectedStationId.value;
final station = controller.stationOptions.firstWhereOrNull(
(s) => s.hydrogenId == stationId,
);
return Card(
elevation: 0,
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(13.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 13)),
const SizedBox(height: 8),
TextFormField(
controller: controller,
keyboardType: keyboardType,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly, // 只允许数字输入
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"加氢站",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
Text("Station", style: TextStyle(fontSize: 10, color: Colors.grey)),
],
enabled: enabled,
style: const TextStyle(fontSize: 14),
decoration: InputDecoration(
isDense: true,
hintText: hint,
hintStyle: TextStyle(fontSize: 14),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)),
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,
),
Icon(Icons.more_vert, color: Colors.grey[300], size: 20),
],
),
const SizedBox(height: 24),
Container(
width: double.infinity,
height: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
image: const DecorationImage(
image: AssetImage("assets/images/bg_map@2x.png"),
fit: BoxFit.cover,
),
),
child: Stack(
children: [
Center(
child: Icon(
Icons.location_on_outlined,
color: Colors.grey[300],
size: 40,
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(16),
bottomRight: Radius.circular(16),
),
),
child: Text(
"${station?.name ?? '请选择站点'} | ${station?.price ?? '0.00'}/Kg",
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.white,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
),
],
),
),
);
}
// :更新氢量逻辑
void _updateAmount(int change) {
// 获取当前输入框的值,默认为 0
double currentAmount = double.tryParse(controller.amountController.text) ?? 0;
@@ -522,98 +762,48 @@ class ReservationPage extends GetView<C_ReservationController> {
controller.amountController.selection = TextSelection.fromPosition(
TextPosition(offset: controller.amountController.text.length),
);
controller.updateUi();
}
Widget _buildStationSelector() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
Widget _buildReservationItem(BuildContext context) {
return Row(
children: [
Container(
padding: EdgeInsets.all(0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('加氢站', style: TextStyle(color: Colors.grey[600], fontSize: 14)),
TextButton(
onPressed: () {
controller.getSiteList();
},
child: const Text('刷新'),
Expanded(
flex: 1,
child: OutlinedButton(
onPressed: () =>
controller.getReservationList(showPopup: true, addStatus: ''),
style: OutlinedButton.styleFrom(
minimumSize: Size(double.infinity, 50.h),
side: const BorderSide(color: Color.fromRGBO(226, 232, 240, 1)),
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
),
],
child: const Text(
'查看预约',
style: TextStyle(
color: Color.fromRGBO(119, 119, 119, 1),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
Obx(
() => DropdownButtonHideUnderline(
child: DropdownButton2<String>(
isExpanded: true,
hint: const Text(
'请选择加氢站',
style: TextStyle(fontSize: 14, color: Colors.grey),
),
// items 列表现在从 stationOptions (StationModel列表) 构建
items: controller.stationOptions
.map(
(station) => DropdownMenuItem<String>(
value: station.hydrogenId, // value 是站点的唯一ID
enabled: station.isSelect == 1,
child: _buildDropdownItem(station), // child 是自定义的 Widget
),
)
.toList(),
value:
// 当前的站点 处理默认
controller.selectedStationId.value ??
(controller.stationOptions.isNotEmpty
? controller.stationOptions.first.hydrogenId
: null),
// 当前选中的是站点ID
onChanged: (value) {
if (value != null) {
controller.selectedStationId.value = value;
}
},
customButton: Obx(() {
// 优先从已选中的 ID 查找
var selectedStation = controller.stationOptions.firstWhereOrNull(
(s) => s.hydrogenId == controller.selectedStationId.value,
);
// 如果找不到已选中的(比如 ID 为空或列表里没有),并且列表不为空,则取第一个作为默认
final stationToShow =
selectedStation ??
(controller.stationOptions.isNotEmpty
? controller.stationOptions.first
: null);
// 如果有要显示的站点,就构建按钮
if (stationToShow != null) {
return _buildSelectedStationButton(stationToShow);
}
// 否则,返回一个空占位符,让 hint 生效
// DropdownButton2 内部会判断,如果 customButton 返回的不是一个有效Widget或根据其内部逻辑就会显示 hint
return const SizedBox.shrink();
}),
buttonStyleData: ButtonStyleData(
height: 40, // 增加高度以容纳两行文字
padding: const EdgeInsets.symmetric(horizontal: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[400]!),
),
),
iconStyleData: const IconStyleData(
icon: Icon(Icons.arrow_drop_down, color: Colors.grey),
iconSize: 24,
),
dropdownStyleData: DropdownStyleData(
maxHeight: 300,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
),
menuItemStyleData: const MenuItemStyleData(
height: 60, // 增加下拉项的高度
const SizedBox(width: 16),
Expanded(
flex: 2,
child: ElevatedButton(
onPressed: controller.submitReservation,
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 50.h),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
backgroundColor: const Color(0xFF006633),
foregroundColor: Colors.white,
elevation: 4,
),
child: const Text(
'提交预约',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
),