联调修改结构

This commit is contained in:
2026-01-14 13:18:22 +08:00
parent 16639e2384
commit f25feaa55a
8 changed files with 205 additions and 72 deletions

View File

@@ -6,7 +6,6 @@ class BaseModel<T> {
final String message; // 消息,例如 "success" final String message; // 消息,例如 "success"
final String msg; // 消息,例如 "success" final String msg; // 消息,例如 "success"
final T? data; // 核心数据,使用泛型 T可以是任何类型 final T? data; // 核心数据,使用泛型 T可以是任何类型
final int time; // 时间戳
final dynamic error; // 错误信息,可以是任何类型或 null final dynamic error; // 错误信息,可以是任何类型或 null
BaseModel({ BaseModel({
@@ -15,7 +14,6 @@ class BaseModel<T> {
required this.message, required this.message,
required this.msg, required this.msg,
this.data, // data 可以为 null this.data, // data 可以为 null
required this.time,
this.error, // error 可以为 null this.error, // error 可以为 null
}); });
@@ -60,7 +58,6 @@ class BaseModel<T> {
status: json['status'] as bool? ?? false, status: json['status'] as bool? ?? false,
message: json['message'] ?? '暂不可用,请稍后', message: json['message'] ?? '暂不可用,请稍后',
msg: json['msg'] ?? '暂不可用,请稍后', msg: json['msg'] ?? '暂不可用,请稍后',
time: _parseInt(json['time']),
data: finalData, data: finalData,
error: json['error'], error: json['error'],
); );
@@ -72,7 +69,6 @@ class BaseModel<T> {
'status': status, 'status': status,
'message': message, 'message': message,
'msg': msg, 'msg': msg,
'time': time,
'data': data, 'data': data,
'error': error, 'error': error,
}; };

View File

