123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- <?php
- namespace App\Services\Client;
- use App\Models\Project;
- use App\Models\AgentInfo;
- use App\Models\CoachUser;
- use App\Enums\AgentStatus;
- use App\Enums\ProjectType;
- use App\Models\ProjectCate;
- 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, $perPage = 10)
- {
- // 生成缓存键
- $cacheKey = "project:list:{$areaCode}:{$projectCateId}:{$type}:{$perPage}";
- return Cache::remember($cacheKey, 3600, function () use ($areaCode, $projectCateId, $type, $perPage) {
- // 获取并验证项目分类
- $projectCate = ProjectCate::find($projectCateId);
- abort_if(!$projectCate, 404, '项目分类不存在');
- abort_if($projectCate->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;
- }
- }
- }
|