Browse Source

fixed:项目-优化项目列表和项目详情

刘学玺 3 months ago
parent
commit
6422cd62a7

+ 41 - 0
app/Enums/AgentAuditStatus.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Enums;
+
+enum AgentAuditStatus: int
+{
+    /**
+     * 未审核
+     */
+    case PENDING = 0;
+
+    /**
+     * 通过
+     */
+    case PASSED = 1;
+
+    /**
+     * 拒绝
+     */
+    case REJECTED = 2;
+
+    /**
+     * 获取枚举值
+     */
+    public function value(): int
+    {
+        return $this->value;
+    }
+
+    /**
+     * 获取枚举描述
+     */
+    public function label(): string
+    {
+        return match($this) {
+            self::PENDING => '未审核',
+            self::PASSED => '通过',
+            self::REJECTED => '拒绝',
+        };
+    }
+}

+ 35 - 0
app/Enums/AgentStatus.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace App\Enums;
+
+enum AgentStatus: int
+{
+    /**
+     * 禁用
+     */
+    case DISABLE = 0;
+
+    /**
+     * 启用
+     */
+    case ENABLE = 1;
+
+    /**
+     * 获取枚举值
+     */
+    public function value(): int
+    {
+        return $this->value;
+    }
+
+    /**
+     * 获取枚举描述
+     */
+    public function label(): string
+    {
+        return match ($this) {
+            self::DISABLE => '禁用',
+            self::ENABLE => '启用',
+        };
+    }
+}

+ 5 - 4
app/Http/Controllers/Client/ProjectController.php

@@ -2,9 +2,9 @@
 
 namespace App\Http\Controllers\Client;
 
+use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
 use App\Services\Client\ProjectService;
