From f25feaa55a336ae7f6e2f0219029de7052247ca3 Mon Sep 17 00:00:00 2001 From: userGyl Date: Wed, 14 Jan 2026 13:18:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=94=E8=B0=83=E4=BF=AE=E6=94=B9=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ln_jq_app/lib/common/model/base_model.dart | 4 - ln_jq_app/lib/common/model/vehicle_info.dart | 4 +- ln_jq_app/lib/main.dart | 9 +- .../pages/b_page/reservation/controller.dart | 123 +++++++++++++++++- .../lib/pages/b_page/reservation/view.dart | 90 +++++++++---- .../lib/pages/c_page/mine/controller.dart | 20 +-- .../pages/c_page/reservation/controller.dart | 25 ++-- ln_jq_app/lib/pages/login/view.dart | 2 +- 8 files changed, 205 insertions(+), 72 deletions(-) diff --git a/ln_jq_app/lib/common/model/base_model.dart b/ln_jq_app/lib/common/model/base_model.dart index 02f020d..b37eb59 100644 --- a/ln_jq_app/lib/common/model/base_model.dart +++ b/ln_jq_app/lib/common/model/base_model.dart @@ -6,7 +6,6 @@ class BaseModel { final String message; // 消息,例如 "success" final String msg; // 消息,例如 "success" final T? data; // 核心数据,使用泛型 T,可以是任何类型 - final int time; // 时间戳 final dynamic error; // 错误信息,可以是任何类型或 null BaseModel({ @@ -15,7 +14,6 @@ class BaseModel { required this.message, required this.msg, this.data, // data 可以为 null - required this.time, this.error, // error 可以为 null }); @@ -60,7 +58,6 @@ class BaseModel { status: json['status'] as bool? ?? false, message: json['message'] ?? '暂不可用,请稍后', msg: json['msg'] ?? '暂不可用,请稍后', - time: _parseInt(json['time']), data: finalData, error: json['error'], ); @@ -72,7 +69,6 @@ class BaseModel { 'status': status, 'message': message, 'msg': msg, - 'time': time, 'data': data, 'error': error, }; diff --git a/ln_jq_app/lib/common/model/vehicle_info.dart b/ln_jq_app/lib/common/model/vehicle_info.dart index 028bc89..a139319 100644 --- a/ln_jq_app/lib/common/model/vehicle_info.dart +++ b/ln_jq_app/lib/common/model/vehicle_info.dart @@ -15,7 +15,7 @@ class VehicleInfo { final String engineNum; final String truckNum; final num hydrogenCapacity; - final num maxHydrogen; + final String maxHydrogen; VehicleInfo({ required this.plateNumber, @@ -36,7 +36,7 @@ class VehicleInfo { engineNum: json["engineNum"] ?? '', truckNum: json["truckNum"] ?? '', hydrogenCapacity: json["hydrogenCapacity"] ?? 0, - maxHydrogen: json["maxHydrogen"] ?? 0, + maxHydrogen: json["maxHydrogen"] ?? '', ); Map toJson() => { diff --git a/ln_jq_app/lib/main.dart b/ln_jq_app/lib/main.dart index 5710b26..1a5f1d1 100644 --- a/ln_jq_app/lib/main.dart +++ b/ln_jq_app/lib/main.dart @@ -74,15 +74,18 @@ void initHttpSet() { // 设置全局响应处理器 HttpService.to.setOnResponseHandler((response) async { try { - final baseModel = BaseModel.fromJson(response.data); + final baseModel = BaseModel.fromJson(response.data); if (baseModel.code == 0 || baseModel.code == 200) { + return null; } else if (baseModel.code == 401) { await StorageService.to.clearLoginInfo(); Get.offAll(() => LoginPage()); return baseModel.message; - }else { - return "服务繁忙,稍后重试"; + } else { + return (baseModel.error.toString()).isEmpty + ? "服务繁忙,稍后重试" + : baseModel.error.toString(); } } on Exception catch (e) { e.printInfo(); 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 bbde41d..9a3c6f6 100644 --- a/ln_jq_app/lib/pages/b_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/b_page/reservation/controller.dart @@ -53,9 +53,71 @@ class ReservationController extends GetxController with BaseControllerMixin { String operatingEnterprise = ""; String hydrogenId = ""; + String jobTipStr = ""; + String jobDetailsStr = ""; + String jobId = ""; + Future renderData() async { showLoading("加载中"); try { + //获取加氢站未执行的状态修改任务信息 + var jobData = await HttpService.to.get('appointment/job/hyd/un-executed'); + if (jobData != null) { + final jobDataResult = BaseModel.fromJson(jobData.data); + if (jobDataResult.code == 0) { + try{ + jobId = jobDataResult.data["id"] ?? ""; + String endTime = jobDataResult.data["endTime"] ?? ""; + String beginTime = jobDataResult.data["beginTime"] ?? ""; + String hydStatus = jobDataResult.data["hydStatus"] ?? ""; + String hydStatusStr = ""; + if (hydStatus == "0") { + hydStatusStr = "营运中"; + } else if (hydStatus == "1") { + hydStatusStr = "维修中"; + } else if (hydStatus == "2") { + hydStatusStr = "站点关闭"; + } else if (hydStatus == "3") { + hydStatusStr = "暂停营业"; + } + + jobDetailsStr = "当前站点已设置$beginTime-$endTime为$hydStatusStr状态"; + + if (endTime.isNotEmpty) { + try { + // 解析时间字符串 + DateTime endDateTime = DateTime.parse(endTime); + DateTime beginDateTime = DateTime.parse(beginTime); + DateTime now = DateTime.now(); // 2. 计算时间差 (endTime - now) + Duration diff = endDateTime.difference(now); + + // 计算小时数 (允许小数,例如 0.5) + // inMinutes / 60 可以得到更精确的小数小时 + double hoursLeft = diff.inMinutes / 60.0; + + if (hoursLeft > 0) { + // 如果是正数,表示还有多久结束 + String timeTip = "${hoursLeft.toStringAsFixed(1)}小时后"; + jobTipStr = "$timeTip$hydStatusStr"; + } else { + jobTipStr = ""; + } + + // 如果是处于非营运状态,自动回填开始和结束时间 + // 假设 customStartTime 是现在,customEndTime 是接口返回的结束时间 + customStartTime = beginDateTime; + customEndTime = endDateTime; + } catch (e) { + print("时间解析失败: $e"); + } + } + }catch (e){ + Logger.d("解析失败: $e"); + } + } + } + + //获取站点信息 var responseData = await HttpService.to.get( 'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}', ); @@ -102,7 +164,7 @@ class ReservationController extends GetxController with BaseControllerMixin { } operatingEnterprise = operatingEnterprise.isEmpty ? "暂未设置" : operatingEnterprise; - updateUi(); + dismissLoading(); } catch (e) { dismissLoading(); @@ -110,6 +172,8 @@ class ReservationController extends GetxController with BaseControllerMixin { } } catch (e) { dismissLoading(); + } finally { + updateUi(); } } @@ -237,14 +301,14 @@ class ReservationController extends GetxController with BaseControllerMixin { }, ); - if (responseData == null || responseData!.data == null) { + if (responseData == null || responseData.data == null) { dismissLoading(); showToast('服务暂不可用,请稍后'); return; } var result = BaseModel.fromJson(responseData.data); if (result.code == 0) { - showSuccessToast("保存成功"); + showSuccessToast("保存成功,已同步通知对应司机"); } dismissLoading(); } catch (e) { @@ -252,6 +316,54 @@ class ReservationController extends GetxController with BaseControllerMixin { } } + /// 显示当前未执行任务的详情弹窗 + void showJob() { + if (jobDetailsStr.isEmpty) { + showToast("当前没有正在生效的任务设置"); + return; + } + + DialogX.to.showConfirmDialog( + title: '当前设置详情', + content: Text( + jobDetailsStr, + style: const TextStyle(fontSize: 15, height: 1.5), + ), + confirmText: '好的', + cancelText: '取消设置', + onCancel: () { + // 点击“取消设置”调用删除接口 + _cancelJob(); + }, + ); + } + + /// 内部私有方法:调用取消/删除任务接口 + void _cancelJob() async { + showLoading("正在取消..."); + try { + var response = await HttpService.to.delete( + 'appointment/job/hyd/$jobId', + ); + + dismissLoading(); + if (response != null) { + var result = BaseModel.fromJson(response.data); + if (result.code == 0) { + showSuccessToast("已成功取消该设置"); + // 成功后重新刷新页面数据,重置状态 + renderData(); + } else { + showErrorToast(result.error); + } + } + } catch (e) { + dismissLoading(); + showErrorToast("取消失败,请稍后重试"); + Logger.d("取消任务失败: $e"); + } + } + /// 发送站点广播 void sendBroadcast() async { String title = broadcastTitleController.text.trim(); @@ -270,10 +382,7 @@ class ReservationController extends GetxController with BaseControllerMixin { try { var responseData = await HttpService.to.post( 'appointment/notice/push/station/broadcast', - data: { - 'title': title, - 'content': content, - }, + data: {'title': title, 'content': content}, ); dismissLoading(); 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 0082b6a..497d1f5 100644 --- a/ln_jq_app/lib/pages/b_page/reservation/view.dart +++ b/ln_jq_app/lib/pages/b_page/reservation/view.dart @@ -109,20 +109,24 @@ class ReservationPage extends GetView { child: Column( children: [ // Tab 切换栏 - Obx(() => Container( - color: Colors.grey[50], - child: Row( - children: [ - _buildTabItem(0, Icons.business_outlined, '站点信息'), - _buildTabItem(1, Icons.campaign_outlined, '站点广播'), - ], - ), - )), + Obx( + () => Container( + color: Colors.grey[50], + child: Row( + children: [ + _buildTabItem(0, Icons.business_outlined, '站点信息'), + _buildTabItem(1, Icons.campaign_outlined, '站点广播'), + ], + ), + ), + ), const Divider(height: 1), // 内容区域 - Obx(() => controller.selectedTabIndex.value == 0 - ? _buildStationInfo(context) - : _buildStationBroadcast(context)), + Obx( + () => controller.selectedTabIndex.value == 0 + ? _buildStationInfo(context) + : _buildStationBroadcast(context), + ), ], ), ); @@ -180,7 +184,25 @@ class ReservationPage extends GetView { _buildDisplayField(label: '官方价格 (元/kg)', value: controller.customerPrice), const SizedBox(height: 16), _buildSectionTitle('运营信息'), - Text('运营状态', style: TextStyle(color: Colors.grey[600], fontSize: 14)), + Row( + children: [ + Text('运营状态', style: TextStyle(color: Colors.grey[600], fontSize: 14)), + //加氢站未执行的状态修改任务 + if (controller.jobTipStr.isNotEmpty) + GestureDetector( + onTap: controller.showJob, + child: Row( + children: [ + Text( + controller.jobTipStr, + style: TextStyle(color: Colors.yellow[800], fontSize: 14), + ), + Icon(AntdIcon.question_circle, size: 14, color: Colors.yellow[800]), + ], + ), + ), + ], + ), const SizedBox(height: 8), DropdownButtonFormField( value: controller.selectedOperationStatus, @@ -239,7 +261,11 @@ class ReservationPage extends GetView { const SizedBox(width: 10), const Text( '站点广播通知', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87), + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), ), ], ), @@ -249,16 +275,17 @@ class ReservationPage extends GetView { SizedBox( height: 45.h, child: TextField( - controller: controller.broadcastTitleController, - maxLength: 30, - decoration: InputDecoration( - hintText: '例如:临时闭站通知', - hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14), - border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), - contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - counterText: '', // 隐藏原生计数器,我们可以按需自定义 + controller: controller.broadcastTitleController, + maxLength: 30, + decoration: InputDecoration( + hintText: '例如:临时闭站通知', + hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14), + border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), + contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + counterText: '', // 隐藏原生计数器,我们可以按需自定义 + ), ), - ),), + ), const SizedBox(height: 20), _buildTextFieldLabel('通知内容'), const SizedBox(height: 8), @@ -283,7 +310,10 @@ class ReservationPage extends GetView { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 0, ), - child: const Text('发送', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + child: const Text( + '发送', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), ), const SizedBox(height: 20), ], @@ -294,7 +324,11 @@ class ReservationPage extends GetView { Widget _buildTextFieldLabel(String label) { return Text( label, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black87), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), ); } @@ -340,7 +374,11 @@ class ReservationPage extends GetView { } /// 构建一个“可点击”的选择行 - Widget _buildClickField({required String label, required String value, required VoidCallback onTap}) { + Widget _buildClickField({ + required String label, + required String value, + required VoidCallback onTap, + }) { return Padding( padding: const EdgeInsets.only(bottom: 12.0), child: Column( diff --git a/ln_jq_app/lib/pages/c_page/mine/controller.dart b/ln_jq_app/lib/pages/c_page/mine/controller.dart index 64070bb..35ff0ad 100644 --- a/ln_jq_app/lib/pages/c_page/mine/controller.dart +++ b/ln_jq_app/lib/pages/c_page/mine/controller.dart @@ -16,7 +16,6 @@ class MineController extends GetxController with BaseControllerMixin { void onInit() { super.onInit(); renderData(); - renderViolation(); } @override @@ -51,9 +50,8 @@ class MineController extends GetxController with BaseControllerMixin { plateNumber = bean.plateNumber; } - showLoading("加载中"); - try { + showLoading("加载中"); await Future.wait([ _fetchCompletionRate(), // 请求1:完成率 _fetchAccidentCount(), // 请求2:事故数 @@ -61,6 +59,8 @@ class MineController extends GetxController with BaseControllerMixin { _rating(), // 司机评分 _msgNotice(), // 红点消息 ]); + + await renderViolation(); } catch (e, stackTrace) { showErrorToast("加载数据失败,请稍后重试 $e"); } finally { @@ -83,8 +83,8 @@ class MineController extends GetxController with BaseControllerMixin { if (response != null) { final result = BaseModel.fromJson(response.data); if (result.code == 0 && result.data != null) { - int total = result.data["total"] ?? 0; - isNotice = total > 0; + String total = result.data["total"].toString(); + isNotice = int.parse(total) > 0; } } } @@ -139,15 +139,11 @@ class MineController extends GetxController with BaseControllerMixin { } } - void renderViolation() async { + Future renderViolation() async { // 违章信息查询 - final originalHeaders = Map.from(HttpService.to.dio.options.headers); try { - HttpService.to.setBaseUrl(AppTheme.jiaqing_service_url); - HttpService.to.dio.options.headers['appId'] = '97ad10eeb6b346f79e0d6ffd81e4d3c3'; - var responseData = await HttpService.to.get( - "vehicleService/violation/queryViolationInfo_V2?plateNum=${plateNumber}", + "appointment/truck/queryViolationInfo_V2?plateNum=${plateNumber}", ); if (responseData == null || responseData.data == null) { @@ -174,8 +170,6 @@ class MineController extends GetxController with BaseControllerMixin { } } catch (e) { } finally { - HttpService.to.setBaseUrl(AppTheme.test_service_url); - HttpService.to.dio.options.headers = originalHeaders; updateUi(); } } 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 cac9ec3..a197682 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/controller.dart @@ -185,8 +185,8 @@ class C_ReservationController extends GetxController with BaseControllerMixin { final now = DateTime.now(); final isToday = selectedDate.value.year == now.year && - selectedDate.value.month == now.month && - selectedDate.value.day == now.day; + selectedDate.value.month == now.month && + selectedDate.value.day == now.day; final List availableSlots = []; for (int i = 0; i < 24; i++) { @@ -234,7 +234,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin { // 查找当前选中的时间对应的新列表中的索引 int initialItem = availableSlots.indexWhere( - (slot) => slot.start.hour == startTime.value.hour, + (slot) => slot.start.hour == startTime.value.hour, ); if (initialItem == -1) { @@ -393,17 +393,16 @@ class C_ReservationController extends GetxController with BaseControllerMixin { 'hydAmount': ampuntStr, }, ); - var result = BaseModel.fromJson(responseData?.data); - if (responseData == null) { + + if (responseData == null || result.code != 0) { dismissLoading(); showToast(result.error); return; } dismissLoading(); - if (result.code == 0) { showSuccessToast("预约成功"); @@ -438,7 +437,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin { } } catch (e) { dismissLoading(); - showToast('服务暂不可用,请稍后'); } } @@ -527,6 +525,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin { reservationList.clear(); } } catch (e) { + Logger.d("${e.toString()}"); showToast('获取预约数据失败'); hasReservationData.value = false; reservationList.clear(); @@ -593,7 +592,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin { plateNumber = bean.plateNumber; vin = bean.vin; plateNumberController = TextEditingController(text: plateNumber); - maxHydrogen = bean.maxHydrogen; + maxHydrogen = num.tryParse(bean.maxHydrogen) ?? 0; getCatinfo(); getJqinfo(); } @@ -689,13 +688,10 @@ class C_ReservationController extends GetxController with BaseControllerMixin { return; } - showLoading("加氢站数据加载中"); - final originalHeaders = Map.from(HttpService.to.dio.options.headers); try { - HttpService.to.setBaseUrl(AppTheme.jiaqing_service_url); - HttpService.to.dio.options.headers['appId'] = '97ad10eeb6b346f79e0d6ffd81e4d3c3'; + showLoading("加氢站数据加载中"); - var responseData = await HttpService.to.get("hydrogen/queryHydrogenSiteInfo"); + var responseData = await HttpService.to.get("appointment/station/queryHydrogenSiteInfo"); if (responseData == null || responseData.data == null) { showToast('暂时无法获取站点信息'); @@ -744,9 +740,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin { showToast('数据异常'); } finally { dismissLoading(); - HttpService.to.setBaseUrl(AppTheme.test_service_url); - HttpService.to.dio.options.headers = originalHeaders; - // 如果未绑定车辆,且本次会话尚未提示过,则弹出提示 if (!StorageService.to.hasShownBindVehicleDialog && StorageService.to.isLoggedIn && diff --git a/ln_jq_app/lib/pages/login/view.dart b/ln_jq_app/lib/pages/login/view.dart index 63b24de..30ba347 100644 --- a/ln_jq_app/lib/pages/login/view.dart +++ b/ln_jq_app/lib/pages/login/view.dart @@ -336,7 +336,7 @@ class _LoginPageState extends State with SingleTickerProviderStateMix try { String encryptedPassword = LoginUtil.encrypt(password); var responseData = await HttpService.to.post( - '/login/password', + 'appointment/login/password', data: { 'account': account, 'password': encryptedPassword,