vehicle_apply_controller.dart 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import 'package:flutter_riverpod/flutter_riverpod.dart';
  2. import 'vehicle_model.dart';
  3. import 'vehicle_api.dart';
  4. class VehicleApplyState {
  5. final VehicleModel vehicle;
  6. final bool isSubmitting;
  7. final bool hasConflict;
  8. final List<String> passengers;
  9. const VehicleApplyState({
  10. required this.vehicle,
  11. this.isSubmitting = false,
  12. this.hasConflict = false,
  13. this.passengers = const [],
  14. });
  15. VehicleApplyState copyWith({
  16. VehicleModel? vehicle,
  17. bool? isSubmitting,
  18. bool? hasConflict,
  19. List<String>? passengers,
  20. }) => VehicleApplyState(
  21. vehicle: vehicle ?? this.vehicle,
  22. isSubmitting: isSubmitting ?? this.isSubmitting,
  23. hasConflict: hasConflict ?? this.hasConflict,
  24. passengers: passengers ?? this.passengers,
  25. );
  26. }
  27. class VehicleApplyController extends StateNotifier<VehicleApplyState> {
  28. final VehicleApi _api;
  29. VehicleApplyController(this._api)
  30. : super(
  31. VehicleApplyState(
  32. vehicle: VehicleModel(
  33. id: '',
  34. applicationNo: '',
  35. applicantId: '',
  36. applicantName: '',
  37. deptId: '',
  38. deptName: '',
  39. purpose: '',
  40. reason: '',
  41. origin: '',
  42. destination: '',
  43. startTime: DateTime.now(),
  44. endTime: DateTime.now().add(const Duration(hours: 4)),
  45. createTime: DateTime.now(),
  46. updateTime: DateTime.now(),
  47. ),
  48. ),
  49. );
  50. void updateVehicleId(String v) {
  51. state = state.copyWith(vehicle: state.vehicle.copyWith(vehicleId: v));
  52. _checkConflict();
  53. }
  54. void updatePurpose(String v) =>
  55. state = state.copyWith(vehicle: state.vehicle.copyWith(purpose: v));
  56. void updateReason(String v) =>
  57. state = state.copyWith(vehicle: state.vehicle.copyWith(reason: v));
  58. void updateOrigin(String v) =>
  59. state = state.copyWith(vehicle: state.vehicle.copyWith(origin: v));
  60. void updateOriginCoords(double? lng, double? lat) => state = state.copyWith(
  61. vehicle: state.vehicle.copyWith(originLongitude: lng, originLatitude: lat),
  62. );
  63. void updateDestination(String v) =>
  64. state = state.copyWith(vehicle: state.vehicle.copyWith(destination: v));
  65. void updateDestCoords(double? lng, double? lat) => state = state.copyWith(
  66. vehicle: state.vehicle.copyWith(destLongitude: lng, destLatitude: lat),
  67. );
  68. void updateStartTime(DateTime t) {
  69. state = state.copyWith(vehicle: state.vehicle.copyWith(startTime: t));
  70. _checkConflict();
  71. }
  72. void updateEndTime(DateTime t) {
  73. state = state.copyWith(vehicle: state.vehicle.copyWith(endTime: t));
  74. _checkConflict();
  75. }
  76. void updatePassengerCount(int v) => state = state.copyWith(
  77. vehicle: state.vehicle.copyWith(passengerCount: v < 1 ? 1 : v),
  78. );
  79. void addPassenger(String name) {
  80. if (!state.passengers.contains(name)) {
  81. state = state.copyWith(passengers: [...state.passengers, name]);
  82. }
  83. }
  84. void removePassenger(String name) {
  85. state = state.copyWith(
  86. passengers: state.passengers.where((p) => p != name).toList(),
  87. );
  88. }
  89. /// Mock conflict detection
  90. void _checkConflict() {
  91. final vid = state.vehicle.vehicleId;
  92. if (vid.isEmpty) {
  93. state = state.copyWith(hasConflict: false);
  94. return;
  95. }
  96. // Mock: 车牌 '京A88888' 在所选时段冲突
  97. final hasConflict =
  98. vid == '京A88888' &&
  99. state.vehicle.startTime.isBefore(DateTime(2026, 6, 4, 12, 0));
  100. state = state.copyWith(hasConflict: hasConflict);
  101. }
  102. bool validate() {
  103. final v = state.vehicle;
  104. if (v.vehicleId.isEmpty) return false;
  105. if (v.reason.trim().isEmpty) return false;
  106. if (v.purpose.isEmpty) return false;
  107. if (!v.endTime.isAfter(v.startTime)) return false;
  108. if (state.hasConflict) return false;
  109. return true;
  110. }
  111. Future<bool> submit() async {
  112. if (!validate()) return false;
  113. state = state.copyWith(isSubmitting: true);
  114. try {
  115. await _api.submit(state.vehicle.copyWith(status: 'pending'));
  116. return true;
  117. } catch (_) {
  118. return false;
  119. } finally {
  120. state = state.copyWith(isSubmitting: false);
  121. }
  122. }
  123. Future<bool> saveDraft() async {
  124. state = state.copyWith(isSubmitting: true);
  125. try {
  126. await _api.saveDraft(state.vehicle);
  127. return true;
  128. } catch (_) {
  129. return false;
  130. } finally {
  131. state = state.copyWith(isSubmitting: false);
  132. }
  133. }
  134. }
  135. final vehicleApplyProvider = StateNotifierProvider.autoDispose
  136. .family<VehicleApplyController, VehicleApplyState, String?>((ref, editId) {
  137. return VehicleApplyController(ref.read(vehicleApiProvider));
  138. });