feat:영업파트너 고객관리 인계일 컬럼 동적 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-19 16:27:12 +09:00
parent 4ddc1efa34
commit 6a7a8d00d0
5 changed files with 93 additions and 4 deletions

View File

@@ -192,6 +192,7 @@ private function getIndexData(Request $request): array
$prospect->hq_status_label = $management?->hq_status_label ?? '대기'; $prospect->hq_status_label = $management?->hq_status_label ?? '대기';
$prospect->manager_user = $management?->manager; $prospect->manager_user = $management?->manager;
$prospect->contracted_at = $management?->contracted_at; $prospect->contracted_at = $management?->contracted_at;
$prospect->handover_at = $management?->handover_at;
$prospect->commission = $this->loadMergedCommission($management); $prospect->commission = $this->loadMergedCommission($management);
@@ -239,6 +240,7 @@ private function getIndexData(Request $request): array
$prospect->hq_status_label = $management?->hq_status_label ?? '대기'; $prospect->hq_status_label = $management?->hq_status_label ?? '대기';
$prospect->manager_user = $management?->manager; $prospect->manager_user = $management?->manager;
$prospect->contracted_at = $management?->contracted_at; $prospect->contracted_at = $management?->contracted_at;
$prospect->handover_at = $management?->handover_at;
// 수당 정보 (management가 있는 경우) // 수당 정보 (management가 있는 경우)
$prospect->commission = $this->loadMergedCommission($management); $prospect->commission = $this->loadMergedCommission($management);
@@ -301,14 +303,47 @@ public function updateHqStatus(int $id, Request $request)
$prospect = TenantProspect::findOrFail($id); $prospect = TenantProspect::findOrFail($id);
$management = SalesTenantManagement::findOrCreateByProspect($prospect->id); $management = SalesTenantManagement::findOrCreateByProspect($prospect->id);
$management->update([ $newStatus = $request->input('hq_status');
'hq_status' => $request->input('hq_status'), $updateData = ['hq_status' => $newStatus];
]);
// 인계로 변경 시 오늘 날짜 자동 세팅, 다른 상태로 변경 시 초기화
if ($newStatus === SalesTenantManagement::HQ_STATUS_HANDOVER) {
$updateData['handover_at'] = now();
} else {
$updateData['handover_at'] = null;
}
$management->update($updateData);
return response()->json([ return response()->json([
'success' => true, 'success' => true,
'hq_status' => $management->hq_status, 'hq_status' => $management->hq_status,
'hq_status_label' => $management->hq_status_label, 'hq_status_label' => $management->hq_status_label,
'handover_at' => $management->handover_at?->format('Y-m-d'),
]);
}
/**
* 인계일 수동 변경
*/
public function updateHandoverDate(int $id, Request $request)
{
$this->checkAdminAccess();
$request->validate([
'handover_at' => 'required|date',
]);
$prospect = TenantProspect::findOrFail($id);
$management = SalesTenantManagement::findOrCreateByProspect($prospect->id);
$management->update([
'handover_at' => $request->input('handover_at'),
]);
return response()->json([
'success' => true,
'handover_at' => $management->handover_at?->format('Y-m-d'),
]); ]);
} }

View File

@@ -60,6 +60,7 @@ class SalesTenantManagement extends Model
'sales_progress', 'sales_progress',
'manager_progress', 'manager_progress',
'hq_status', 'hq_status',
'handover_at',
'incentive_status', 'incentive_status',
'notes', 'notes',
// 입금 정보 // 입금 정보
@@ -85,6 +86,7 @@ class SalesTenantManagement extends Model
'onboarding_completed_at' => 'datetime', 'onboarding_completed_at' => 'datetime',
'membership_paid_at' => 'datetime', 'membership_paid_at' => 'datetime',
'commission_paid_at' => 'datetime', 'commission_paid_at' => 'datetime',
'handover_at' => 'datetime',
// 입금 정보 // 입금 정보
'deposit_amount' => 'decimal:2', 'deposit_amount' => 'decimal:2',
'deposit_paid_date' => 'date', 'deposit_paid_date' => 'date',

View File