@@ -15,7 +15,7 @@ class VehicleInfo {
final String engineNum; final String engineNum;
final String truckNum; final String truckNum;
final num hydrogenCapacity; final num hydrogenCapacity;
final num maxHydrogen; final String maxHydrogen;
VehicleInfo({ VehicleInfo({
required this.plateNumber, required this.plateNumber,
@@ -36,7 +36,7 @@ class VehicleInfo {
engineNum: json["engineNum"] ?? '', engineNum: json["engineNum"] ?? '',
truckNum: json["truckNum"] ?? '', truckNum: json["truckNum"] ?? '',
hydrogenCapacity: json["hydrogenCapacity"] ?? 0, hydrogenCapacity: json["hydrogenCapacity"] ?? 0,
maxHydrogen: json["maxHydrogen"] ?? 0, maxHydrogen: json["maxHydrogen"] ?? '',
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

View File

@@ -74,15 +74,18 @@ void initHttpSet() {
// 设置全局响应处理器 // 设置全局响应处理器
HttpService.to.setOnResponseHandler((response) async { HttpService.to.setOnResponseHandler((response) async {
try { try {
final baseModel = BaseModel<dynamic>.fromJson(response.data); final baseModel = BaseModel.fromJson(response.data);
if (baseModel.code == 0 || baseModel.code == 200) { if (baseModel.code == 0 || baseModel.code == 200) {
return null; return null;
} else if (baseModel.code == 401) { } else if (baseModel.code == 401) {
await StorageService.to.clearLoginInfo(); await StorageService.to.clearLoginInfo();
Get.offAll(() => LoginPage()); Get.offAll(() => LoginPage());
return baseModel.message; return baseModel.message;
}else { } else {
return "服务繁忙,稍后重试"; return (baseModel.error.toString()).isEmpty
? "服务繁忙,稍后重试"
: baseModel.error.toString();
} }
} on Exception catch (e) { } on Exception catch (e) {
e.printInfo(); e.printInfo();

View File

@@ -53,9 +53,71 @@ class ReservationController extends GetxController with BaseControllerMixin {
String operatingEnterprise = ""; String operatingEnterprise = "";
String hydrogenId = ""; String hydrogenId = "";
String jobTipStr = "";
String jobDetailsStr = "";
String jobId = "";
Future<void> renderData() async { Future<void> renderData() async {
showLoading("加载中"); showLoading("加载中");
try { 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( var responseData = await HttpService.to.get(
'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}', 'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}',
); );
@@ -102,7 +164,7 @@ class ReservationController extends GetxController with BaseControllerMixin {
} }
operatingEnterprise = operatingEnterprise.isEmpty ? "暂未设置" : operatingEnterprise; operatingEnterprise = operatingEnterprise.isEmpty ? "暂未设置" : operatingEnterprise;
updateUi();
dismissLoading(); dismissLoading();
} catch (e) { } catch (e) {
dismissLoading(); dismissLoading();
@@ -110,6 +172,8 @@ class ReservationController extends GetxController with BaseControllerMixin {
} }
} catch (e) { } catch (e) {
dismissLoading(); 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(); dismissLoading();
showToast('服务暂不可用,请稍后'); showToast('服务暂不可用,请稍后');
return; return;
} }
var result = BaseModel.fromJson(responseData.data); var result = BaseModel.fromJson(responseData.data);
if (result.code == 0) { if (result.code == 0) {
showSuccessToast("保存成功"); showSuccessToast("保存成功,已同步通知对应司机");
} }
dismissLoading(); dismissLoading();
} catch (e) { } 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 { void sendBroadcast() async {
String title = broadcastTitleController.text.trim(); String title = broadcastTitleController.text.trim();
@@ -270,10 +382,7 @@ class ReservationController extends GetxController with BaseControllerMixin {
try { try {
var responseData = await HttpService.to.post( var responseData = await HttpService.to.post(
'appointment/notice/push/station/broadcast', 'appointment/notice/push/station/broadcast',
data: { data: {'title': title, 'content': content},
'title': title,
'content': content,
},
); );
dismissLoading(); dismissLoading();

View File

@@ -109,7 +109,8 @@ class ReservationPage extends GetView<ReservationController> {
child: Column( child: Column(
children: [ children: [
// Tab 切换栏 // Tab 切换栏
Obx(() => Container( Obx(
() => Container(
color: Colors.grey[50], color: Colors.grey[50],
child: Row( child: Row(
children: [ children: [
@@ -117,12 +118,15 @@ class ReservationPage extends GetView<ReservationController> {
_buildTabItem(1, Icons.campaign_outlined, '站点广播'), _buildTabItem(1, Icons.campaign_outlined, '站点广播'),
], ],
), ),
)), ),
),
const Divider(height: 1), const Divider(height: 1),
// 内容区域 // 内容区域
Obx(() => controller.selectedTabIndex.value == 0 Obx(
() => controller.selectedTabIndex.value == 0
? _buildStationInfo(context) ? _buildStationInfo(context)
: _buildStationBroadcast(context)), : _buildStationBroadcast(context),
),
], ],
), ),
); );
@@ -180,7 +184,25 @@ class ReservationPage extends GetView<ReservationController> {
_buildDisplayField(label: '官方价格 (元/kg)', value: controller.customerPrice), _buildDisplayField(label: '官方价格 (元/kg)', value: controller.customerPrice),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildSectionTitle('运营信息'), _buildSectionTitle('运营信息'),
Row(
children: [
Text('运营状态', style: TextStyle(color: Colors.grey[600], fontSize: 14)), 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), const SizedBox(height: 8),
DropdownButtonFormField<String>( DropdownButtonFormField<String>(
value: controller.selectedOperationStatus, value: controller.selectedOperationStatus,
@@ -239,7 +261,11 @@ class ReservationPage extends GetView<ReservationController> {
const SizedBox(width: 10), const SizedBox(width: 10),
const Text( const Text(
'站点广播通知', '站点广播通知',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87), style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
), ),
], ],
), ),
@@ -258,7 +284,8 @@ class ReservationPage extends GetView<ReservationController> {
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
counterText: '', // 隐藏原生计数器,我们可以按需自定义 counterText: '', // 隐藏原生计数器,我们可以按需自定义
), ),
),), ),
),
const SizedBox(height: 20), const SizedBox(height: 20),
_buildTextFieldLabel('通知内容'), _buildTextFieldLabel('通知内容'),
const SizedBox(height: 8), const SizedBox(height: 8),
@@ -283,7 +310,10 @@ class ReservationPage extends GetView<ReservationController> {
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
elevation: 0, 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), const SizedBox(height: 20),
], ],
@@ -294,7 +324,11 @@ class ReservationPage extends GetView<ReservationController> {
Widget _buildTextFieldLabel(String label) { Widget _buildTextFieldLabel(String label) {
return Text( return Text(
label, 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<ReservationController> {
} }
/// 构建一个“可点击”的选择行 /// 构建一个“可点击”的选择行
Widget _buildClickField({required String label, required String value, required VoidCallback onTap}) { Widget _buildClickField({
required String label,
required String value,
required VoidCallback onTap,
}) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 12.0), padding: const EdgeInsets.only(bottom: 12.0),
child: Column( child: Column(

View File

@@ -16,7 +16,6 @@ class MineController extends GetxController with BaseControllerMixin {
void onInit() { void onInit() {
super.onInit(); super.onInit();
renderData(); renderData();
renderViolation();
} }
@override @override
@@ -51,9 +50,8 @@ class MineController extends GetxController with BaseControllerMixin {
plateNumber = bean.plateNumber; plateNumber = bean.plateNumber;
} }
showLoading("加载中");
try { try {
showLoading("加载中");
await Future.wait([ await Future.wait([
_fetchCompletionRate(), // 请求1完成率 _fetchCompletionRate(), // 请求1完成率
_fetchAccidentCount(), // 请求2事故数 _fetchAccidentCount(), // 请求2事故数
@@ -61,6 +59,8 @@ class MineController extends GetxController with BaseControllerMixin {
_rating(), // 司机评分 _rating(), // 司机评分
_msgNotice(), // 红点消息 _msgNotice(), // 红点消息
]); ]);
await renderViolation();
} catch (e, stackTrace) { } catch (e, stackTrace) {
showErrorToast("加载数据失败,请稍后重试 $e"); showErrorToast("加载数据失败,请稍后重试 $e");
} finally { } finally {
@@ -83,8 +83,8 @@ class MineController extends GetxController with BaseControllerMixin {
if (response != null) { if (response != null) {
final result = BaseModel.fromJson(response.data); final result = BaseModel.fromJson(response.data);
if (result.code == 0 && result.data != null) { if (result.code == 0 && result.data != null) {
int total = result.data["total"] ?? 0; String total = result.data["total"].toString();
isNotice = total > 0; isNotice = int.parse(total) > 0;
} }
} }
} }
@@ -139,15 +139,11 @@ class MineController extends GetxController with BaseControllerMixin {
} }
} }
void renderViolation() async { Future<void> renderViolation() async {
// 违章信息查询 // 违章信息查询
final originalHeaders = Map<String, dynamic>.from(HttpService.to.dio.options.headers);
try { try {
HttpService.to.setBaseUrl(AppTheme.jiaqing_service_url);
HttpService.to.dio.options.headers['appId'] = '97ad10eeb6b346f79e0d6ffd81e4d3c3';
var responseData = await HttpService.to.get( var responseData = await HttpService.to.get(
"vehicleService/violation/queryViolationInfo_V2?plateNum=${plateNumber}", "appointment/truck/queryViolationInfo_V2?plateNum=${plateNumber}",
); );
if (responseData == null || responseData.data == null) { if (responseData == null || responseData.data == null) {
@@ -174,8 +170,6 @@ class MineController extends GetxController with BaseControllerMixin {
} }
} catch (e) { } catch (e) {
} finally { } finally {
HttpService.to.setBaseUrl(AppTheme.test_service_url);
HttpService.to.dio.options.headers = originalHeaders;
updateUi(); updateUi();
} }
} }

View File

@@ -393,17 +393,16 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
'hydAmount': ampuntStr, 'hydAmount': ampuntStr,
}, },
); );
var result = BaseModel.fromJson(responseData?.data); var result = BaseModel.fromJson(responseData?.data);
if (responseData == null) {
if (responseData == null || result.code != 0) {
dismissLoading(); dismissLoading();
showToast(result.error); showToast(result.error);
return; return;
} }
dismissLoading(); dismissLoading();
if (result.code == 0) { if (result.code == 0) {
showSuccessToast("预约成功"); showSuccessToast("预约成功");
@@ -438,7 +437,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
} }
} catch (e) { } catch (e) {
dismissLoading(); dismissLoading();
showToast('服务暂不可用,请稍后');
} }
} }
@@ -527,6 +525,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
reservationList.clear(); reservationList.clear();
} }
} catch (e) { } catch (e) {
Logger.d("${e.toString()}");
showToast('获取预约数据失败'); showToast('获取预约数据失败');
hasReservationData.value = false; hasReservationData.value = false;
reservationList.clear(); reservationList.clear();
@@ -593,7 +592,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
plateNumber = bean.plateNumber; plateNumber = bean.plateNumber;
vin = bean.vin; vin = bean.vin;
plateNumberController = TextEditingController(text: plateNumber); plateNumberController = TextEditingController(text: plateNumber);
maxHydrogen = bean.maxHydrogen; maxHydrogen = num.tryParse(bean.maxHydrogen) ?? 0;
getCatinfo(); getCatinfo();
getJqinfo(); getJqinfo();
} }
@@ -689,13 +688,10 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
return; return;
} }
showLoading("加氢站数据加载中");
final originalHeaders = Map<String, dynamic>.from(HttpService.to.dio.options.headers);
try { try {
HttpService.to.setBaseUrl(AppTheme.jiaqing_service_url); showLoading("加氢站数据加载中");
HttpService.to.dio.options.headers['appId'] = '97ad10eeb6b346f79e0d6ffd81e4d3c3';
var responseData = await HttpService.to.get("hydrogen/queryHydrogenSiteInfo"); var responseData = await HttpService.to.get("appointment/station/queryHydrogenSiteInfo");
if (responseData == null || responseData.data == null) { if (responseData == null || responseData.data == null) {
showToast('暂时无法获取站点信息'); showToast('暂时无法获取站点信息');
@@ -744,9 +740,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
showToast('数据异常'); showToast('数据异常');
} finally { } finally {
dismissLoading(); dismissLoading();
HttpService.to.setBaseUrl(AppTheme.test_service_url);
HttpService.to.dio.options.headers = originalHeaders;
// 如果未绑定车辆,且本次会话尚未提示过,则弹出提示 // 如果未绑定车辆,且本次会话尚未提示过,则弹出提示
if (!StorageService.to.hasShownBindVehicleDialog && if (!StorageService.to.hasShownBindVehicleDialog &&
StorageService.to.isLoggedIn && StorageService.to.isLoggedIn &&

View File

@@ -336,7 +336,7 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
try { try {
String encryptedPassword = LoginUtil.encrypt(password); String encryptedPassword = LoginUtil.encrypt(password);
var responseData = await HttpService.to.post( var responseData = await HttpService.to.post(
'/login/password', 'appointment/login/password',
data: { data: {
'account': account, 'account': account,
'password': encryptedPassword, 'password': encryptedPassword,