feat:영업파트너 고객관리 인계일 컬럼 동적 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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}"]`);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
Reference in New Issue
Block a user