user()->isAdmin() && !auth()->user()->isSuperAdmin()) { abort(403, '관리자만 접근할 수 있습니다.'); } } /** * 전체 고객 목록 페이지 */ public function index(Request $request): View|Response { $this->checkAdminAccess(); if ($request->header('HX-Request')) { return response('', 200)->header('HX-Redirect', route('sales.admin-prospects.index')); } // 영업 역할을 가진 사용자 목록 (영업파트너) $salesPartners = User::whereHas('userRoles', function ($q) { $q->whereHas('role', function ($rq) { $rq->whereIn('name', ['sales', 'manager', 'recruiter']); }); })->orderBy('name')->get(); // 필터 $filters = [ 'search' => $request->get('search'), 'status' => $request->get('status'), 'registered_by' => $request->get('registered_by'), // 특정 영업파트너 필터 ]; // 쿼리 빌드 $query = TenantProspect::with(['registeredBy', 'tenant']); // 검색 if (!empty($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('company_name', 'like', "%{$search}%") ->orWhere('business_number', 'like', "%{$search}%") ->orWhere('ceo_name', 'like', "%{$search}%") ->orWhere('contact_phone', 'like', "%{$search}%"); }); } // 상태 필터 if (!empty($filters['status'])) { $query->where('status', $filters['status']); } // 영업파트너 필터 if (!empty($filters['registered_by'])) { $query->where('registered_by', $filters['registered_by']); } $prospects = $query->orderByDesc('created_at')->paginate(20); // 각 가망고객의 진행률 계산 foreach ($prospects as $prospect) { $progress = SalesScenarioChecklist::getProspectProgress($prospect->id); $prospect->sales_progress = $progress['sales']['percentage']; $prospect->manager_progress = $progress['manager']['percentage']; // management 정보 $management = SalesTenantManagement::where('tenant_prospect_id', $prospect->id)->first(); $prospect->hq_status = $management?->hq_status ?? 'pending'; $prospect->hq_status_label = $management?->hq_status_label ?? '대기'; $prospect->manager_user = $management?->manager; } // 전체 통계 $stats = [ 'total' => TenantProspect::count(), 'active' => TenantProspect::where('status', TenantProspect::STATUS_ACTIVE)->count(), 'expired' => TenantProspect::where('status', TenantProspect::STATUS_EXPIRED)->count(), 'converted' => TenantProspect::where('status', TenantProspect::STATUS_CONVERTED)->count(), ]; // 영업파트너별 통계 $partnerStats = TenantProspect::selectRaw('registered_by, COUNT(*) as total') ->groupBy('registered_by') ->with('registeredBy') ->get() ->map(function ($item) { return [ 'user' => $item->registeredBy, 'total' => $item->total, ]; }); return view('sales.admin-prospects.index', compact('prospects', 'stats', 'salesPartners', 'partnerStats', 'filters')); } /** * 고객 상세 모달 */ public function modalShow(int $id): View { $this->checkAdminAccess(); $prospect = TenantProspect::with(['registeredBy', 'tenant'])->findOrFail($id); // 진행률 $progress = SalesScenarioChecklist::getProspectProgress($prospect->id); $prospect->sales_progress = $progress['sales']['percentage']; $prospect->manager_progress = $progress['manager']['percentage']; // management 정보 $management = SalesTenantManagement::findOrCreateByProspect($prospect->id); return view('sales.admin-prospects.partials.show-modal', compact('prospect', 'management', 'progress')); } /** * 개발 진행 상태 변경 */ public function updateHqStatus(int $id, Request $request) { $this->checkAdminAccess(); $request->validate([ 'hq_status' => 'required|in:' . implode(',', array_keys(SalesTenantManagement::$hqStatusLabels)), ]); $prospect = TenantProspect::findOrFail($id); $management = SalesTenantManagement::findOrCreateByProspect($prospect->id); $management->update([ 'hq_status' => $request->input('hq_status'), ]); return response()->json([ 'success' => true, 'hq_status' => $management->hq_status, 'hq_status_label' => $management->hq_status_label, ]); } }