vehicle_apply_controller.dart 4.7 KB

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