From feedc8c511613eab5ab781ca4af607bc881691e9 Mon Sep 17 00:00:00 2001 From: userGyl Date: Thu, 13 Nov 2025 15:56:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=AB=E7=A0=81=E7=BB=93=E6=9E=9C=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ln_jq_app/lib/common/model/vehicle_info.dart | 52 ++++++++++++++++++ .../pages/c_page/reservation/controller.dart | 2 +- .../lib/pages/c_page/reservation/view.dart | 38 +++++++------ ln_jq_app/lib/pages/qr_code/controller.dart | 48 +++++++++++------ ln_jq_app/lib/storage_service.dart | 54 +++++++++++-------- 5 files changed, 139 insertions(+), 55 deletions(-) create mode 100644 ln_jq_app/lib/common/model/vehicle_info.dart diff --git a/ln_jq_app/lib/common/model/vehicle_info.dart b/ln_jq_app/lib/common/model/vehicle_info.dart new file mode 100644 index 0000000..028bc89 --- /dev/null +++ b/ln_jq_app/lib/common/model/vehicle_info.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; + +// 将 JSON 字符串转换为 VehicleInfo 对象的辅助函数 +VehicleInfo vehicleInfoFromJson(String str) => VehicleInfo.fromJson(json.decode(str)); + +// 将 VehicleInfo 对象转换为 JSON 字符串的辅助函数 +String vehicleInfoToJson(VehicleInfo data) => json.encode(data.toJson()); + +/// 车辆信息数据模型 +class VehicleInfo { + final String plateNumber; + final String vin; + final String modelName; + final String brandName; + final String engineNum; + final String truckNum; + final num hydrogenCapacity; + final num maxHydrogen; + + VehicleInfo({ + required this.plateNumber, + required this.vin, + required this.modelName, + required this.brandName, + required this.engineNum, + required this.truckNum, + required this.hydrogenCapacity, + required this.maxHydrogen, + }); + + factory VehicleInfo.fromJson(Map json) => VehicleInfo( + plateNumber: json["plateNumber"] ?? '', + vin: json["vin"] ?? '', + modelName: json["modelName"] ?? '', + brandName: json["brandName"] ?? '', + engineNum: json["engineNum"] ?? '', + truckNum: json["truckNum"] ?? '', + hydrogenCapacity: json["hydrogenCapacity"] ?? 0, + maxHydrogen: json["maxHydrogen"] ?? 0, + ); + + Map toJson() => { + "plateNumber": plateNumber, + "vin": vin, + "modelName": modelName, + "brandName": brandName, + "engineNum": engineNum, + "truckNum": truckNum, + "hydrogenCapacity": hydrogenCapacity, + "maxHydrogen": maxHydrogen, + }; +} 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 4322612..4adc156 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/controller.dart @@ -421,7 +421,7 @@ class ReservationController extends GetxController with BaseControllerMixin { var responseData = await HttpService.to.get("hydrogen/queryHydrogenSiteInfo"); - if (responseData == null && responseData!.data == null) { + if (responseData == null || responseData.data == null) { showToast('暂时无法获取站点信息'); dismissLoading(); return; diff --git a/ln_jq_app/lib/pages/c_page/reservation/view.dart b/ln_jq_app/lib/pages/c_page/reservation/view.dart index e8befe9..1d18ad8 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/view.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/view.dart @@ -1,8 +1,9 @@ import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; +import 'package:ln_jq_app/common/model/vehicle_info.dart'; import 'package:ln_jq_app/pages/qr_code/view.dart'; +import 'package:ln_jq_app/storage_service.dart'; import 'controller.dart'; @@ -116,7 +117,7 @@ class ReservationPage extends GetView { children: [ Text(value, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold)), const SizedBox(height: 4), - Text(label, style: const TextStyle(color: Colors.grey, fontSize: 11 )), + Text(label, style: const TextStyle(color: Colors.grey, fontSize: 11)), ], ); } @@ -142,11 +143,7 @@ class ReservationPage extends GetView { ), ), const SizedBox(width: 8), - Icon( - Icons.propane_rounded, - size: 50, - color: Colors.blue.withOpacity(0.5), - ), + Icon(Icons.propane_rounded, size: 50, color: Colors.blue.withOpacity(0.5)), ], ), ), @@ -162,8 +159,18 @@ class ReservationPage extends GetView { const SizedBox(width: 8), isButton ? GestureDetector( - onTap: () { - Get.to(() => const QrCodePage()); + onTap: () async { + //判断是否绑定成功 + var scanResult = await Get.to(() => const QrCodePage()); + if (scanResult == true) { + VehicleInfo? bean = StorageService.to.vehicleInfo; + + if (bean != null) { + showToast( + "已绑定${bean.plateNumber}-${StorageService.to.hasVehicleInfo}", + ); + } + } }, child: Container( margin: EdgeInsetsGeometry.only(left: 10.w), @@ -181,7 +188,10 @@ class ReservationPage extends GetView { Text( value, style: const TextStyle( - color: Colors.blue, fontSize: 11, fontWeight: FontWeight.w500), + color: Colors.blue, + fontSize: 11, + fontWeight: FontWeight.w500, + ), ), ], ), @@ -411,13 +421,9 @@ class ReservationPage extends GetView { ), dropdownStyleData: DropdownStyleData( maxHeight: 200, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - ), - ), - menuItemStyleData: const MenuItemStyleData( - height: 40, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)), ), + menuItemStyleData: const MenuItemStyleData(height: 40), ), ), ), diff --git a/ln_jq_app/lib/pages/qr_code/controller.dart b/ln_jq_app/lib/pages/qr_code/controller.dart index e6083f4..626b5a1 100644 --- a/ln_jq_app/lib/pages/qr_code/controller.dart +++ b/ln_jq_app/lib/pages/qr_code/controller.dart @@ -6,6 +6,9 @@ import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:image/image.dart' as img; import 'package:image_picker/image_picker.dart'; +import 'package:ln_jq_app/common/model/base_model.dart'; +import 'package:ln_jq_app/common/model/vehicle_info.dart'; +import 'package:ln_jq_app/storage_service.dart'; import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart'; import 'package:zxing_lib/common.dart'; import 'package:zxing_lib/qrcode.dart'; @@ -134,28 +137,43 @@ class QrCodeController extends GetxController showErrorToast('相机权限未被授予,请到权限管理中打开'); } if (!isPhotosGranted) { - showErrorToast( - '相册权限未被授予,请到权限管理中打开', - ); + showErrorToast('相册权限未被授予,请到权限管理中打开'); } } //扫码结果处理 - void renderResult(String resultStr) { - Get.defaultDialog( - title: "扫描结果", - middleText: resultStr, - onConfirm: () { - Get.back(); - resumeScanner(); - }, - onCancel: () { - resumeScanner(); - }, - ); + void renderResult(String resultStr) async { + showLoading("正在获取车辆信息..."); + try { + var responseData = await HttpService.to.get( + "appointment/truck/base-info?vin=$resultStr", + ); + if (responseData == null || responseData.data == null) { + showToast('无法获取车辆信息,请检查网络或稍后重试'); + resumeScanner(); + return; + } + + var result = BaseModel.fromJson(responseData.data); + final vehicle = VehicleInfo.fromJson(result.data as Map); + //保存使用 + await StorageService.to.saveVehicleInfo(vehicle); + + Get.back(result: true); + + } on DioException catch (e) { + showErrorToast("网络请求失败,请稍后重试"); + resumeScanner(); + } catch (e, stackTrace) { + showErrorToast("处理失败,请稍后重试"); + resumeScanner(); // 未知异常,恢复扫描 + } finally { + dismissLoading(); + } } + @override void onClose() { qrViewController?.dispose(); diff --git a/ln_jq_app/lib/storage_service.dart b/ln_jq_app/lib/storage_service.dart index 7636bf2..f614f0e 100644 --- a/ln_jq_app/lib/storage_service.dart +++ b/ln_jq_app/lib/storage_service.dart @@ -1,5 +1,6 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; +import 'package:ln_jq_app/common/model/vehicle_info.dart'; /// 定义登录渠道的枚举类型 enum LoginChannel { @@ -15,10 +16,11 @@ class StorageService extends GetxService { static const String _tokenKey = 'user_token'; static const String _userIdKey = 'user_id'; static const String _channelKey = 'login_channel'; - // 为新字段增加键名 static const String _nameKey = 'user_name'; static const String _phoneKey = 'user_phone'; static const String _idCardKey = 'user_id_card'; + // 车辆信息的键名 + static const String _vehicleInfoKey = 'vehicle_info'; // 提供一个静态的 'to' 方法,方便全局访问 static StorageService get to => Get.find(); @@ -31,30 +33,27 @@ class StorageService extends GetxService { /// --- Getter 方法,用于读取状态 --- - /// 判断是否已登录 (通过检查 token 是否存在且不为空) - bool get isLoggedIn => - _box - .read(_tokenKey) - ?.isNotEmpty ?? false; - - /// 获取 Token + bool get isLoggedIn => _box.read(_tokenKey)?.isNotEmpty ?? false; String? get token => _box.read(_tokenKey); - - /// 获取 UserId String? get userId => _box.read(_userIdKey); - - /// 获取 Name String? get name => _box.read(_nameKey); - - /// 获取 Phone String? get phone => _box.read(_phoneKey); - - /// 获取 ID Card String? get idCard => _box.read(_idCardKey); + /// 判断是否已有车辆信息缓存 + bool get hasVehicleInfo => _box.hasData(_vehicleInfoKey); + + /// 获取已缓存的车辆信息 + VehicleInfo? get vehicleInfo { + final vehicleJson = _box.read(_vehicleInfoKey); + if (vehicleJson != null) { + // 使用我们之前创建的辅助函数来解析 + return vehicleInfoFromJson(vehicleJson); + } + return null; + } ///获取当前登录渠道 - /// 从存储中读取字符串,并转换为枚举类型 LoginChannel get loginChannel { final channelString = _box.read(_channelKey); if (channelString == 'station') { @@ -66,12 +65,10 @@ class StorageService extends GetxService { } /// --- 操作方法 --- - /// 保存用户信息 - /// @param channel - 登录渠道,station 或 driver Future saveLoginInfo({ required String token, required String userId, - required String channel, // 接收一个字符串类型的渠道 + required String channel, String? name, String? phone, String? idCard, @@ -79,20 +76,31 @@ class StorageService extends GetxService { await _box.write(_tokenKey, token); await _box.write(_userIdKey, userId); await _box.write(_channelKey, channel); - // 保存新增的字段,如果为 null, GetStorage 会移除该键 await _box.write(_nameKey, name); await _box.write(_phoneKey, phone); await _box.write(_idCardKey, idCard); } - ///删除用户信息,增加删除渠道信息 + /// 保存车辆信息 + Future saveVehicleInfo(VehicleInfo data) async { + // 使用辅助函数将对象转换为 JSON 字符串并保存 + await _box.write(_vehicleInfoKey, vehicleInfoToJson(data)); + } + + /// 清除车辆信息 + Future clearVehicleInfo() async { + await _box.remove(_vehicleInfoKey); + } + + /// 删除用户信息 (登出) Future clearLoginInfo() async { await _box.remove(_tokenKey); await _box.remove(_userIdKey); await _box.remove(_channelKey); - // 退出时一并清除新增的字段 await _box.remove(_nameKey); await _box.remove(_phoneKey); await _box.remove(_idCardKey); + // 登出时一并清除车辆信息 + await clearVehicleInfo(); } }