diff --git a/ln_jq_app/lib/pages/b_page/base_widgets/view.dart b/ln_jq_app/lib/pages/b_page/base_widgets/view.dart index 28114b5..71f8bb3 100644 --- a/ln_jq_app/lib/pages/b_page/base_widgets/view.dart +++ b/ln_jq_app/lib/pages/b_page/base_widgets/view.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:getx_scaffold/common/index.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:ln_jq_app/pages/b_page/base_widgets/controller.dart'; +import 'package:ln_jq_app/pages/b_page/reservation/view.dart'; import 'package:ln_jq_app/pages/b_page/site/view.dart'; -import 'package:ln_jq_app/pages/c_page/reservation/view.dart'; class B_BaseWidgetsPage extends GetView { B_BaseWidgetsPage({super.key}); diff --git a/ln_jq_app/lib/pages/b_page/reservation/controller.dart b/ln_jq_app/lib/pages/b_page/reservation/controller.dart index 0391da1..1b0f620 100644 --- a/ln_jq_app/lib/pages/b_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/b_page/reservation/controller.dart @@ -1,18 +1,60 @@ +import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; +import 'package:ln_jq_app/pages/login/view.dart'; class ReservationController extends GetxController with BaseControllerMixin { @override - String get builderId => 'b_reservation'; + String get builderId => 'b_reservation'; // 确保ID与View中一致 - ReservationController(); + // --- 运营状态下拉菜单所需的状态 --- + // 下拉菜单的选项列表 + final List operationStatusOptions = ['营运中', '维修中', '暂停营业', '站点关闭']; + + // 当前选中的值,默认为'运营中' + late String selectedOperationStatus; + + ReservationController() { + selectedOperationStatus = operationStatusOptions[0]; // 初始化选中值 + } @override void onInit() { super.onInit(); + // 可以在这里从服务器加载站点的初始信息 + renderData(); } - @override - void onClose() { - super.onClose(); + Future renderData() async { + showLoading("加载中"); + + // 模拟网络请求延迟 + await Future.delayed(const Duration(seconds: 1)); + + dismissLoading(); + updateUi(); + } + + /// 更新运营状态的方法 + void onOperationStatusChanged(String? newValue) { + if (newValue != null) { + selectedOperationStatus = newValue; + updateUi(); + } + } + + void saveInfo() { + // TODO: 在这里执行保存信息的逻辑 + // 1. 获取所有输入框和下拉框的最新值 + // 2. 调用API接口,将数据提交到服务器 + // 3. 根据接口返回结果给出提示(成功或失败) + Get.snackbar('提示', '保存成功!'); // 示例:显示一个成功的提示 + } + + void logout() { + // TODO: 在这里执行退出登录的逻辑 + // 1. 清理本地缓存的用户信息 + // 2. 调用退出登录接口 + // 3. 导航到登录页面 + Get.offAll(() => LoginPage()); } } diff --git a/ln_jq_app/lib/pages/b_page/reservation/view.dart b/ln_jq_app/lib/pages/b_page/reservation/view.dart index fc4e480..bbb7204 100644 --- a/ln_jq_app/lib/pages/b_page/reservation/view.dart +++ b/ln_jq_app/lib/pages/b_page/reservation/view.dart @@ -1,27 +1,234 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; - -import 'controller.dart'; - +import 'package:ln_jq_app/pages/b_page/reservation/controller.dart'; class ReservationPage extends GetView { const ReservationPage({super.key}); - // 主视图 - Widget _buildView() { - return [ - TextX.titleLarge('预约'), - ].toColumn(mainAxisSize: MainAxisSize.min).center(); - } - @override Widget build(BuildContext context) { return GetBuilder( init: ReservationController(), id: 'b_reservation', builder: (_) { - return _buildView(); + return Scaffold( + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildHeaderCard(), + const SizedBox(height: 12), + _buildInfoFormCard(context), + const SizedBox(height: 12), + _buildTipsCard(), + const SizedBox(height: 12), + _buildLogoutButton(), + ], + ), + ), + ), + ); }, ); } + + /// 构建顶部的站点信息头卡片 + Widget _buildHeaderCard() { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + child: Column( + children: [ + ListTile( + leading: const Icon(Icons.local_gas_station, color: Colors.blue, size: 40), + title: const Text('H2加氢站', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)), + subtitle: const Text('上海市浦东新区张江高科技园区'), + trailing: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: Colors.blue[100], + borderRadius: BorderRadius.circular(12), + ), + child: const Text('运营中', style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold, fontSize: 12)), + ), + ), + const Divider(height: 1, indent: 16, endIndent: 16), + Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildHeaderStat('¥45', '氢气价格'), + _buildHeaderStat('24h', '营业时间'), + _buildHeaderStat('98%', '设备状态'), + ], + ), + ), + ], + ), + ); + } + + /// 构建头部卡片中的单个统计项 + Widget _buildHeaderStat(String value, String label) { + return Column( + children: [ + Text(value, style: const TextStyle(color: Colors.blue, fontSize: 20, fontWeight: FontWeight.bold)), + const SizedBox(height: 4), + Text(label, style: const TextStyle(color: Colors.grey, fontSize: 12)), + ], + ); + } + + /// 构建包含所有信息表单的卡片 + Widget _buildInfoFormCard(BuildContext context) { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // --- 基本信息 --- + _buildSectionTitle('基本信息'), + _buildDisplayField(label: '站点名称', value: 'H2加氢站'), + _buildDisplayField(label: '运营企业', value: '上海氢能科技有限公司'), + _buildDisplayField(label: '站点地址', value: '上海市浦东新区张江高科技园区'), + const SizedBox(height: 16), + + // --- 价格信息 --- + _buildSectionTitle('价格信息'), + _buildDisplayField(label: '氢气价格 (元/kg)', value: '45'), + _buildDisplayField(label: '官方价格 (元/kg)', value: '50'), + const SizedBox(height: 16), + + // --- 运营信息 --- + _buildSectionTitle('运营信息'), + Text('运营状态', style: TextStyle(color: Colors.grey[600], fontSize: 14)), + const SizedBox(height: 8), + //下拉选择框 + DropdownButtonFormField( + value: controller.selectedOperationStatus, + items: controller.operationStatusOptions.map((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + onChanged: controller.onOperationStatusChanged, + decoration: InputDecoration( + border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)), + contentPadding: const EdgeInsets.symmetric(horizontal: 12.0), + ), + ), + const SizedBox(height: 12), + _buildDisplayField(label: '营业时间', value: '24小时营业'), + _buildDisplayField(label: '联系电话', value: '021-12345678'), + const SizedBox(height: 24), + + //保存按钮 + ElevatedButton( + onPressed: controller.saveInfo, + style: ElevatedButton.styleFrom( + minimumSize: const Size(double.infinity, 48), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + child: const Text('保存信息', style: TextStyle(fontSize: 16)), + ), + ], + ), + ), + ); + } + + /// 构建静态提示信息卡片 + Widget _buildTipsCard() { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + _buildInfoItem(Icons.info_outline, '请确保信息准确无误'), + const SizedBox(height: 10), + _buildInfoItem(Icons.help_outline, '价格信息将实时更新到用户端'), + const SizedBox(height: 10), + _buildInfoItem(Icons.headset_mic_outlined, '如有疑问请联系技术支持: 400-123-4567'), + ], + ), + ), + ); + } + + /// 构建退出登录按钮 + Widget _buildLogoutButton() { + return ElevatedButton( + onPressed: controller.logout, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + foregroundColor: Colors.white, + minimumSize: const Size(double.infinity, 48), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), + elevation: 2, + ), + child: const Text('退出登录', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + ); + } + + /// 构建带标题的表单区域 + Widget _buildSectionTitle(String title) { + return Padding( + padding: const EdgeInsets.only(bottom: 12.0), + child: Row( + children: [ + Container(width: 4, height: 16, color: Colors.blue), + const SizedBox(width: 8), + Text(title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + ], + ), + ); + } + + /// 构建一个“标签+纯文本”的显示行 + Widget _buildDisplayField({required String label, required String value}) { + 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), + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0), + decoration: BoxDecoration( + color: Colors.grey[200], // 使用灰色背景以区分 + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.grey[300]!), + ), + child: Text( + value, + style: const TextStyle(fontSize: 14, color: Colors.black87), + ), + ), + ], + ), + ); + } + + /// 构建带图标的提示信息行 + Widget _buildInfoItem(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: 14, color: Colors.black54))), + ], + ); + } } diff --git a/ln_jq_app/lib/pages/b_page/site/controller.dart b/ln_jq_app/lib/pages/b_page/site/controller.dart index 31ce9f8..0c24ac2 100644 --- a/ln_jq_app/lib/pages/b_page/site/controller.dart +++ b/ln_jq_app/lib/pages/b_page/site/controller.dart @@ -1,33 +1,114 @@ import 'package:getx_scaffold/getx_scaffold.dart'; +enum ReservationStatus { pending, completed, rejected } + +class ReservationModel { + final String id; + final String plateNumber; + final String amount; + final String time; + final String contactPerson; + final String contactPhone; + ReservationStatus status; // 状态是可变的 + + ReservationModel({ + required this.id, + required this.plateNumber, + required this.amount, + required this.time, + required this.contactPerson, + required this.contactPhone, + this.status = ReservationStatus.pending, + }); +} + class SiteController extends GetxController with BaseControllerMixin { @override String get builderId => 'site'; - SiteController(); + /// 状态变量:是否有预约数据 bool hasReservationData = false; + // 新增预约数据列表 + List reservationList = []; + @override void onInit() { super.onInit(); + // 页面初始化时自动加载数据 fetchReservationData(); } + /// 模拟获取预约数据的方法 Future fetchReservationData() async { - showLoading("加载中"); + // 模拟网络请求延迟 await Future.delayed(const Duration(seconds: 1)); - hasReservationData = !hasReservationData; + // ==================== 3. 填充模拟数据 ==================== + reservationList = [ + ReservationModel( + id: '1', + plateNumber: '浙F08860F', + amount: '52kg', + time: '2025-11-04 21:54-22:24', + contactPerson: '王小龙', + contactPhone: '15888332828', + status: ReservationStatus.pending, + ), + ReservationModel( + id: '2', + plateNumber: '浙F08860F', + amount: '52kg', + time: '2025-11-04 14:54-15:24', + contactPerson: '王小龙', + contactPhone: '15888332828', + status: ReservationStatus.completed, // 示例:已完成状态 + ), + ReservationModel( + id: '3', + plateNumber: '浙F08860F', + amount: '52kg', + time: '2025-11-04 15:54-16:24', + contactPerson: '王小龙', + contactPhone: '15888332828', + status: ReservationStatus.rejected, // 示例:已拒绝状态 + ), + ReservationModel( + id: '4', + plateNumber: '浙F08860F', + amount: '52kg', + time: '2025-11-04 12:54-13:24', + contactPerson: '王小龙', + contactPhone: '15888332828', + status: ReservationStatus.pending, + ), + ]; + + hasReservationData = reservationList.isNotEmpty; dismissLoading(); updateUi(); } + /// 确认预约 + Future confirmReservation(String id) async { + print('确认预约: $id'); + // TODO: 在这里调用确认接口 + // 接口调用成功后,更新本地数据状态并刷新UI + final item = reservationList.firstWhere((item) => item.id == id); + item.status = ReservationStatus.completed; + updateUi(); + } - // 如果需要一个方法来清空数据 - void clearData() { - hasReservationData = false; + /// 拒绝预约 + Future rejectReservation(String id) async { + print('拒绝预约: $id'); + // TODO: 在这里调用拒绝接口 + // 接口调用成功后,更新本地数据状态并刷新UI + final item = reservationList.firstWhere((item) => item.id == id); + item.status = ReservationStatus.rejected; + updateUi(); } } diff --git a/ln_jq_app/lib/pages/b_page/site/index.dart b/ln_jq_app/lib/pages/b_page/site/index.dart new file mode 100644 index 0000000..6474d5f --- /dev/null +++ b/ln_jq_app/lib/pages/b_page/site/index.dart @@ -0,0 +1,4 @@ +library load_container; + +export 'controller.dart'; +export 'view.dart'; diff --git a/ln_jq_app/lib/pages/b_page/site/view.dart b/ln_jq_app/lib/pages/b_page/site/view.dart index 61934fa..9b87e36 100644 --- a/ln_jq_app/lib/pages/b_page/site/view.dart +++ b/ln_jq_app/lib/pages/b_page/site/view.dart @@ -1,21 +1,19 @@ import 'package:flutter/material.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; +import 'package:ln_jq_app/common/styles/theme.dart'; import 'controller.dart'; - +///加氢预约 class SitePage extends GetView { const SitePage({super.key}); @override Widget build(BuildContext context) { - // 使用 GetBuilder 包裹,并从 controller 初始化 return GetBuilder( - init: controller, - id: controller.builderId, + init: SiteController(), + id: 'site', builder: (_) { - return SingleChildScrollView( - child: _buildView(), - ); + return SingleChildScrollView(child: _buildView()); }, ); } @@ -158,7 +156,7 @@ class SitePage extends GetView { ), ), - // ==================== 新增的第三个卡片: 提示信息 ==================== + //第三部分 Card( elevation: 3, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), @@ -168,20 +166,11 @@ class SitePage extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildInfoItem( - Icons.info_outline, - '数据每5分钟自动刷新一次', - ), + _buildInfoItem(Icons.info_outline, '数据每5分钟自动刷新一次'), const SizedBox(height: 8), - _buildInfoItem( - Icons.help_outline, - '点击车牌号可查看详细信息', - ), + _buildInfoItem(Icons.help_outline, '点击车牌号可查看详细信息'), const SizedBox(height: 8), - _buildInfoItem( - Icons.headset_mic_outlined, - '如有疑问请联系客服: 400-123-4567', - ), + _buildInfoItem(Icons.headset_mic_outlined, '如有疑问请联系客服: 400-123-4567'), ], ), ), @@ -234,20 +223,204 @@ class SitePage extends GetView { ); } - /// 【预留】构建“有预约数据”的列表视图 + /// 构建“有预约数据”的列表视图 Widget _buildReservationListView() { return Container( color: Colors.white, - child: const Center( - child: Padding( - padding: EdgeInsets.all(48.0), - child: Text('这里将显示预约信息列表', style: TextStyle(color: Colors.grey)), - ), + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + // 因为外层已有滚动,这里禁用内部滚动 + itemCount: controller.reservationList.length, + padding: const EdgeInsets.all(12.0), + itemBuilder: (context, index) { + final item = controller.reservationList[index]; + // 调用新的方法来构建每一项 + return _buildReservationItem(item); + }, + separatorBuilder: (context, index) => const SizedBox(height: 12), // 列表项之间的间距 ), ); } - /// 【新增】构建带图标的提示信息行 + Widget _buildReservationItem(ReservationModel item) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.grey[200]!, width: 1.0), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + spreadRadius: 1, + blurRadius: 3, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + children: [ + // 顶部:序号、车牌号、状态 + Padding( + padding: const EdgeInsets.fromLTRB(8, 12, 16, 12), + child: Row( + children: [ + // 序号 + Container( + width: 24, + height: 24, + alignment: Alignment.center, + decoration: const BoxDecoration( + color: Colors.blue, + shape: BoxShape.circle, + ), + child: Text( + item.id, + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(width: 8), + const Icon(Icons.directions_car, color: Colors.black54), + const SizedBox(width: 4), + // 车牌号 + Expanded( + child: Text( + item.plateNumber, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: AppTheme.themeColor, + ), + ), + ), + // 状态标签 + _buildStatusChip(item.status), + ], + ), + ), + const Divider(height: 1), + // 中部:详细信息 + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), + child: Column( + children: [ + _buildDetailRow( + Icons.local_gas_station, + '加氢量', + item.amount, + valueColor: Colors.red, + ), + const SizedBox(height: 8), + _buildDetailRow(Icons.access_time, '预约时间', item.time), + const SizedBox(height: 8), + _buildDetailRow(Icons.person, '联系人', item.contactPerson), + const SizedBox(height: 8), + _buildDetailRow( + Icons.phone, + '联系电话', + item.contactPhone, + valueColor: AppTheme.themeColor, + ), + ], + ), + ), + // 底部:操作按钮 (仅在待处理时显示) + if (item.status == ReservationStatus.pending) + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 12), + child: Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () => controller.confirmReservation(item.id), + style: ElevatedButton.styleFrom(backgroundColor: Colors.blue), + child: const Text('确定'), + ), + ), + const SizedBox(width: 16), + Expanded( + child: ElevatedButton( + onPressed: () => controller.rejectReservation(item.id), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), + child: const Text('拒绝'), + ), + ), + ], + ), + ), + ], + ), + ); + } + + /// 构建状态标签 + Widget _buildStatusChip(ReservationStatus status) { + String text; + Color color; + switch (status) { + case ReservationStatus.pending: + text = '待处理'; + color = Colors.orange; + break; + case ReservationStatus.completed: + text = '已完成'; + color = Colors.greenAccent; + break; + case ReservationStatus.rejected: + text = '已拒绝'; + color = Colors.red; + break; + } + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.circle, color: color, size: 8), + const SizedBox(width: 4), + Text( + text, + style: TextStyle(color: color, fontSize: 12, fontWeight: FontWeight.bold), + ), + ], + ), + ); + } + + /// 构建信息详情行 + Widget _buildDetailRow( + IconData icon, + String label, + String value, { + Color valueColor = Colors.black87, + }) { + return Row( + children: [ + Icon(icon, color: Colors.grey, size: 20), + const SizedBox(width: 8), + Text('$label: ', style: const TextStyle(fontSize: 14, color: Colors.grey)), + Expanded( + child: Text( + value, + style: TextStyle( + fontSize: 14, + color: valueColor, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ); + } + + /// 底部构建带图标的提示信息行 Widget _buildInfoItem(IconData icon, String text) { return Row( children: [ diff --git a/ln_jq_app/lib/pages/login/view.dart b/ln_jq_app/lib/pages/login/view.dart index ab07ade..9c28c1e 100644 --- a/ln_jq_app/lib/pages/login/view.dart +++ b/ln_jq_app/lib/pages/login/view.dart @@ -151,7 +151,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix ElevatedButton( onPressed: () { // 司机端登录 - Get.to(() => BaseWidgetsPage()); + Get.offAll(() => BaseWidgetsPage()); }, style: ElevatedButton.styleFrom( backgroundColor: AppTheme.themeColor, @@ -221,7 +221,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix ), onPressed: () { // 加氢站登录逻辑 - Get.to(() => B_BaseWidgetsPage()); + Get.offAll(() => B_BaseWidgetsPage()); }, child: Text('登录'), ),