|
@@ -724,4 +724,116 @@ class OrderService
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 技师扫码开始服务
|
|
|
+ *
|
|
|
+ * @param int $userId 技师用户ID
|
|
|
+ * @param int $orderId 订单ID
|
|
|
+ * @param string $qrCode 客户二维码
|
|
|
+ */
|
|
|
+ public function startService(int $userId, int $orderId, string $qrCode): array
|
|
|
+ {
|
|
|
+ return DB::transaction(function () use ($userId, $orderId, $qrCode) {
|
|
|
+ try {
|
|
|
+ // 获取技师信息
|
|
|
+ $user = MemberUser::with(['coach'])->findOrFail($userId);
|
|
|
+ $coach = $user->coach;
|
|
|
+ abort_if(! $coach, 404, '技师信息不存在');
|
|
|
+
|
|
|
+ // 获取订单信息
|
|
|
+ $order = Order::query()
|
|
|
+ ->where('id', $orderId)
|
|
|
+ ->lockForUpdate()
|
|
|
+ ->first();
|
|
|
+ abort_if(! $order, 404, '订单不存在');
|
|
|
+
|
|
|
+ // 检查是否是该技师的订单
|
|
|
+ abort_if($order->coach_id !== $coach->id, 403, '无权操作此订单');
|
|
|
+
|
|
|
+ // 检查订单状态
|
|
|
+ abort_if(! in_array($order->state, [
|
|
|
+ OrderStatus::ARRIVED->value,
|
|
|
+ OrderStatus::PAID->value,
|
|
|
+ ]), 400, '订单状态不正确');
|
|
|
+
|
|
|
+ // 验证二维码
|
|
|
+ $this->validateQrCode($order, $qrCode);
|
|
|
+
|
|
|
+ $now = now();
|
|
|
+
|
|
|
+ // 更新订单状态为服务中
|
|
|
+ $order->state = OrderStatus::SERVING->value;
|
|
|
+ $order->save();
|
|
|
+
|
|
|
+ // 记录订单状态变更日志
|
|
|
+ OrderRecord::create([
|
|
|
+ 'order_id' => $orderId,
|
|
|
+ 'state' => OrderRecordStatus::STARTED->value,
|
|
|
+ 'object_id' => $coach->id,
|
|
|
+ 'object_type' => CoachUser::class,
|
|
|
+ 'remark' => '开始服务',
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // TODO: 发送通知给用户
|
|
|
+ // event(new ServiceStartedEvent($order));
|
|
|
+
|
|
|
+ Log::info('技师开始服务', [
|
|
|
+ 'coach_id' => $coach->id,
|
|
|
+ 'order_id' => $orderId,
|
|
|
+ 'service_start_time' => $now,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'status' => true,
|
|
|
+ 'message' => '开始服务成功',
|
|
|
+ 'data' => [
|
|
|
+ 'order_id' => $orderId,
|
|
|
+ 'status' => $order->state,
|
|
|
+ 'service_start_time' => $now,
|
|
|
+ ],
|
|
|
+ ];
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('开始服务失败', [
|
|
|
+ 'user_id' => $userId,
|
|
|
+ 'order_id' => $orderId,
|
|
|
+ 'qr_code' => $qrCode,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'trace' => $e->getTraceAsString(),
|
|
|
+ ]);
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证客户二维码
|
|
|
+ *
|
|
|
+ * @param Order $order 订单对象
|
|
|
+ * @param string $qrCode 扫描的二维码
|
|
|
+ */
|
|
|
+ private function validateQrCode(Order $order, string $qrCode): void
|
|
|
+ {
|
|
|
+ // 二维码格式: order_{order_id}_{timestamp}_{sign}
|
|
|
+ $parts = explode('_', $qrCode);
|
|
|
+ abort_if(count($parts) !== 4, 400, '二维码格式错误');
|
|
|
+
|
|
|
+ [$prefix, $scanOrderId, $timestamp, $sign] = $parts;
|
|
|
+
|
|
|
+ // 验证前缀
|
|
|
+ abort_if($prefix !== 'order', 400, '无效的二维码');
|
|
|
+
|
|
|
+ // 验证订单ID
|
|
|
+ abort_if((int) $scanOrderId !== $order->id, 400, '二维码与订单不匹配');
|
|
|
+
|
|
|
+ // 验证时间戳(二维码5分钟内有效)
|
|
|
+ $qrTimestamp = (int) $timestamp;
|
|
|
+ $now = time();
|
|
|
+ abort_if($now - $qrTimestamp > 300, 400, '二维码已过期');
|
|
|
+
|
|
|
+ // 验证签名
|
|
|
+ $correctSign = md5("order_{$order->id}_{$timestamp}_".config('app.key'));
|
|
|
+ abort_if($sign !== $correctSign, 400, '二维码签名错误');
|
|
|
+ }
|
|
|
}
|