142 lines
4.4 KiB
Dart
142 lines
4.4 KiB
Dart
import 'dart:async';
|
||
import 'package:autosos_flutter/api/order_api.dart';
|
||
import 'package:autosos_flutter/config/constant.dart';
|
||
import 'package:autosos_flutter/model/order.dart';
|
||
import 'package:autosos_flutter/model/payment.dart';
|
||
import 'package:autosos_flutter/service/audio_service.dart';
|
||
import 'package:autosos_flutter/service/location_service.dart';
|
||
import 'package:flutter/foundation.dart';
|
||
|
||
/// 订单状态机 + 业务编排服务(对应 Android 订单状态机)
|
||
class OrderService {
|
||
static final OrderService instance = OrderService._();
|
||
OrderService._();
|
||
|
||
Order? _current;
|
||
Order? get currentOrder => _current;
|
||
|
||
/// 状态变化回调
|
||
final _stateController = StreamController<OrderStateEvent>.broadcast();
|
||
Stream<OrderStateEvent> get stateStream => _stateController.stream;
|
||
|
||
/// 救援中(conducting)→ 上报当前位置的轨迹点
|
||
Timer? _trackUploadTimer;
|
||
|
||
/// 设置当前订单
|
||
void setCurrent(Order? order) {
|
||
_current = order;
|
||
if (order != null) {
|
||
Constant.isService = order.status == OrderStatus.conducting;
|
||
_stateController.add(OrderStateEvent.updated(order));
|
||
}
|
||
}
|
||
|
||
/// 接单
|
||
Future<Order> grab(int orderId) async {
|
||
final resp = await OrderApi.instance.grabOrder(orderId);
|
||
if (!resp.isSuccess) throw Exception(resp.message ?? '接单失败');
|
||
final order = resp.data!;
|
||
setCurrent(order);
|
||
return order;
|
||
}
|
||
|
||
/// 到达现场
|
||
Future<void> arrive({double? lat, double? lng}) async {
|
||
if (_current == null) throw Exception('当前无进行中订单');
|
||
final loc = LocationService.instance.last;
|
||
final r = await OrderApi.instance.arriveScene(
|
||
_current!.id,
|
||
lat: lat ?? (loc?['latitude'] as num?)?.toDouble(),
|
||
lng: lng ?? (loc?['longitude'] as num?)?.toDouble(),
|
||
);
|
||
if (!r.isSuccess) throw Exception(r.message ?? '上报到达失败');
|
||
final updated = _current!.copyWith(
|
||
status: OrderStatus.conducting,
|
||
arrivedAt: DateTime.now(),
|
||
);
|
||
setCurrent(updated);
|
||
_startTrack();
|
||
}
|
||
|
||
/// 完成订单
|
||
Future<dynamic> complete({
|
||
required List<AmountItem> amountItems,
|
||
String? remark,
|
||
}) async {
|
||
if (_current == null) throw Exception('当前无订单');
|
||
final r = await OrderApi.instance.completeOrder(
|
||
orderId: _current!.id,
|
||
amountItems: amountItems,
|
||
remark: remark,
|
||
);
|
||
if (!r.isSuccess) throw Exception(r.message ?? '完成订单失败');
|
||
_stopTrack();
|
||
setCurrent(_current!.copyWith(
|
||
status: OrderStatus.completed,
|
||
completedAt: DateTime.now(),
|
||
));
|
||
return r.data;
|
||
}
|
||
|
||
/// 取消订单
|
||
Future<void> cancel() async {
|
||
if (_current == null) return;
|
||
_stopTrack();
|
||
setCurrent(_current!.copyWith(status: OrderStatus.cancelled));
|
||
}
|
||
|
||
/// 启动轨迹上传
|
||
void _startTrack() {
|
||
_trackUploadTimer?.cancel();
|
||
_trackUploadTimer = Timer.periodic(const Duration(seconds: 10), (_) async {
|
||
if (_current == null) return;
|
||
final loc = LocationService.instance.last;
|
||
if (loc == null) return;
|
||
try {
|
||
await OrderApi.instance.uploadTrackPoints(_current!.id, [
|
||
{
|
||
'lat': (loc['latitude'] as num?)?.toDouble() ?? 0,
|
||
'lng': (loc['longitude'] as num?)?.toDouble() ?? 0,
|
||
'time': DateTime.now().toIso8601String(),
|
||
'speed': (loc['speed'] as num?)?.toDouble() ?? 0,
|
||
'bearing': (loc['bearing'] as num?)?.toDouble() ?? 0,
|
||
}
|
||
]);
|
||
} catch (e) {
|
||
debugPrint('Track upload failed: $e');
|
||
}
|
||
});
|
||
}
|
||
|
||
/// 停止轨迹上传
|
||
void _stopTrack() {
|
||
_trackUploadTimer?.cancel();
|
||
_trackUploadTimer = null;
|
||
}
|
||
|
||
/// 收到新订单推送时触发本地语音提醒
|
||
Future<void> onPushNewOrder(Map<String, dynamic> payload) async {
|
||
final type = (payload['type'] as num?)?.toInt() ?? 0;
|
||
if (type == Constant.NEW_ORDER_INSIDE) {
|
||
AudioService.instance.newInsideOrder();
|
||
} else if (type == Constant.NEW_ORDER_JIUJIU) {
|
||
AudioService.instance.newJiuJiuOrder();
|
||
}
|
||
}
|
||
|
||
void dispose() {
|
||
_stopTrack();
|
||
_stateController.close();
|
||
}
|
||
}
|
||
|
||
/// 订单状态变化事件
|
||
class OrderStateEvent {
|
||
final OrderStateEventType type;
|
||
final Order? order;
|
||
const OrderStateEvent(this.type, this.order);
|
||
|
||
factory OrderStateEvent.updated(Order o) => OrderStateEvent(OrderStateEventType.updated, o);
|
||
}
|
||
|
||
enum OrderStateEventType { updated, completed, cancelled, paid } |