-use Illuminate\Http\Request;
 
 /**
  * @group 用户端
@@ -56,13 +56,14 @@ class ProjectController extends Controller
      */
     public function index(Request $request)
     {
-
+        // 验证请求参数
         $validated = $request->validate([
-            'area_code' => 'required|string',
+            'area_code' => ['required', 'string', 'regex:/^\d{6}$/'],
             'project_cate_id' => 'nullable|integer',
-            'type' => 'required|in:1,2',
+            'type' => 'required|in:1,2'
         ]);
 
+        // 调用服务层获取项目列表
         return $this->success(
             $this->service->getProjectList(
                 $validated['area_code'],

+ 172 - 128
app/Services/Client/ProjectService.php

@@ -2,83 +2,48 @@
 
 namespace App\Services\Client;
 
-use App\Enums\ProjectStatus;
-use App\Enums\ProjectType;
-use App\Enums\TechnicianAuthStatus;
-use App\Enums\TechnicianStatus;
+use App\Models\Project;
 use App\Models\AgentInfo;
 use App\Models\CoachUser;
-use App\Models\Project;
+use App\Enums\AgentStatus;
+use App\Enums\ProjectType;
 use App\Models\ProjectCate;
-use Illuminate\Support\Facades\Log;
+use App\Enums\ProjectStatus;
+use App\Enums\AgentAuditStatus;
+use App\Enums\TechnicianStatus;
+use App\Enums\TechnicianAuthStatus;
+use Illuminate\Support\Facades\Cache;
 
 class ProjectService
 {
     /**
      * 获取项目列表
+     * 根据区域代码和分类获取可用的项目列表
+     *
+     * @param string $areaCode 区域代码(6位数字)
+     * @param int|null $projectCateId 项目分类ID
+     * @param int $type 项目类型(1:普通项目,2:加钟项目)
+     * @param int $perPage 每页数量
+     * @return mixed
      */
-    public function getProjectList($areaCode, $projectCateId = null, $type = ProjectType::VISIT)
+    public function getProjectList($areaCode, $projectCateId = null, $type = ProjectType::VISIT, $perPage = 10)
     {
-        try {
+        // 生成缓存键
+        $cacheKey = "project:list:{$areaCode}:{$projectCateId}:{$type}:{$perPage}";
 
-            // 获取项目分类
-            $projectCate = ProjectCate::find($projectCateId);
+        return Cache::remember($cacheKey, 3600, function () use ($areaCode, $projectCateId, $type, $perPage) {
 
-            abort_if(! $projectCate, 404, '项目分类不存在');
+            // 获取并验证项目分类
+            $projectCate = ProjectCate::find($projectCateId);
+            abort_if(!$projectCate, 404, '项目分类不存在');
             abort_if($projectCate->state != ProjectStatus::OPEN->value(), 404, '项目分类状态异常');
 
-            // 根据区域代码获取代理商
+            // 查找区域代理商
             $agent = $this->findAvailableAgent($areaCode);
 
             // 获取项目列表
-            if ($agent) {
-                $agentCate = $agent->cates()->where('project_cate_id', $projectCate->id)->first();
-                abort_if(! $agentCate || ($agentCate->state != ProjectStatus::OPEN->value()), 404, '当前区域未开通服务');
-
-                if (in_array($type, [ProjectType::VISIT->value()])) {
-                    $projects = $agentCate->projects()
-                        ->where('state', ProjectStatus::OPEN->value())
-                        ->with('basicInfo')
-                        ->whereHas('basicInfo', fn ($q) => $q->where('type', [ProjectType::VISIT->value()]))
-                        ->paginate(10);
-                    // 遍历项目,替换成代理商设置
-
-                }
-                if (in_array($type, [ProjectType::OVERTIME->value()])) {
-
-                    $projects = $agentCate->projects()
-                        ->where('state', ProjectStatus::OPEN->value())
-                        ->with('basicInfo')
-                        ->whereHas('basicInfo', fn ($q) => $q->whereIn('type', [ProjectType::VISIT->value(), ProjectType::OVERTIME->value()]))
-                        ->paginate(10);
-                    // 遍历项目,替换成代理商设置
-                }
-            } else {
-                if (in_array($type, [ProjectType::VISIT->value()])) {
-                    $projects = $projectCate?->projects()
-                        ->whereIn('type', [ProjectType::VISIT->value()])
-                        ->where('state', ProjectStatus::OPEN->value())
-                        ->paginate(10);
-                }
-                if (in_array($type, [ProjectType::OVERTIME->value()])) {
-                    $projects = $projectCate?->projects()
-                        ->whereIn('type', [ProjectType::VISIT->value(), ProjectType::OVERTIME->value()])
-                        ->where('state', ProjectStatus::OPEN->value())
-                        ->paginate(10);
-                }
-            }
-
-            return $projects;
-
-        } catch (\Exception $e) {
-            Log::error('获取项目列表失败', [
-                'error' => $e->getMessage(),
-                'areaCode' => $areaCode,
-                'projectCateId' => $projectCateId,
-                'type' => $type,
-            ]);
-            throw $e;
-        }
+            return $this->getProjects($projectCate, $type, $agent, $perPage);
+        });
     }
 
     /**
@@ -92,110 +57,189 @@ class ProjectService
      */
     public function getProjectDetail($projectId, $areaCode)
     {
-
         // 查询系统项目
-        $project = Project::where('state', ProjectStatus::OPEN->value())->find($projectId);
-        abort_if(! $project, 404, '项目不存在');
+        $project = $this->getSystemProject($projectId);
 
         // 根据区域代码获取代理商
         $agent = $this->findAvailableAgent($areaCode);
         if ($agent) {
-            // 查询代理商项目
-            $agentProject = $agent->projects()->where('project_id', $projectId)->first();
-            // 遍历代理商项目,替换系统项目
-            if ($agentProject) {
-                // 合并代理商项目的金额、时长、距离到系统项目
-                $project->price = $agentProject->price ?? $project->price;  // 金额
-                $project->duration = $agentProject->duration ?? $project->duration; // 时长
-                $project->distance = $agentProject->distance ?? $project->distance; // 距离
-            }
+            $this->mergeAgentSettings($project, $agent);
             $project->agent_id = $agent->id;
         }
 
         return $project;
     }
 
+    /**
+     * 获取系统项目
+     *
+     * @param  int  $projectId  项目ID
+     * @return Project
+     * @throws \Illuminate\Http\Exceptions\HttpResponseException
+     */
+    private function getSystemProject($projectId)
+    {
+        $project = Project::where('state', ProjectStatus::OPEN->value())->find($projectId);
+        abort_if(!$project, 404, '项目不存在');
+        return $project;
+    }
+
     /**
      * 获取技师开通的项目列表
      */
     public function getCoachProjectList($coachId, $areaCode, $projectCateId)
     {
-        try {
-            // 查询技师信息
-            $coach = CoachUser::where('id', $coachId)
-                ->where('state', TechnicianStatus::ACTIVE->value)
-                ->with(['info', 'qual', 'real'])
+        // 查询技师信息
+        $coach = CoachUser::where('id', $coachId)
+            ->where('state', TechnicianStatus::ACTIVE->value)
+            ->with(['info', 'qual', 'real'])
+            ->first();
+
+        abort_if(! $coach, 404, '技师不存在');
+        abort_if(! $coach->info, 404, '技师信息不存在');
+        abort_if($coach->info->state !== TechnicianAuthStatus::PASSED->value, 404, '技师未通过审核');
+        abort_if(! $coach->qual, 404, '技师资格证书不存在');
+        abort_if($coach->qual->state !== TechnicianAuthStatus::PASSED->value, 404, '技师资格证书未通过审核');
+        abort_if(! $coach->real, 404, '技师实名认证记录不存在');
+        abort_if($coach->real->state !== TechnicianAuthStatus::PASSED->value, 404, '技师实名认证未通过审核');
+
+        // 获取技师开通的项目ID列表
+        $projectIds = $coach->projects()
+            ->where('state', ProjectStatus::OPEN->value)
+            ->pluck('project_id');
+
+        // 根据区域代码获取代理商
+        $agent = $this->findAvailableAgent($areaCode);
+
+        if ($agent) {
+            $agentCate = $agent->cates()
+                ->where('project_cate_id', $projectCateId)
                 ->first();
 
-            abort_if(! $coach, 404, '技师不存在');
-            abort_if(! $coach->info, 404, '技师信息不存在');
-            abort_if($coach->info->state !== TechnicianAuthStatus::PASSED->value, 404, '技师未通过审核');
-            abort_if(! $coach->qual, 404, '技师资格证书不存在');
-            abort_if($coach->qual->state !== TechnicianAuthStatus::PASSED->value, 404, '技师资格证书未通过审核');
-            abort_if(! $coach->real, 404, '技师实名认证记录不存在');
-            abort_if($coach->real->state !== TechnicianAuthStatus::PASSED->value, 404, '技师实名认证未通过审核');
-
-            // 获取技师开通的项目ID列表
-            $projectIds = $coach->projects()
-                ->where('state', ProjectStatus::OPEN->value)
+            $projectIds = $agentCate->projects()
+                ->whereIn('project_id', $projectIds)
                 ->pluck('project_id');
+        }
 
-            // 根据区域代码获取代理商
-            $agent = $this->findAvailableAgent($areaCode);
+        return $coach->projects()
+            ->with('basicInfo')
+            ->whereIn('project_id', $projectIds)
+            ->get();
+    }
 
-            if ($agent) {
-                $agentCate = $agent->cates()
-                    ->where('project_cate_id', $projectCateId)
-                    ->first();
+    /**
+     * 获取项目列表
+     * 根据条件获取系统项目或代理商项目
+     *
+     * @param ProjectCate $projectCate 项目分类
+     * @param int $type 项目类型
+     * @param Agent|null $agent 代理商(可选)
+     * @param int $perPage 每页数量
+     * @return mixed
+     */
+    private function getProjects(ProjectCate $projectCate, int $type, $agent = null, int $perPage = 10)
+    {
+        // 构建基础查询
+        $query = $projectCate->projects()
+            ->where('state', ProjectStatus::OPEN->value());
+
+        // 处理项目类型查询
+        if ($type == ProjectType::OVERTIME->value()) {
+            $query->whereIn('type', [
+                ProjectType::VISIT->value(),
+                ProjectType::OVERTIME->value()
+            ]);
+        } else {
+            $query->where('type', ProjectType::VISIT->value());
+        }
+
+        // 如果有代理商,处理代理商项目设置
+        if ($agent) {
+            $agentCate = $agent->cates()
+                ->where('project_cate_id', $projectCate->id)
+                ->first();
 
-                $projectIds = $agentCate->projects()
-                    ->whereIn('project_id', $projectIds)
-                    ->pluck('project_id');
+            // 验证代理商分类状态
+            abort_if(
+                $agentCate && ($agentCate->state != ProjectStatus::OPEN->value()),
+                404,
+                '当前区域未开通服务'
+            );
+
+            // 获取分页数据
+            $projects = $query->paginate($perPage);
+
+            // 处理代理商设置
+            foreach ($projects as $project) {
+                $this->mergeAgentSettings($project, $agent);
             }
 
-            return $coach->projects()
-                ->with('basicInfo')
-                ->whereIn('project_id', $projectIds)
-                ->get();
-
-        } catch (\Exception $e) {
-            Log::error('获取技师项目列表失败', [
-                'error' => $e->getMessage(),
-                'coachId' => $coachId,
-                'areaCode' => $areaCode,
-                'projectCateId' => $projectCateId,
-            ]);
-            throw $e;
+            return $projects;
         }
+
+        // 返回系统默认项目
+        return $query->paginate($perPage);
     }
 
     /**
      * 递归查找可用的代理商
+     * 从6位区域代码开始,每次去掉最后2位,直到找到代理商或只剩2位
+     * 查找规则:
+     * 1. 先查找精确匹配的区域代码
+     * 2. 如果找不到,则去掉最后2位,查找上级区域
+     * 3. 重复步骤2直到只剩2位区域代码
+     * 4. 如果全部未找到则返回null
      *
-     * @param  string  $areaCode  区域代码
-     * @return Agent|null
+     * @param string $areaCode 区域代码(2-6位数字)
+     * @return Agent|null 返回找到的代理商或null
+     * @throws \Exception 当查询过程中发生错误时抛出异常
      */
     private function findAvailableAgent($areaCode)
     {
-        // 先查找当前区域的代理商
-        // 区域代码不足6位,右边补0
-        $fullAreaCode = str_pad($areaCode, 6, '0', STR_PAD_RIGHT);
-        $agent = AgentInfo::where('area_code', $fullAreaCode)
-            ->where('state', 'enable')
-            ->first();
+        // 生成缓存键
+        $cacheKey = "agent:area:{$areaCode}";
 
-        if ($agent) {
-            return $agent;
-        }
+        return Cache::remember($cacheKey, 3600, function () use ($areaCode) {
+            // 现有的查找逻辑
+            $fullAreaCode = str_pad($areaCode, 6, '0', STR_PAD_RIGHT);
 
-        // 如果找不到,且区域代码长度大于2,则向上查找
-        if (strlen($areaCode) > 2) {
-            // 去掉最后两位,获取上级区域代码
-            $parentAreaCode = substr($areaCode, 0, -2);
+            $agent = AgentInfo::where('area_code', $fullAreaCode)
+                ->where('state', AgentStatus::ENABLE->value)
+                ->where('audit_state', AgentAuditStatus::PASSED->value)
+                ->first();
 
-            return $this->findAvailableAgent($parentAreaCode);
-        }
+            if ($agent) {
+                return $agent;
+            }
+
+            if (strlen($areaCode) > 2) {
+                $parentAreaCode = substr($areaCode, 0, -2);
+                return $this->findAvailableAgent($parentAreaCode);
+            }
+
+            return null;
+        });
+    }
+
+    /**
+     * 合并代理商项目设置
+     * 将代理商的自定义设置覆盖到项目默认设置中
+     *
+     * @param Project $project 项目对象
+     * @param Agent $agent 代理商对象
+     */
+    private function mergeAgentSettings(&$project, $agent)
+    {
+        // 查找代理商对该项目的设置
+        $agentProject = $agent->projects()
+            ->where('project_id', $project->id)
+            ->first();
 
-        return null;
+        // 如果有设置则覆盖默认值
+        if ($agentProject) {
+            $project->price = $agentProject->price ?? $project->price;
+            $project->duration = $agentProject->duration ?? $project->duration;
+            $project->distance = $agentProject->distance ?? $project->distance;
+        }
     }
 }