123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- <?php
- namespace App\Services\Coach;
- use App\Enums\OrderStatus;
- use App\Enums\TechnicianAuthStatus;
- use App\Enums\TechnicianLocationType;
- use App\Enums\TechnicianStatus;
- use App\Models\MemberUser;
- use App\Models\Order;
- use App\Services\SettingItemService;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Redis;
- class OrderService
- {
- private SettingItemService $settingService;
- public function __construct(SettingItemService $settingService)
- {
- $this->settingService = $settingService;
- }
- /**
- * 获取可抢订单列表
- *
- * @param int $userId 技师用户ID
- * @param array $params 请求参数
- * @return \Illuminate\Pagination\LengthAwarePaginator
- */
- public function getGrabList(int $userId, array $params)
- {
- try {
- // 加载用户和技师信息
- $user = MemberUser::with([
- 'coach',
- 'coach.info',
- 'coach.real',
- 'coach.qual',
- 'coach.locations',
- 'coach.projects',
- ])->findOrFail($userId);
- // 验证技师信息
- [$coach, $location] = $this->validateCoach($user);
- // 获取技师项目信息
- $coachProjects = $coach->projects;
- $coachProjectIds = $coachProjects->pluck('project_id')->toArray();
- // 获取系统配置
- $settings = $this->getSystemSettings();
- // 获取附近订单
- $orderDistances = $this->getNearbyOrders($location);
- // 构建订单查询
- $query = $this->buildOrderQuery($coachProjectIds, $orderDistances);
- // 处理订单数据
- $this->processOrderData($query, $orderDistances, $coachProjects, $settings);
- // 分页获取数据
- return $query->paginate(
- $params['per_page'] ?? 10,
- ['*'],
- 'page',
- $params['page'] ?? 1
- );
- } catch (\Exception $e) {
- Log::error('获取可抢订单列表失败', [
- 'user_id' => $userId,
- 'params' => $params,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString(),
- ]);
- throw $e;
- }
- }
- /**
- * 验证技师信息
- */
- private function validateCoach(MemberUser $user): array
- {
- $coach = $user->coach;
- abort_if(! $coach, 404, '技师不存在');
- abort_if(! $coach->info, 404, '技师信息不存在');
- abort_if($coach->info->state != TechnicianStatus::ACTIVE->value, 404, '技师状态异常');
- abort_if($coach->real->state != TechnicianAuthStatus::PASSED->value, 404, '技师实名认证未通过');
- abort_if($coach->qual->state != TechnicianAuthStatus::PASSED->value, 404, '技师资质认证未通过');
- $location = $coach->locations()
- ->where('type', TechnicianLocationType::COMMON->value)
- ->first();
- abort_if(! $location, 404, '技师定位地址不存在');
- return [$coach, $location];
- }
- /**
- * 获取系统配置
- */
- private function getSystemSettings(): array
- {
- return [
- 'coach_income' => $this->settingService->getItemDetail('coach_income')->default_value ?? 0,
- 'min_distance' => $this->settingService->getItemDetail('qibugongli')->default_value ?? 0,
- 'base_price' => $this->settingService->getItemDetail('qibujia')->default_value ?? 0,
- 'per_km_price' => $this->settingService->getItemDetail('meigonglijiage')->default_value ?? 0,
- ];
- }
- /**
- * 获取附近订单
- */
- private function getNearbyOrders($location, float $maxDistance = 40): array
- {
- $nearbyOrders = Redis::georadius(
- 'order_locations',
- $location->longitude,
- $location->latitude,
- $maxDistance,
- 'km',
- ['WITHCOORD', 'WITHDIST']
- );
- if (! $nearbyOrders) {
- Log::warning('获取附近订单失败', [
- 'location' => [
- 'longitude' => $location->longitude,
- 'latitude' => $location->latitude,
- ],
- ]);
- return [];
- }
- $orderDistances = [];
- foreach ($nearbyOrders as $order) {
- $orderId = str_replace('order:', '', $order[0]);
- $distance = round($order[1], 1);
- $orderDistances[$orderId] = $distance;
- }
- return $orderDistances;
- }
- /**
- * 构建订单查询
- */
- private function buildOrderQuery(array $coachProjectIds, array $orderDistances)
- {
- return Order::query()
- ->select([
- 'id',
- 'order_no',
- 'project_id',
- 'location',
- 'address',
- 'latitude',
- 'longitude',
- 'service_time',
- 'created_at',
- 'agent_id',
- DB::raw('0 as distance'),
- ])
- ->with(['project', 'agent.projects'])
- ->where('state', OrderStatus::CREATED)
- ->whereIn('project_id', $coachProjectIds)
- ->whereIn('id', array_keys($orderDistances))
- ->orderBy('created_at', 'desc');
- }
- /**
- * 处理订单数据
- */
- private function processOrderData($query, array $orderDistances, $coachProjects, array $settings): void
- {
- $query->get()->each(function ($order) use ($orderDistances, $coachProjects, $settings) {
- // 设置距离
- $order->distance = $orderDistances[$order->id];
- // 处理代理商项目价格
- $this->processAgentPrice($order);
- // 处理技师项目信息
- $this->processCoachProject($order, $coachProjects, $settings);
- });
- }
- /**
- * 处理代理商价格
- */
- private function processAgentPrice($order): void
- {
- if ($order->agent_id && $order->agent && $order->agent->projects) {
- $agentProject = $order->agent->projects
- ->where('id', $order->project_id)
- ->where('state', 1)
- ->first();
- if ($agentProject) {
- $order->project->price = $agentProject->agent_price;
- $order->project->duration = $agentProject->duration;
- }
- }
- }
- /**
- * 处理技师项目信息
- */
- private function processCoachProject($order, $coachProjects, array $settings): void
- {
- $coachProject = $coachProjects->where('project_id', $order->project_id)->first();
- if (! $coachProject) {
- return;
- }
- // 计算技师佣金
- $order->project->coach_income = round($order->project->price * $settings['coach_income'], 2);
- // 处理优惠金额
- if ($coachProject->discount_amount > 0) {
- $order->project->discount_amount = $coachProject->discount_amount;
- $order->project->final_price = $order->project->price - $coachProject->discount_amount;
- }
- // 处理路费
- if ($coachProject->traffic_fee > 0) {
- $this->calculateTrafficFee($order, $coachProject, $settings);
- }
- }
- /**
- * 计算路费
- */
- private function calculateTrafficFee($order, $coachProject, array $settings): void
- {
- $trafficFee = $settings['base_price'];
- if ($order->distance > $settings['min_distance']) {
- $trafficFee += ($order->distance - $settings['min_distance']) * $settings['per_km_price'];
- }
- $order->project->traffic_fee = round($trafficFee, 2);
- // 双程收费
- if ($coachProject->is_round_trip) {
- $order->project->traffic_fee *= 2;
- }
- // 计算最终价格
- $order->project->final_price = ($order->project->final_price ?? $order->project->price)
- + $order->project->traffic_fee;
- }
- }
|