ソースを参照

Merge branch 'master' of ssh://gogs.yinbin.ink:30004/didong/owl-admin

Yin Bin 4 ヶ月 前
コミット
aede2e6bcf

+ 34 - 0
app/DTO/OrderAmount.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\DTO;
+
+class OrderAmount
+{
+    public float $total_amount;
+
+    public float $balance_amount;
+
+    public float $pay_amount;
+
+    public float $coupon_amount;
+
+    public float $project_amount;
+
+    public float $delivery_fee;
+
+    public function __construct(
+        float $total_amount,
+        float $balance_amount,
+        float $pay_amount,
+        float $coupon_amount,
+        float $project_amount,
+        float $delivery_fee
+    ) {
+        $this->total_amount = $total_amount;
+        $this->balance_amount = $balance_amount;
+        $this->pay_amount = $pay_amount;
+        $this->coupon_amount = $coupon_amount;
+        $this->project_amount = $project_amount;
+        $this->delivery_fee = $delivery_fee;
+    }
+}

+ 3 - 1
app/Http/Controllers/Client/OrderController.php

@@ -246,6 +246,7 @@ class OrderController extends Controller
      * @bodyParam project_id int required 项目ID. Example: 1
      * @bodyParam agent_id int 代理商ID. Example: 1
      * @bodyParam use_balance boolean 使用余额. Example: 0
+     * @bodyParam distance float 距离. Example: 0
      *
      * @response {
      *   "total_amount": 0,
@@ -265,8 +266,9 @@ class OrderController extends Controller
         $projectId = $request->input('project_id');
         $agentId = $request->input('agent_id');
         $useBalance = $request->input('use_balance', 0);
+        $distance = $request->input('distance', 0);
 
-        return $this->service->calculateOrderAmount($userId, $addressId, $coachId, $projectId, $agentId, $useBalance);
+        return $this->service->calculateOrderAmount($userId, $addressId, $coachId, $projectId, $agentId, $useBalance, $distance);
     }
 
     /**

+ 698 - 493
app/Services/Client/OrderService.php

@@ -5,9 +5,7 @@ namespace App\Services\Client;
 use App\Models\AgentConfig;
 use App\Models\AgentInfo;
 use App\Models\CoachConfig;
-use App\Models\CoachSchedule;
 use App\Models\CoachUser;
-use App\Models\Coupon;
 use App\Models\MemberUser;
 use App\Models\Order;
 use App\Models\OrderGrabRecord;
@@ -16,7 +14,6 @@ use App\Models\Project;
 use App\Models\SysConfig;
 use App\Models\User;
 use App\Models\WalletRefundRecord;
-use Carbon\Carbon;
 use Exception;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
@@ -39,76 +36,74 @@ class OrderService
     /**
      * 订单初始化
      */
