jjsos_autosos_flutter/lib/service/order_service.dart

142 lines
4.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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 }