- 가망고객 행을 별도 partial(prospect-row.blade.php)로 분리
- 매니저 드롭다운에서 선택 시 HTMX로 해당 행만 새로고침
- 컨트롤러에 getProspectRow 메서드 추가
- 라우트 추가: salesmanagement/dashboard/prospect/{id}/row
이제 매니저 지정 후 새로고침 없이 화면이 동적으로 업데이트됩니다.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
209 lines
12 KiB
PHP
209 lines
12 KiB
PHP
{{-- 가망고객 개별 행 (영업 진행중) --}}
|
|
@php
|
|
$prospectProgress = \App\Models\Sales\SalesScenarioChecklist::getProspectProgress($prospect->id);
|
|
$prospectManagement = \App\Models\Sales\SalesTenantManagement::findOrCreateByProspect($prospect->id);
|
|
|
|
// 계약 금액 정보 조회 (management_id 기반)
|
|
$prospectContractTotals = \App\Models\Sales\SalesContractProduct::where('management_id', $prospectManagement->id)
|
|
->selectRaw('SUM(registration_fee) as total_registration_fee, SUM(subscription_fee) as total_subscription_fee, COUNT(*) as product_count')
|
|
->first();
|
|
$prospectTotalRegFee = $prospectContractTotals->total_registration_fee ?? 0;
|
|
$prospectTotalSubFee = $prospectContractTotals->total_subscription_fee ?? 0;
|
|
$prospectProductCount = $prospectContractTotals->product_count ?? 0;
|
|
|
|
// 개발 진행 상태 (100% 완료 시 표시)
|
|
$prospectHqStatuses = \App\Models\Sales\SalesTenantManagement::$hqStatusLabels;
|
|
$prospectHqStatusOrder = \App\Models\Sales\SalesTenantManagement::$hqStatusOrder;
|
|
$prospectCurrentHqStep = $prospectHqStatusOrder[$prospectManagement->hq_status ?? 'pending'] ?? 0;
|
|
$isProspectHqEnabled = $prospectProgress['sales']['percentage'] >= 100 && $prospectProgress['manager']['percentage'] >= 100;
|
|
|
|
// 현재 사용자의 역할 확인
|
|
$currentUserId = auth()->id();
|
|
$isRegistrar = $prospect->registered_by === $currentUserId; // 영업권 등록자
|
|
$isManager = $prospectManagement->manager_user_id === $currentUserId; // 담당 매니저
|
|
$hasDifferentManager = $prospectManagement->manager_user_id && $prospectManagement->manager_user_id !== $currentUserId;
|
|
|
|
// 버튼 표시 여부
|
|
$showSalesButton = $isRegistrar; // 등록자만 영업 버튼
|
|
$showManagerButton = $isManager || (!$hasDifferentManager && $isRegistrar); // 매니저이거나, 다른 매니저 미지정 시 등록자
|
|
$showManagerProgress = $showManagerButton; // 매니저 프로그레스바도 동일
|
|
@endphp
|
|
<div class="prospect-row flex items-center gap-4 px-4 py-3 hover:bg-orange-50 transition-colors" data-prospect-id="{{ $prospect->id }}">
|
|
<!-- 업체명 및 정보 + 매니저 드롭다운 + 영업/매니저 버튼 -->
|
|
<div class="flex items-center gap-3 flex-shrink-0">
|
|
<div class="min-w-0">
|
|
<div class="flex items-center gap-2">
|
|
<div class="font-bold text-gray-900 truncate">{{ $prospect->company_name }}</div>
|
|
<span class="px-2 py-0.5 text-xs font-medium rounded-full {{ $prospect->status_color }}">
|
|
{{ $prospect->status_label }}
|
|
</span>
|
|
</div>
|
|
<div class="text-xs text-gray-500 mt-0.5">
|
|
@if($prospect->ceo_name)
|
|
<span>대표: {{ $prospect->ceo_name }}</span>
|
|
<span class="mx-1">|</span>
|
|
@endif
|
|
<span>{{ $prospect->business_number ?? '-' }}</span>
|
|
</div>
|
|
</div>
|
|
{{-- 매니저 드롭다운 --}}
|
|
<div class="flex-shrink-0">
|
|
@include('sales.dashboard.partials.manager-dropdown', ['prospect' => $prospect, 'prospectManagement' => $prospectManagement])
|
|
</div>
|
|
{{-- 영업/매니저 진행 버튼 --}}
|
|
<div class="flex-shrink-0 flex items-center gap-1">
|
|
@if($showSalesButton)
|
|
<button
|
|
x-on:click="openProspectScenarioModal({{ $prospect->id }}, 'sales')"
|
|
class="inline-flex items-center gap-1 px-2 py-1 rounded text-xs font-medium bg-blue-600 text-white hover:bg-blue-700 transition-colors"
|
|
title="영업 시나리오">
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
|
</svg>
|
|
영업
|
|
</button>
|
|
@endif
|
|
@if($showManagerButton)
|
|
<button
|
|
x-on:click="openProspectScenarioModal({{ $prospect->id }}, 'manager')"
|
|
class="inline-flex items-center gap-1 px-2 py-1 rounded text-xs font-medium bg-green-600 text-white hover:bg-green-700 transition-colors"
|
|
title="매니저 시나리오">
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
매니저
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 진행 현황 (영업/매니저 프로그레스 바) -->
|
|
<div class="flex-1 min-w-0 flex items-center gap-4" id="prospect-progress-{{ $prospect->id }}">
|
|
{{-- 영업/매니저 프로그레스 바 --}}
|
|
<div class="flex-1 space-y-1">
|
|
{{-- 영업 (등록자에게만 표시) --}}
|
|
@if($showSalesButton)
|
|
<div class="flex items-center gap-1" title="영업 {{ $prospectProgress['sales']['percentage'] }}%">
|
|
<span class="text-xs font-medium text-blue-600 w-5 flex-shrink-0">영</span>
|
|
<div class="flex-1 bg-gray-200 rounded-full h-1.5 min-w-0">
|
|
<div class="bg-blue-500 h-1.5 rounded-full transition-all" id="prospect-sales-bar-{{ $prospect->id }}" style="width: {{ $prospectProgress['sales']['percentage'] }}%"></div>
|
|
</div>
|
|
<span class="text-xs text-gray-500 w-8 text-right flex-shrink-0" id="prospect-sales-pct-{{ $prospect->id }}">{{ $prospectProgress['sales']['percentage'] }}%</span>
|
|
</div>
|
|
@endif
|
|
{{-- 매니저 (매니저에게만 표시) --}}
|
|
@if($showManagerProgress)
|
|
<div class="flex items-center gap-1" title="매니저 {{ $prospectProgress['manager']['percentage'] }}%">
|
|
<span class="text-xs font-medium text-green-600 w-5 flex-shrink-0">매</span>
|
|
<div class="flex-1 bg-gray-200 rounded-full h-1.5 min-w-0">
|
|
<div class="bg-green-500 h-1.5 rounded-full transition-all" id="prospect-manager-bar-{{ $prospect->id }}" style="width: {{ $prospectProgress['manager']['percentage'] }}%"></div>
|
|
</div>
|
|
<span class="text-xs text-gray-500 w-8 text-right flex-shrink-0" id="prospect-manager-pct-{{ $prospect->id }}">{{ $prospectProgress['manager']['percentage'] }}%</span>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- 구분선 --}}
|
|
<div class="w-px h-8 bg-gray-200 flex-shrink-0"></div>
|
|
|
|
{{-- 개발 진행 상태 --}}
|
|
<div class="flex-1 min-w-0">
|
|
@if($isProspectHqEnabled)
|
|
{{-- 영업/매니저 100% 완료: 개발 진행 상태 표시 --}}
|
|
<div class="flex items-center gap-3">
|
|
{{-- 8단계 프로그레스 바 --}}
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-0.5">
|
|
@foreach($prospectHqStatuses as $statusKey => $statusLabel)
|
|
@php
|
|
$stepNum = $prospectHqStatusOrder[$statusKey];
|
|
$isCompleted = $stepNum < $prospectCurrentHqStep;
|
|
$isCurrent = $stepNum === $prospectCurrentHqStep;
|
|
@endphp
|
|
<div class="group relative flex-1">
|
|
<div class="h-2.5 rounded-sm transition-all {{ $isCompleted ? 'bg-purple-500' : ($isCurrent ? 'bg-purple-300' : 'bg-gray-100') }}"></div>
|
|
<div class="absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap z-10 pointer-events-none">
|
|
{{ $statusLabel }}
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
{{-- 현재 상태 배지 --}}
|
|
<span class="flex-shrink-0 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium
|
|
@if($prospectManagement->hq_status === 'handover') bg-emerald-100 text-emerald-700
|
|
@elseif($prospectManagement->hq_status === 'pending') bg-yellow-100 text-yellow-700
|
|
@else bg-purple-100 text-purple-700 @endif">
|
|
{{ $prospectManagement->hq_status_label }}
|
|
</span>
|
|
</div>
|
|
@else
|
|
{{-- 아직 100% 미완료: 비활성 상태 --}}
|
|
<div class="flex items-center gap-3">
|
|
{{-- 비활성 프로그래스 바 --}}
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-0.5">
|
|
@for($i = 0; $i < 8; $i++)
|
|
<div class="flex-1 h-2.5 rounded-sm bg-gray-100"></div>
|
|
@endfor
|
|
</div>
|
|
</div>
|
|
{{-- 대기 배지 --}}
|
|
<span class="flex-shrink-0 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-orange-100 text-orange-600">
|
|
영업 진행중
|
|
</span>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 계약 금액 정보 -->
|
|
<div class="flex-shrink-0 text-right border-l border-gray-200 pl-4">
|
|
@if($prospectProductCount > 0)
|
|
<div class="space-y-0.5">
|
|
<div>
|
|
<p class="text-xs text-gray-400">개발비</p>
|
|
<p class="text-sm font-bold text-indigo-600">₩{{ number_format($prospectTotalRegFee) }}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs text-gray-400">월 구독료</p>
|
|
<p class="text-sm font-bold text-green-600">₩{{ number_format($prospectTotalSubFee) }}</p>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<div class="space-y-0.5">
|
|
<p class="text-xs text-gray-400">계약상품</p>
|
|
<p class="text-sm font-medium text-gray-300">미선택</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- 영업권 유효기간 (100% 달성 시 표시 안함) -->
|
|
@php
|
|
$isFullyCompleted = $prospectProgress['sales']['percentage'] >= 100 && $prospectProgress['manager']['percentage'] >= 100;
|
|
@endphp
|
|
@if(!$isFullyCompleted)
|
|
<div class="flex-shrink-0 text-center border-l border-gray-200 pl-4">
|
|
@if($prospect->isActive())
|
|
<div class="text-xs text-gray-400">영업권 만료</div>
|
|
<div class="text-lg font-bold text-orange-600">D-{{ $prospect->remaining_days }}</div>
|
|
@elseif($prospect->isExpired())
|
|
<div class="text-xs text-gray-400">상태</div>
|
|
<div class="text-sm font-medium text-gray-500">만료됨</div>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
<!-- 고객 관리 바로가기 -->
|
|
<div class="flex-shrink-0 border-l border-gray-200 pl-4">
|
|
<a href="{{ route('sales.prospects.index') }}?search={{ $prospect->business_number }}"
|
|
class="inline-flex items-center gap-1 px-3 py-1.5 rounded text-xs font-medium bg-gray-600 text-white hover:bg-gray-700 transition-colors">
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
</svg>
|
|
상세
|
|
</a>
|
|
</div>
|
|
</div>
|