-    public function initialize($userId, $data)
+    public function initialize(int $userId, array $data): array
     {
-        $user = MemberUser::find($userId);
+        try {
+            // 参数验证
+            abort_if(empty($data), 400, '订单初始化参数不能为空');
 
-        if (! $user) {
-            throw new Exception('用户不存在');
-        }
+            DB::beginTransaction();
+            try {
+                $user = MemberUser::find($userId);
+                abort_if(! $user || $user->state != 'enable', 400, '用户状态异常');
 
-        if ($user->state != 'enable') {
-            throw new Exception('用户状态异常');
-        }
+                // 查询用户钱包
+                $wallet = $user->wallet;
 
-        // 查询用户钱包
-        $wallet = $user->wallet;
-
-        // 查询默认地址
-        $address = $user->address;
-
-        $areaCode = $address ? $address->area_code : $data['area_code'];
-
-        // 查询技师数据
-        $coach = CoachUser::where('state', 'enable')
-            ->whereHas('info', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->whereHas('real', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->whereHas('qual', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->with(['info:id,nickname,avatar,gender'])
-            ->find($data['coach_id']);
-
-        if (! $coach) {
-            throw new Exception('技师不存在');
-        }
+                // 查询默认地址
+                $address = $user->address;
 
-        // 查询技师排班
-        // $schedule = CoachSchedule::where('coach_id', $coachId)
-        //     ->where('date', date('Y-m-d'))
-        //     ->first();
+                $areaCode = $address ? $address->area_code : $data['area_code'];
 
-        // // 查询用户优惠券
-        // $coupons = Coupon::where('user_id', $userId)
-        //     ->where('state', 'enable')
-        //     ->where('expire_time', '>', now())
-        //     ->get();
+                // 查询技师数据
+                $coach = $this->validateCoach($data['coach_id']);
 
-        // 获取项目详情
-        $project = $this->projectService->getProjectDetail($data['project_id'], $areaCode);
+                // 查询技师排班
+                // $schedule = CoachSchedule::where('coach_id', $coachId)
+                //     ->where('date', date('Y-m-d'))
+                //     ->first();
 
-        // 计算订单金额
-        $amounts = $this->calculateOrderAmount($userId, $address?->id, $data['coach_id'], $data['project_id'], $project?->agent_id);
+                // // 查询用户优惠券
+                // $coupons = Coupon::where('user_id', $userId)
+                //     ->where('state', 'enable')
+                //     ->where('expire_time', '>', now())
+                //     ->get();
 
-        return [
-            'wallet' => $wallet,
-            'coach' => $coach,
-            'project' => $project,
-            'address' => $address,
-            // 'schedule' => $schedule,
-            'amounts' => $amounts,
-            // 'coupons' => $coupons
-        ];
+                // 获取项目详情
+                $project = $this->projectService->getProjectDetail($data['project_id'], $areaCode);
+
+                // 计算订单金额
+                $amounts = $this->calculateOrderAmount($userId, $address?->id, $data['coach_id'], $data['project_id'], $project?->agent_id);
+
+                DB::commit();
+
+                return [
+                    'wallet' => $wallet,
+                    'coach' => $coach,
+                    'project' => $project,
+                    'address' => $address,
+                    // 'schedule' => $schedule,
+                    'amounts' => $amounts,
+                    // 'coupons' => $coupons
+                ];
+            } catch (\Exception $e) {
+                DB::rollBack();
+                throw $e;
+            }
+        } catch (\Exception $e) {
+            Log::error('订单初始化失败', [
+                'userId' => $userId,
+                'data' => $data,
+                'error' => $e->getMessage(),
+            ]);
+            throw $e;
+        }
     }
 
     /**
      * 创建订单
      */
-    public function createOrder($userId, array $data)
+    public function createOrder(int $userId, array $data): array
     {
         try {
             return DB::transaction(function () use ($userId, $data) {
@@ -124,42 +119,26 @@ class OrderService
                 // 2. 创建订单
                 $orderType = isset($data['order_id']) ? 'add_time' : 'normal';
 
+                // 关键操作:验证必要参数
+                abort_if(empty($data['project_id']), 400, '项目ID不能为空');
+                abort_if(empty($data['service_time']), 400, '服务时间不能为空');
+                abort_if($orderType == 'normal' && empty($data['coach_id']), 400, '技师ID不能为空');
+                abort_if($orderType == 'normal' && empty($data['address_id']), 400, '地址ID不能为空');
+
                 if ($orderType == 'normal') {
+                    // 普通订单验证技师
+                    $coach = $this->validateCoach($data['coach_id']);
+                } else {
+                    // 加钟订单验证
+                    $originalOrder = $this->getOriginalOrder($user, $data['order_id']);
 
-                    // 查询技师及其认证状态
-                    $coach = CoachUser::where('id', $data['coach_id'])
-                        ->where('state', 'enable')
-                        ->whereHas('info', function ($query) {
-                            $query->where('state', 'approved');
-                        })
-                        ->whereHas('qual', function ($query) {
-                            $query->where('state', 'approved');
-                        })
-                        ->whereHas('real', function ($query) {
-                            $query->where('state', 'approved');
-                        })
-                        ->firstOrFail();
+                    // 关键操作:验证原订单技师状态
+                    $coach = $this->validateCoach($originalOrder->coach_id);
 
-                } else {
-                    // 1. 检查原订单
-                    $originalOrder = $user->orders->where('id', $data['order_id'])
-                        ->whereIn('state', ['service_ing', 'service_end']) // 只有服务中和服务结束的订单可以加钟
-                        ->firstOrFail();
-
-                    // 2. 设置加钟订单的服务时间
-                    if ($originalOrder->state == 'service_ing') {
-                        // 服务中订单,加钟开始时间为原订单结束时间
-                        $startTime = now(); // Carbon::parse($originalOrder->service_time)->addMinutes($originalOrder->project->duration);
-                    } else {
-                        // 服务结束订单,加钟开始时间为当前时间
-                        $startTime = now();
-                    }
+                    // 关键操作:验证原订单状态
+                    abort_if(! in_array($originalOrder->state, ['service_ing', 'service_end']), 400, '原订单状态不允许加钟');
 
-                    // 3. 构建加钟订单数据
-                    $data['order_id'] = $data['order_id']; // 关联原订单ID
-                    $data['address_id'] = $originalOrder->address_id;
-                    $data['service_time'] = $startTime;
-                    $data['coach_id'] = $originalOrder->coach_id;
+                    $data = $this->prepareAddTimeData($originalOrder, $data);
                 }
 
                 $address = $user->addresses()
@@ -167,79 +146,23 @@ class OrderService
                     ->firstOrFail();
 
                 // 计算订单金额
-                $amounts = $this->calculateOrderAmount(
-                    $userId,
-                    $data['address_id'],
-                    $data['coach_id'],
-                    $data['project_id'],
-                    $project->agent_id,
-                    $data['use_balance'] ?? false
-                );
-
-                $order = new Order;
-
-                $order->user_id = $userId;
-                $order->project_id = $data['project_id'];
-                $order->coach_id = $data['coach_id'];
-                $order->type = $orderType;
-                $order->state = 'wait_pay';
-                $order->source = 'platform';
-                $order->total_amount = $amounts['total_amount'];
-                $order->balance_amount = $amounts['balance_amount'];
-                $order->pay_amount = $amounts['pay_amount'];
-                $order->project_amount = $amounts['project_amount'];
-                $order->traffic_amount = $orderType == 'add_time' ? 0 : $amounts['delivery_fee'];
-                $order->payment_type = ($data['use_balance'] && $amounts['pay_amount'] == 0) ? 'balance' : null;
-
-                $order->service_time = $data['service_time'];
-
-                // 从用户地址获取位置信息
-                $order->address_id = $data['address_id'];
-                $order->longitude = $address->longitude; // 经度
-                $order->latitude = $address->latitude;   // 纬度
-                $order->location = $address->location;   // 定位地址
-                $order->address = $address->address;     // 详细地址
-                $order->area_code = $address->area_code; // 行政区划代码
+                $amounts = $this->calculateOrderAmount($userId, $address->id, $data['coach_id'], $data['project_id'], $project->agent_id, $data['use_balance'] ?? false);
 
-                $order->save();
+                // 关键操作:验证订单金额
+                abort_if($amounts['total_amount'] <= 0, 400, '订单金额异常');
 
-                // 3. 创建订单记录
-                OrderRecord::create([
-                    'order_id' => $order->id,
-                    'object_id' => $userId,
-                    'object_type' => MemberUser::class,
-                    'state' => $orderType == 'add_time' ? 'add_time' : 'create',
-                    'remark' => $orderType == 'add_time' ? '加钟订单' : '创建订单',
-                ]);
+                // 关键操作:验证余额支付
+                if ($amounts['payment_type'] == 'balance') {
+                    $wallet = $user->wallet;
+                    abort_if($wallet->available_balance < $amounts['balance_amount'], 400, '可用余额不足');
+                }
 
-                // 4. 余额支付处理
+                // 创建订单记录
+                $order = $this->createOrderRecord($userId, $data, $orderType, $address, $amounts);
+
+                // 余额支付处理
                 if ($order->payment_type == 'balance') {
-                    $order->state = $orderType == 'normal' ? 'wait_receive' : 'service_ing';
-                    $order->save();
-
-                    // 创建订单支付记录
-                    OrderRecord::create([
-                        'order_id' => $order->id,
-                        'object_id' => $userId,
-                        'object_type' => MemberUser::class,
-                        'state' => 'pay',
-                        'remark' => '余额支付',
-                    ]);
-
-                    // 扣除用户钱包总余额
-                    $user->wallet->decrement('total_balance', $order->balance_amount);
-                    // 扣除用户钱包可用余额
-                    $user->wallet->decrement('available_balance', $order->balance_amount);
-                    $user->wallet->save();
-
-                    // 创建技师排班
-                    // CoachSchedule::create([
-                    //     'coach_id' => $data['coach_id'],
-                    //     'date' => date('Y-m-d'),
-                    //     'state' => 'busy',
-                    // ]);
-
-                    // TODO: 发送抢单通知
+                    $this->handleBalancePayment($user, $order, $orderType);
                 }
 
                 return [
@@ -257,146 +180,225 @@ class OrderService
         }
     }
 
+    // 提取方法:验证技师
+    public function validateCoach(int $coachId): CoachUser
+    {
+        $coach = CoachUser::where('id', $coachId)
+            ->where('state', 'enable')
+            ->whereHas('info', fn ($q) => $q->where('state', 'approved'))
+            ->whereHas('qual', fn ($q) => $q->where('state', 'approved'))
+            ->whereHas('real', fn ($q) => $q->where('state', 'approved'))
+            ->firstOrFail();
+
+        return $coach;
+    }
+
+    // 提取方法:获取原始订单
+    private function getOriginalOrder($user, $orderId): Order
+    {
+        $originalOrder = $user->orders->where('id', $orderId)
+            ->whereIn('state', ['service_ing', 'service_end'])
+            ->firstOrFail();
+
+        return $originalOrder;
+    }
+
+    // 提取方法:准备加钟订单数据
+    private function prepareAddTimeData($originalOrder, $data): array
+    {
+        if ($originalOrder->state == 'service_ing') {
+            $startTime = now();
+        } else {
+            $startTime = now();
+        }
+
+        return [
+            ...$data,
+            'order_id' => $data['order_id'],
+            'address_id' => $originalOrder->address_id,
+            'service_time' => $startTime,
+            'coach_id' => $originalOrder->coach_id,
+        ];
+    }
+
+    // 提取方法:创建订单记录
+    private function createOrderRecord($userId, $data, $orderType, $address, $amounts): Order
+    {
+        $order = new Order;
+        $order->user_id = $userId;
+        $order->project_id = $data['project_id'];
+        $order->coach_id = $data['coach_id'];
+        $order->type = $orderType;
+        $order->state = 'wait_pay';
+        $order->source = 'platform';
+        $order->total_amount = $amounts->total_amount;
+        $order->balance_amount = $amounts->balance_amount;
+        $order->pay_amount = $amounts->pay_amount;
+        $order->project_amount = $amounts->project_amount;
+        $order->traffic_amount = $orderType == 'add_time' ? 0 : $amounts->delivery_fee;
+        $order->payment_type = ($data['use_balance'] && $amounts->pay_amount == 0) ? 'balance' : null;
+        $order->service_time = $data['service_time'];
+        $order->address_id = $data['address_id'];
+        $order->longitude = $address->longitude;
+        $order->latitude = $address->latitude;
+        $order->location = $address->location;
+        $order->address = $address->address;
+        $order->area_code = $address->area_code;
+        $order->save();
+
+        OrderRecord::create([
+            'order_id' => $order->id,
+            'object_id' => $userId,
+            'object_type' => MemberUser::class,
+            'state' => $orderType == 'add_time' ? 'add_time' : 'create',
+            'remark' => $orderType == 'add_time' ? '加钟订单' : '创建订单',
+        ]);
+
+        return $order;
+    }
+
+    // 提取方法:处理余额支付
+    private function handleBalancePayment($user, $order, $orderType): void
+    {
+        $order->state = $orderType == 'normal' ? 'wait_receive' : 'service_ing';
+        $order->save();
+
+        OrderRecord::create([
+            'order_id' => $order->id,
+            'object_id' => $user->id,
+            'object_type' => MemberUser::class,
+            'state' => 'pay',
+            'remark' => '余额支付',
+        ]);
+
+        $user->wallet->decrement('total_balance', $order->balance_amount);
+        $user->wallet->decrement('available_balance', $order->balance_amount);
+        $user->wallet->save();
+    }
+
     /**
      * 取消订单
      */
-    public function cancelOrder($userId, $orderId)
+    public function cancelOrder(int $userId, int $orderId): array
     {
         return DB::transaction(function () use ($userId, $orderId) {
             try {
-                $user = MemberUser::where('id', $userId)->firstOrFail();
-                $order = $user->orders()->find($orderId);
-
-                if (! $order) {
-                    throw new Exception('订单不存在');
-                }
+                // 1. 验证用户和订单
+                $order = $this->validateOrderForCancel($userId, $orderId);
 
-                // 判断订单状态
-                if ($order->state == 'wait_receive') { // 已接单
-                    // 扣除20%费用
-                    $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.2;
-                    $this->handleRefund($user, $order, $deductAmount, false);
-                } elseif ($order->state == 'on_the_way') { // 已出发
-                    // 扣除50%费用并扣除路费
-                    $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.5;
-                    $this->handleRefund($user, $order, $deductAmount, true);
-                } elseif ($order->state == 'wait_pay') {
-                    // 待支付状态直接取消,无需退款
-                } else {
-                    throw new Exception('当前订单状态不允许取消');
-                }
-
-                // 添加订单取消记录
-                OrderRecord::create([
-                    'order_id' => $orderId,
-                    'object_id' => $userId,
-                    'object_type' => MemberUser::class,
-                    'state' => 'cancel',
-                    'remark' => '用户取消订单',
-                ]);
+                // 2. 处理退款
+                $this->handleCancelRefund($order);
 
-                // 修改订单状态
-                $order->state = 'cancel';
-                $order->save();
+                // 3. 完成订单取消
+                $this->completeCancel($order, $userId);
 
                 return ['message' => '订单已取消'];
+
             } catch (Exception $e) {
-                Log::error('取消订单失败:', [
-                    'message' => $e->getMessage(),
-                    'user_id' => $userId,
-                    'order_id' => $orderId,
-                ]);
+                $this->logCancelOrderError($e, $userId, $orderId);
                 throw $e;
             }
         });
     }
 
+    /**
+     * 验证订单取消条件
+     */
+    private function validateOrderForCancel(int $userId, int $orderId): Order
+    {
+        // 复用之前的用户验证逻辑
+        $user = MemberUser::where('id', $userId)
+            ->where('state', 'enable')
+            ->firstOrFail();
+
+        // 验证订单状态
+        $order = Order::where('user_id', $userId)
+            ->where('id', $orderId)
+            ->whereIn('state', ['wait_pay', 'wait_receive', 'on_the_way'])
+            ->lockForUpdate()
+            ->firstOrFail();
+
+        return $order;
+    }
+
+    /**
+     * 处理订单取消退款
+     */
+    private function handleCancelRefund(Order $order): void
+    {
+        $user = $order->user;
+
+        switch ($order->state) {
+            case 'wait_receive': // 已接单
+                // 扣除20%费用
+                $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.2;
+                $this->handleRefund($user, $order, $deductAmount, false);
+                break;
+
+            case 'on_the_way': // 已出发
+                // 扣除50%费用并扣除路费
+                $deductAmount = ($order->payment_amount + $order->balance_amount - $order->traffic_amount) * 0.5;
+                $this->handleRefund($user, $order, $deductAmount, true);
+                break;
+
+            case 'wait_pay':
+                // 待支付状态直接取消,无需退款
+                break;
+
+            default:
+                abort(400, '当前订单状态不允许取消');
+        }
+    }
+
+    /**
+     * 完成订单取消
+     */
+    private function completeCancel(Order $order, int $userId): void
+    {
+        // 添加订单取消记录
+        OrderRecord::create([
+            'order_id' => $order->id,
+            'object_id' => $userId,
+            'object_type' => MemberUser::class,
+            'state' => 'cancel',
+            'remark' => '用户取消订单',
+        ]);
+
+        // 修改订单状态
+        $order->state = 'cancel';
+        $order->cancel_time = now(); // 添加取消时间
+        $order->save();
+
+        // 如果有技师,可能需要通知技师订单已取消
+        if ($order->coach_id) {
+            // TODO: 发送通知给技师
+            // event(new OrderCancelledEvent($order));
+        }
+    }
+
     /**
      * 处理退款
      */
-    private function handleRefund($user, $order, $deductAmount, $deductTrafficFee)
+    private function handleRefund(MemberUser $user, Order $order, float $deductAmount, bool $deductTrafficFee): void
     {
-        // 计算实际退款金额
+        // 关键操作:计算实际退款金额
         $refundAmount = $order->payment_amount + $order->balance_amount;
         if ($deductTrafficFee) {
             $refundAmount -= $order->traffic_amount;
-            // 记录技师路费收入
-            // ...
+            // TODO: 记录技师路费收入
         }
         $refundAmount -= $deductAmount;
 
         // 优先从余额支付金额中扣除
         $balanceRefund = min($order->balance_amount, $refundAmount);
         if ($balanceRefund > 0) {
-
-            // 添加钱包退款记录
-            $refundRecord = $user->wallet->refundRecords()->create([
-                'refund_method' => 'balance',
-                'total_refund_amount' => $order->payment_amount + $order->balance_amount,
-                'actual_refund_amount' => '0.00',
-                'wallet_balance_refund_amount' => $balanceRefund,
-                'recharge_balance_refund_amount' => '0.00',
-                'remark' => '订单取消退还余额',
-                'order_id' => $order->id,
-            ]);
-
-            // 添加钱包交易记录
-            $user->wallet->transRecords()->create([
-                'amount' => $balanceRefund,
-                'owner_type' => $refundRecord::class,
-                'owner_id' => $refundRecord->id,
-                'remark' => '订单取消退还余额',
-                'trans_type' => 'income',
-                'storage_type' => 'balance',
-                'amount' => $balanceRefund,
-                'before_balance' => $user->wallet->total_balance,
-                'after_balance' => $user->wallet->total_balance + $balanceRefund,
-                'before_recharge_balance' => '0.00',
-                'after_recharge_balance' => '0.00',
-                'trans_time' => now(),
-                'state' => 'success',
-            ]);
-
-            $user->wallet->increment('total_balance', $balanceRefund);
-            $user->wallet->increment('available_balance', $balanceRefund);
-            $user->wallet->save();
+            $this->createRefundRecords($user, $order, $balanceRefund);
         }
 
         // 剩余退款金额从支付金额中退还
         $paymentRefund = $refundAmount - $balanceRefund;
         if ($paymentRefund > 0) {
-
-            // 添加钱包退款记录
-            $refundRecord = $user->wallet->refundRecords()->create([
-                'refund_method' => 'balance',
-                'total_refund_amount' => $order->payment_amount + $order->balance_amount,
-                'actual_refund_amount' => '0.00',
-                'wallet_balance_refund_amount' => $balanceRefund,
-                'recharge_balance_refund_amount' => '0.00',
-                'remark' => '订单取消退还余额',
-                'order_id' => $order->id,
-            ]);
-
-            // 添加钱包交易记录
-            $user->wallet->transRecords()->create([
-                'amount' => $balanceRefund,
-                'owner_type' => $refundRecord::class,
-                'owner_id' => $refundRecord->id,
-                'remark' => '订单取消退还余额',
-                'trans_type' => 'income',
-                'storage_type' => 'balance',
-                'amount' => $balanceRefund,
-                'before_balance' => $user->wallet->total_balance,
-                'after_balance' => $user->wallet->total_balance + $balanceRefund,
-                'before_recharge_balance' => '0.00',
-                'after_recharge_balance' => '0.00',
-                'trans_time' => now(),
-                'state' => 'success',
-            ]);
-
-            $user->wallet->increment('total_balance', $paymentRefund);
-            $user->wallet->increment('available_balance', $paymentRefund);
-            $user->wallet->save();
+            $this->createRefundRecords($user, $order, $paymentRefund, 'payment');
         }
 
         // 记录平台收入
@@ -406,52 +408,161 @@ class OrderService
         }
     }
 
+    /**
+     * 创建退款记录
+     */
+    private function createRefundRecords($user, $order, $amount, $type = 'balance'): void
+    {
+        $refundMethod = $type;
+        $remark = $type == 'balance' ? '订单取消退还余额' : '订单取消退还支付金额';
+
+        // 创建退款记录
+        $refundRecord = $user->wallet->refundRecords()->create([
+            'refund_method' => $refundMethod,
+            'total_refund_amount' => $order->payment_amount + $order->balance_amount,
+            'actual_refund_amount' => '0.00',
+            'wallet_balance_refund_amount' => $type == 'balance' ? $amount : '0.00',
+            'recharge_balance_refund_amount' => '0.00',
+            'remark' => $remark,
+            'order_id' => $order->id,
+        ]);
+
+        // 创建交易记录
+        $user->wallet->transRecords()->create([
+            'amount' => $amount,
+            'owner_type' => get_class($refundRecord),
+            'owner_id' => $refundRecord->id,
+            'remark' => $remark,
+            'trans_type' => 'income',
+            'storage_type' => 'balance',
+            'before_balance' => $user->wallet->total_balance,
+            'after_balance' => $user->wallet->total_balance + $amount,
+            'before_recharge_balance' => '0.00',
+            'after_recharge_balance' => '0.00',
+            'trans_time' => now(),
+            'state' => 'success',
+        ]);
+
+        // 更新钱包余额
+        $user->wallet->increment('total_balance', $amount);
+        $user->wallet->increment('available_balance', $amount);
+        $user->wallet->save();
+    }
+
+    /**
+     * 记录订单取消错误日志
+     */
+    private function logCancelOrderError(Exception $e, int $userId, int $orderId): void
+    {
+        // 复用之前的日志记录方法
+        Log::error('取消订单失败:', [
+            'message' => $e->getMessage(),
+            'user_id' => $userId,
+            'order_id' => $orderId,
+            'trace' => $e->getTraceAsString(),
+        ]);
+    }
+
     /**
      * 结束订单
      */
-    public function finishOrder($userId, $orderId)
+    public function finishOrder(int $userId, int $orderId): array
     {
         return DB::transaction(function () use ($userId, $orderId) {
             try {
-                // 1. 参数校验
-                $order = Order::where('user_id', $userId)
-                    ->where('id', $orderId)
-                    ->where('state', 'service_ing') // 订单状态必须是服务中
-                    ->firstOrFail();
+                // 1. 验证用户和订单
+                $order = $this->validateOrderForFinish($userId, $orderId);
 
-                if (! $order) {
-                    throw new Exception('订单不能结束');
-                }
+                // 2. 验证技师状态
+                $this->validateCoach($order->coach_id);
 
-                // 2. 创建订单历史记录
-                OrderRecord::create([
-                    'order_id' => $orderId,
-                    'object_id' => $userId,
-                    'object_type' => MemberUser::class,
-                    'state' => 'finish',
-                    'remark' => '服务完成',
-                ]);
+                // 3. 验证服务时长
+                $this->validateServiceDuration($order);
 
-                // 3. 修改订单状态为服务结束
-                $order->state = 'service_end';
-                $order->save();
+                // 4. 完成订单
+                $this->completeOrder($order, $userId);
 
                 return ['message' => '订单已完成'];
+
             } catch (Exception $e) {
-                Log::error('结束订单失败:', [
-                    'message' => $e->getMessage(),
-                    'user_id' => $userId,
-                    'order_id' => $orderId,
-                ]);
+                $this->logFinishOrderError($e, $userId, $orderId);
                 throw $e;
             }
         });
     }
 
+    /**
+     * 验证订单完成条件
+     */
+    private function validateOrderForFinish(int $userId, int $orderId): Order
+    {
+        // 验证用户状态
+        $user = MemberUser::where('id', $userId)
+            ->where('state', 'enable')
+            ->firstOrFail();
+
+        // 验证订单状态
+        $order = Order::where('user_id', $userId)
+            ->where('id', $orderId)
+            ->where('state', 'service_ing')
+            ->lockForUpdate()
+            ->firstOrFail();
+
+        return $order;
+    }
+
+    /**
+     * 验证服务时长
+     */
+    private function validateServiceDuration(Order $order): void
+    {
+        // 计算服务时长
+        $serviceStartTime = $order->service_start_time ?? $order->created_at;
+        $serviceDuration = now()->diffInMinutes($serviceStartTime);
+
+        // 获取项目要求的最短服务时长
+        $minDuration = $order->project->duration ?? 0;
+
+        abort_if($serviceDuration < $minDuration, 400, "服务时长不足{$minDuration}分钟");
+    }
+
+    /**
+     * 完成订单
+     */
+    private function completeOrder(Order $order, int $userId): void
+    {
+        // 1. 创建订单记录
+        OrderRecord::create([
+            'order_id' => $order->id,
+            'object_id' => $userId,
+            'object_type' => MemberUser::class,
+            'state' => 'finish',
+            'remark' => '服务完成',
+        ]);
+
+        // 2. 更新订单状态
+        $order->state = 'service_end';
+        $order->finish_time = now();
+        $order->save();
+    }
+
+    /**
+     * 记录订单完成错误日志
+     */
+    private function logFinishOrderError(Exception $e, int $userId, int $orderId): void
+    {
+        Log::error('结束订单失败:', [
+            'message' => $e->getMessage(),
+            'user_id' => $userId,
+            'order_id' => $orderId,
+            'trace' => $e->getTraceAsString(),
+        ]);
+    }
+
     /**
      * 确认技师离开
      */
-    public function confirmLeave($userId, $orderId)
+    public function confirmLeave(int $userId, int $orderId): array
     {
         return DB::transaction(function () use ($userId, $orderId) {
             try {
@@ -474,11 +585,11 @@ class OrderService
                     'remark' => '技师已离开',
                 ]);
 
-                // 3. 修��订单状态为撤离
+                // 3. 修订单状态为撤离
                 $order->state = 'leave';
                 $order->save();
 
-                return ['message' => '已确技师离开'];
+                return ['message' => '已确技师离开'];
             } catch (Exception $e) {
                 Log::error('确认技师离开失败:', [
                     'message' => $e->getMessage(),
@@ -493,7 +604,7 @@ class OrderService
     /**
      * 获取订单列表
      */
-    public function getOrderList($user_id)
+    public function getOrderList(int $user_id): \Illuminate\Contracts\Pagination\LengthAwarePaginator
     {
         $user = MemberUser::find($user_id);
 
@@ -508,7 +619,7 @@ class OrderService
     /**
      * 获取订单详情
      */
-    public function getOrderDetail($userId, $orderId)
+    public function getOrderDetail(int $userId, int $orderId): Order
     {
         $user = MemberUser::find($userId);
 
@@ -524,14 +635,15 @@ class OrderService
     /**
      * 订单退款
      */
-    public function refundOrder($orderId)
+    public function refundOrder(int $orderId): array
     {
-        $userId = Auth::id();
+        // 使用 Auth::user() 获取用户对象
+        $user = Auth::user();
 
-        return DB::transaction(function () use ($orderId, $userId) {
+        return DB::transaction(function () use ($orderId, $user) {
             // 查询并锁定订单
             $order = Order::where('id', $orderId)
-                ->where('user_id', $userId)
+                ->where('user_id', $user->id)
                 ->where('state', 'pending')
                 ->lockForUpdate()
                 ->firstOrFail();
@@ -543,7 +655,7 @@ class OrderService
             // 添加订单记录
             OrderRecord::create([
                 'order_id' => $orderId,
-                'object_id' => $userId,
+                'object_id' => $user->id,
                 'object_type' => 'user',
                 'state' => 'refund',
                 'remark' => '订单退款',
@@ -552,7 +664,7 @@ class OrderService
             // 创建退款记录
             WalletRefundRecord::create([
                 'order_id' => $orderId,
-                'user_id' => $userId,
+                'user_id' => $user->id,
                 'amount' => $order->total_amount,
                 'state' => 'success',
             ]);
@@ -564,7 +676,7 @@ class OrderService
     /**
      * 获取代理商配置
      */
-    public function getAgentConfig($agentId)
+    public function getAgentConfig(int $agentId): array
     {
         $agent = AgentInfo::where('id', $agentId)
             ->where('state', 'enable')
@@ -582,7 +694,7 @@ class OrderService
     /**
      * 获取技师配置
      */
-    public function getCoachConfig($coachId)
+    public function getCoachConfig(int $coachId): array
     {
         $coach = CoachUser::where('id', $coachId)
             ->where('state', 'enable')
@@ -599,257 +711,350 @@ class OrderService
 
     /**
      * 计算路费金额
+     *
+     * @param  int  $coachId  技师ID
+     * @param  int  $projectId  项目ID
+     * @param  int|null  $agentId  代理商ID
+     * @param  float  $distance  距离(公里)
+     * @return float 路费金额
+     *
+     * @throws Exception
      */
-    public function calculateDeliveryFee($coachId, $projectId, $agentId, $distance)
-    {
-
-        // 查询技师数据
-        $coach = CoachUser::where('state', 'enable')
-            ->whereHas('info', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->whereHas('real', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->whereHas('qual', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->find($coachId);
-
-        if (! $coach) {
-            throw new Exception('技师不存在');
-        }
+    public function calculateDeliveryFee(
+        int $coachId,
+        int $projectId,
+        ?int $agentId,
+        float $distance
+    ): float {
+        try {
+            // 1. 校验技师
+            $coach = CoachUser::where('state', 'enable')
+                ->whereHas('info', fn ($q) => $q->where('state', 'approved'))
+                ->whereHas('real', fn ($q) => $q->where('state', 'approved'))
+                ->whereHas('qual', fn ($q) => $q->where('state', 'approved'))
+                ->with(['projects' => fn ($q) => $q->where('project_id', $projectId)])
+                ->find($coachId);
 
-        // 查询技师项目
-        $coachProject = $coach->projects()
-            ->where('state', 'enable')
-            ->where('project_id', $projectId)
-            ->first();
-        if (! $coachProject) {
-            throw new Exception('项目不存在');
-        }
+            abort_if(! $coach, 404, '技师不存在或状态异常');
 
-        // 技师免收路费
-        if ($coachProject->traffic_fee_type == 'free') {
-            return 0;
-        }
+            // 2. 校验技师项目
+            $coachProject = $coach->projects->first();
 
-        // 查询代理商
-        $agent = AgentInfo::where('state', 'enable')->find($agentId);
-        if ($agent) {
-            $agentProject = $agent->projects()
-                ->where('state', 'enable')
-                ->where('project_id', $projectId)
-                ->first();
+            abort_if(! $coachProject, 404, '技师项目不存在');
 
-            if (! $agentProject) {
-                throw new Exception('代理商项目不存在');
+            // 3. 判断是否免收路费
+            if ($coachProject->traffic_fee_type == 'free') {
+                return 0;
             }
-            $config = $agent->projectConfig;
 
-        } else {
-            // 系统配置
-            $config = SysConfig::where('key', 'delivery_fee')->firstOrFail();
-            dd('暂停处理');
-        }
+            // 4. 获取路费配置
+            $config = $this->getDeliveryFeeConfig($agentId);
 
-        $fee = 0;
-        if ($distance <= $config->min_distance) {
-            $fee = $config->min_fee;
-        } else {
-            $extraDistance = $distance - $config->min_distance;
-            $fee = $config->min_fee + ($extraDistance * $config->per_km_fee);
-        }
+            abort_if(! $config, 404, '路费配置不存在');
+
+            // 5. 计算路费
+            $fee = $this->calculateFee($distance, $config);
+
+            // 6. 判断是否往返
+            return $coachProject->delivery_fee_type == 'round_trip'
+                ? bcmul($fee, '2', 2)
+                : $fee;
 
-        return $coachProject->delivery_fee_type == 'round_trip' ? $fee * 2 : $fee;
+        } catch (Exception $e) {
+            Log::error(__CLASS__.'->'.__FUNCTION__.'计算路费失败:', [
+                'message' => $e->getMessage(),
+                'coach_id' => $coachId,
+                'project_id' => $projectId,
+                'agent_id' => $agentId,
+                'distance' => $distance,
+                'trace' => $e->getTraceAsString(),
+            ]);
+            throw $e;
+        }
     }
 
     /**
-     * 计算订单金额
+     * 获取路费配置
      */
-    public function calculateOrderAmount($userId, $addressId, $coachId, $projectId, $agentId, $useBalance = false)
+    private function getDeliveryFeeConfig(?int $agentId): ?object
     {
-        // 参数校验
-        $user = MemberUser::find($userId);
-        if (! $user) {
-            throw new Exception('用户不存在');
+        // 优先获取代理商配置
+        if ($agentId) {
+            $agent = AgentInfo::where('state', 'enable')
+                ->with(['projectConfig'])
+                ->find($agentId);
+
+            if ($agent && $agent->projectConfig) {
+                return $agent->projectConfig;
+            }
         }
 
-        if ($user->state != 'enable') {
-            throw new Exception('用户状态异常');
-        }
+        // 获取系统配置
+        return SysConfig::where('key', 'delivery_fee')->first();
+    }
 
-        // 查询地址
-        $address = $user->address()->find($addressId);
-
-        // 查询技师数据
-        $coach = CoachUser::where('state', 'enable')
-            ->whereHas('info', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->whereHas('real', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->whereHas('qual', function ($query) {
-                $query->where('state', 'approved');
-            })
-            ->with(['info:id,nickname,avatar,gender'])
-            ->find($coachId);
-
-        if (! $coach) {
-            throw new Exception('技师不存在');
+    /**
+     * 计算路费
+     */
+    private function calculateFee(float $distance, object $config): float
+    {
+        // 最小距离内按起步价计算
+        if ($distance <= $config->min_distance) {
+            return (float) $config->min_fee;
         }
 
-        // 查询技师项目
-        $coachProject = $coach->projects()
-            ->where('state', 'enable')
-            ->where('project_id', $projectId)
-            ->first();
-        if (! $coachProject) {
-            throw new Exception('项目不存在');
-        }
+        // 超出最小距离部分按每公里费用计算
+        $extraDistance = bcsub($distance, $config->min_distance, 2);
+        $extraFee = bcmul($extraDistance, $config->per_km_fee, 2);
 
-        // 查询项目
-        $project = $coachProject->basicInfo;
+        return bcadd($config->min_fee, $extraFee, 2);
+    }
 
-        if (! $project) {
-            throw new Exception('项目不存在');
-        }
+    /**
+     * 计算订单金额
+     *
+     * @param  int  $userId  用户ID
+     * @param  int  $addressId  地址ID
+     * @param  int  $coachId  技师ID
+     * @param  int  $projectId  项目ID
+     * @param  int  $agentId  代理商ID
+     * @param  bool  $useBalance  是否使用余额
+     * @param  float  $distance  距离
+     *
+     * @throws Exception
+     */
+    public function calculateOrderAmount(
+        int $userId,
+        int $addressId,
+        int $coachId,
+        int $projectId,
+        ?int $agentId = null,
+        bool $useBalance = false,
+        float $distance = 0
+    ): array {
+        try {
+            // 1. 参数校验
+            $user = MemberUser::find($userId);
+            abort_if(! $user || $user->state != 'enable', 404, '用户不存在或状态异常');
 
-        if ($project->state != 'enable') {
-            throw new Exception('项目状态异常');
-        }
+            // 2. 查询技师项目
+            $coach = $this->validateCoach($coachId);
+
+            abort_if(! $coach, 404, '技师不存在或状态异常');
 
-        // 查询代理商
-        $agent = AgentInfo::where('state', 'enable')->find($agentId);
-        if ($agent) {
-            $agentProject = $agent->projects()
+            $coachProject = $coach->projects()
                 ->where('state', 'enable')
                 ->where('project_id', $projectId)
                 ->first();
 
-            if (! $agentProject) {
-                throw new Exception('代理商项目不在');
+            abort_if(! $coachProject, 404, '技师项目不存在');
+
+            // 3. 查询基础项目
+            $project = Project::where('id', $projectId)
+                ->where('state', 'enable')
+                ->first();
+
+            abort_if(! $project, 404, '项目不存在或状态异常');
+
+            // 4. 计算距离
+            if ($distance <= 0) {
+                $address = $user->addresses()->findOrFail($addressId);
+                $coachService = app(CoachService::class);
+                $coachDetail = $coachService->getCoachDetail($coachId, $address->latitude, $address->longitude);
+                $distance = $coachDetail['distance'] ?? 0;
+            }
+
+            // 5. 获取项目价格
+            $projectAmount = $this->getProjectPrice($project, $agentId, $projectId);
+
+            // 6. 计算路费
+            $deliveryFee = $this->calculateDeliveryFee($coachId, $projectId, $agentId, $distance);
+
+            // 7. 计算优惠券金额
+            $couponAmount = $this->calculateCouponAmount();
+
+            // 8. 计算总金额
+            $totalAmount = bcadd($projectAmount, $deliveryFee, 2);
+            $totalAmount = bcsub($totalAmount, $couponAmount, 2);
+            $totalAmount = max(0, $totalAmount);
+
+            // 9. 计算余额支付金额
+            $balanceAmount = 0;
+            $payAmount = $totalAmount;
+
+            if ($useBalance && $totalAmount > 0) {
+                $wallet = $user->wallet;
+                abort_if(! $wallet, 404, '用户钱包不存在');
+
+                if ($wallet->available_balance >= $totalAmount) {
+                    $balanceAmount = $totalAmount;
+                    $payAmount = 0;
+                } else {
+                    $balanceAmount = $wallet->available_balance;
+                    $payAmount = bcsub($totalAmount, $balanceAmount, 2);
+                }
             }
 
-            $project->price = $agentProject->price;
-            $project->duration = $agentProject->duration;
-            $project->distance = $address->distance;
+            return [
+                'total_amount' => $totalAmount,
+                'balance_amount' => $balanceAmount,
+                'pay_amount' => $payAmount,
+                'coupon_amount' => $couponAmount,
+                'project_amount' => $projectAmount,
+                'delivery_fee' => $deliveryFee,
+            ];
+
+        } catch (Exception $e) {
+            Log::error(__CLASS__.'->'.__FUNCTION__.'计算订单金额失败:', [
+                'message' => $e->getMessage(),
+                'user_id' => $userId,
+                'project_id' => $projectId,
+                'trace' => $e->getTraceAsString(),
+            ]);
+            throw $e;
         }
+    }
 
-        // 计算金额
-        $projectAmount = $project->price;
-        $deliveryFee = $this->calculateDeliveryFee($coachId, $projectId, $agentId, $address?->distance);
-        // $tipAmount = request()->has('order_id') ? Order::find(request()->input('order_id'))->tip_amount : 0;
+    /**
+     * 获取项目价格
+     */
+    private function getProjectPrice($project, ?int $agentId, int $projectId): float
+    {
+        $price = $project->price;
 
+        if ($agentId) {
+            $agent = AgentInfo::where('state', 'enable')->find($agentId);
+            if ($agent) {
+                $agentProject = $agent->projects()
+                    ->where('state', 'enable')
+                    ->where('project_id', $projectId)
+                    ->first();
+
+                if ($agentProject) {
+                    $price = $agentProject->price;
+                }
+            }
+        }
+
+        return (float) $price;
+    }
+
+    /**
+     * 计算优惠券金额
+     */
+    private function calculateCouponAmount(): float
+    {
         $couponAmount = 0;
         if (request()->has('coupon_id')) {
-            // $coupon = Coupon::where('id', request()->input('coupon_id'))
-            //     ->where('state', 'enable')
-            //     ->firstOrFail();
-            // $couponAmount = $coupon->amount;
+            // TODO: 优惠券逻辑
         }
 
-        $totalAmount = $projectAmount + $deliveryFee - $couponAmount;
+        return $couponAmount;
+    }
 
+    /**
+     * 计算支付金额分配
+     */
+    private function calculatePaymentAmounts($user, float $totalAmount, bool $useBalance): array
+    {
         $balanceAmount = 0;
         $payAmount = $totalAmount;
 
         if ($useBalance) {
             $wallet = $user->wallet;
-            if ($wallet && $wallet->available_balance >= $totalAmount) {
+            if (! $wallet) {
+                throw new Exception('用户钱包不存在');
+            }
+
+            if ($wallet->available_balance >= $totalAmount) {
                 $balanceAmount = $totalAmount;
                 $payAmount = 0;
-            } elseif ($wallet) {
+            } else {
                 $balanceAmount = $wallet->available_balance;
-                $payAmount = $totalAmount - $balanceAmount;
+                $payAmount = bcsub($totalAmount, $balanceAmount, 2);
             }
         }
 
-        return [
-            'total_amount' => $totalAmount,
-            'balance_amount' => $balanceAmount,
-            'pay_amount' => $payAmount,
-            'coupon_amount' => $couponAmount,
-            // 'tip_amount' => $tipAmount,
-            'project_amount' => $projectAmount,
-            'delivery_fee' => $deliveryFee,
-        ];
+        return [$balanceAmount, $payAmount];
     }
 
     /**
      * 指定技师
      */
-    public function assignCoach($userId, $orderId, $coachId)
+    public function assignCoach(int $userId, int $orderId, int $coachId): bool
     {
         return DB::transaction(function () use ($userId, $orderId, $coachId) {
-            // 参数校验
-            $user = MemberUser::where('id', $userId)
-                ->where('state', 'enable')
-                ->firstOrFail();
-
-            $order = Order::where('id', $orderId)
-                ->where('user_id', $userId)
-                ->whereIn('state', [0, 1, 6])
-                ->firstOrFail();
-
-            $coach = CoachUser::where('id', $coachId)
-                ->where('state', 'enable')
-                ->where('auth_state', 'passed')
-                ->firstOrFail();
-
-            // $schedule = CoachSchedule::where('coach_id', $coachId)
-            //     ->where('date', date('Y-m-d'))
-            //     ->where('state', 'free')
-            //     ->firstOrFail();
-
-            // 修改订单
-            $order->coach_id = $coachId;
-            if ($order->state == 'created') {
-                $amounts = $this->calculateOrderAmount($userId, $order->address_id, $coachId, $order->project_id, $order->agent_id, $order->payment_type == 'balance');
+            try {
+                // 参数校验
+                $user = MemberUser::where('id', $userId)
+                    ->where('state', 'enable')
+                    ->firstOrFail();
 
-                $order->total_amount = $amounts['total_amount'];
-                $order->balance_amount = $amounts['balance_amount'];
-                $order->pay_amount = $amounts['pay_amount'];
-                $order->coupon_amount = $amounts['coupon_amount'];
-                // $order->tip_amount = $amounts['tip_amount'];
-                $order->project_amount = $amounts['project_amount'];
-                $order->delivery_fee = $amounts['delivery_fee'];
+                $order = Order::where('id', $orderId)
+                    ->where('user_id', $userId)
+                    ->whereIn('state', [0, 1, 6])
+                    ->firstOrFail();
 
-                if ($order->payment_type == 'balance') {
-                    $order->state = 'paid';
+                $coach = $this->validateCoach($coachId);
+
+                // 修改订单
+                $order->coach_id = $coachId;
+                if ($order->state == 'created') {
+                    $amounts = $this->calculateOrderAmount(
+                        $userId,
+                        $order->address_id,
+                        $coachId,
+                        $order->project_id,
+                        $order->agent_id,
+                        $order->payment_type === 'balance'
+                    );
+
+                    $order->total_amount = $amounts->total_amount;
+                    $order->balance_amount = $amounts->balance_amount;
+                    $order->pay_amount = $amounts->pay_amount;
+                    $order->coupon_amount = $amounts->coupon_amount;
+                    $order->project_amount = $amounts->project_amount;
+                    $order->delivery_fee = $amounts->delivery_fee;
+
+                    if ($order->payment_type === 'balance') {
+                        $order->state = 'paid';
+                    }
                 }
-            }
-            if ($order->state == 'paid') {
-                $order->state = 'assigned';
-            }
-            $order->save();
-
-            // 创建订单历史
-            OrderRecord::create([
-                'order_id' => $order->id,
-                'type' => 'assigned',
-                'user_id' => $userId,
-                'coach_id' => $coachId,
-            ]);
+                if ($order->state == 'paid') {
+                    $order->state = 'assigned';
+                }
+                $order->save();
 
-            OrderRecord::create([
-                'order_id' => $order->id,
-                'type' => 'accepted',
-                'user_id' => $userId,
-                'coach_id' => $coachId,
-                'remark' => '抢单成功',
-            ]);
+                // 创建订单历史
+                OrderRecord::create([
+                    'order_id' => $order->id,
+                    'type' => 'assigned',
+                    'user_id' => $userId,
+                    'coach_id' => $coachId,
+                ]);
 
-            // 更新抢单池
-            OrderGrabRecord::where('order_id', $orderId)
-                ->update(['state' => 'success', 'coach_id' => $coachId]);
+                OrderRecord::create([
+                    'order_id' => $order->id,
+                    'type' => 'accepted',
+                    'user_id' => $userId,
+                    'coach_id' => $coachId,
+                    'remark' => '抢单成功',
+                ]);
 
-            // 更新排班
-            // $schedule->state = 'busy';
-            // $schedule->save();
+                // 更新抢单池
+                OrderGrabRecord::where('order_id', $orderId)
+                    ->update(['state' => 'success', 'coach_id' => $coachId]);
 
-            return true;
+                return true;
+            } catch (Exception $e) {
+                Log::error('分配技师失败:', [
+                    'message' => $e->getMessage(),
+                    'user_id' => $userId,
+                    'order_id' => $orderId,
+                    'coach_id' => $coachId,
+                ]);
+                throw $e;
+            }
         });
     }
 }

+ 9 - 5
app/Services/Client/ProjectService.php

@@ -17,14 +17,18 @@ class ProjectService
         // 根据区域代码获取代理商
         $agent = $this->findAvailableAgent($areaCode);
 
+        // 获取项目分类
+        $projectCate = ProjectCate::find($projectCateId);
         // 获取项目列表
         if ($agent) {
-            dd($agent->cates());
-            $projects = Project::where('state', 'enable')
-                ->where('agent_id', $agent->id)
-                ->paginate(10);
+            $agentCate = $agent->cates()->find($projectCate->id);
+            if ($type == 'normal') {
+                $projects = $agentCate->projects()->where('state', 'enable')->whereHas('basicInfo', fn ($q) => $q->where('type', 'normal'))->paginate(10);
+            } else {
+                $projects = $agentCate->projects()->where('state', 'enable')->paginate(10);
+            }
         } else {
-            $projectCate = ProjectCate::find($projectCateId);
+
             if ($type == 'normal') {
                 $projects = $projectCate?->services()->where('type', 'normal')->get();
             } else {

+ 11 - 0
routes/api.php

@@ -94,4 +94,15 @@ Route::middleware('auth:sanctum')->group(function () {
         // Route::post('calculate-delivery-fee', [OrderController::class, 'calculateDeliveryFee']);
     });
 
+    Route::prefix('client')->group(function () {
+        Route::post('/orders', [OrderController::class, 'create']);
+        Route::post('/orders/{orderId}/cancel', [OrderController::class, 'cancel']);
+        Route::post('/orders/{orderId}/finish', [OrderController::class, 'finish']);
+        Route::post('/orders/{orderId}/confirm-leave', [OrderController::class, 'confirmLeave']);
+        Route::get('/orders', [OrderController::class, 'list']);
+        Route::get('/orders/{orderId}', [OrderController::class, 'detail']);
+        Route::post('/orders/{orderId}/refund', [OrderController::class, 'refund']);
+        Route::post('/orders/{orderId}/assign-coach', [OrderController::class, 'assignCoach']);
+    });
+
 });