value, OrderStatus::ACCEPTED->value, OrderStatus::DEPARTED->value, OrderStatus::ARRIVED->value, ]; abort_if(! in_array($order->state, $allowedStates), 422, '当前订单状态不允许更换技师'); // 记录原技师ID $oldCoachId = $order->coach_id; // 更新订单技师 $order->coach_id = $data['new_coach_id']; $order->save(); // 记录技师更换历史 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => Auth::user()->id, 'object_type' => 'admin', 'old_coach_id' => $oldCoachId, 'new_coach_id' => $data['new_coach_id'], 'state' => OrderRecordStatus::CHANGE_COACH->value, 'remark' => $data['reason'] ?? null, ]); DB::commit(); return [ 'code' => 200, 'message' => '更换技师成功', 'data' => null, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('更换订单技师失败', [ 'order_id' => $data['order_id'], 'new_coach_id' => $data['new_coach_id'], 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 指定抢单技师 * * @param array $data 包含 order_id, coach_id 和可选的 remark */ public function assignOrderCoach(array $data): array { try { DB::beginTransaction(); // 获取订单信息 $order = Order::findOrFail($data['order_id']); // 验证订单状态是否为待抢单 abort_if($order->state !== OrderStatus::CREATED->value, 422, '当前订单状态不允许指定技师'); // 更新订单技师和状态 $order->coach_id = $data['coach_id']; $order->state = OrderStatus::ASSIGNED->value; $order->save(); // 记录指定技师历史 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => Auth::user()->id, 'object_type' => 'admin', 'old_coach_id' => null, 'new_coach_id' => $data['coach_id'], 'state' => OrderRecordStatus::ASSIGNED->value, 'remark' => $data['remark'] ?? '平台指派', ]); DB::commit(); return [ 'code' => 200, 'message' => '指定技师成功', 'data' => null, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('指定抢单技师失败', [ 'order_id' => $data['order_id'], 'coach_id' => $data['coach_id'], 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 获取订单抢单技师列表 * * @param int $orderId 订单ID */ public function getOrderGrabList(int $orderId): array { try { // 获取订单信息 $order = Order::findOrFail($orderId); // 获取抢单记录 $grabRecords = OrderGrabRecord::with(['coach', 'coach.info']) ->where('order_id', $orderId) ->orderBy('created_at', 'desc') ->get(); $data = $grabRecords->map(function ($record) { return [ 'id' => $record->id, 'coach_id' => $record->coach_id, 'nickname' => $record->coach->info->nickname ?? '', 'avatar' => $record->coach->info->avatar ?? '', 'distance' => $record->distance, 'state' => $record->state, 'created_at' => $record->created_at->format('Y-m-d H:i:s'), ]; }); return [ 'code' => 200, 'message' => '获取成功', 'data' => $data, ]; } catch (\Exception $e) { Log::error('获取订单抢单技师列表失败', [ 'order_id' => $orderId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 获取附近技师列表 * * @param int $orderId 订单ID * @param int $distance 搜索范围(米) */ public function getNearbyCoaches(int $orderId, int $distance = 5000): array { try { // 获取订单信息 $order = Order::findOrFail($orderId); // 获取附近技师 // TODO: 优化查询 $nearbyCoaches = CoachLocation::with(['coach', 'coach.info', 'coach.score']) ->selectRaw('*, ST_Distance_Sphere( point(longitude, latitude), point(?, ?) ) as distance', [$order->longitude, $order->latitude]) ->having('distance', '<=', $distance) ->orderBy('distance') ->get(); $data = $nearbyCoaches->map(function ($location) { return [ 'id' => $location->coach->id, 'nickname' => $location->coach->info->nickname ?? '', 'avatar' => $location->coach->info->avatar ?? '', 'distance' => round($location->distance / 1000, 1), // 转换公里 'work_status' => $location->coach->work_status, 'work_status_text' => TechnicianWorkStatus::fromValue($location->coach->work_status)->label(), 'rating' => $location->coach->score->rating_score ?? 5.0, 'order_count' => $location->coach->score->order_count ?? 0, 'created_at' => $location->coach->created_at->format('Y-m-d H:i:s'), ]; }); return [ 'code' => 200, 'message' => '获取成功', 'data' => $data, ]; } catch (\Exception $e) { Log::error('获取附近技师列表失败', [ 'order_id' => $orderId, 'distance' => $distance, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 重置订单技师 * * @param array $data 包含 order_id 和可选的 reason */ public function resetOrderCoach(array $data): array { try { DB::beginTransaction(); // 获取订单信息 $order = Order::findOrFail($data['order_id']); // 验证订单状态是否允许重置技师 $allowedStates = [ OrderStatus::PAID->value, OrderStatus::ACCEPTED->value, OrderStatus::DEPARTED->value, OrderStatus::ARRIVED->value, ]; abort_if(! in_array($order->state, $allowedStates), 422, '当前订单状态不允许重置技师'); // 记录原技师ID $oldCoachId = $order->coach_id; // 更新订单信息 $order->coach_id = null; $order->state = OrderStatus::PAID->value; // 重置为支付状态 $order->save(); // 记录技师重置历史 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => Auth::user()->id, 'object_type' => 'admin', 'old_coach_id' => $oldCoachId, 'new_coach_id' => null, 'state' => OrderRecordStatus::RESET_COACH->value, 'remark' => $data['reason'] ?? null, ]); DB::commit(); return [ 'code' => 200, 'message' => '重置技师成功', 'data' => null, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('重置订单技师失败', [ 'order_id' => $data['order_id'], 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 临时接单 * * @param array $data 包含 order_id 和可选的 reason */ public function temporaryAcceptOrder(array $data): array { try { DB::beginTransaction(); // 获取订单信息 $order = Order::findOrFail($data['order_id']); // 验证订单状态是否为已支付状态 abort_if($order->state !== OrderStatus::PAID->value, 422, '当前订单状态不允许接单'); // 验证订单必须已指定技师 abort_if(empty($order->coach_id), 422, '订单未指定技师'); // 更新订单信息 $order->state = OrderStatus::ACCEPTED->value; // 更新为已接单状态 $order->save(); // 记录临时接单历史 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => Auth::user()->id, 'object_type' => 'admin', 'old_coach_id' => null, 'new_coach_id' => $order->coach_id, 'state' => OrderRecordStatus::TEMPORARY_ACCEPTED->value, 'remark' => $data['reason'] ?? '平台临时接单', ]); DB::commit(); return [ 'code' => 200, 'message' => '接单成功', 'data' => null, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('临时接单失败', [ 'order_id' => $data['order_id'], 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 开始服务 * * @param array $data 包含 order_id 和可选的 reason */ public function startOrderService(array $data): array { try { DB::beginTransaction(); // 获取订单信息 $order = Order::findOrFail($data['order_id']); // 验证订单状态是否允许开始服务 $allowedStates = [ OrderStatus::ACCEPTED->value, OrderStatus::DEPARTED->value, OrderStatus::ARRIVED->value, ]; abort_if(! in_array($order->state, $allowedStates), 422, '当前订单状态不允许开始服务'); // 更新订单状态 $order->state = OrderStatus::STARTED->value; $order->save(); // 记录开始服务历史 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => Auth::user()->id, 'object_type' => 'admin', 'old_coach_id' => $order->coach_id, 'new_coach_id' => $order->coach_id, 'state' => OrderRecordStatus::STARTED->value, 'remark' => $data['reason'] ?? '平台代扫核销码', ]); DB::commit(); return [ 'code' => 200, 'message' => '开始服务成功', 'data' => null, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('开始服务失败', [ 'order_id' => $data['order_id'], 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 结束服务 * * @param array $data 包含 order_id 和可选的 reason */ public function endOrderService(array $data): array { try { DB::beginTransaction(); // 获取订单信息 $order = Order::findOrFail($data['order_id']); // 验证订单状态是否为已开始服务状态 abort_if($order->state !== OrderStatus::STARTED->value, 422, '当前订单状态不允许结束服务'); // 更新订单状态 $order->state = OrderStatus::LEFT->value; $order->save(); // 记录结束服务历史 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => Auth::user()->id, 'object_type' => 'admin', 'old_coach_id' => $order->coach_id, 'new_coach_id' => $order->coach_id, 'state' => OrderRecordStatus::LEFT->value, 'remark' => $data['reason'] ?? '平台代确认撤离', ]); DB::commit(); return [ 'code' => 200, 'message' => '结束服务成功', 'data' => null, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('结束服务失败', [ 'order_id' => $data['order_id'], 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } /** * 处理报警 * * @param array $data 包含 exc_record_id 和 handle_result */ public function handleOrderAlarm(array $data): array { try { DB::beginTransaction(); // 获取并验证异常记录 $excRecord = OrderExcRecord::where('id', $data['exc_record_id']) ->firstOrFail(); // 获取关联的订单信息 $order = Order::findOrFail($excRecord->order_id); // 更新异常记录状态 $excRecord->handle_result = $data['handle_result']; $excRecord->handler_id = Auth::user()->id; $excRecord->handle_time = now(); $excRecord->save(); // 记录处理历史 OrderRecord::create([ 'order_id' => $order->id, 'object_id' => Auth::user()->id, 'object_type' => 'admin', 'old_coach_id' => $order->coach_id, 'new_coach_id' => $order->coach_id, 'state' => OrderRecordStatus::ALARM_HANDLED->value, 'remark' => $data['handle_result'], ]); DB::commit(); return [ 'code' => 200, 'message' => '处理成功', 'data' => null, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('处理报警失败', [ 'exc_record_id' => $data['exc_record_id'], 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw $e; } } }