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 9b9a40a..a0a9611 100644 --- a/ln_jq_app/lib/pages/b_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/b_page/reservation/controller.dart @@ -1,32 +1,47 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; +import 'package:intl/intl.dart'; import 'package:ln_jq_app/common/model/base_model.dart'; import 'package:ln_jq_app/pages/login/view.dart'; +import '../../../common/styles/theme.dart'; import '../../../storage_service.dart'; class ReservationController extends GetxController with BaseControllerMixin { @override - String get builderId => 'b_reservation'; // 确保ID与View中一致 + String get builderId => 'b_reservation'; - // --- 运营状态下拉菜单所需的状态 --- - // 下拉菜单的选项列表 final List operationStatusOptions = ["营运中", "维修中", "暂停营业", "站点关闭"]; - - // 当前选中的值,默认为'运营中' String selectedOperationStatus = "营运中"; + // --- 其它状态下的时间选择 --- + DateTime? customStartTime; + DateTime? customEndTime; + + String get customStartTimeStr => customStartTime != null + ? DateFormat('yyyy-MM-dd HH:mm').format(customStartTime!) + : '点击选择开始时间'; + + String get customEndTimeStr => customEndTime != null + ? DateFormat('yyyy-MM-dd HH:mm').format(customEndTime!) + : '点击选择结束时间'; + @override void onInit() { super.onInit(); + // 1. 初始化默认时间 + customStartTime = DateTime.now(); + customEndTime = customStartTime!.add(const Duration(days: 1)); renderData(); } String name = ""; String address = ""; String phone = ""; - String costPrice = ""; //氢气价格 - String customerPrice = ""; //官方价格 + String costPrice = ""; + String customerPrice = ""; String startBusiness = ""; String endBusiness = ""; String timeStr = ""; @@ -35,7 +50,6 @@ class ReservationController extends GetxController with BaseControllerMixin { Future renderData() async { showLoading("加载中"); - try { var responseData = await HttpService.to.get( 'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}', @@ -49,32 +63,30 @@ class ReservationController extends GetxController with BaseControllerMixin { try { var result = BaseModel.fromJson(responseData.data); - - name = result.data["name"]; + name = result.data["name"] ?? ""; hydrogenId = result.data["hydrogenId"].toString(); - address = result.data["address"]; - var rawCostPrice = result.data["costPrice"]; - if (rawCostPrice != null && rawCostPrice.toString().isNotEmpty) { - costPrice = "¥$rawCostPrice"; - } else { - costPrice = "暂无价格"; - } - var customerPriceTemp = result.data["customerPrice"]; - if (customerPriceTemp != null && customerPriceTemp.toString().isNotEmpty) { - customerPrice = "$customerPriceTemp"; - } else { - customerPrice = "暂无价格"; - } + address = result.data["address"] ?? ""; - phone = result.data["phone"]; - startBusiness = result.data["startBusiness"]; - endBusiness = result.data["endBusiness"]; + var rawCostPrice = result.data["costPrice"]; + costPrice = (rawCostPrice != null && rawCostPrice.toString().isNotEmpty) + ? "¥$rawCostPrice" + : "暂无价格"; + + var customerPriceTemp = result.data["customerPrice"]; + customerPrice = + (customerPriceTemp != null && customerPriceTemp.toString().isNotEmpty) + ? "$customerPriceTemp" + : "暂无价格"; + + phone = result.data["phone"] ?? ""; + startBusiness = result.data["startBusiness"] ?? ""; + endBusiness = result.data["endBusiness"] ?? ""; operatingEnterprise = result.data["operatingEnterprise"].toString(); + String temp = result.data["siteStatusName"].toString(); selectedOperationStatus = (temp.isEmpty || temp == "null") ? "营运中" : temp; if (startBusiness.isNotEmpty && endBusiness.isNotEmpty) { - // 营业时间为24小时的特殊处理 if (startBusiness == "00:00:00" && endBusiness == "23:59:59") { timeStr = "24小时营业"; } else { @@ -85,11 +97,9 @@ class ReservationController extends GetxController with BaseControllerMixin { } operatingEnterprise = operatingEnterprise.isEmpty ? "暂未设置" : operatingEnterprise; - updateUi(); dismissLoading(); } catch (e) { - // 如果解析 JSON 失败 dismissLoading(); showToast('数据异常'); } @@ -98,7 +108,6 @@ class ReservationController extends GetxController with BaseControllerMixin { } } - /// 更新运营状态的方法 void onOperationStatusChanged(String? newValue) { if (newValue != null) { selectedOperationStatus = newValue; @@ -106,9 +115,102 @@ class ReservationController extends GetxController with BaseControllerMixin { } } - void saveInfo() async { - showLoading("保存中"); + /// 使用底部滚轮形式选择时间(下拉框效果) + void pickDateTime(BuildContext context, bool isStart) { + DateTime now = DateTime.now(); + DateTime initialDate = isStart ? (customStartTime ?? now) : (customEndTime ?? now); + // 确保初始时间不早于最小允许时间 + // 将 minimumDate 稍微提前一点点(比如1分钟) + DateTime minLimit = isStart + ? now.subtract(const Duration(minutes: 1)) + : (customStartTime ?? now).subtract(const Duration(minutes: 1)); + + if (initialDate.isBefore(minLimit)) { + initialDate = isStart ? now : (customStartTime ?? now); + } + + DateTime tempDate = initialDate; + + Get.bottomSheet( + Container( + height: 300, + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CupertinoButton( + onPressed: () => Get.back(), + child: const Text('取消', style: TextStyle(color: Colors.grey)), + ), + CupertinoButton( + onPressed: () { + if (isStart) { + customStartTime = tempDate; + // 如果开始时间变动后,结束时间早于开始时间,自动顺延一天 + if (customEndTime != null && + customEndTime!.isBefore(customStartTime!)) { + customEndTime = customStartTime!.add(const Duration(days: 1)); + } + } else { + if (tempDate.isBefore(customStartTime ?? DateTime.now())) { + showToast('结束时间不能早于开始时间'); + return; + } + customEndTime = tempDate; + } + updateUi(); + Get.back(); + }, + child: const Text( + '确定', + style: TextStyle( + color: AppTheme.themeColor, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + const Divider(height: 1), + Expanded( + child: CupertinoDatePicker( + mode: CupertinoDatePickerMode.dateAndTime, + initialDateTime: initialDate, + minimumDate: minLimit, + use24hFormat: true, + onDateTimeChanged: (DateTime newDate) { + tempDate = newDate; + }, + ), + ), + ], + ), + ), + backgroundColor: Colors.transparent, + ); + } + + void saveInfo() async { + if (selectedOperationStatus != "营运中") { + if (customStartTime == null || customEndTime == null) { + showToast("请选择开始和结束时间"); + return; + } + } + + showLoading("保存中"); try { var responseData = await HttpService.to.post( 'appointment/station/updateStationStatus', @@ -123,11 +225,17 @@ class ReservationController extends GetxController with BaseControllerMixin { : selectedOperationStatus == "暂停营业" ? "3" : 0, + 'beginTime': selectedOperationStatus == "营运中" + ? null + : DateFormat('yyyy-MM-dd HH:mm:ss').format(customStartTime!), + 'endTime': selectedOperationStatus == "营运中" + ? null + : DateFormat('yyyy-MM-dd HH:mm:ss').format(customEndTime!), 'updateTime': getNowDateTimeString(), }, ); - if (responseData == null && responseData!.data == null) { + if (responseData == null || responseData!.data == null) { dismissLoading(); showToast('服务暂不可用,请稍后'); return; @@ -143,10 +251,7 @@ class ReservationController extends GetxController with BaseControllerMixin { } void logout() async { - // TODO: 在这里执行退出登录的逻辑 - //清理本地缓存的用户信息 导航到登录页面 await StorageService.to.clearLoginInfo(); - 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 432fdaa..15d9ef0 100644 --- a/ln_jq_app/lib/pages/b_page/reservation/view.dart +++ b/ln_jq_app/lib/pages/b_page/reservation/view.dart @@ -127,14 +127,12 @@ class ReservationPage extends GetView { _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), - ); + return DropdownMenuItem(value: value, child: Text(value)); }).toList(), onChanged: controller.onOperationStatusChanged, decoration: InputDecoration( @@ -142,8 +140,27 @@ class ReservationPage extends GetView { contentPadding: const EdgeInsets.symmetric(horizontal: 12.0), ), ), - const SizedBox(height: 12), - _buildDisplayField(label: '营业时间', value: controller.timeStr), + const SizedBox(height: 16), + + // 根据状态动态显示 UI + if (controller.selectedOperationStatus == "营运中") + _buildDisplayField(label: '营业时间', value: controller.timeStr) + else + Column( + children: [ + _buildClickField( + label: '开始时间', + value: controller.customStartTimeStr, + onTap: () => controller.pickDateTime(context, true), + ), + _buildClickField( + label: '结束时间', + value: controller.customEndTimeStr, + onTap: () => controller.pickDateTime(context, false), + ), + ], + ), + _buildDisplayField(label: '联系电话', value: controller.phone), const SizedBox(height: 24), @@ -162,70 +179,6 @@ class ReservationPage extends GetView { ); } - /// 构建静态提示信息卡片 - 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-021-1773'), - const SizedBox(height: 10), - Row( - children: [ - Icon(Icons.verified_outlined, color: Colors.blue, size: 20), - const SizedBox(width: 10), - Expanded( - child: FutureBuilder( - future: getVersion(), - builder: (context, snapshot) { - // 判断是否还在加载 - if (snapshot.connectionState == ConnectionState.waiting) { - return const Text(""); - } - - // 如果加载完成且有数据 - if (snapshot.hasData) { - return TextX.labelSmall("当前版本: ${snapshot.data}",color: Colors.black54,); - } - - // 错误处理 - return const Text(""); - }, - ), - ), - ], - ) - ], - ), - ), - ); - } - - /// 构建退出登录按钮 - 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( @@ -253,7 +206,7 @@ class ReservationPage extends GetView { width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0), decoration: BoxDecoration( - color: Colors.grey[200], // 使用灰色背景以区分 + color: Colors.grey[200], borderRadius: BorderRadius.circular(8.0), border: Border.all(color: Colors.grey[300]!), ), @@ -267,6 +220,104 @@ class ReservationPage extends GetView { ); } + /// 构建一个“可点击”的选择行 + Widget _buildClickField({required String label, required String value, 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( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.blue.withOpacity(0.5)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + value, + style: const TextStyle(fontSize: 14, color: Colors.black87), + ), + const Icon(Icons.calendar_month, size: 18, color: Colors.blue), + ], + ), + ), + ), + ], + ), + ); + } + + /// 构建静态提示信息卡片 + 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-021-1773'), + const SizedBox(height: 10), + Row( + children: [ + Icon(Icons.verified_outlined, color: Colors.blue, size: 20), + const SizedBox(width: 10), + Expanded( + child: FutureBuilder( + future: getVersion(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Text(""); + } + if (snapshot.hasData) { + return TextX.labelSmall( + "当前版本: ${snapshot.data}", + color: Colors.black54, + ); + } + return const Text(""); + }, + ), + ), + ], + ), + ], + ), + ), + ); + } + + /// 构建退出登录按钮 + 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 _buildInfoItem(IconData icon, String text) { return Row( diff --git a/ln_jq_app/lib/pages/c_page/reservation/controller.dart b/ln_jq_app/lib/pages/c_page/reservation/controller.dart index 589a36d..cac9ec3 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/controller.dart @@ -394,14 +394,16 @@ class C_ReservationController extends GetxController with BaseControllerMixin { }, ); + var result = BaseModel.fromJson(responseData?.data); + if (responseData == null) { dismissLoading(); - showToast('服务暂不可用,请稍后'); + showToast(result.error); return; } dismissLoading(); - var result = BaseModel.fromJson(responseData.data); + if (result.code == 0) { showSuccessToast("预约成功");