@@ -219,6 +219,20 @@ function updateHqStatus(prospectId, status) {
selectEl.className += 'bg-purple-100 text-purple-700 border-purple-300'; selectEl.className += 'bg-purple-100 text-purple-700 border-purple-300';
} }
selectEl.dataset.originalValue = status; selectEl.dataset.originalValue = status;
// 인계일 셀 동적 업데이트
const handoverCell = document.getElementById(`handover-cell-${prospectId}`);
if (handoverCell) {
if (status === 'handover' && result.handover_at) {
handoverCell.innerHTML = `<input type="date"
id="handover-date-${prospectId}"
class="w-28 h-7 text-xs px-1 border-2 border-emerald-300 rounded cursor-pointer hover:border-emerald-400 focus:outline-none focus:border-emerald-500 text-emerald-600 font-medium bg-emerald-50"
value="${result.handover_at}"
onchange="saveHandoverDate(${prospectId}, this.value)">`;
} else {
handoverCell.innerHTML = `<span class="text-sm text-gray-400">-</span>`;
}
}
} else { } else {
alert('상태 변경에 실패했습니다.'); alert('상태 변경에 실패했습니다.');
selectEl.value = originalValue; selectEl.value = originalValue;
@@ -336,6 +350,31 @@ function confirmDelete() {
}); });
} }
// 인계일 저장
function saveHandoverDate(prospectId, date) {
if (!date) return;
fetch(`/sales/admin-prospects/${prospectId}/handover-date`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'Accept': 'application/json'
},
body: JSON.stringify({ handover_at: date })
})
.then(response => response.json())
.then(result => {
if (!result.success) {
alert(result.message || '인계일 저장에 실패했습니다.');
}
})
.catch(error => {
console.error('Error:', error);
alert('인계일 저장 중 오류가 발생했습니다.');
});
}
// 납입 날짜 저장 (date input에서 호출) // 납입 날짜 저장 (date input에서 호출)
function saveCommissionDate(prospectId, field, date) { function saveCommissionDate(prospectId, field, date) {
const input = document.querySelector(`input[data-prospect-id="${prospectId}"][data-field="${field}"]`); const input = document.querySelector(`input[data-prospect-id="${prospectId}"][data-field="${field}"]`);

View File

@@ -93,6 +93,7 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none foc
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">1 납입</th> <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">1 납입</th>
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">2 납입</th> <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">2 납입</th>
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">개발 상태</th> <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">개발 상태</th>
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">인계일</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">상태</th> <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">상태</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">관리</th> <th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">관리</th>
</tr> </tr>
@@ -185,6 +186,17 @@ class="text-xs font-medium rounded-lg px-2 py-1 border cursor-pointer
@endforeach @endforeach
</select> </select>
</td> </td>
<td class="px-2 py-3 whitespace-nowrap text-center" id="handover-cell-{{ $prospect->id }}">
@if($prospect->hq_status === 'handover')
<input type="date"
id="handover-date-{{ $prospect->id }}"
class="w-28 h-7 text-xs px-1 border-2 border-emerald-300 rounded cursor-pointer hover:border-emerald-400 focus:outline-none focus:border-emerald-500 text-emerald-600 font-medium bg-emerald-50"
value="{{ $prospect->handover_at ? \Carbon\Carbon::parse($prospect->handover_at)->format('Y-m-d') : '' }}"
onchange="saveHandoverDate({{ $prospect->id }}, this.value)">
@else
<span class="text-sm text-gray-400">-</span>
@endif
</td>
<td class="px-4 py-3 whitespace-nowrap"> <td class="px-4 py-3 whitespace-nowrap">
@if(in_array($prospect->status, ['active', 'completed'])) @if(in_array($prospect->status, ['active', 'completed']))
<button type="button" <button type="button"
@@ -217,7 +229,7 @@ class="text-red-500 hover:text-red-700"
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="12" class="px-6 py-12 text-center text-gray-500"> <td colspan="13" class="px-6 py-12 text-center text-gray-500">
등록된 고객이 없습니다. 등록된 고객이 없습니다.
</td> </td>
</tr> </tr>

View File

@@ -1253,6 +1253,7 @@
Route::get('admin-prospects/refresh', [\App\Http\Controllers\Sales\AdminProspectController::class, 'refresh'])->name('admin-prospects.refresh'); Route::get('admin-prospects/refresh', [\App\Http\Controllers\Sales\AdminProspectController::class, 'refresh'])->name('admin-prospects.refresh');
Route::get('admin-prospects/{id}/modal-show', [\App\Http\Controllers\Sales\AdminProspectController::class, 'modalShow'])->name('admin-prospects.modal-show'); Route::get('admin-prospects/{id}/modal-show', [\App\Http\Controllers\Sales\AdminProspectController::class, 'modalShow'])->name('admin-prospects.modal-show');
Route::post('admin-prospects/{id}/hq-status', [\App\Http\Controllers\Sales\AdminProspectController::class, 'updateHqStatus'])->name('admin-prospects.update-hq-status'); Route::post('admin-prospects/{id}/hq-status', [\App\Http\Controllers\Sales\AdminProspectController::class, 'updateHqStatus'])->name('admin-prospects.update-hq-status');
Route::post('admin-prospects/{id}/handover-date', [\App\Http\Controllers\Sales\AdminProspectController::class, 'updateHandoverDate'])->name('admin-prospects.update-handover-date');
Route::post('admin-prospects/{id}/commission-date', [\App\Http\Controllers\Sales\AdminProspectController::class, 'updateCommissionDate'])->name('admin-prospects.update-commission-date'); Route::post('admin-prospects/{id}/commission-date', [\App\Http\Controllers\Sales\AdminProspectController::class, 'updateCommissionDate'])->name('admin-prospects.update-commission-date');
Route::delete('admin-prospects/{id}/commission-date', [\App\Http\Controllers\Sales\AdminProspectController::class, 'clearCommissionDate'])->name('admin-prospects.clear-commission-date'); Route::delete('admin-prospects/{id}/commission-date', [\App\Http\Controllers\Sales\AdminProspectController::class, 'clearCommissionDate'])->name('admin-prospects.clear-commission-date');
Route::delete('admin-prospects/{id}', [\App\Http\Controllers\Sales\AdminProspectController::class, 'destroy'])->name('admin-prospects.destroy')->middleware('super.admin'); Route::delete('admin-prospects/{id}', [\App\Http\Controllers\Sales\AdminProspectController::class, 'destroy'])->name('admin-prospects.destroy')->middleware('super.admin');