Files
ln-ios/ln_jq_app/lib/pages/c_page/reservation/view.dart
2025-11-07 18:08:41 +08:00

359 lines
13 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:get/get.dart';
// import 'package:getx_scaffold/getx_scaffold.dart'; // 如果不使用其中的扩展,可以注释掉
import 'controller.dart';
class ReservationPage extends GetView<ReservationController> {
const ReservationPage({super.key});
@override
Widget build(BuildContext context) {
// 【修改】使用 Get.put 来初始化 Controller而不是在 GetBuilder 中。这是更推荐的做法。
// Get.lazyPut 会在第一次使用时才创建实例。
Get.lazyPut(() => ReservationController());
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildUserInfoCard(),
const SizedBox(height: 12),
_buildCarInfoCard(),
const SizedBox(height: 12),
_buildReservationFormCard(context), // 将 context 传入
const SizedBox(height: 12),
_buildTipsCard(),
],
),
),
);
}
/// 构建顶部用户信息卡片
Widget _buildUserInfoCard() {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const CircleAvatar(
radius: 24,
backgroundColor: Colors.blue,
child: Icon(Icons.person, color: Colors.white, size: 30),
),
const SizedBox(width: 12),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'王小龙',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: 4),
Text(
'15888332828',
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.blue[50],
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.blue, width: 0.5),
),
child: const Row(
children: [
Icon(Icons.shield_outlined, color: Colors.blue, size: 14),
SizedBox(width: 4),
Text('已认证', style: TextStyle(color: Colors.blue, fontSize: 10, fontWeight: FontWeight.bold)),
],
),
)
],
),
),
const Divider(height: 1, indent: 16, endIndent: 16),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildStatItem('0Kg', '累计加氢'),
_buildStatItem('0次', '加氢次数'),
],
),
),
],
),
);
}
// 用户信息卡片中的小统计项
Widget _buildStatItem(String value, String label) {
return Column(
children: [
Text(value, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Text(label, style: const TextStyle(color: Colors.grey, fontSize: 12)),
],
);
}
/// 构建车辆信息卡片
Widget _buildCarInfoCard() {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: Column(
children: [
_buildInfoRow('车牌号:', '扫码绑定'),
const SizedBox(height: 12),
_buildInfoRow('剩余氢量:', '0Kg'),
const SizedBox(height: 12),
_buildInfoRow('百公里氢耗:', '0KG/100KM'),
],
),
),
const SizedBox(width: 16),
Icon(Icons.propane_tank_outlined, size: 80, color: Colors.blue.withOpacity(0.5)),
],
),
),
);
}
// 车辆信息卡片中的信息行
Widget _buildInfoRow(String label, String value) {
bool isButton = value == '扫码绑定';
return Row(
children: [
Text(label, style: const TextStyle(color: Colors.grey, fontSize: 14)),
const SizedBox(width: 8),
isButton
? ElevatedButton.icon(
onPressed: () { /* TODO: 扫码绑定逻辑 */ },
icon: const Icon(Icons.qr_code_scanner, size: 16),
label: Text(value),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 12),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
),
)
: Text(value, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500)),
],
);
}
/// 构建预约表单卡片
Widget _buildReservationFormCard(BuildContext context) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(16.0),
// 【修改】使用 Obx 包裹以自动响应 Rx 变量的变化
child: Obx(() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildPickerRow(
label: '日期',
value: controller.formattedDate,
icon: Icons.calendar_today_outlined,
onTap: () => controller.pickDate(context),
),
_buildPickerRow(
label: '开始时间',
value: controller.formattedStartTime,
icon: Icons.access_time_outlined,
onTap: () => controller.pickTime(context, true),
),
_buildPickerRow(
label: '结束时间',
value: controller.formattedEndTime,
icon: Icons.access_time_outlined,
onTap: () => controller.pickTime(context, false),
),
_buildTextField(label: '预约氢量(kg)', controller: controller.amountController, hint: '请输入氢量(kg)', keyboardType: TextInputType.number),
_buildTextField(label: '车牌号', controller: controller.plateNumberController, hint: '请输入车牌号'),
_buildStationSelector(),
const SizedBox(height: 24),
ElevatedButton(
onPressed: controller.submitReservation,
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
child: const Text('提交预约', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
],
)),
),
);
}
// 表单中的可点击行 (用于日期和时间选择)
Widget _buildPickerRow({required String label, required String value, required IconData icon, required VoidCallback onTap}) {
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 14)),
const SizedBox(height: 8),
InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey[400]!),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(value, style: const TextStyle(fontSize: 16)),
Icon(icon, color: Colors.grey, size: 20),
],
),
),
),
],
),
);
}
// 表单中的文本输入框
Widget _buildTextField({required String label, required TextEditingController controller, required String hint, TextInputType? keyboardType}) {
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 14)),
const SizedBox(height: 8),
TextFormField(
controller: controller,
keyboardType: keyboardType,
decoration: InputDecoration(
hintText: hint,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
),
),
],
),
);
}
// 构建加氢站选择器
Widget _buildStationSelector() {
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('加氢站', style: TextStyle(color: Colors.grey[600], fontSize: 14)),
TextButton(onPressed: () { /* TODO: 刷新站点列表 */ }, child: const Text('刷新')),
],
),
// 【修改】使用 Obx 包裹 DropdownButtonFormField 以响应 Rx 变量
Obx(() => DropdownButtonFormField<String>(
value: controller.selectedStation.value,
isExpanded: true,
items: controller.stationOptions.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Text(value, style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(width: 8),
if (value.contains('银河路')) // 示例:给特定站点加标签
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.orange[100],
borderRadius: BorderRadius.circular(4),
),
child: const Text('维修中', style: TextStyle(color: Colors.orange, fontSize: 10)),
),
],
),
const Text(
'江苏省苏州市常熟市东南街道银河路80号 | ¥45.00/kg',
style: TextStyle(color: Colors.grey, fontSize: 12),
overflow: TextOverflow.ellipsis,
),
],
),
);
}).toList(),
onChanged: (newValue) {
if (newValue != null) {
controller.selectedStation.value = newValue;
}
},
decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)),
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
),
)),
],
),
);
}
/// 构建提示信息卡片
Widget _buildTipsCard() {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
_buildTipItem(Icons.info_outline, '请提前30分钟到达加氢站'),
const SizedBox(height: 10),
_buildTipItem(Icons.rule, '请确保车辆证件齐全'),
const SizedBox(height: 10),
_buildTipItem(Icons.headset_mic_outlined, '如有疑问请联系客服: 400-123-4567'),
],
),
),
);
}
// 提示信息卡片中的列表项
Widget _buildTipItem(IconData icon, String text) {
return Row(
children: [
Icon(icon, color: Colors.blue, size: 20),
const SizedBox(width: 10),
Expanded(child: Text(text, style: const TextStyle(fontSize: 12, color: Colors.black54))),
],
);
}
}