diff --git a/ln_jq_app/README.md b/ln_jq_app/README.md index b86a337..912724e 100644 --- a/ln_jq_app/README.md +++ b/ln_jq_app/README.md @@ -3,3 +3,6 @@ 加氢预约app +android jks +小羚羚 +Ln123456. \ No newline at end of file diff --git a/ln_jq_app/android/build.gradle.kts b/ln_jq_app/android/build.gradle.kts index dbee657..4400c96 100644 --- a/ln_jq_app/android/build.gradle.kts +++ b/ln_jq_app/android/build.gradle.kts @@ -1,5 +1,8 @@ allprojects { repositories { + // 使用阿里云镜像 + maven("https://maven.aliyun.com/repository/public") + maven("https://maven.aliyun.com/repository/google") google() mavenCentral() } diff --git a/ln_jq_app/lib/main.dart b/ln_jq_app/lib/main.dart index b438392..bf362a7 100644 --- a/ln_jq_app/lib/main.dart +++ b/ln_jq_app/lib/main.dart @@ -7,6 +7,7 @@ import 'package:ln_jq_app/storage_service.dart'; import 'common/styles/theme.dart'; import 'pages/home/view.dart'; +import 'pages/login/view.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -54,15 +55,17 @@ void initHttpSet() { // 设置基础 URL HttpService.to.setBaseUrl(AppTheme.test_service_url); //指定请求头 - HttpService.to.dio.interceptors.add( - TokenInterceptor(tokenKey: 'asoco-token'), - ); + HttpService.to.dio.interceptors.add(TokenInterceptor(tokenKey: 'asoco-token')); // 设置全局响应处理器 HttpService.to.setOnResponseHandler((response) async { try { final baseModel = BaseModel.fromJson(response.data); if (baseModel.code == 0) { return null; + } else if (baseModel.code == 401) { + await StorageService.to.clearLoginInfo(); + Get.offAll(() => LoginPage()); + return baseModel.message; } else { return baseModel.message; } @@ -71,5 +74,4 @@ void initHttpSet() { return '服务器异常'; } }); - } 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 a51550d..b705500 100644 --- a/ln_jq_app/lib/pages/b_page/site/controller.dart +++ b/ln_jq_app/lib/pages/b_page/site/controller.dart @@ -1,8 +1,15 @@ +import 'dart:async'; + import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:ln_jq_app/common/model/base_model.dart'; import 'package:ln_jq_app/storage_service.dart'; -enum ReservationStatus { pending, completed, rejected } +enum ReservationStatus { + pending, // 待处理 ( addStatus: 1) + completed, // 已完成 ( addStatus: 2) + rejected, // 已拒绝 ( 3) + unknown, // 未知状态 +} class ReservationModel { final String id; @@ -22,6 +29,45 @@ class ReservationModel { required this.contactPhone, this.status = ReservationStatus.pending, }); + + /// 工厂构造函数,用于从JSON创建ReservationModel实例 + factory ReservationModel.fromJson(Map json) { + //1完成 0待处理 2已拒绝 + ReservationStatus currentStatus; + int statusFromServer = json['addStatus'] as int? ?? 0; + switch (statusFromServer) { + case 0: + currentStatus = ReservationStatus.pending; + break; + case 1: + currentStatus = ReservationStatus.completed; + break; + case 2: + currentStatus = ReservationStatus.rejected; + break; + default: + currentStatus = ReservationStatus.unknown; + } + + // 格式化时间显示 + String startTime = json['startTime']?.toString() ?? ''; + String endTime = json['endTime']?.toString() ?? ''; + String timeRange = (startTime.isNotEmpty && endTime.isNotEmpty) + ? '${json['date']?.toString() ?? ''} ${startTime.substring(11, 16)}-${endTime.substring(11, 16)}' // 截取 HH:mm + : '时间未定'; + + return ReservationModel( + // id, hydAmount 需要转换为 String + id: json['id']?.toString() ?? '', + plateNumber: json['plateNumber']?.toString() ?? '未知车牌', + amount: '${json['hydAmount']?.toString() ?? '0'}kg', + // 拼接单位 + time: timeRange, + contactPerson: json['contacts']?.toString() ?? '无联系人', + contactPhone: json['phone']?.toString() ?? '无联系电话', + status: currentStatus, + ); + } } class SiteController extends GetxController with BaseControllerMixin { @@ -35,91 +81,156 @@ class SiteController extends GetxController with BaseControllerMixin { // 新增预约数据列表 List reservationList = []; + Timer? _refreshTimer; @override void onInit() { super.onInit(); - // 页面初始化时自动加载数据 - fetchReservationData(); renderData(); + + startAutoRefresh(); } - /// 模拟获取预约数据的方法 + @override + void onClose() { + stopAutoRefresh(); + super.onClose(); + } + + void startAutoRefresh() { + // 先停止已存在的定时器,防止重复启动 + stopAutoRefresh(); + + // 创建一个每5分钟执行一次的周期性定时器 + _refreshTimer = Timer.periodic(const Duration(minutes: 5), (timer) { + fetchReservationData(); + }); + } + + /// 【6. 新增】停止定时器的方法 + void stopAutoRefresh() { + // 如果定时器存在并且是激活状态,就取消它 + _refreshTimer?.cancel(); + _refreshTimer = null; // 置为null,方便判断 + print("【自动刷新】定时器已停止。"); + } + + /// 获取预约数据的方法 Future fetchReservationData() async { showLoading("加载中"); - // 模拟网络请求延迟 - await Future.delayed(const Duration(seconds: 1)); + try { + var response = await HttpService.to.post( + "appointment/orderAddHyd/sitOrderPage", + data: { + 'stationName': name, // 使用从 renderData 中获取到的 name + 'pageNum': 1, + 'pageSize': 30, // 暂时不考虑分页,一次获取30条 + }, + ); - // ==================== 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, - ), - ]; + // 安全校验 + if (response == null || response.data == null) { + showToast('暂时无法获取预约数据'); + hasReservationData = false; + reservationList = []; + return; + } - hasReservationData = reservationList.isNotEmpty; + final baseModel = BaseModel.fromJson(response.data); - dismissLoading(); - updateUi(); + if (baseModel.code == 0 && baseModel.data != null) { + // 【核心修改】处理接口返回的列表数据 + final dataMap = baseModel.data as Map; + + final List listFromServer = dataMap['list'] ?? []; + + // 使用 .map() 遍历列表,将每个 item 转换为一个 ReservationModel 对象 + reservationList = listFromServer.map((item) { + return ReservationModel.fromJson(item as Map); + }).toList(); + + // 根据列表是否为空来更新 hasReservationData 状态 + hasReservationData = reservationList.isNotEmpty; + } else { + // 接口返回业务错误 + showToast(baseModel.message); + hasReservationData = false; + reservationList = []; // 清空列表 + } + } catch (e) { + // 捕获网络或解析异常 + showToast('获取预约数据失败'); + hasReservationData = false; + reservationList = []; // 清空列表 + } finally { + // 无论成功失败,最后都要关闭加载动画并更新UI + dismissLoading(); + updateUi(); + } } /// 确认预约 Future confirmReservation(String id) async { - print('确认预约: $id'); - // TODO: 在这里调用确认接口 - // 接口调用成功后,更新本地数据状态并刷新UI final item = reservationList.firstWhere((item) => item.id == id); - item.status = ReservationStatus.completed; - updateUi(); + DialogX.to.showConfirmDialog( + title: '确认预约', + message: '确定要确认车牌号${item.plateNumber}的预约吗', + onConfirm: () { + upDataService(id, 1, item); + }, + onCancel: () {}, + ); } /// 拒绝预约 Future rejectReservation(String id) async { - print('拒绝预约: $id'); - // TODO: 在这里调用拒绝接口 - // 接口调用成功后,更新本地数据状态并刷新UI final item = reservationList.firstWhere((item) => item.id == id); - item.status = ReservationStatus.rejected; - updateUi(); + DialogX.to.showConfirmDialog( + title: '拒绝预约', + message: '确定要拒绝车牌号${item.plateNumber}的预约吗', + onConfirm: () { + upDataService(id, 2, item); + }, + onCancel: () {}, + ); + } + + void upDataService(String id, int status, ReservationModel item) async { + showLoading("确认中"); + + try { + var responseData = await HttpService.to.post( + 'appointment/orderAddHyd/completeOrder', + data: {'id': id, 'addStatus': status}, + ); + + if (responseData == null && responseData!.data == null) { + dismissLoading(); + showToast('服务暂不可用,请稍后'); + return; + } + var result = BaseModel.fromJson(responseData.data); + if (result.code == 0) { + showSuccessToast("操作成功"); + } + dismissLoading(); + + if (status == 1) { + item.status = ReservationStatus.completed; + } else if (status == 2) { + item.status = ReservationStatus.rejected; + } + updateUi(); + } catch (e) { + dismissLoading(); + } } String leftHydrogen = ""; String orderAmount = ""; String completedAmount = ""; + String name = ""; Future renderData() async { try { @@ -138,8 +249,12 @@ class SiteController extends GetxController with BaseControllerMixin { leftHydrogen = result.data["leftHydrogen"] ?? ""; orderAmount = result.data["orderAmount"].toString(); completedAmount = result.data["completedAmount"].toString(); + name = result.data["name"].toString(); - leftHydrogen = leftHydrogen.isEmpty ? "统计中" : leftHydrogen; + leftHydrogen = leftHydrogen.isEmpty ? "统计中" : leftHydrogen.toString(); + + //加载列表数据 + fetchReservationData(); } catch (e) { showToast('数据异常'); } 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 4fadf8b..046dad5 100644 --- a/ln_jq_app/lib/pages/b_page/site/view.dart +++ b/ln_jq_app/lib/pages/b_page/site/view.dart @@ -3,6 +3,7 @@ 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}); @@ -236,14 +237,14 @@ class SitePage extends GetView { itemBuilder: (context, index) { final item = controller.reservationList[index]; // 调用新的方法来构建每一项 - return _buildReservationItem(item); + return _buildReservationItem(index, item); }, separatorBuilder: (context, index) => const SizedBox(height: 12), // 列表项之间的间距 ), ); } - Widget _buildReservationItem(ReservationModel item) { + Widget _buildReservationItem(int index, ReservationModel item) { return Container( decoration: BoxDecoration( color: Colors.white, @@ -275,7 +276,7 @@ class SitePage extends GetView { shape: BoxShape.circle, ), child: Text( - item.id, + "${index + 1}", style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, @@ -373,6 +374,10 @@ class SitePage extends GetView { text = '已拒绝'; color = Colors.red; break; + default: + text = '未知状态'; + color = Colors.grey; + break; } return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),