state != ProjectStatus::OPEN->value(), 404, '项目分类状态异常'); // 查找区域代理商 $agent = $this->findAvailableAgent($areaCode); // 获取项目列表 return $this->getProjects($projectCate, $type, $agent, $perPage); }); } /** * 如果代理商存在,则返回代理商项目,否则返回系统项目 * * @param int $projectId 项目ID * @param string $areaCode 区域代码 * @return Project 项目模型 * * @throws \Illuminate\Http\Exceptions\HttpResponseException 项目不存在时抛出404异常 */ public function getProjectDetail($projectId, $areaCode) { // 查询系统项目 $project = $this->getSystemProject($projectId); // 根据区域代码获取代理商 $agent = $this->findAvailableAgent($areaCode); if ($agent) { $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) { // 查询技师信息 $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(); $projectIds = $agentCate->projects() ->whereIn('project_id', $projectIds) ->pluck('project_id'); } return $coach->projects() ->with('basicInfo') ->whereIn('project_id', $projectIds) ->get(); } /** * 获取项目列表 * 根据条件获取系统项目或代理商项目 * * @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(); // 验证代理商分类状态 abort_if( $agentCate && ($agentCate->state != ProjectStatus::OPEN->value()), 404, '当前区域未开通服务' ); // 获取分页数据 $projects = $query->paginate($perPage); // 处理代理商设置 foreach ($projects as $project) { $this->mergeAgentSettings($project, $agent); } return $projects; } // 返回系统默认项目 return $query->paginate($perPage); } /** * 递归查找可用的代理商 * 从6位区域代码开始,每次去掉最后2位,直到找到代理商或只剩2位 * 查找规则: * 1. 先查找精确匹配的区域代码 * 2. 如果找不到,则去掉最后2位,查找上级区域 * 3. 重复步骤2直到只剩2位区域代码 * 4. 如果全部未找到则返回null * * @param string $areaCode 区域代码(2-6位数字) * @return Agent|null 返回找到的代理商或null * @throws \Exception 当查询过程中发生错误时抛出异常 */ private function findAvailableAgent($areaCode) { // 生成缓存键 $cacheKey = "agent:area:{$areaCode}"; return Cache::remember($cacheKey, 3600, function () use ($areaCode) { // 现有的查找逻辑 $fullAreaCode = str_pad($areaCode, 6, '0', STR_PAD_RIGHT); $agent = AgentInfo::where('area_code', $fullAreaCode) ->where('state', AgentStatus::ENABLE->value) ->where('audit_state', AgentAuditStatus::PASSED->value) ->first(); 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(); // 如果有设置则覆盖默认值 if ($agentProject) { $project->price = $agentProject->price ?? $project->price; $project->duration = $agentProject->duration ?? $project->duration; $project->distance = $agentProject->distance ?? $project->distance; } } }